home *** CD-ROM | disk | FTP | other *** search
/ Math Solutions 1995 October / Math_Solutions_CD-ROM_Walnut_Creek_October_1995.iso / pc / mac / discrete / lib / ctgapmoc.g < prev    next >
Encoding:
Text File  |  1993-05-05  |  48.4 KB  |  1,462 lines

  1. #############################################################################
  2. ##
  3. #A  ctgapmoc.g                  GAP library                     Thomas Breuer
  4. ##
  5. #A  @(#)$Id: ctgapmoc.g,v 3.4 1992/12/23 16:33:06 sam Rel $
  6. ##
  7. #Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  8. ##
  9. ##  This file contains functions used for conversion of GAP tables
  10. ##  to MOC format.
  11. ##
  12. #H  $Log: ctgapmoc.g,v $
  13. #H  Revision 3.4  1992/12/23  16:33:06  sam
  14. #H  fixed minor bug
  15. #H
  16. #H  Revision 3.3  1992/12/03  13:34:46  sam
  17. #H  fixed bug in 'PrintToMOC'
  18. #H
  19. #H  Revision 3.2  1992/11/16  12:36:38  jmueller
  20. #H  changed 'PrintToMOC' in case of <tbl>, <chars>
  21. #H
  22. #H  Revision 3.1  1992/08/12  15:08:51  sam
  23. #H  corrected encoding of MOC3 numbers
  24. #H
  25. #H  Revision 3.0  1992/08/12  13:26:24  sam
  26. #H  initial revision under RCS
  27. #H
  28. ##
  29.  
  30. #############################################################################
  31. ##
  32. #F  FieldInfo( <F> )
  33. ##
  34. ##  returns for a number field <F> a record with components
  35. ##  'nofcyc'  : the conductor of <F>,
  36. ##  'repres'  : a list of orbit representatives forming the Parker base
  37. ##              of the number field,
  38. ##  'stabil'  : a smallest generating system of the stabilizer, and
  39. ##  'MOCfield': the field with the Parker as 'base' component.
  40. ##
  41. FieldInfo := function( F )
  42.     local i, j, n, orbits, cycs, coeffs, base, repres, rank, max, pos,
  43.           sub, sub2, stabil, elm, numbers, orb, orders, gens;
  44.  
  45.     if F = Rationals then
  46.       return rec( nofcyc:= 1,
  47.                   repres:= [ 0 ],
  48.                   stabil:= [],
  49.                   MOCfield:= Rationals );
  50.     fi;
  51.  
  52.     n:= NofCyc( F.generators );
  53.  
  54.     # representatives of orbits under the action of 'F.stabilizer'
  55.     # on '[ 0 .. n ]'
  56.     numbers:= [ 0 .. n-1 ];
  57.     orbits:= [];
  58.     while numbers <> [] do
  59.       orb:= Set( List( numbers[1] * F.stabilizer, x -> x mod n ) );
  60.       Add( orbits, orb );
  61.       SubtractSet( numbers, orb );
  62.     od;
  63.  
  64.     # orbitsums under the corresponding action on 'n'--th roots of unity
  65.     cycs:= List( orbits, x -> Sum( x, y -> E(n)^y ) );
  66.     coeffs:= List( cycs, x -> CoeffsCyc( x, n ) );
  67.  
  68.     # the Parker base
  69.     gens:= [ 1 ];
  70.     base:= [ coeffs[1] ];
  71.     repres:= [ 0 ];
  72.     rank:= 1;
  73.  
  74. # besser 'while' !!
  75.  
  76.     for i in [ 1 .. Length( coeffs ) ] do
  77.       if RankMat( Union( base, [ coeffs[i] ] ) ) > rank then
  78.         rank:= rank + 1;
  79.         Add( gens, cycs[i] );
  80.         Add( base, coeffs[i] );
  81.         Add( repres, orbits[i][1] );
  82.       else
  83.  
  84. # weg !!
  85.  
  86.         Unbind( cycs[i] );
  87.         Unbind( coeffs[i] );
  88.         Unbind( orbits[i] );
  89.       fi;
  90.     od;
  91.  
  92.     # compute small generating system for the stabilizer:
  93.     # Start with the empty generating system.
  94.     # Add the smallest number of maximal multiplicative order to
  95.     # the generating system, remove all points in the new group.
  96.     # Proceed until one has a generating system for the stabilizer.
  97.     orders:= List( F.stabilizer, x -> OrderMod( x, n ) );
  98.     orders[1]:= 0;
  99.     max:= Maximum( orders );
  100.     stabil:= [];
  101.     sub:= [ 1 ];
  102.     while max <> 0 do
  103.       pos:= Position( orders, max );
  104.       elm:= F.stabilizer[ pos ];
  105.       AddSet( stabil, elm );
  106.       sub2:= sub;
  107.       for i in [ 1 .. max-1 ] do
  108.         sub2:= Union( sub2, List( sub, x -> ( x * elm^i ) mod n ) );
  109.       od;
  110.       sub:= sub2;
  111.       for j in sub do
  112.         orders[ Position( F.stabilizer, j ) ]:= 0;
  113.       od;
  114.       max:= Maximum( orders );
  115.     od;
  116.  
  117.     return rec( nofcyc:= n,
  118.                 repres:= repres,
  119.                 stabil:= stabil,
  120.                 MOCfield:= NF( 0, gens ) );
  121.     end;
  122.  
  123.  
  124. #############################################################################
  125. ##
  126. #F  Subfields( <F> )
  127. ##
  128. ##  returns the list of subfields of the number field <F>
  129. ##
  130. Subfields := function( F )
  131.     local n, cl;
  132.     if not IsNumberField( F ) then Error( "<F> must be a number field" ); fi;
  133.     n:= NofCyc( F.generators );
  134.     cl:= ConjugacyClassesSubgroups( GaloisGroup( F ) );
  135.     cl:= List( cl, x -> List( Elements( x.representative), y -> y.galois ) );
  136.     return List( cl, x -> NF( n, x ) );
  137.     end;
  138.  
  139.  
  140. #############################################################################
  141. ##
  142. #F  MAKElb11( <listofns> )
  143. ##
  144. ##  prints field information for fields with conductor $Q_n$ where <n> is in
  145. ##  the list <listofns>;
  146. ##
  147. ##  'MAKElb11( [ 3 .. 189 ] )' will print something very similar to
  148. ##  Richard Parker\'s file 'lb11'.
  149. ##
  150. MAKElb11 := function( listofns )
  151.     local n, f, k, j, fields, info, num, stabs;
  152.  
  153.     # 12 entries per row
  154.     num:= 12;
  155.  
  156.     for n in listofns do
  157.  
  158.       if n > 2 and n mod 4 <> 2 then
  159.  
  160.         fields:= Filtered( Subfields( CF(n) ),
  161.                            x -> NofCyc( x.generators ) = n );
  162.         fields:= List( fields, FieldInfo );
  163.         stabs:=  List( fields,
  164.                        x -> Concatenation( [ x.nofcyc, Length( x.repres ),
  165.                                            Length(x.stabil) ], x.stabil ) );
  166.         fields:= List( fields,
  167.                        x -> Concatenation( [ x.nofcyc, Length( x.repres ) ],
  168.                                            x.repres, [ Length( x.stabil ) ],
  169.                                            x.stabil ) );
  170.  
  171.         # sort fields according to degree and stabilizer generators
  172.         fields:= Permuted( fields, Sortex( stabs ) );
  173.         for f in fields do
  174.           for k in [ 0 .. QuoInt( Length( f ), num ) - 1 ] do
  175.             for j in [ 1 .. num ] do
  176.               Print( String( f[ k*num + j ], 4 ) );
  177.             od;
  178.             Print( "\n " );
  179.           od;
  180.           for j in [ num * QuoInt( Length(f), num ) + 1 .. Length(f) ] do
  181.             Print( String( f[j], 4 ) );
  182.           od;
  183.           Print( "\n" );
  184.         od;
  185.  
  186.       fi;
  187.  
  188.     od;
  189.     end;
  190.  
  191.  
  192. #############################################################################
  193. ##
  194. #F  StructureConstants( <ring> )
  195. ##
  196. ##  The multiplication in a ring <ring> with vector space base
  197. ##  $'<ring>.base' = ( v_1, \ldots, v_n )$ is determined by the so--called
  198. ##  structure matrices $M_k = [ m_{ijk} ]_{ij}, 1 \leq i \leq n$.
  199. ##  The $M_k$ are defined by $v_i v_j = \sum_{k} m_{i,j,k} v_k$.
  200. ##  Let $a = [ a_1, \ldots, a_n ], b = [ b_1, \ldots, b_n ]$.  Then
  201. ##  \[ ( \sum_i a_i v_i ) ( \sum_j b_j v_j )
  202. ##     = \sum_{i,j} a_i b_j ( v_i v_j )
  203. ##     = \sum_k ( \sum_j ( \sum_i a_i m_{i,j,k} ) b_j ) v_k
  204. ##     = \sum_k ( a M_k b^{tr} ) v_k \ . \]
  205. ##
  206. ##  'StructureConstants' returns the list $[ M_1, \ldots, M_n ]$.
  207. ##
  208. ##  *Note*\:\ To compute the structure matrices it is necessary to have a
  209. ##  'Coefficients' function for <ring>.
  210. ##
  211. StructureConstants := function( ring )
  212.     local i, j, k, n, prod, result;
  213.     n:= Length( ring.base );
  214.     result:= [];
  215.     for k in [ 1 .. n ] do
  216.       result[k]:= [];
  217.     od;
  218.     for i in [ 1 .. n ] do
  219.       for k in [ 1 .. n ] do
  220.         result[k][i]:= [];
  221.       od;
  222.       for j in [ 1 .. n ] do
  223.         prod:= Coefficients( ring, ring.base[i] * ring.base[j] );
  224.         for k in [ 1 .. n ] do
  225.           result[k][i][j]:= prod[k];
  226.         od;
  227.       od;
  228.     od;
  229.     return result;
  230.     end;
  231.  
  232.  
  233. #############################################################################
  234. ##
  235. #F  PowerInfo( <listoffields>, <galoisfams>, <powermap>, <prime> )
  236. ##
  237. ##  For a list <listoffields> of fields or zeros (as produced in
  238. ##  "MOCTable") the information of labels '30220' and '30230' is
  239. ##  computed.  This is a sequence
  240. ##  \[ x_{1,1} x_{1,2} \ldots x_{1,m_1} 0 x_{2,1} x_{2,2} \ldots x_{2,m_2}
  241. ##   0 \ldots 0 x_{n,1} x_{n,2} \ldots x_{n,m_n} 0 \]
  242. ##  with the followong meaning.
  243. ##  Let $[ a_1, a_2, \ldots, a_n ]$ be a character in MOC format.
  244. ##  The value of the character obtained on indirection by the <prime>--th
  245. ##  power map at position $i$ is
  246. ##  \[ x_{i,1} a_{x_{i,2}} + x_{i,3} a_{x_{i,4}} + \ldots
  247. ##   + x_{i,m_i-1} a_{x_{i,m_i}} \ . \]
  248. ##
  249. ##  The information is computed as follows.
  250. ##
  251. ##  If $g$ and $g^{<prime>}$ generate the same cyclic group, write the
  252. ##  <prime>--th conjugates of the base vectors $v_1, \ldots, v_k$ as
  253. ##  $\tilde{v_i} = \sum_{j=1}^{k} c_{ij} v_j$.  The $j$--th coefficient
  254. ##  of the <prime>--th conjugate of $\sum_{i=1}^{k} a_i v_i$ is then
  255. ##  $\sum_{i=1}^{k} a_i c_{ij}$.
  256. ##
  257. ##  If $g$ and $g^{<prime>}$ generate different cyclic groups, write the
  258. ##  base vectors $w_1, \ldots, w_{k^{\prime}}$ in terms of the $v_i$ as
  259. ##  $w_i = \sum_{j=1}^{k} c_{ij} v_j$.  The $v_j$--coefficient of the
  260. ##  indirection of $\sum_{i=1}^{k^{\prime}} a_i w_i$ is then
  261. ##  $\sum_{i=1}^{k^{\prime}} a_i c_{ij}$.
  262. ##
  263. ##  For $<prime> = -1$ (complex conjugation) we have of course
  264. ##  $k = k^{\prime}$ and $w_i = \overline{v_i}$.  In this case the
  265. ##  parameter <powermap> may have any value.  Otherwise <powermap>
  266. ##  must be the 'powermap' component of the underlying character table;
  267. ##  for any Galois automorphism of a cyclic subgroup, it must contain
  268. ##  a map covering this automorphism.
  269. ##
  270. ##  <galoisfams> is a list that describes the Galois conjugacy;
  271. ##  its format is equal to that of the 'galoisfams' component in the
  272. ##  record returned by 'GaloisMat'.
  273. ##
  274. ##  'PowerInfo' returns a list containing the information for <prime>,
  275. ##  the part of class 'i' is stored in a list at position 'i'.
  276. ##
  277. ##  *Note* that 'listoffields' refers to all classes, not only
  278. ##  representatives of cyclic subgroups; non-leader classes of Galois
  279. ##  families must have value 0.
  280. ##
  281. PowerInfo := function( listoffields, galoisfams, powermap, prime )
  282.     local i, j, k, c, n, f, power, im, oldim, imf, pp, entry;
  283.  
  284.     power:= [];
  285.     i:= 1;
  286.     while i <= Length( listoffields ) do
  287.  
  288.       if listoffields[i] in [ 1, Rationals ] then
  289.  
  290.         # rational class
  291.         if prime = -1 then
  292.           Add( power, [ 1, i, 0 ] );
  293.         else
  294.  
  295.           # 'prime'--th power of class 'i' (of course rational)
  296.           Add( power, [ 1, powermap[ prime ][i], 0 ] );
  297.  
  298.         fi;
  299.  
  300.       elif listoffields[i] <> 0 then
  301.  
  302.         # the field
  303.         f:= listoffields[i];
  304.  
  305.         if prime = -1 then
  306.  
  307.           # the coefficient matrix
  308.           c:= List( f.base, x -> Coefficients( f, GaloisCyc( x, -1 ) ) );
  309.           im:= i;
  310.  
  311.         else
  312.  
  313.           # the image class and field
  314.           oldim:= powermap[ prime ][i];
  315.           if galoisfams[ oldim ] = 1 then
  316.             im:= oldim;
  317.           else
  318.             im:= 1;
  319.             while not IsList( galoisfams[ im ] ) or
  320.                   not oldim in galoisfams[ im ][1] do
  321.               im:= im+1;
  322.             od;
  323.           fi;
  324.  
  325.           if listoffields[ im ] = 1 then
  326.  
  327.             # maps to rational class 'im'
  328.             c:= [ Coefficients( f, 1 ) ];
  329.  
  330.           elif im = i then
  331.  
  332.             # just Galois conjugacy
  333.             c:= List( f.base, x -> Coefficients( f, GaloisCyc(x,prime) ) );
  334.  
  335.           else
  336.  
  337.             # compute embedding of the image field
  338.             imf:= listoffields[ im ];
  339.             pp:= false;
  340.             for j in [ 2 .. Length( powermap ) ] do
  341.               if IsBound( powermap[j] ) and powermap[j][ im ] = oldim then
  342.                 pp:= j;
  343.               fi;
  344.             od;
  345.             if pp = false then
  346.               Error( "PowerInfo cannot compute Galois autom. for ", im,
  347.                      " -> ", oldim, " from powermap" );
  348.             fi;
  349.  
  350.             c:= List( imf.base, x -> Coefficients( f, GaloisCyc(x,pp) ) );
  351.  
  352.           fi;
  353.  
  354.         fi;
  355.  
  356.         entry:= [];
  357.  
  358.         n:= Length( c );
  359.         for j in [ 1 .. Length( c[1] ) ] do
  360.           for k in [ 1 .. n ] do
  361.             if c[k][j] <> 0 then
  362.               Append( entry, [ c[k][j], im + k - 1 ] );
  363.             fi;
  364.           od;
  365.           Add( entry, 0 );
  366.         od;
  367.         Add( power, entry );
  368.  
  369.       fi;
  370.       i:= i+1;
  371.     od;
  372.     return power;
  373.     end;
  374.  
  375.  
  376. #############################################################################
  377. ##
  378. #F  ScanMOC( <list> )
  379. ##
  380. ##  returns a record containing the information encoded in the list <list>
  381. ##  the components of the result are the labels in <list>.  If <list> is in
  382. ##  MOC2 format (10000--format) the names of components are 30000--numbers,
  383. ##  if it is in MOC3 format the names of components have yABC--format.
  384. ##
  385. ScanMOC := function( list )
  386.     local digits, positive, negative, specials, number,
  387.           pos, result, scannumber2, scannumber3, label, component;
  388.  
  389.     # some constants used for MOC3 format
  390.     digits:= [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ];
  391.     positive:= [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" ];
  392.     negative:= [ "k", "l", "m", "n", "o", "p", "q", "r", "s" ];
  393.     specials:= [ "t", "u", "v", "w" ];
  394.  
  395.     # check the argument
  396.     if IsString( list ) then list:= List( list ); fi;
  397.     if not IsList( list ) then
  398.       Error( "argument must be a list" );
  399.     fi;
  400.  
  401.     # local functions: scan a number of MOC2 or MOC3 format
  402.     scannumber2:= function()
  403.     number:= 0;
  404.     while list[ pos ] < 10000 do
  405.  
  406.       # number is not complete
  407.       number:= 10000 * number + list[ pos ];
  408.       pos:= pos + 1;
  409.     od;
  410.     if list[ pos ] < 20000 then
  411.       number:= 10000 * number + list[ pos ] - 10000;
  412.     else
  413.       number:= - ( 10000 * number + list[ pos ] - 20000 );
  414.     fi;
  415.     pos:= pos + 1;
  416.     return number;
  417.     end;
  418.  
  419.     scannumber3:= function()
  420.     number:= 0;
  421.     while list[ pos ] in digits do
  422.  
  423.       # number is not complete
  424.       number:= 10000 * number
  425.                     + 1000 * Position( digits, list[ pos   ] )
  426.                     +  100 * Position( digits, list[ pos+1 ] )
  427.                     +   10 * Position( digits, list[ pos+2 ] )
  428.                     +        Position( digits, list[ pos+3 ] )
  429.                     - 1111;
  430.       pos:= pos + 4;
  431.     od;
  432.  
  433.     # end of number or small number
  434.     if list[ pos ] in positive then
  435.  
  436.       # small positive number
  437.       number:= Position( positive, list[ pos ] ) - 1;
  438.  
  439.     elif list[ pos ] in negative then
  440.  
  441.       # small negative number
  442.       number:= - Position( negative, list[ pos ] );
  443.  
  444.     else
  445.  
  446.       if list[ pos ] = "t" then
  447.         number:= 10 * Position( digits, list[ pos+1 ] )
  448.                  +    Position( digits, list[ pos+2 ] )
  449.                  - 11;
  450.         pos:= pos + 2;
  451.       elif list[ pos ] = "u" then
  452.         number:= - 10 * Position( digits, list[ pos+1 ] )
  453.                  -      Position( digits, list[ pos+2 ] )
  454.                  + 11;
  455.         pos:= pos + 2;
  456.       elif list[ pos ] = "v" then
  457.         number:= 10000 * number
  458.                     + 1000 * Position( digits, list[ pos+1 ] )
  459.                     +  100 * Position( digits, list[ pos+2 ] )
  460.                     +   10 * Position( digits, list[ pos+3 ] )
  461.                     +        Position( digits, list[ pos+4 ] )
  462.                     - 1111;
  463.         pos:= pos + 4;
  464.       elif list[ pos ] = "w" then
  465.         number:= - 10000 * number
  466.                     - 1000 * Position( digits, list[ pos+1 ] )
  467.                     -  100 * Position( digits, list[ pos+2 ] )
  468.                     -   10 * Position( digits, list[ pos+3 ] )
  469.                     -        Position( digits, list[ pos+4 ] )
  470.                     + 1111;
  471.         pos:= pos + 4;
  472.       fi;
  473.     fi;
  474.     pos:= pos + 1;
  475.     return number;
  476.     end;
  477.  
  478.     # convert <list>
  479.     result:= rec();
  480.     pos:= 1;
  481.  
  482.     if IsInt( list[1] ) then
  483.  
  484.       # MOC2 format
  485.       if list[1] = 30100 then pos:= 2; fi;
  486.       while pos <= Length( list ) and list[ pos ] <> 31000 do
  487.         label:= list[ pos ];
  488.         pos:= pos + 1;
  489.         component:= [];
  490.         while pos <= Length( list ) and list[ pos ] < 30000 do
  491.           Add( component, scannumber2() );
  492.         od;
  493.         result.( label ):= component;
  494.       od;
  495.  
  496.     else
  497.  
  498.       # MOC3 format
  499.       if Sublist( list, [ 1 .. 4 ] ) = [ "y", "1", "0", "0" ] then
  500.         pos:= 5;
  501.       fi;
  502.  
  503.       while pos <= Length( list ) and list[ pos ] <> "z" do
  504.  
  505.         # label: 'yABC'
  506.         label:= ConcatenationString( list[ pos   ], list[ pos+1 ],
  507.                                      list[ pos+2 ], list[ pos+3 ] );
  508.         pos:= pos + 4;
  509.         component:= [];
  510.         while pos <= Length( list ) and not list[ pos ] in [ "y", "z" ] do
  511.           Add( component, scannumber3() );
  512.         od;
  513.         result.( label ):= component;
  514.       od;
  515.     fi;
  516.  
  517.     return result;
  518.     end;
  519.  
  520.  
  521. #############################################################################
  522. ##
  523. #F  MOCChars( <tbl>, <gapchars> )
  524. ##
  525. ##  returns translations of {\GAP} format characters <gapchars> to MOC
  526. ##  format.  <tbl> must be a {\GAP} format table or a MOC format table.
  527. ##
  528. MOCChars := function( tbl, gapchars )
  529.     local i, result, chi, MOCchi;
  530.  
  531.     # take the MOC format (if necessary, construct the MOC format table first)
  532.     if not IsBound( tbl.isMOCformat ) then
  533.       if IsBound( tbl.MOCtbl ) then
  534.         tbl:= tbl.MOCtbl;
  535.       else
  536.         tbl:= MOCTable( tbl );
  537.       fi;
  538.     fi;
  539.  
  540.     # translate the characters
  541.     result:= [];
  542.     for chi in gapchars do
  543.       MOCchi:= [];
  544.       for i in [ 1 .. Length( tbl.fields ) ] do
  545.         if tbl.fields[i] = Rationals then
  546.           Add( MOCchi, chi[ tbl.repcycsub[i] ] );
  547.         else
  548.           Append( MOCchi, Coefficients( tbl.fields[i],
  549.                                         chi[ tbl.repcycsub[i] ] ) );
  550.         fi;
  551.       od;
  552.       Add( result, MOCchi );
  553.     od;
  554.     return result;
  555.     end;
  556.  
  557.  
  558. #############################################################################
  559. ##
  560. #F  GAPChars( <tbl>, <mocchars> )
  561. ##
  562. ##  returns translations of MOC format characters <mocchars> to {\GAP}
  563. ##  format.  <tbl> must be a {\GAP} format table or a MOC format table.
  564. ##
  565. ##  <mocchars> may also be a list of integers, e.g., a component containing
  566. ##  characters in a record produced by "ScanMOC".
  567. ##
  568. GAPChars := function( tbl, mocchars )
  569.     local i, j, val, result, chi, GAPchi, map, pos, numb, nccl;
  570.  
  571.     # take the MOC format table (if necessary, construct it first)
  572.     if not IsBound( tbl.isMOCformat ) then
  573.       if IsBound( tbl.MOCtbl ) then
  574.         tbl:= tbl.MOCtbl;
  575.       else
  576.         tbl:= MOCTable( tbl );
  577.       fi;
  578.     fi;
  579.  
  580.     # 'map[i]' is the list of columns of the MOC table that belong to
  581.     # the 'i'--th cyclic subgroup of the MOC table
  582.     map:= [];
  583.     pos:= 0;
  584.     for i in [ 1 .. Length( tbl.fields ) ] do
  585.       Add( map, pos + [ 1 .. Length( tbl.fields[i].base ) ] );
  586.       pos:= pos + Length( tbl.fields[i].base );
  587.     od;
  588.  
  589.     result:= [];
  590.  
  591.     # if 'mocchars' is not a list of lists, divide it into pieces of length
  592.     # 'nccl'
  593.     if not IsList( mocchars[1] ) then
  594.       nccl:= Length( tbl.GAPtbl.centralizers );
  595.       mocchars:= List( [ 1 .. Length( mocchars ) / nccl ],
  596.                        i -> Sublist( mocchars, [ (i-1)*nccl+1 .. i*nccl ] ) );
  597.     fi;
  598.  
  599.     for chi in mocchars do
  600.       GAPchi:= [];
  601.       # loop over classes of the {\GAP} table
  602.       for i in [ 1 .. Length( tbl.galconjinfo ) / 2 ] do
  603.  
  604.         # the number of the cyclic subgroup in the MOC table
  605.         numb:= tbl.galconjinfo[ 2*i - 1 ];
  606.         if tbl.fields[ numb ] = Rationals then
  607.  
  608.           # rational class
  609.           GAPchi[i]:= chi[ map[ tbl.galconjinfo[ 2*i-1 ] ][1] ];
  610.  
  611.         elif tbl.galconjinfo[ 2*i ] = 1 then
  612.  
  613.           # representative of cyclic subgroup, not rational
  614.           GAPchi[i]:= Sublist( chi, map[ numb ] ) * tbl.fields[ numb ].base;
  615.  
  616.         else
  617.  
  618.           # irrational class, no representative:
  619.           # conjugate the value on the representative class
  620.           GAPchi[i]:=
  621.              GaloisCyc( GAPchi[ ( Position( tbl.galconjinfo, numb ) + 1 ) / 2 ],
  622.                         tbl.galconjinfo[ 2*i ] );
  623.  
  624.         fi;
  625.       od;
  626.       Add( result, GAPchi );
  627.     od;
  628.     return result;
  629.     end;
  630.  
  631.  
  632. #############################################################################
  633. ##
  634. #V  MOCTableOps  . . . . . . . . . . . . . . . . .  operations for MOC tables
  635. ##
  636. MOCTableOps := rec( 
  637.      Print:=         function( tbl )
  638.                        local i, flds, val;
  639.                        Print( "rec( " );
  640.                        flds:= RecFields( tbl );
  641.                        for i in [ 1 .. Length( flds ) - 1 ] do
  642.                          val:= tbl.( flds[i] );
  643.                          if flds[i] = "operations" then
  644.                            Print( "operations := MOCTableOps, " );
  645.                          elif flds[i] = "ordinary" then
  646.                            Print( "ordinary := \"",
  647.                                   tbl.ordinary.name, "\", " );
  648.                          elif flds[i] = "GAPtbl" then
  649.                            Print( "GAPtbl := CharTable( \"",
  650.                                   tbl.GAPtbl.name, "\" ), " );
  651.                          elif IsString( val ) then
  652.                            Print( flds[i], " := \"", val, "\", " );
  653.                          else
  654.                            Print( flds[i], " := ", val, ", " );
  655.                          fi;
  656.                        od;
  657.                        if flds <> [] then
  658.                          i:= Length( flds );
  659.                          val:=  tbl.( flds[i] );
  660.                          if flds[i] = "operations" then
  661.                            Print( "operations := MOCTableOps" );
  662.                          elif flds[i] = "ordinary" then
  663.                            Print( "ordinary := \"",
  664.                                   tbl.ordinary.name, "\", " );
  665.                          elif flds[i] = "GAPtbl" then
  666.                            Print( "GAPtbl := CharTable( \"",
  667.                                   tbl.GAPtbl.name, "\" ), " );
  668.                          elif IsString( val ) then
  669.                            Print( flds[i], " := \"", val, "\"" );
  670.                          else
  671.                            Print( flds[i], " := ", val );
  672.                          fi;
  673.                        fi;
  674.                        Print( " )" );
  675.                      end                                                );
  676.  
  677.  
  678. #############################################################################
  679. ##
  680. #F  MOCTable( <gaptbl> )
  681. #F  MOCTable( <gaptbl>, <basicset> )
  682. ##
  683. ##  return the MOC table record of the {\GAP} table <gaptbl> and stores it
  684. ##  in the component 'MOCtbl' of <gaptbl>.
  685. ##
  686. ##  The first form can be used for ordinary ($G.0$) tables, for $G.p$ tables
  687. ##  one has to specify a basic set <basicset> which must be a list of 
  688. ##  positions of the basic set characters in the 'irreducibles' component
  689. ##  of the corresponding ordinary table (which is stored in
  690. ##  <gaptbl>.ordinary).
  691. ##
  692. ##  The result contains the information of <gaptbl> in a format similar to
  693. ##  the MOC 3 format, the table itself can e.g. easily be printed out or be
  694. ##  used to print out characters using "PrintToMOC".
  695. ##
  696. ##  The components of the result are
  697. ##  'name'        : the string 'MOCTable(<name>)' where <name> is the name
  698. ##                  of <gaptbl>,
  699. ##  'isMOCformat' : has value 'true',
  700. ##  'GAPtbl'      : the record <gaptbl>,
  701. ##  'operations'  : equal to 'MOCTableOps', containing just an appropriate
  702. ##                  'Print' function,
  703. ##  'prime'       : the characteristic of the field (label 30105 in MOC),
  704. ##  'centralizers': centralizer orders for cyclic subgroups (label 30130)
  705. ##  'orders'      : element orders for cyclic subgroups (label 30140)
  706. ##  'fields'      : at position 'i' the number field generated by the
  707. ##                  character values of the 'i'--th cyclic subgroup;
  708. ##                  the 'base' component of each field is a Parker base,
  709. ##                  (the length of 'fields' is equal to the value of label
  710. ##                  30110 in MOC).
  711. ##  'cycsubgps'   : 'cycsubgps[i] = j' means that class 'i' of
  712. ##                  the {\GAP} table belongs to the 'j'--th cyclic subgroup
  713. ##                  of the {\GAP} table,
  714. ##  'repcycsub'   : 'repcycsub[j] = i' means that class 'i' of
  715. ##                  the {\GAP} table is the representative of
  716. ##                  the 'j'--th cyclic subgroup of the {\GAP} table.
  717. ##                  *Note* that the representatives of {\GAP} table and
  718. ##                  MOC table need not agree!
  719. ##  'galconjinfo' : a list $[ r_1,c_1,r_2,c_2,\ldots,r_n,c_n ]$
  720. ##                  which means that the $i$--th class of the GAP table is
  721. ##                  the $c_i$--th conjugate of the representative of
  722. ##                  the $r_i$--th cyclic subgroup on the MOC table.
  723. ##                  (This is used to translate back to GAP format,
  724. ##                  stored under label 30160)
  725. ##  '30170'       : (power maps) for each cyclic subgroup (except
  726. ##                  the trivial one) and each prime divisor of
  727. ##                  the representative order store four values, the number
  728. ##                  of the subgroup, the power, the number of the cyclic
  729. ##                  subgroup containing the image, and the power to which
  730. ##                  the representative must be raised to give the image
  731. ##                  class.  (This is used only to construct the '30230'
  732. ##                  power map/embedding information.)
  733. ##                  In 'result.30170' only a list of lists (one for each
  734. ##                  cyclic subgroup) of all these values is stored,
  735. ##                  it will not be used by {\GAP}.
  736. ##  'tensinfo'    : tensor product information, used to compute the
  737. ##                  coefficients of the Parker base for tensor products
  738. ##                  of characters (label 30210 in MOC).
  739. ##                  For a field with vector space base $(v_1,v_2,\ldots,v_n)$
  740. ##                  the tensor product information of a cyclic subgroup
  741. ##                  in MOC (as computed by 'fct') is either 1 (for rational
  742. ##                  classes) or a sequence
  743. ##                  \[ n x_{1,1} y_{1,1} z_{1,1} x_{1,2} y_{1,2} z_{1,2}
  744. ##                     \ldots x_{1,m_1} y_{1,m_1} z_{1,m_1} 0 x_{2,1} y_{2,1}
  745. ##                     z_{2,1} x_{2,2} y_{2,2} z_{2,2} \ldots x_{2,m_2}
  746. ##                     y_{2,m_2} z_{2,m_2} 0 \ldots x_{n,m_n} y_{n,m_n}
  747. ##                     z_{n,m_n} 0 \]
  748. ##                  which means that the coefficient of $v_k$ in the product
  749. ##                  \[ ( \sum_{i=1}^{n} a_i v_i ) ( \sum_{j=1}^{n} b_j v_j ) \]
  750. ##                  is equal to
  751. ##                  \[ \sum_{i=1}^{m_k} x_{k,i} a_{y_{k,i}} b_{z_{k,i}}\ . \]
  752. ##                  On a MOC table in {\GAP} the 'tensinfo' component is
  753. ##                  a list of lists, each containing exactly the sequence
  754. ##  'invmap'      : inverse map to compute complex conjugate characters,
  755. ##                  label 30220 in MOC.
  756. ##  'powerinfo'   : field embeddings for $p$--th symmetrizations, $p$ prime
  757. ##                  in '[ 2 .. 19 ]'; note that the necessary power maps
  758. ##                  must be stored on <gaptbl> to compute this component.
  759. ##                  (label 30230 in MOC)
  760. ##  '30900'       : basic set of restricted ordinary irreducibles in the
  761. ##                  case of nonzero characteristic, all ordinary irreducibles
  762. ##                  else.
  763. ##
  764. MOCTable := function( arg )
  765.     if Length( arg ) = 1 and IsRec( arg[1] ) then
  766.       return MOCTable0( arg[1] );
  767.     elif Length( arg ) = 2 and IsRec( arg[1] ) and IsList( arg[2] ) then
  768.       return MOCTableP( arg[1], arg[2] );
  769.     else
  770.       Error( "usage: MOCTable( <gaptbl> ) resp.",
  771.                    " MOCTable( <gaptbl>, <basicset> )" );
  772.     fi;
  773.     end;
  774.  
  775.  
  776. #############################################################################
  777. ##
  778. #F  MOCTable0( <gaptbl> )
  779. ##
  780. ##  MOC format table of ordinary {\GAP} table <gaptbl>
  781. ##
  782. MOCTable0 := function( gaptbl )
  783.     local i, j, k, d, n, p, result, trans, gal, extendedfields, entry, pow,
  784.           im, cl, field, struct, rep, aut;
  785.  
  786.     # initialize the record
  787.     result:= rec( name   := ConcatenationString("MOCTable(",gaptbl.name,")"),
  788.                   isMOCformat:= true,
  789.                   prime  := 0,
  790.                   fields := [],
  791.                   GAPtbl := gaptbl,
  792.                   operations := MOCTableOps );
  793.     gaptbl.MOCtbl:= result;
  794.  
  795.     # 1. Compute necessary information to encode the irrational columns.
  796.     #
  797.     #    Each family of $n$ Galois conjugate classes is replaced by $n$
  798.     #    integral columns, each number field with Parker base as
  799.     #    integral base is stored in the component 'fields' of the result.
  800.     #
  801.     trans:= TransposedMat( gaptbl.irreducibles );
  802.     gal:= GaloisMat( trans ).galoisfams;
  803.  
  804.     result.cycsubgps:= [];
  805.     result.repcycsub:= [];
  806.     result.galconjinfo:= [];
  807.     for i in [ 1 .. Length( gal ) ] do
  808.       if gal[i] = 1 then
  809.         Add( result.repcycsub, i );
  810.         result.cycsubgps[i]:= Length( result.repcycsub );
  811.         Append( result.galconjinfo, [ Length( result.repcycsub ), 1 ] );
  812.       elif gal[i] <> 0 then
  813.         Add( result.repcycsub, i );
  814.         n:= Length( result.repcycsub );
  815.         for k in gal[i][1] do
  816.           result.cycsubgps[k]:= n;
  817.         od;
  818.         Append( result.galconjinfo, [ Length( result.repcycsub ), 1 ] );
  819.       else
  820.         rep:= result.repcycsub[ result.cycsubgps[i] ];
  821.         aut:= gal[ rep ][2][ Position( gal[ rep ][1], i ) ]
  822.                  mod NofCyc( trans[i] );
  823.         Append( result.galconjinfo, [ result.cycsubgps[i], aut ] );
  824.       fi;
  825.     od;
  826.  
  827.     # centralizer orders and element orders
  828.     # (for representatives of cyclic subgroups only)
  829.     result.centralizers:= Sublist( gaptbl.centralizers, result.repcycsub );
  830.     result.orders:= Sublist( gaptbl.orders, result.repcycsub );
  831.  
  832.     # the fields (for cyclic subgroups only)
  833.     result.fields:= List( result.repcycsub,
  834.                           i -> FieldInfo( Field( trans[i] ) ).MOCfield );
  835.  
  836.     # fields for all classes (used by 'PowerInfo')
  837.     extendedfields:= List( [ 1 .. Length( gal ) ], x -> 0 );
  838.     for i in [ 1 .. Length( result.repcycsub ) ] do
  839.       extendedfields[ result.repcycsub[i] ]:= result.fields[i];
  840.     od;
  841.  
  842.     # '30170' powermaps:
  843.     # for each cyclic subgroup (except the trivial one) and each prime
  844.     # divisor of the representative order store four values, the number
  845.     # of the subgroup, the power, the number of the cyclic subgroup
  846.     # containing the image, and the power to which the representative
  847.     # must be raised to give the image class.
  848.     # (This is used only to construct the '30230' power map/embedding
  849.     # information.)
  850.     # In 'result.30170' only a list of lists (one for each cyclic subgroup)
  851.     # of all these values is stored, it will not be used by {\GAP}.
  852.     #
  853.     result.30170:= [ [] ];
  854.     for i in [ 2 .. Length( result.repcycsub ) ] do
  855.  
  856.       entry:= [];
  857.       for d in Set( FactorsInt( gaptbl.orders[ result.repcycsub[i] ] ) ) do
  858.  
  859.         # cyclic subgroup 'i' to power 'd'
  860.         Add( entry, i );
  861.         Add( entry, d );
  862.         pow:= gaptbl.powermap[d][ result.repcycsub[i] ];
  863.  
  864.         if gal[ pow ] = 1 then
  865.  
  866.           # rational class
  867.           Add( entry, Position( result.repcycsub, pow ) );
  868.           Add( entry, 1 );
  869.  
  870.         else
  871.  
  872.           # get the representative 'im'
  873.           im:= result.repcycsub[ result.cycsubgps[ pow ] ];
  874.           cl:= Position( gal[ im ][1], pow );
  875.  
  876.           # the image is class 'im' to power 'gal[ im ][2][cl]'
  877.           Add( entry, Position( result.repcycsub, im ) );
  878.           Add( entry, gal[ im ][2][cl]
  879.                               mod gaptbl.orders[ result.repcycsub[i] ] );
  880.  
  881.         fi;
  882.  
  883.       od;
  884.  
  885.       Add( result.30170, entry );
  886.  
  887.     od;
  888.  
  889.     # tensor product information, used to compute the coefficients of
  890.     # the Parker base for tensor products of characters.
  891.     result.tensinfo:= [];
  892.     for field in result.fields do
  893.       if field = Rationals then
  894.         Add( result.tensinfo, [ 1 ] );
  895.       else
  896.         struct:= StructureConstants( field );
  897.         n:= Length( struct );
  898.         entry:= [ n ];
  899.         for i in [ 1 .. n ] do
  900.           for j in [ 1 .. n ] do
  901.             for k in [ 1 .. n ] do
  902.               if struct[i][j][k] <> 0 then
  903.                 Append( entry, [ struct[i][j][k], j, k ] );
  904.               fi;
  905.             od;
  906.           od;
  907.           Add( entry, 0 );
  908.         od;
  909.         Add( result.tensinfo, entry );
  910.       fi;
  911.     od;
  912.  
  913.     # '30220' inverse map (to compute complex conjugate characters)
  914.     result.invmap:= PowerInfo( extendedfields, gal, 0, -1 );
  915.  
  916.     # '30230' power map (field embeddings for $p$--th symmetrizations,
  917.     #                    $p$ prime in '[ 2 .. 19 ]');
  918.     #         note that the necessary power maps must be stored on 'gaptbl'
  919.  
  920.     # add missing power maps
  921.     for p in [ 2 .. Maximum( Maximum( gaptbl.orders ), 19 ) ] do
  922.       if not IsBound( gaptbl.powermap[p] ) and IsPrimeInt( p ) then
  923.         gaptbl.powermap[p]:=
  924.                Parametrized( Powermap( gaptbl, p, rec( quick:= true ) ) );
  925.       fi;
  926.     od;
  927.  
  928.     result.powerinfo:= [];
  929.     for p in [ 2, 3, 5, 7, 11, 13, 17, 19 ] do
  930.       result.powerinfo[p]:=
  931.                 PowerInfo( extendedfields, gal, gaptbl.powermap, p );
  932.     od;
  933.  
  934.     # '30900': here all irreducible characters
  935.     result.30900:= MOCChars( result, gaptbl.irreducibles );
  936.  
  937.     return result;
  938.     end;
  939.  
  940.  
  941. #############################################################################
  942. ##
  943. #F  MOCTableP( <gaptbl>, <basicset> )
  944. ##
  945. ##  MOC format table of modular {\GAP} table <gaptbl>, with basic set of
  946. ##  ordinary irreducibles at positions in '<gaptbl>.ordinary.irreducibles'
  947. ##  given in <basicset>
  948. ##
  949. MOCTableP := function( gaptbl, basicset )
  950.     local i, j, p, result, fusion, mocfusion, images, ordinary, fld, pblock,
  951.           invpblock, ppart, ord, degrees, defect, deg, charfusion, pos,
  952.           repcycsub, ncharsperblock, restricted, invcharfusion, inf, mapp;
  953.  
  954.     # check the arguments
  955.     if not ( IsRec( gaptbl ) and IsBound( gaptbl.ordinary ) and
  956.              IsList( basicset ) ) then
  957.       Error( "<gaptbl> must be a record with component 'ordinary',",
  958.              " <basicset> must be a list" );
  959.     fi;
  960.  
  961.     # if necessary, compute the MOC format table of the ordinary table 
  962.     if not IsBound( gaptbl.ordinary.MOCtbl ) then
  963.       MOCTable0( gaptbl.ordinary );
  964.     fi;
  965.  
  966.     # transfer information from ordinary MOC table to 'result'
  967.     ordinary:= gaptbl.ordinary.MOCtbl;
  968.     fusion:= GetFusionMap( gaptbl, gaptbl.ordinary );
  969.     images:= Set( Sublist( ordinary.cycsubgps, fusion ) );
  970.  
  971.     # initialize the record
  972.     result:= rec( name   := ConcatenationString("MOCTable(",gaptbl.name,")"),
  973.                   isMOCformat:= true,
  974.                   prime  := gaptbl.prime,
  975.                   fields := [],
  976.                   ordinary:= gaptbl.ordinary.MOCtbl,
  977.                   GAPtbl := gaptbl,
  978.                   operations := MOCTableOps );
  979.     gaptbl.MOCtbl:= result;
  980.  
  981.     result.cycsubgps:= List( fusion,
  982.                    x -> Position( images, ordinary.cycsubgps[x] ) );
  983.     repcycsub:= ProjectionMap( result.cycsubgps );
  984.     result.repcycsub:= repcycsub;
  985.  
  986.     mocfusion:= CompositionMaps( ordinary.cycsubgps, fusion );
  987.  
  988.     # fusion map to restrict characters from 'ordinary' to 'result'
  989.     charfusion:= [];
  990.     pos:= 1;
  991.     for i in [ 1 .. Length( result.cycsubgps ) ] do
  992.       Add( charfusion, pos );
  993.       pos:= pos + 1;
  994.       while pos <= Length( result.ordinary.GAPtbl.orders ) and
  995.             result.ordinary.GAPtbl.orders[ pos ] mod gaptbl.prime = 0 do
  996.         pos:= pos + 1;
  997.       od;
  998.     od;
  999.  
  1000.     StoreFusion( result, ordinary, charfusion );
  1001.     invcharfusion:= InverseMap( charfusion );
  1002.  
  1003.     result.galconjinfo:= [];
  1004.     for i in fusion do
  1005.       Append( result.galconjinfo,
  1006.               [ Position( images, ordinary.galconjinfo[ 2*i-1 ] ),
  1007.                 ordinary.galconjinfo[ 2*i ] ] );
  1008.     od;
  1009.  
  1010.     for fld in [ "centralizers", "orders", "fields", "30170",
  1011.                  "tensinfo", "invmap" ] do
  1012.       result.( fld ):= List( result.repcycsub,
  1013.                              i -> ordinary.( fld )[ mocfusion[i] ] );
  1014.     od;
  1015.  
  1016.     mapp:= InverseMap( CompositionMaps( ordinary.cycsubgps,
  1017.                CompositionMaps( charfusion,
  1018.                    InverseMap( result.cycsubgps ) ) ) );
  1019.     for i in [ 2 .. Length( result.30170 ) ] do
  1020.       for j in 2 * [ 1 .. Length( result.30170[i] ) / 2 ] - 1 do
  1021.         result.30170[i][j]:= mapp[ result.30170[i][j] ];
  1022.       od;
  1023.     od;
  1024.  
  1025.  
  1026.     result.powerinfo:= [];
  1027.     for p in [ 2, 3, 5, 7, 11, 13, 17, 19 ] do
  1028.  
  1029.       inf:= List( result.repcycsub,
  1030.                   i -> ordinary.powerinfo[p][ mocfusion[i] ] );
  1031.       for i in [ 1 .. Length( inf ) ] do
  1032.         pos:= 2;
  1033.         while pos < Length( inf[i] ) do
  1034.           while inf[i][ pos + 1 ] <> 0 do
  1035.             inf[i][ pos ]:= invcharfusion[ inf[i][ pos ] ];
  1036.             pos:= pos + 2;
  1037.           od;
  1038.           inf[i][ pos ]:= invcharfusion[ inf[i][ pos ] ];
  1039.           pos:= pos + 3;
  1040.         od;
  1041.       od;
  1042.       result.powerinfo[p]:= inf;
  1043.  
  1044.     od;
  1045.  
  1046.     # '30310' number of $p$--blocks
  1047.     pblock:= List( gaptbl.ordinary.irredinfo,
  1048.                    x -> x.pblock[ result.prime ] );
  1049.     invpblock:= InverseMap( pblock );
  1050.     for i in [ 1 .. Length( invpblock ) ] do
  1051.       if IsInt( invpblock[i] ) then
  1052.         invpblock[i]:= [ invpblock[i] ];
  1053.       fi;
  1054.     od;
  1055.     result.30310:= Maximum( pblock );
  1056.  
  1057.     # '30320' defect, numbers of ordinary and modular characters per block
  1058.     result.30320:= [ ];
  1059.     ppart:= 0;
  1060.     ord:= gaptbl.order;
  1061.     while ord mod gaptbl.prime = 0 do
  1062.       ppart:= ppart + 1;
  1063.       ord:= ord / gaptbl.prime;
  1064.     od;
  1065.  
  1066.     for i in [ 1 .. Length( invpblock ) ] do
  1067.       defect:= gaptbl.prime ^ ppart;
  1068.       for j in invpblock[i] do
  1069.         deg:= gaptbl.ordinary.irreducibles[j][1];
  1070.         while deg mod defect <> 0 do
  1071.           defect:= defect / gaptbl.prime;
  1072.         od;
  1073.       od;
  1074.       restricted:= List( Sublist(gaptbl.ordinary.irreducibles,invpblock[i]),
  1075.                          x -> Sublist( x, fusion ) );
  1076.       ncharsperblock:=
  1077.            Sum( restricted,
  1078.                 y -> gaptbl.operations.ScalarProduct( gaptbl, y, y ) );
  1079.       Add( result.30320,
  1080.            [ ppart - Length( FactorsInt( defect ) ),
  1081.              Length( invpblock[i] ),
  1082.              ncharsperblock ] );
  1083.     od;
  1084.  
  1085.     # '30350' distribution of ordinary irreducibles to blocks
  1086.     #         (irreducible character number 'i' has number 'i')
  1087.     result.30350:= Copy( invpblock );
  1088.  
  1089.     # '30360' distribution of basic set characters to blocks:
  1090.     result.30360:= List( invpblock,
  1091.                          x -> List( Intersection( x, basicset ),
  1092.                                     y -> Position( basicset, y ) ) );
  1093.  
  1094.     # '30370' positions of basic set characters in 'irreducibles' (per block)
  1095.     result.30370:= List( invpblock, x -> Intersection( x, basicset ) );
  1096.  
  1097.     # '30550' decomposition of ordinary irreducibles in basic set
  1098.     basicset:= Sublist( ordinary.GAPtbl.irreducibles, basicset );
  1099.     basicset:= MOCChars( result, Restricted( basicset, fusion ) );
  1100.     result.30550:= DecompositionInt( basicset,
  1101.                           Restricted( ordinary.30900, charfusion ), 30 );
  1102.  
  1103.     # '30900' basic set of restricted ordinary irreducibles,
  1104.     result.30900:= basicset;
  1105.  
  1106.     return result;
  1107.     end;
  1108.  
  1109.  
  1110. #############################################################################
  1111. ##
  1112. #F  PrintToMOC( <moctbl> )
  1113. #F  PrintToMOC( <moctbl>, <chars> )
  1114. ##
  1115. ##  prints the MOC3 format of the character table <moctbl>.  If the second
  1116. ##  argument <chars> is specified, the (MOC format) characters in <chars>
  1117. ##  are stored under label '30900', else the basic set of ordinary
  1118. ##  irreducibles is stored there.
  1119. ##  <moctbl> must be a MOC table in {\GAP} as produced by "MOCTable".
  1120. ##
  1121. ##  The MOC3 code of a 5 digit number in MOC2 code is given by the
  1122. ##  following list.
  1123. ##  (Note that the code must contain only lower case letters.)
  1124. ##
  1125. ##  'ABCD'    for '0ABCD'
  1126. ##  'a'       for '10000'
  1127. ##  'b'       for '10001'          'k'       for '20001'
  1128. ##  'c'       for '10002'          'l'       for '20002'
  1129. ##  'd'       for '10003'          'm'       for '20003'
  1130. ##  'e'       for '10004'          'n'       for '20004'
  1131. ##  'f'       for '10005'          'o'       for '20005'
  1132. ##  'g'       for '10006'          'p'       for '20006'
  1133. ##  'h'       for '10007'          'q'       for '20007'
  1134. ##  'i'       for '10008'          'r'       for '20008'
  1135. ##  'j'       for '10009'          's'       for '20009'
  1136. ##  'tAB'     for '100AB'
  1137. ##  'uAB'     for '200AB'
  1138. ##  'vABCD'   for '1ABCD'
  1139. ##  'wABCD'   for '2ABCD'
  1140. ##  'yABC'    for '30ABC'
  1141. ##  'z'       for '31000'
  1142. ##
  1143. ##  *Note* that any long number in MOC2 format is divided into packages of
  1144. ##  length 4, the beginning (!) filled with leading zeros if necessary.
  1145. ##  Such a number with decimals $d_1, d_2, \ldots, d_{4n+k}$ is the sequence
  1146. ##  \[ 0d_1d_2d_3d_4 \ldots 0d_{4n-3}d_4n-2}d_{4n-1}d_{4n}
  1147. ##     xd_{4n+1}\ldots d_{4n+k} \]
  1148. ##  where $0 \leq k \leq 3$, and the first digit of $x$ is $1$ if the number
  1149. ##  is positive, it is $2$ if the number is negative, and then follow $(4-k)$
  1150. ##  zeros.
  1151. ##
  1152. PrintToMOC := function( arg )
  1153.     local i, j, d, p,              # loop variables
  1154.           tbl,                     # contained in 'arg'
  1155.           ncol, free,              # number of columns for printing
  1156.           sizescreen,              # remember size of screen
  1157.           lettP, lettN, digit,     # lists of letters for encoding
  1158.           Pr, PrintNumber,         # local functions for printing
  1159.           trans, gal,
  1160.           repcycsub,
  1161.           ord,                     # corresponding ordinary table
  1162.           fus, invfus,             # transfer between ord. and modular table
  1163.           restr,                   # restricted ordinary irreducibles
  1164.           basicset, BS,            # numbers in basic set, basic set itself
  1165.           aut, gallist, fields,
  1166.           F,
  1167.           pow, im, cl,
  1168.           info, chi,
  1169.           dec;
  1170.  
  1171.     # 1. Preliminaries\:
  1172.     #    initialisations, local functions needed for encoding and printing
  1173.  
  1174.     # number of columns for printing
  1175.     ncol:= 80;
  1176.     sizescreen:= SizeScreen();
  1177.     SizeScreen( [ 82 ] );
  1178.     free:= ncol;
  1179.  
  1180.     # encode numbers in '[ -9 .. 9 ]' as letters
  1181.     lettP:= [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" ];
  1182.     lettN:= [ "k", "l", "m", "n", "o", "p", "q", "r", "s" ];
  1183.     digit:= [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ];
  1184.  
  1185.     # local function 'Pr'\:\ print 'string' in lines of length 'ncol'
  1186.     Pr:= function( string )
  1187.     local len;
  1188.     len:= LengthString( string );
  1189.     if len <= free then
  1190.       Print( string );
  1191.       free:= free - len;
  1192.     else
  1193.       Print( SubString( string, 1, free ), "\n" );
  1194.       string:= SubString( string, free+1, len );
  1195.       for i in [ 1 .. Int( LengthString( string ) / ncol ) ] do
  1196.         Print( SubString( string, 1, ncol ), "\n" );
  1197.         string:= SubString( string, ncol+1, LengthString( string ) );
  1198.       od;
  1199.       Print( string );
  1200.       free:= ncol - LengthString( string );
  1201.     fi;
  1202.     end;
  1203.  
  1204.     # local function 'PrintNumber'\:\ print MOC3 code of number 'number'
  1205.     PrintNumber:= function( number )
  1206.     local i, sumber, sumber1, sumber2, len, rest;
  1207.     sumber:= String( AbsInt( number ) );
  1208.     len:= LengthString( sumber );
  1209.     if len > 4 then
  1210.  
  1211.       # long number, fill with leading zeros
  1212.       rest:= len mod 4;
  1213.       if rest = 0 then rest:= 4; fi;
  1214.       for i in [ 1 .. 4-rest ] do
  1215.         sumber:= ConcatenationString( "0", sumber );
  1216.         len:= len+1;
  1217.       od;
  1218.  
  1219.       sumber1:= SubString( sumber, 1, len - 4 );
  1220.       sumber2:= SubString( sumber, len - 3, len );
  1221.  
  1222.       # code of last digits is always 'vABCD' or 'wABCD'
  1223.       if number >= 0 then
  1224.         sumber:= ConcatenationString( sumber1, "v" );
  1225.       else
  1226.         sumber:= ConcatenationString( sumber1, "w" );
  1227.       fi;
  1228.       sumber:= ConcatenationString( sumber, sumber2 );
  1229.  
  1230.     else
  1231.  
  1232.       # short numbers (up to 9999), encode the last digits
  1233.       if len = 1 then
  1234.         if number >= 0 then
  1235.           sumber:= ConcatenationString(
  1236.                       lettP[ Position( digit, sumber ) ] );
  1237.         else
  1238.           sumber:= ConcatenationString(
  1239.                       lettN[ Position( digit, sumber ) - 1 ] );
  1240.         fi;
  1241.       elif len = 2 then
  1242.         if number >= 0 then
  1243.           sumber:= ConcatenationString( "t", sumber );
  1244.         else
  1245.           sumber:= ConcatenationString( "u", sumber );
  1246.         fi;
  1247.       elif len = 3 then
  1248.         if number >= 0 then
  1249.           sumber:= ConcatenationString( "v0", sumber );
  1250.         else
  1251.           sumber:= ConcatenationString( "w0", sumber );
  1252.         fi;
  1253.       else
  1254.         if number >= 0 then
  1255.           sumber:= ConcatenationString( "v", sumber );
  1256.         else
  1257.           sumber:= ConcatenationString( "w", sumber );
  1258.         fi;
  1259.       fi;
  1260.     fi;
  1261.  
  1262.     # print the code in lines of length 'ncol'
  1263.     Pr( sumber );
  1264.     end;
  1265.  
  1266.     # check the input
  1267.     if not ( Length( arg ) in [ 1, 2 ] and IsRec( arg[1] ) and
  1268.              ( Length( arg ) = 1 or IsList( arg[2] ) ) ) then
  1269.       Error( "usage: PrintToMOC( <moctbl> ) resp.",
  1270.                    " PrintToMOC( <moctbl>, <chars> )" );
  1271.     fi;
  1272.  
  1273.     tbl:= arg[1];
  1274.  
  1275.     # '30100' start of the table
  1276.     Pr( "y100" );
  1277.  
  1278.     # '30105' characteristic of the field
  1279.     Pr( "y105" );
  1280.     PrintNumber( tbl.prime );
  1281.  
  1282.     # '30110' number of p-regular classes and of cyclic subgroups
  1283.     Pr( "y110" );
  1284.     PrintNumber( Length( tbl.GAPtbl.centralizers ) );
  1285.     PrintNumber( Length( tbl.centralizers ) );
  1286.  
  1287.     # '30130' centralizer orders
  1288.     Pr( "y130" );
  1289.     for i in tbl.centralizers do PrintNumber( i ); od;
  1290.  
  1291.     # '30140' representative orders of cyclic subgroups
  1292.     Pr( "y140" );
  1293.     for i in tbl.orders do PrintNumber( i ); od;
  1294.  
  1295.     # '30150' field information
  1296.     Pr( "y150" );
  1297.  
  1298.     # loop over cyclic subgroups
  1299.     for i in tbl.fields do
  1300.       if i = Rationals then
  1301.  
  1302.         PrintNumber( 1 );
  1303.  
  1304.       else
  1305.  
  1306.         F:= FieldInfo( i );
  1307.         PrintNumber( F.nofcyc );           # $\Q(e_N)$ is the conductor
  1308.         PrintNumber( Length( F.repres ) ); # degree of the field
  1309.         for j in F.repres do
  1310.           PrintNumber( j );                # representatives of the orbits
  1311.         od;
  1312.         PrintNumber( Length( F.stabil ) ); # no. of generators for stabilizer
  1313.         for j in F.stabil do
  1314.           PrintNumber( j );                # generators for stabilizer
  1315.         od;
  1316.  
  1317.       fi;
  1318.     od;
  1319.  
  1320.     # '30160' galconjinfo of classes:
  1321.     Pr( "y160" );
  1322.     for i in tbl.galconjinfo do PrintNumber( i ); od;
  1323.  
  1324.     # '30170' powermaps
  1325.     Pr( "y170" );
  1326.     for i in Flat( tbl.30170 ) do PrintNumber( i ); od;
  1327.  
  1328.     # '30210' tensor product information
  1329.     Pr( "y210" );
  1330.     for i in Flat( tbl.tensinfo ) do PrintNumber( i ); od;
  1331.  
  1332.     # '30220' inverse map (to compute complex conjugate characters)
  1333.     Pr( "y220" );
  1334.     for i in Flat( tbl.invmap ) do PrintNumber( i ); od;
  1335.  
  1336.     # '30230' power map (field embeddings for $p$--th symmetrizations,
  1337.     #                    $p$ in '[ 2, 3, 5, 7, 11, 13, 17, 19 ]');
  1338.     #         note that the necessary power maps must be stored on 'tbl'
  1339.     Pr( "y230" );
  1340.     for p in [ 2, 3, 5, 7, 11, 13, 17 ] do
  1341.       PrintNumber( p );
  1342.       for j in Flat( tbl.powerinfo[p] ) do PrintNumber( j ); od;
  1343.       Pr( "y050" );
  1344.     od;
  1345.     # no '30050' at the end!
  1346.     PrintNumber( 19 );
  1347.     for j in Flat( tbl.powerinfo[19] ) do PrintNumber( j ); od;
  1348.  
  1349.     # '30310' number of p-blocks
  1350.     if IsBound( tbl.30310 ) then
  1351.       Pr( "y310" );
  1352.       PrintNumber( tbl.30310 );
  1353.     fi;
  1354.  
  1355.     # '30320' defect, number of ordinary and modular characters per block
  1356.     if IsBound( tbl.30320 ) then
  1357.       Pr( "y320" );
  1358.       for i in tbl.30320 do
  1359.         PrintNumber( i[1] );
  1360.         PrintNumber( i[2] );
  1361.         PrintNumber( i[3] );
  1362.         Pr( "y050" );
  1363.       od;
  1364.     fi;
  1365.  
  1366.     # '30350' relative numbers of ordinary characters per block
  1367.     if IsBound( tbl.30350 ) then
  1368.       Pr( "y350" );
  1369.       for i in tbl.30350 do
  1370.         for j in i do PrintNumber( j ); od;
  1371.         Pr( "y050" );
  1372.       od;
  1373.     fi;
  1374.  
  1375.     # '30360' distribution of basic set characters to blocks\:
  1376.     #         relative numbers in the basic set
  1377.     if IsBound( tbl.30360 ) then
  1378.       Pr( "y360" );
  1379.       for i in tbl.30360 do
  1380.         for j in i do PrintNumber( j ); od;
  1381.         Pr( "y050" );
  1382.       od;
  1383.     fi;
  1384.  
  1385.     # '30370' relative numbers of basic set characters (blockwise)
  1386.     if IsBound( tbl.30370 ) then
  1387.       Pr( "y370" );
  1388.       for i in tbl.30370 do
  1389.         for j in i do PrintNumber( j ); od;
  1390.         Pr( "y050" );
  1391.       od;
  1392.     fi;
  1393.  
  1394.     # '30500' matrices of scalar products of Brauer characters with PS
  1395.     #         (per block)
  1396.     if IsBound( tbl.30500 ) then
  1397.       Pr( "y700" );
  1398.       for i in tbl.30700 do
  1399.         for j in Concatenation( i ) do PrintNumber( j ); od;
  1400.         Pr( "y050" );
  1401.       od;
  1402.     fi;
  1403.  
  1404.     # '30510' absolute numbers of '30500' characters
  1405.     if IsBound( tbl.30510 ) then
  1406.       Pr( "y510" );
  1407.       for i in tbl.30510 do PrintNumber( i ); od;
  1408.     fi;
  1409.  
  1410.     # '30550' decomposition of ordinary characters into basic set
  1411.     if IsBound( tbl.30550 ) then
  1412.       Pr( "y550" );
  1413.       for i in Concatenation( tbl.30550 ) do
  1414.         PrintNumber( i );
  1415.       od;
  1416.     fi;
  1417.  
  1418.     # '30590' ??
  1419.     # '30690' ??
  1420.  
  1421.     # '30700' matrices of scalar products of PS with BS (per block)
  1422.     if IsBound( tbl.30700 ) then
  1423.       Pr( "y700" );
  1424.       for i in tbl.30700 do
  1425.         for j in Concatenation( i ) do PrintNumber( j ); od;
  1426.         Pr( "y050" );
  1427.       od;
  1428.     fi;
  1429.  
  1430.     # '30710'
  1431.     if IsBound( tbl.30710 ) then
  1432.       Pr( "y710" );
  1433.       for i in tbl.30710 do PrintNumber( i ); od;
  1434.     fi;
  1435.  
  1436.     # '30900' basic set of restricted ordinary irreducibles,
  1437.     #         or characters in <chars>
  1438.  
  1439.     Pr( "y900" );
  1440.     if Length( arg ) = 2 then
  1441.  
  1442.       # case 'PrintToMOC( <tbl>, <chars> )'
  1443.       for chi in arg[2] do
  1444.         for i in chi do PrintNumber( i ); od;
  1445.       od;
  1446.  
  1447.     elif IsBound( tbl.30900 ) then
  1448.  
  1449.       # case 'PrintToMOC( <tbl> )'
  1450.       for i in Concatenation( tbl.30900 ) do PrintNumber( i ); od;
  1451.  
  1452.     fi;
  1453.  
  1454.     # '31000' end of table
  1455.     Pr( "z\n" );
  1456.  
  1457.     # reset size of screen
  1458.     SizeScreen( sizescreen );
  1459.     end;
  1460.  
  1461.  
  1462.