1#############################################################################
2##
3#W  matdisp.g             GAP 4 package `browse'                Thomas Breuer
4##
5#Y  Copyright (C)  2011,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany
6##
7
8
9#############################################################################
10##
11#F  NCurses.BrowseDenseList( <list>, <arec> )
12#M  Browse( <list> )
13##
14##  <#GAPDoc Label="Matrix_section">
15##  <Section Label="sec:matrixdisp">
16##  <Heading>Matrix Display</Heading>
17##
18##  The &GAP; library provides several <Ref Oper="Display" BookName="ref"/>
19##  methods for matrices.
20##  In order to cover the functionality of these methods,
21##  &Browse; provides the function <Ref Func="NCurses.BrowseDenseList"/>
22##  that uses the standard facilities of the function
23##  <Ref Func="NCurses.BrowseGeneric"/>, i.&nbsp;e.,
24##  one can scroll in the matrix, searching and sorting are provided etc.
25##  <P/>
26##  The idea is to customize this function for different special cases,
27##  and to install corresponding <Ref Oper="Browse"/> methods.
28##  Examples are methods for matrices over finite fields and residue
29##  class rings of the rational integers,
30##  see <Ref Meth="Browse" Label="for a list of lists"/>.
31##  <P/>
32##  The code can be found in the file <F>app/matdisp.g</F> of the package.
33##
34##  <ManSection>
35##  <Func Name="NCurses.BrowseDenseList" Arg="list, arec"/>
36##
37##  <Returns>
38##  nothing.
39##  </Returns>
40##
41##  <Description>
42##  Let <A>list</A> be a dense list whose entries are lists,
43##  for example a matrix, and let <A>arec</A> be a record.
44##  This function displays <A>list</A> in a window, as a two-dimensional
45##  array with row and column positions as row and column labels,
46##  respectively.
47##  <P/>
48##  The following components of <A>arec</A> are supported.
49##  <List>
50##  <Mark><C>header</C></Mark>
51##  <Item>
52##    If bound, the value must be a valid value of the <C>work.header</C>
53##    component of a browse table,
54##    see <Ref Func="BrowseData.IsBrowseTable"/>;
55##    for example, the value can be a list of strings.
56##    If this component is not bound then the browse table has no header.
57##  </Item>
58##  <Mark><C>convertEntry</C></Mark>
59##  <Item>
60##    If bound, the value must be a unary function that returns a string
61##    describing its argument.
62##    The default is the operation <Ref Func="String" BookName="ref"/>.
63##    Another possible value is <C>NCurses.ReplaceZeroByDot</C>, which
64##    returns the string <C>"."</C> if the argument is a zero element
65##    in the sense of <Ref Func="IsZero" BookName="ref"/>,
66##    and returns the <Ref Func="String" BookName="ref"/> value otherwise.
67##    For each entry in a row of <A>list</A>, the <C>convertEntry</C> value
68##    is shown in the browse table.
69##  </Item>
70##  <Mark><C>labelsRow</C></Mark>
71##  <Item>
72##    If bound, the value must be a list of row label rows for
73##    <A>list</A>, as described in Section
74##    <Ref Func="BrowseData.IsBrowseTable"/>.
75##    The default is <C>[ [ "1" ], [ "2" ], ... ]</C>.
76##  </Item>
77##  <Mark><C>labelsCol</C></Mark>
78##  <Item>
79##    If bound, the value must be a list of column label rows for
80##    <A>list</A>, as described in Section
81##    <Ref Func="BrowseData.IsBrowseTable"/>.
82##    The default is <C>[ [ "1", "2", ... ] ]</C>.
83##  </Item>
84##  </List>
85##  <P/>
86##  The full functionality of the function
87##  <Ref Func="NCurses.BrowseGeneric"/> is available.
88##  </Description>
89##  </ManSection>
90##
91##  <ManSection>
92##  <Meth Name="Browse" Arg="list" Label="for a list of lists"/>
93##
94##  <Returns>
95##  nothing.
96##  </Returns>
97##
98##  <Description>
99##  Several methods for the operation <Ref Oper="Browse"/> are installed for
100##  the case that the argument is a list of lists.
101##  These methods cover a default method for lists of lists and the
102##  <Ref Oper="Display" BookName="ref"/> methods for matrices over
103##  finite fields and residue class rings of the rational integers.
104##  Note that matrices over finite prime fields, small extension fields, and
105##  large extension fields are displayed differently,
106##  and the same holds for the corresponding <Ref Oper="Browse"/> methods.
107##  <P/>
108##  <Example><![CDATA[
109##  gap> n:= [ 14, 14, 14, 14 ];;
110##  gap> input:= Concatenation( n, n, n, "Q" );;  # ``do nothing and quit''
111##  gap> BrowseData.SetReplay( input );
112##  gap> Browse( RandomMat( 10, 10, Integers ) );
113##  gap> BrowseData.SetReplay( input );
114##  gap> Browse( RandomMat( 10, 10, GF(3) ) );
115##  gap> BrowseData.SetReplay( input );
116##  gap> Browse( RandomMat( 10, 10, GF(4) ) );
117##  gap> BrowseData.SetReplay( input );
118##  gap> Browse( RandomMat( 10, 10, Integers mod 6 ) );
119##  gap> BrowseData.SetReplay( input );
120##  gap> Browse( RandomMat( 10, 10, GF( NextPrimeInt( 2^16 ) ) ) );
121##  gap> BrowseData.SetReplay( input );
122##  gap> Browse( RandomMat( 10, 10, GF( 2^20 ) ) );
123##  gap> BrowseData.SetReplay( false );
124##  ]]></Example>
125##  </Description>
126##  </ManSection>
127##  </Section>
128##  <#/GAPDoc>
129##
130NCurses.ReplaceZeroByDot:= function( val )
131    if IsZero( val ) then
132      return ".";
133    else
134      return String( val );
135    fi;
136    end;
137
138NCurses.BrowseDenseList:= function( list, arec )
139      local m, n, r;
140
141      if IsEmpty( list ) or not ForAll( list, IsList ) then
142        TryNextMethod();
143      fi;
144
145      m:= Length( list );
146      n:= Maximum( List( list, Length ) );
147
148      # Create the default table.
149      r:= rec(
150        work:= rec(
151          align:= "c",
152
153          # Avoid computing strings for all entries in advance.
154          main:= [],
155          Main:= function( t, i, j )
156            if IsBound( list[i][j] ) then
157              return r.work.convertEntry( list[i][j] );
158            else
159              return "";
160            fi;
161          end,
162          m:= m,
163          n:= n,
164
165          labelsRow:= List( [ 1 .. m ], i -> [ String( i ) ] ),
166          labelsCol:= [ List( [ 1 .. n ], String ) ],
167          sepLabelsCol:= [ "", "-" ],
168          sepLabelsRow:= [ "", " |" ],
169          sepCol:= Concatenation( List( [ 1 .. n ], x -> " " ), [ "" ] ),
170          SpecialGrid:= BrowseData.SpecialGridLineDrawPlus,
171        ),
172      );
173
174      # Customize the browse table.
175      if IsBound( arec.header ) then
176        r.work.header:= arec.header;
177      fi;
178      if IsBound( arec.labelsRow ) then
179        r.work.labelsRow:= arec.labelsRow;
180      fi;
181      if IsBound( arec.labelsCol ) then
182        r.work.labelsCol:= arec.labelsCol;
183      fi;
184      if IsBound( arec.convertEntry ) then
185        r.work.convertEntry:= arec.convertEntry;
186      else
187        r.work.convertEntry:= String;
188#T support a user default
189      fi;
190
191      NCurses.BrowseGeneric( r );
192    end;
193
194
195##########################################################################
196##
197#M  Browse( <list> )
198##
199##  The default just shows row and column labels.
200##  The table has no header, and `String' is used to convert entries.
201##
202InstallMethod( Browse,
203    [ "IsDenseList" ],
204    function( list )
205      NCurses.BrowseDenseList( list, rec() );
206    end );
207
208
209##########################################################################
210##
211#M  Browse( <ffe-mat> )
212##
213##  This method corresponds to the `Display' method from `lib/matrix.gi'
214##  that is installed with the condition "IsFFECollColl and IsMatrix".
215##
216InstallMethod( Browse,
217    [ "IsFFECollColl and IsMatrix" ],
218    function( m )
219    local deg, chr, q, z;
220
221    if Length( m[1] ) = 0 then
222      TryNextMethod();
223    fi;
224
225    if IsZmodnZObj( m[1][1] ) then
226      NCurses.BrowseDenseList( List( m, r -> List( r, i -> i![1] ) ),
227          rec( header:= [ Concatenation( "matrix over Integers mod ",
228                              String( Characteristic( m[1][1] ) ) ),
229                          "" ],
230               convertEntry:= NCurses.ReplaceZeroByDot,
231             ) );
232    else
233      # get the degree and characteristic
234      deg:= Lcm( List( m, DegreeFFE ) );
235      chr:= Characteristic( m[1][1] );
236
237      if deg = 1 then
238        # if it is a finite prime field, use integers for display
239        NCurses.BrowseDenseList( m,
240            rec( header:= [ Concatenation( "matrix over prime field GF(",
241                                String( chr ), ")" ), "" ],
242                 convertEntry:= function( val )
243                   val:= IntFFE( val );
244                   if val = 0 then
245                     return ".";
246                   else
247                     return String( val );
248                   fi;
249                 end,
250               ) );
251      else
252        # if it is a finite extension field, use mixed integers/z notation
253        q:= chr^deg;
254        z:= Z(q);
255
256        NCurses.BrowseDenseList( m,
257            rec( header:= [ Concatenation( "finite field matrix, z = Z(",
258                                String( q ), ")" ), "" ],
259                 convertEntry:= function( val )
260                   if DegreeFFE( val ) = 1 then
261                     val:= IntFFE( val );
262                     if val = 0 then
263                       return ".";
264                     else
265                       return String( val );
266                     fi;
267                   else
268                     return Concatenation( "z^", String( LogFFE( val, z ) ) );
269                   fi;
270                 end,
271               ) );
272      fi;
273    fi;
274    end );
275
276
277##########################################################################
278##
279#M  Browse( <ZmodnZ-mat> )
280##
281##  This method corresponds to the `Display' method from `lib/matrix.gi'
282##  that is installed with the condition
283##  "IsZmodnZObjNonprimeCollColl and IsMatrix".
284##
285InstallMethod( Browse,
286    [ "IsZmodnZObjNonprimeCollColl and IsMatrix" ],
287    function( m )
288    local deg, chr, q, z;
289
290    if Length( m[1] ) = 0 then
291      TryNextMethod();
292    fi;
293
294    NCurses.BrowseDenseList( List( m, r -> List( r, i -> i![1] ) ),
295        rec( header:= [ Concatenation( "matrix over Integers mod ",
296                            String( Characteristic( m[1][1] ) ) ),
297                        "" ],
298             convertEntry:= NCurses.ReplaceZeroByDot,
299           ) );
300    end );
301
302
303##########################################################################
304##
305#M  Browse( <ffe-mat> )
306##
307##  This method corresponds to the `Display' method from `lib/ffeconway.gi'
308##  that is installed with the condition "IsFFECollColl and IsMatrix".
309##
310InstallMethod( Browse,
311    [ "IsFFECollColl and IsMatrix" ], 10, # prefer this to existing method
312    function(m)
313    local deg, chr;
314
315    if Length( m ) = 0 or Length( m[1] ) = 0 then
316      TryNextMethod();
317    fi;
318
319    deg:= Lcm( List( m, DegreeFFE ) );
320    chr:= Characteristic( m[1][1] );
321    if deg = 1 or chr^deg <= MAXSIZE_GF_INTERNAL then
322      TryNextMethod();
323    fi;
324
325    NCurses.BrowseDenseList( m,
326        rec( header:= [ Concatenation( "finite field matrix, z = Z(",
327                            String( chr ), ", ", String( deg ),
328                            "); z2 = z^2, etc." ), "" ],
329             convertEntry:= function( val )
330               local s, y, j, a;
331
332               if IsZero( val ) then
333                 return ".";
334               else
335                 s:= "";
336                 y:= FFECONWAY.WriteOverLargerField( val, deg );
337                 for j in [ 0 .. deg-1 ] do
338                   a:= IntFFE( y![1][j+1] );
339                   if a <> 0 then
340                     if Length( s ) <> 0 then
341                       Append( s, "+" );
342                     fi;
343                     if a <> 1 then
344                       Append( s, String( a ) );
345                     fi;
346                     if j <> 0 then
347                       Append( s, "z" );
348                       if j <> 1 then
349                         Append( s, String( j ) );
350                       fi;
351                     fi;
352                   fi;
353                 od;
354                 return s;
355               fi;
356             end ) );
357    end );
358
359
360#############################################################################
361##
362#E
363
364