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

  1. #############################################################################
  2. ##
  3. #A  ctbasic.g                   GAP library                     Thomas Breuer
  4. #A                                                           & Goetz Pfeiffer
  5. ##
  6. #A  @(#)$Id: ctbasic.g,v 3.36 1993/02/11 18:16:33 sam Rel $
  7. ##
  8. #Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  9. ##
  10. ##  This file contains basic functions for dealing with characters in GAP.
  11. ##
  12. #H  $Log: ctbasic.g,v $
  13. #H  Revision 3.36  1993/02/11  18:16:33  sam
  14. #H  changes in 'SortCharactersCharTable' (due to new string handling)
  15. #H
  16. #H  Revision 3.35  1993/02/11  15:23:55  sam
  17. #H  changes in 'CharTableOps', 'BrauerTableOps'
  18. #H
  19. #H  Revision 3.34  1993/02/11  11:06:16  sam
  20. #H  change in 'BrauerTableOps'
  21. #H
  22. #H  Revision 3.33  1993/02/09  08:57:02  sam
  23. #H  changed 'ScalarProduct' to be a dispatcher only
  24. #H
  25. #H  Revision 3.32  1992/12/23  16:41:06  sam
  26. #H  fixed bug in DisplayCharTable, due to changes in the kernel of GAP
  27. #H
  28. #H  Revision 3.31  1992/09/07  07:17:35  sam
  29. #H  bug in 'CharTable' fixed
  30. #H
  31. #H  Revision 3.30  1992/08/10  15:46:25  sam
  32. #H  added dispatcher 'CharTable'
  33. #H
  34. #H  Revision 3.29  1992/07/01  16:39:29  sam
  35. #H  added function 'SortCharTable'
  36. #H
  37. #H  Revision 3.28  1992/06/16  15:16:14  sam
  38. #H  recorrected 'DisplayCharTable'
  39. #H
  40. #H  Revision 3.27  1992/06/16  12:14:47  goetz
  41. #H  corrected 'DisplayCharTable'.
  42. #H
  43. #H  Revision 3.25  1992/06/01  13:38:03  goetz
  44. #H  changed 'DisplayCharTable' to print more types of data.
  45. #H
  46. #H  Revision 3.24  1992/05/30  14:30:23  sam
  47. #H  now 'tbl.group.conjugacyClasses' are sorted by 'SortClassesCharTable'
  48. #H
  49. #H  Revision 3.23  1992/04/03  17:45:36  martin
  50. #H  changed the author line
  51. #H
  52. #H  Revision 3.22  1992/04/02  16:57:44  martin
  53. #H  replaced 'Linelength' by 'ScreenSize'
  54. #H
  55. #H  Revision 3.21  1992/03/10  17:19:59  goetz
  56. #H  changed return format of 'NrPolyhedralSubgroups'.
  57. #H
  58. #H  Revision 3.20  1992/03/03  14:05:30  sam
  59. #H  added 'ClassStructureCharTable'
  60. #H
  61. #H  Revision 3.19  1992/01/07  15:22:07  sam
  62. #H  removed use of 'RecField', 'SetRecField'
  63. #H
  64. #H  Revision 3.18  1992/01/07  15:10:56  sam
  65. #H  changed 'SortClassesCharTable' for case of permutation ()
  66. #H
  67. #H  Revision 3.17  1991/12/20  10:10:13  sam
  68. #H  renamed 'Kernel' to 'KernelChar'
  69. #H
  70. #H  Revision 3.16  1991/12/19  16:23:08  sam
  71. #H  stylistic changes in 'TestCharTable'
  72. #H
  73. #H  Revision 3.15  1991/12/07  16:29:29  sam
  74. #H  changed 'BrauerTableOps.Print' for field 'ordinary'
  75. #H
  76. #H  Revision 3.14  1991/12/04  17:18:04  sam
  77. #H  changed 'CASPER' in header to 'GAP'
  78. #H
  79. #H  Revision 3.13  1991/12/04  13:49:15  martin
  80. #H  added a single <space>
  81. #H
  82. #H  Revision 3.12  1991/12/03  16:32:41  sam
  83. #H  correction concerning table automorphisms
  84. #H
  85. #H  Revision 3.11  1991/12/03  08:35:59  sam
  86. #H  now 'automorphisms' is a group, not a list
  87. #H
  88. #H  Revision 3.10  1991/12/03  08:30:47  sam
  89. #H  deleted 'Ordinal', 'Sortex', 'Permuted',
  90. #H  removed history,
  91. #H  changed 'tableautomorphisms' to 'automorphisms',
  92. #H  indented functions
  93. #H
  94. #H  Revision 3.9  1991/11/14  18:13:47  sam
  95. #H  changed 'CoeffsCyc' to 'COEFFSCYC',
  96. #H  added ' ' in 'CharTableOps.Print'
  97. #H
  98. #H  Revision 3.8  1991/11/06  16:32:27  sam
  99. #H  added 'Print' to 'CharTableOps'
  100. #H
  101. #H  Revision 3.7  1991/10/18  15:53:46  sam
  102. #H  'Position' returns 'false' not '0' ...
  103. #H
  104. #H  Revision 3.6  1991/10/08  08:13:01  sam
  105. #H  added 'CharTableOps'
  106. #H
  107. #H  Revision 3.5  1991/10/07  15:29:26  sam
  108. #H  changed 'ScalarProduct' to '<tbl>.operations.ScalarProduct'
  109. #H
  110. #H  Revision 3.4  1991/10/07  15:21:42  sam
  111. #H  changed 'TestCharTable' (now uses 'ElementOrdersPowermap')
  112. #H
  113. #H  Revision 3.3  1991/10/01  14:24:24  casper
  114. #H  changed 'Gcd' to 'GcdInt'
  115. #H
  116. #H  Revision 3.2  1991/09/05  14:48:16  sam
  117. #H  changed 'Quo' to 'QuoInt', 'Abs' to 'AbsInt'
  118. #H
  119. #H  Revision 3.1  1991/09/03  13:08:07  goetz
  120. #H  changed 'reps' to 'orders'.
  121. #H
  122. #H  Revision 3.0  1991/09/03  12:58:37  casper
  123. #H  Initial Revision.
  124. #H
  125. ##
  126.  
  127. #############################################################################
  128. ##
  129. #F  InfoCharTable1( ... ) . . . info function for the character table package
  130. #F  InfoCharTable2( ... ) . . . info function for the character table package
  131. ##
  132.     if not IsBound( InfoCharTable1 )  then InfoCharTable1 := Ignore;  fi;
  133.     if not IsBound( InfoCharTable2 )  then InfoCharTable2 := Ignore;  fi;
  134.  
  135.  
  136. #############################################################################
  137. ##
  138. #F  IsCharTable( <obj> )  . . . . . . . . is an object a character table
  139. ##
  140. IsCharTable := function ( obj )
  141.     return IsRec(obj) and IsBound(obj.centralizers) and IsBound(obj.name);
  142.     end;
  143.  
  144.  
  145. #############################################################################
  146. ##
  147. #V  CharTableOps   . . . . . . . . . . . . .  operations for character tables
  148. ##
  149. CharTableOps := rec( 
  150.      ScalarProduct := function( D, x1, x2 )
  151.      local i, scpr, order, weight, inv;
  152.      order:= D.order;
  153.      weight:= D.classes;
  154.      scpr:= 0;
  155.      for i in [ 1 .. Length( x1 ) ] do
  156.        if IsInt( x2[i] ) then
  157.          scpr:= scpr + x1[i] * x2[i] * weight[i];
  158.        else    # then proper cyclotomic or unknown
  159.          scpr:= scpr + x1[i] * GaloisCyc( x2[i], -1 ) * weight[i];
  160.        fi;
  161.      od;
  162.      scpr:= scpr / order;
  163.      if IsInt( scpr ) then return scpr; fi;
  164.      if IsRat( scpr ) then
  165.        InfoCharTable2("#E ScalarProduct: sum not divisible by group order\n");
  166.      elif IsCyc( scpr ) then
  167.        InfoCharTable2("#E ScalarProduct: summation not integer valued\n");  
  168.      fi;
  169.      return scpr;
  170.      end,
  171.  
  172.      Print:= function( tbl )
  173.      local i, flds, val;
  174.      Print( "rec( " );
  175.      flds:= RecFields( tbl );
  176.      for i in [ 1 .. Length( flds ) - 1 ] do
  177.        val:= tbl.( flds[i] );
  178.        if flds[i] = "operations" then
  179.          Print( "operations := CharTableOps, " );
  180.        elif IsString( val ) and TYPE( val ) = "string" then
  181.          Print( flds[i], " := \"", val, "\", " );
  182.        else
  183.          Print( flds[i], " := ", val, ", " );
  184.        fi;
  185.      od;
  186.      if flds <> [] then
  187.        i:= Length( flds );
  188.        val:=  tbl.( flds[i] );
  189.        if flds[i] = "operations" then
  190.          Print( "operations := CharTableOps" );
  191.        elif IsString( val ) and TYPE( val ) = "string" then
  192.          Print( flds[i], " := \"", val, "\"" );
  193.        else
  194.          Print( flds[i], " := ", val );
  195.        fi;
  196.      fi;
  197.      Print( " )" );
  198.      end                                                );
  199.  
  200.  
  201. #############################################################################
  202. ##
  203. #V  BrauerTableOps   . . . . . . . . . . . . . . operations for Brauer tables
  204. ##
  205. BrauerTableOps := rec( 
  206.      ScalarProduct := function( D, x1, x2 )
  207.      local i, scpr, order, weight, inv;
  208.      order:= D.order;
  209.      weight:= D.classes;
  210.      scpr:= 0;
  211.      for i in [ 1 .. Length( x1 ) ] do
  212.        if IsInt( x2[i] ) then
  213.          scpr:= scpr + x1[i] * x2[i] * weight[i];
  214.        else    # then proper cyclotomic or unknown
  215.          scpr:= scpr + x1[i] * GaloisCyc( x2[i], -1 ) * weight[i];
  216.        fi;
  217.      od;
  218.      scpr:= scpr / order;
  219.      if IsInt( scpr ) then return scpr; fi;
  220.      if IsRat( scpr ) then
  221.        InfoCharTable2("#E ScalarProduct: sum not divisible by group order\n");
  222.      elif IsCyc( scpr ) then
  223.        InfoCharTable2("#E ScalarProduct: summation not integer valued\n");  
  224.      fi;
  225.      return scpr;
  226.      end,
  227.  
  228.      Print:= function( tbl )
  229.      local i, flds, val;
  230.      Print( "rec( " );
  231.      flds:= RecFields( tbl );
  232.      for i in [ 1 .. Length( flds ) - 1 ] do
  233.        val:= tbl.( flds[i] );
  234.        if flds[i] = "operations" then
  235.          Print( "operations := BrauerTableOps, " );
  236.        elif flds[i] = "ordinary" then
  237.          Print( "ordinary := CharTable( \"",
  238.                 tbl.ordinary.name, "\" ), " );
  239.        elif IsString( val ) and TYPE( val ) = "string" then
  240.          Print( flds[i], " := \"", val, "\", " );
  241.        else
  242.          Print( flds[i], " := ", val, ", " );
  243.        fi;
  244.      od;
  245.      if flds <> [] then
  246.        i:= Length( flds );
  247.        val:=  tbl.( flds[i] );
  248.        if flds[i] = "operations" then
  249.          Print( "operations := BrauerTableOps" );
  250.        elif IsString( val ) and TYPE( val ) = "string" then
  251.          Print( flds[i], " := \"", val, "\"" );
  252.        else
  253.          Print( flds[i], " := ", val );
  254.        fi;
  255.      fi;
  256.      Print( " )" );
  257.      end                                                );
  258.  
  259.  
  260. #############################################################################
  261. ##
  262. #F  KernelChar( <char> ) . . . . . . .  the set of classes forming the kernel
  263. ##
  264. KernelChar := function( char )
  265.     local i, kernel;
  266.     kernel:= [];
  267.     for i in [ 1 .. Length( char ) ] do
  268.       if char[i] = char[1] then Add( kernel, i ); fi;
  269.     od;
  270.     return kernel;
  271.     end;
  272.  
  273.  
  274. #############################################################################
  275. ##
  276. #F  InitClassesCharTable( <tbl> )  . . initialize classes of character tables
  277. ##
  278. InitClassesCharTable := function( tbl )
  279.     local x, order, initclasses;
  280.     if not IsInt( tbl.centralizers[1] ) then return; fi; # generic tables
  281.     order:= tbl.centralizers[1];
  282.     initclasses:= List( tbl.centralizers, x -> order / x );
  283.     if not ForAll( initclasses, IsInt ) then
  284.       Print( "#E InitClassesCharTable: not all centralizer orders divide",
  285.              " the group order\n" );
  286.     fi;
  287.     tbl.classes:= initclasses;
  288.     return initclasses;
  289.     end;
  290.  
  291.  
  292. #############################################################################
  293. ##
  294. #F  InverseClassesCharTable( <tbl> )
  295. ##
  296. ##  returns the list mapping each class of the character table <tbl> to its
  297. ##  inverse class (can be regarded as (-1)-th powermap).
  298. ##
  299. ##  computed from characters stored in <tbl>.irreducibles
  300. ##
  301. InverseClassesCharTable := function( tbl )
  302.     local i, elm, isinverse, inv, isinv, irreds, candidates, remain;
  303.  
  304.     inv:= [ 1 ];             # The inverse of the identity is the identity.
  305.     if not IsBound( tbl.irreducibles ) or tbl.irreducibles = [] then
  306.       Print( "#E InverseClassesCharTable: no irreducibles stored\n" );
  307.       return List( [ 1 .. Length( tbl.centralizers ) ], x -> Unknown() );
  308.     fi;
  309.     irreds:= tbl.irreducibles;
  310.  
  311.     isinverse:= function( i, elm )         # is 'elm' the inverse of 'i' ?
  312.     local k;
  313.     for k in [ 1 .. Length( irreds ) ] do
  314.       if IsUnknown( irreds[k][elm] ) then
  315.         return Unknown();
  316.       elif irreds[k][i] <> GaloisCyc( irreds[k][elm], -1 ) then
  317.         return false;
  318.       fi;
  319.     od;
  320.     return true;
  321.     end;
  322.  
  323.     remain:= [ 2 .. Length( irreds[1] ) ];
  324.     for i in [ 2 .. Length( irreds[1] ) ] do
  325.       if not IsBound( inv[i] ) then
  326.         candidates:= [];
  327.         for elm in remain do
  328.           isinv:= isinverse( i, elm );
  329.           if isinv = true then
  330.             AddSet( candidates, elm );
  331.           elif IsUnknown( isinv ) then
  332.             inv[i]:= Unknown();
  333.           fi;
  334.         od;
  335.         if not IsBound( inv[i] ) then
  336.           if Length( candidates ) = 1 then
  337.             inv[ candidates[1] ]:= i;
  338.             inv[ i ]:= candidates[1];
  339.             remain:= Difference( remain, Set( [ i, inv[i] ] ) );
  340.           else
  341.             inv[i]:= candidates;
  342.           fi;
  343.         fi;
  344.       fi;
  345.     od;
  346.     return inv;
  347.     end;
  348.  
  349.  
  350. #############################################################################
  351. ##
  352. #F  PrintToCAS( <tbl>, <filename> )
  353. #F  PrintToCAS( <filename>, <tbl> )
  354. ##
  355. ##  prints a CAS library tbl of the GAP table <tbl> to the file
  356. ##  <filename> with linelength 'SizeScreen()[1]'
  357. ##
  358. PrintToCAS := function( filename, tbl )
  359.     local funct, ll;
  360.     if IsString( tbl ) and IsRec( filename ) then   # allow other succession
  361.       ll:= tbl;
  362.       tbl:= filename;
  363.       filename:= ll;
  364.     fi;
  365.     ll:= SizeScreen()[1];
  366.     
  367.     funct:= function( tbl )
  368.     local i, j, strin, convertcyclotom, convertrow, column, fus;
  369.     if IsBound( tbl.name ) then                      # name
  370.       Print( "'", tbl.name, "'\n" );
  371.     else
  372.       Print( "'NN'\n" );
  373.     fi;
  374.     Print( "00/00/00. 00.00.00.\n" );                 # date
  375.     if IsBound( tbl.centralizers ) then               # nccl, cvw, ctw
  376.       Print( "(", String( Length( tbl.centralizers ) ), ","
  377.                 , String( Length( tbl.centralizers ) ), ",0," );
  378.     else
  379.       Print( "(0,0,0," );
  380.     fi;
  381.     if IsBound( tbl.irreducibles ) then               # max
  382.       Print( String( Length( tbl.irreducibles ) ), "," );
  383.       if Length( tbl.irreducibles ) = Length( Set( tbl.irreducibles ) ) then
  384.         Print( "-1," );                               # link
  385.       else
  386.         Print( "0," );                                # link
  387.       fi;
  388.     fi;
  389.     Print( "0)\n" );                                  # tilt
  390.     if IsBound( tbl.text ) then                       # text
  391.       Print( "text:\n(#", tbl.text, "#),\n" );
  392.     fi;
  393.     if IsBound( tbl.order ) then                      # order
  394.       Print( "order=", String( tbl.order ) );
  395.     fi;
  396.     #
  397.     convertcyclotom:= function( cyc )
  398.     local i, str, coeffs;
  399.     coeffs:= COEFFSCYC( cyc );
  400.     str:= ConcatenationString( "\n<w", String( Length( coeffs ) ), "," );
  401.     if coeffs[1] <> 0 then
  402.       str:= ConcatenationString( str, String( coeffs[1] ) );
  403.     fi;
  404.     i:= 2;
  405.     while i <= Length( coeffs ) do
  406.       if LengthString( str ) + LengthString( String( coeffs[i] ) )
  407.                              + LengthString( String( i-1 ) ) + 4 >= ll then
  408.         Print( str, "\n" );
  409.         str:= "";
  410.       fi;
  411.       if coeffs[i] < 0 then
  412.         str:= ConcatenationString( str, "-" );
  413.         if coeffs[i] <> -1 then
  414.           str:= ConcatenationString( str, String( -coeffs[i] ) );
  415.         fi;
  416.         str:= ConcatenationString( str, "w", String( i-1 ) );
  417.       elif coeffs[i] > 0 then
  418.         str:= ConcatenationString( str, "+" );
  419.         if coeffs[i] <> 1 then
  420.           str:= ConcatenationString( str, String( coeffs[i] ) );
  421.         fi;
  422.         str:= ConcatenationString( str, "w", String( i-1 ) );
  423.       fi;
  424.       i:= i+1;
  425.     od;
  426.     Print( str, "\n>\n" );
  427.     end;
  428.     #    
  429.     convertrow:= function( list )
  430.     local i, str;
  431.     if IsCycInt( list[1] ) and not IsInt( list[1] ) then
  432.       convertcyclotom( list[1] );
  433.       str:= "";
  434.     elif IsUnknown( list[1] ) or IsList( list[1] ) then
  435.       str:= "?";
  436.     else
  437.       str:= String( list[1] );
  438.     fi;
  439.     i:= 2;
  440.     while i <= Length( list ) do
  441.       if IsCycInt( list[i] ) and not IsInt( list[i] ) then
  442.         Print( str, "," );
  443.         convertcyclotom( list[i] );
  444.         str:= "";
  445.       elif IsUnknown( list[i] ) or IsList( list[i] ) then
  446.         if LengthString( str ) + 4 < ll then
  447.           str:= ConcatenationString( str, ",?" );
  448.         else
  449.           Print( str, ",?\n" );
  450.           str:= "";
  451.         fi;
  452.       else
  453.         if LengthString(str) + LengthString( String(list[i]) ) + 5 < ll then
  454.           str:= ConcatenationString( str, ",", String( list[i] ) );
  455.         else
  456.           Print( str, ",\n" );
  457.           str:= String( list[i] );
  458.         fi;
  459.       fi;
  460.       i:= i+1;
  461.     od;
  462.     Print( str, "\n" );
  463.     end;
  464.     #
  465.     if IsBound( tbl.centralizers ) then                 # centralizers
  466.       Print( ",\ncentralizers:(\n" );
  467.       convertrow( tbl.centralizers );
  468.       Print( ")" );
  469.     fi;
  470.     if IsBound( tbl.orders ) then                       # orders
  471.       Print( ",\nreps:(\n" );
  472.       convertrow( tbl.orders );
  473.       Print( ")" );
  474.     fi;
  475.     if IsBound( tbl.print ) then                        # print
  476.       Print( ",\nprint:(\n" );
  477.       convertrow( tbl.print );
  478.       Print( ")" );
  479.     fi;
  480.     if IsBound( tbl.powermap ) then                     # powermaps
  481.       for i in [ 1 .. Length( tbl.powermap ) ] do
  482.         if IsBound( tbl.powermap[i] ) then
  483.           Print( ",\npowermap:", String(i), "(\n" );
  484.           convertrow( tbl.powermap[i] );
  485.           Print( ")" );
  486.         fi;
  487.       od;
  488.     fi;
  489.     if IsBound( tbl.classtext ) then                    # classtext
  490.                                                         # (partitions)
  491.       Print(",\nclasstext:'part'\n($[" );
  492.       convertrow( tbl.classtext[1] );
  493.       Print( "]$" );
  494.       for i in [ 2 .. Length( tbl.classtext ) ] do
  495.         Print( "\n,$[" );
  496.         convertrow( tbl.classtext[i] );
  497.         Print( "]$" );
  498.       od;
  499.       Print( ")" );
  500.     fi;
  501.     if IsBound( tbl.fusions ) then                      # fusions
  502.       for fus in tbl.fusions do
  503.         if IsBound( fus.type ) then
  504.           if fus.type = "normal" then
  505.             Print( ",\nnormal subgroup " );
  506.           elif fus.type = "factor" then
  507.             Print( ",\nfactor " );
  508.           else
  509.             Print( ",\n" );
  510.           fi;
  511.         else
  512.           Print( ",\n" );
  513.         fi;
  514.         Print( "fusion:'", fus.name, "'(\n" );
  515.         convertrow( fus.map );
  516.         Print( ")" );
  517.       od;
  518.     fi;
  519.     if IsBound( tbl.characters ) then                  # characters ...
  520.       Print( ",\ncharacters:" );
  521.       for i in tbl.characters do
  522.         Print( "\n(" );
  523.         convertrow( i );
  524.         Print( ")" );
  525.       od;
  526.     elif IsBound( tbl.irreducibles ) then              # ... or irreducibles
  527.       Print( ",\ncharacters:" );
  528.       for i in tbl.irreducibles do
  529.         Print( "\n(" );
  530.         convertrow( i );
  531.         Print( ")" );
  532.       od;
  533.     fi;
  534.     if IsBound( tbl.irredinfo ) then                   # indicators and blocks
  535.       if IsBound( tbl.irredinfo[1].block ) then
  536.         for i in [ 2 .. Length( tbl.irredinfo[1].block ) ] do
  537.           if IsBound( tbl.irredinfo[1].block[i] ) then
  538.             column:= [];
  539.             for j in [ 1 .. Length( tbl.irreducibles ) ] do
  540.               column[j]:= tbl.irredinfo[j].block[i];
  541.             od;
  542.             Print( ",\nblocks:", String( i ), "(\n" );
  543.             convertrow( column );
  544.             Print( ")" );
  545.           fi;
  546.         od;
  547.       fi;
  548.       if IsBound( tbl.irredinfo[1].indicator ) then
  549.         for i in [ 2 .. Length( tbl.irredinfo[1].indicator ) ] do
  550.           if IsBound( tbl.irredinfo[1].indicator[i] ) then
  551.             column:= [];
  552.             for j in [ 1 .. Length( tbl.irreducibles ) ] do
  553.               column[j]:= tbl.irredinfo[j].indicator[i];
  554.             od;
  555.             Print( ",\nindicator:", String( i ), "(\n" );
  556.             convertrow( column );
  557.             Print( ")" );
  558.           fi;
  559.         od;
  560.       fi;
  561.     fi;
  562.     if ll > 27 then
  563.       Print( ";\n/// converted from GAP" );
  564.     else
  565.       Print( ";\n///" );
  566.     fi;
  567.     return "\n";
  568.     end;
  569.     PrintTo( filename, funct( tbl ) );
  570.     end;
  571.  
  572.  
  573. #############################################################################
  574. ##
  575. #F  TestCharTable( <tbl> )
  576. ##
  577. ##  checks consistency of informations in the head of the character table
  578. ##  <tbl>, checks if the first orthogonality relation is satisfied.
  579. ##
  580. TestCharTable := function( tbl )
  581.     local i, j, k, x, flag, order, nccl, classes, centralizers, powermap,
  582.           characters, map, row, sum;
  583.     if not IsCharTable( tbl ) then
  584.       Print( "#E TestCharTable: object is not a character table,",
  585.              " no tests\n" );
  586.       return false;
  587.     fi;
  588.     flag:= true;
  589.     centralizers:= tbl.centralizers;
  590.     if IsBound( tbl.order ) then
  591.       order:= tbl.order;
  592.     else
  593.       order:= centralizers[1];
  594.     fi;
  595.     if centralizers[1] <> order then
  596.       Print( "#E TestCharTable(", tbl.name,
  597.              "): centralizer of identity not equal to group order\n" );
  598.       flag:= false;
  599.     fi;
  600.     nccl:= Length( centralizers );
  601.     if not ( IsBound( tbl.classes ) and IsList( tbl.classes ) ) then
  602.       classes:= List( tbl.centralizers, x-> order / x );
  603.     else
  604.       classes:= tbl.classes;
  605.     fi;
  606.     if Sum( classes ) <> order then
  607.       Print( "#E TestCharTable(", tbl.name,
  608.              "): sum of classlengths not equal to group order\n" );
  609.       flag:= false;
  610.     fi;
  611.     if Length( classes ) <> nccl then
  612.       Print( "#E TestCharTable(", tbl.name,
  613.              "): number of conjugacy classes not unique\n" );
  614.       flag:= false;
  615.     fi;
  616.     if ForAny( [ 1..nccl ], i -> classes[i]*centralizers[i] <> order ) then
  617.       Print( "#E TestCharTable(", tbl.name,
  618.              "): classlengths and centralizer orders inconsistent\n" );
  619.       flag:= false;
  620.     fi;
  621.     if IsBound( tbl.orders ) then
  622.       if nccl <> Length( tbl.orders ) then
  623.         Print( "#E TestCharTable(", tbl.name,
  624.                "): number of conjugacy classes not unique\n" );
  625.         flag:= false;
  626.       else
  627.         for i in [ 1 .. Length( tbl.orders ) ] do
  628.           if not ( ( IsInt( tbl.orders[i] )
  629.                      and tbl.centralizers[i] mod tbl.orders[i] = 0 ) or
  630.                    ( IsSet( tbl.orders[i] )
  631.                      and Set( List( tbl.orders[i],
  632.                           x-> tbl.centralizers[i] mod x ) ) = [ 0 ] ) ) then
  633.             Print( "#E TestCharTable(", tbl.name,
  634.                    "): not all representative orders divide the\n",
  635.                    "#E   corresponding centralizer order\n" );
  636.             flag:= false;
  637.           fi;
  638.         od;
  639.       fi;
  640.     fi;
  641.     if IsBound( tbl.powermap ) then
  642.       for map in Set( tbl.powermap ) do
  643.         if nccl <> Length( map ) then
  644.           Print( "#E TestCharTable(", tbl.name,
  645.                  "): number of conjugacy classes not unique\n" );
  646.           flag:= false;
  647.         fi;
  648.       od;
  649.  
  650.       # if all powermaps are stored, check if they are consistent with
  651.       # the representative orders
  652.  
  653.       if IsBound( tbl.orders ) and
  654.          ForAll( Set( FactorsInt( order ) ),
  655.                  x -> IsBound( tbl.powermap[x] ) ) and
  656.          tbl.orders <> ElementOrdersPowermap( tbl.powermap ) then
  657.         flag:= false;
  658.         Print( "#E TestCharTable(", tbl.name,
  659.                "): representative orders and powermaps inconsistent\n" );
  660.       fi;
  661.     fi;
  662.     if IsBound( tbl.classnames ) then
  663.       for k in [ 1 .. nccl ] do
  664.         if tbl.( tbl.classnames[k] ) <> k then
  665.           Print( "#E TestCharTable(", tbl.name,
  666.                  "): classnames inconsistent for class", k, "\n" );
  667.           flag:= false;
  668.         fi;
  669.       od;
  670.     fi;
  671.     if IsBound( tbl.irreducibles ) then
  672.       if flag = false then
  673.         Print("#E TestCharTable: corrupt table, no test of orthogonality\n");
  674.         return false;
  675.       fi;
  676.       characters:= tbl.irreducibles;
  677.       for i in [ 1 .. Length( characters ) ] do
  678.         row:= [];
  679.         for j in [ 1 .. Length( characters[i] ) ] do
  680.           row[j]:= GaloisCyc( characters[i][j], -1 ) * classes[j];
  681.         od;
  682.         for j in [ 1 .. i ] do
  683.           sum:= row * characters[j];
  684.           if ( i = j and sum <> order ) or ( i <> j and sum <> 0 ) then
  685.             flag:= false;
  686.             Print( "#E TestCharTable(", tbl.name,
  687.                    "): Scpr( ., X[", i, "], X[", j, "] ) = ",
  688.                    sum / order, "\n" );
  689.           fi;
  690.         od;
  691.       od;
  692.       if centralizers <> Sum( characters,
  693.                               x -> List( x, y -> y * GaloisCyc(y,-1) ) ) then
  694.         flag:= false;
  695.         Print( "#E TestCharTable(", tbl.name,
  696.                "): centralizer orders inconsistent with irreducibles\n" );
  697.       fi;
  698.       if IsBound(tbl.irredinfo) and IsBound(tbl.irredinfo[1].indicator) then
  699.         for i in [ 2 .. Length( tbl.irredinfo[1].indicator ) ] do
  700.           if IsBound( tbl.irredinfo[1].indicator[i] ) then
  701.             if List( tbl.irredinfo, x -> x.indicator[i] )
  702.                <> Indicator( tbl, tbl.irreducibles, i ) then
  703.               Print( "#E TestCharTable(", tbl.name,
  704.                      "): ", Ordinal( i ), " indicator not correct\n" );
  705.               flag:= false;
  706.             fi;
  707.           fi;
  708.         od;
  709.       fi;
  710.     fi;
  711.     return flag;
  712.     end;
  713.  
  714.  
  715. #############################################################################
  716. ##
  717. #F  'ClassNamesCharTable( <tbl> ) . . . . . . . . . . . . . . . . class names
  718. ##
  719. ##  'ClassNamesCharTable'  computes  names  for the classes of  the character
  720. ##  table <tbl> as strings consisting of the order of an element of the class
  721. ##  and and least one distinguishing letter.
  722. ##
  723. ##  The list of these names at the same time the returned value of this
  724. ##  function and stored on the table <tbl> as record field 'classnames'.
  725. ##  
  726. ##  Moreover for each class a record field with its name is constructed,
  727. ##  containing the position of this name in the list 'classnames' as its
  728. ##  value.
  729. ##
  730. ##  If the record field 'classnames' of <tbl> is unbound,
  731. ##  'ClassNamesCharTable' is automatically called by  'DisplayCharTable' (see
  732. ##  "DisplayCharTable").
  733. ##
  734. ##  Note that once the class names are computed the resulting record fields
  735. ##  are stored on <tbl>. They are not deleted by another call of
  736. ##  'ClassNamesCharTable'.
  737. ##
  738. ClassNamesCharTable := function(tbl)
  739.     local alpha, number, names, i, j, name;
  740.  
  741.     name:= function(n)
  742.        local ll, name;
  743.  
  744.        name:= "";
  745.        ll:= Length(alpha);
  746.        while n > 0 do
  747.           name:= ConcatenationString(alpha[(n-1) mod ll + 1], name);
  748.           n:= QuoInt(n-1, ll);
  749.        od;
  750.        return name;
  751.     end;
  752.  
  753.     alpha:= ["a","b","c","d","e","f","g","h","i","j","k","l",
  754.              "m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
  755.  
  756.     names:= [];
  757.     number:= [];  # to count number of classes of equal order
  758.  
  759.     for i in [1..Length(tbl.orders)] do
  760.        if not IsBound(number[tbl.orders[i]]) then
  761.          number[tbl.orders[i]]:= 1;
  762.        fi;
  763.        names[i]:= ConcatenationString(String(tbl.orders[i]),
  764.                                       name(number[tbl.orders[i]]));
  765.        number[tbl.orders[i]]:= number[tbl.orders[i]] + 1;
  766.     od;
  767.  
  768.     # store result on character table
  769.     tbl.classnames:= names;
  770.     for i in [1..Length(names)] do
  771.        tbl.( names[i] ):= i;
  772.     od;
  773.  
  774.     return names;
  775.  
  776.     end;
  777.  
  778.  
  779. #############################################################################
  780. ##
  781. #F  CharTable( <group> )
  782. ##
  783. ##  returns '<group>.operations.CharTable( <group> )' resp.
  784. ##  '<group>.charTable' if one of these components exists.
  785. ##
  786. #F  CharTable( <tblname> )
  787. #F  CharTable( <series>, <parameters> )
  788. ##
  789. ##  return the value of 'CharTableLibrary' with the same argument(s).
  790. ##
  791. CharTable := function( arg )
  792.  
  793.     if Length(arg) < 1 or not ( IsString(arg[1]) or IsGroup(arg[1]) ) then
  794.       Error( "usage: CharTable( <grp> ) resp. CharTable( <tblname> )\n",
  795.              "         resp. CharTable( <series>, <parameters> )" );
  796.     fi;
  797.  
  798.     if IsGroup( arg[1] ) then
  799.  
  800.       if IsBound( arg[1].charTable ) then
  801.         return Copy( arg[1].charTable );
  802.       elif IsBound( arg[1].operations.CharTable ) then
  803.         return arg[1].operations.CharTable( arg[1] );
  804.       else
  805.         Error( "Sorry, I don't know how to ",
  806.                "construct the table of <grp>\n");
  807.       fi;
  808.  
  809.     else
  810.  
  811.       return CharTableLibrary( arg );
  812.  
  813.     fi;
  814.     end;
  815.  
  816.  
  817. #############################################################################
  818. ##
  819. #F  DisplayCharTable( <tbl> [, <arec> ] )
  820. ##
  821. DisplayCharTable := function(arg)
  822.     local i, j,          # loop variables
  823.           tbl,           # character table
  824.           chars,         # list of characters
  825.           cnr,           # list of character numbers
  826.           cletter,       # character name
  827.           classes,       # list of classes
  828.           powermap,      # list of primes
  829.           centralizers,  # boolean
  830.           cen,           # factorized centralizers
  831.           fak,           # factorization
  832.           prime,         # loop over primes
  833.           primes,        # prime factors of order
  834.           prin,          # column widths
  835.           nam,           # classnames
  836.           col,           # number of columns already printed
  837.           acol,          # nuber of columns on next page
  838.           len,           # width of next page
  839.           ncols,         # total number of columns
  840.           q,             # quadratic cyc / powermap entry
  841.           usage,         # usage
  842.           indicator,     # list of primes
  843.           indic,         # indicators
  844.           iw,            # width of indicator column
  845.           letters,       # the alphabet
  846.           irrstack,      # list of known cycs
  847.           colWidth,      # local function
  848.           irrName,       # local function
  849.           dispEntry;     # local function
  850.  
  851.     colWidth:= function(col)
  852.        local chi, width;
  853.  
  854.        width:= LengthString(nam[col]);
  855.        for chi in chars do
  856.           if (IsCyc(chi[col]) and not IsInt(chi[col]))
  857.                      or IsList(chi[col]) or IsUnknown(chi[col]) then
  858.              width:= Maximum(width, 3);
  859.           else
  860.              width:= Maximum(width, LengthString(String(chi[col])));
  861.           fi;
  862.        od;
  863.        return width + 1;
  864.     end;
  865.  
  866.     irrName:= function(n)
  867.        local i, ll, name;
  868.  
  869.        name:= "";
  870.        ll:= Length(letters);
  871.        while n > 0 do
  872.           name:= ConcatenationString(letters[(n-1) mod ll + 1], name);
  873.           n:= QuoInt(n-1, ll);
  874.        od;
  875.        return(name);
  876.     end;
  877.  
  878.     dispEntry:= function(entry, width)
  879.        local i, done, val;
  880.  
  881.        if IsCyc(entry) and not IsInt(entry) then
  882.           # find shorthand for cyclo
  883.           i:= 1; done:= false;
  884.           while i <= Length(irrstack) and not done do
  885.              if entry = irrstack[i] then
  886.                 entry:= irrName(i);
  887.                 done:= true;
  888.              elif entry = -irrstack[i] then
  889.                 entry:= ConcatenationString("-", irrName(i));
  890.                 done:= true;
  891.              fi;
  892.              if not done then
  893.                 val:= GaloisCyc(irrstack[i], -1);
  894.                 if entry = val then
  895.                    entry:= ConcatenationString("/", irrName(i));
  896.                    done:= true;
  897.                 elif entry = -val then
  898.                    entry:= ConcatenationString("-/", irrName(i));
  899.                    done:= true;
  900.                 fi;
  901.              fi;
  902.              if not done then
  903.                 val:= StarCyc(irrstack[i]);
  904.                 if entry = val then
  905.                    entry:= ConcatenationString("*", irrName(i));
  906.                    done:= true;
  907.                 elif -entry = val then
  908.                    entry:= ConcatenationString("-*", irrName(i));
  909.                    done:= true;
  910.                 fi;
  911.              fi;
  912.              i:= i+1;
  913.           od;
  914.           if not done then 
  915.              Add(irrstack, entry);
  916.              entry:= irrName(Length(irrstack));
  917.           fi;
  918.        elif entry = 0 then
  919.           entry:= ".";
  920.        elif ( IsList( entry ) and not IsString( entry ) )
  921.             or IsUnknown( entry ) then
  922.           entry:= "?";
  923.        else
  924.           entry:= String(entry);
  925.        fi;
  926.  
  927.        # printformat(entry, width);
  928.        entry:= String(entry, width);
  929.        Print(entry, "\c");
  930.     end;
  931.  
  932.     # scan arg
  933.     usage:= "usage: DisplayCharTable( <tbl> [, <arec>] )";
  934.     if Length(arg) = 1 then
  935.        if not IsCharTable(arg[1]) then
  936.           Error(usage);
  937.        fi;
  938.     elif Length(arg) = 2 then
  939.        if not IsCharTable(arg[1]) or not IsRec(arg[2]) then
  940.           Error(usage);
  941.        fi;
  942.     else
  943.        Error(usage);
  944.     fi;
  945.        
  946.     irrstack:= [];
  947.     letters:= ["A","B","C","D","E","F","G","H","I","J","K","L","M",
  948.                  "N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
  949.     
  950.     tbl:= arg[1];
  951.     # default:
  952.     chars:= tbl.irreducibles;
  953.     classes:= [1..Length(tbl.orders)];
  954.     powermap:= Filtered( [1..Length(tbl.powermap)],
  955.                          x->IsBound(tbl.powermap[x]));
  956.     centralizers:= true;
  957.     cletter:= "X";
  958.     cnr:= [1..Length(chars)];
  959.     indicator:= [];
  960.  
  961.     # options
  962.     if IsBound(arg[2]) then
  963.        if IsBound(arg[2].chars) then
  964.           if IsMat(arg[2].chars) then
  965.              chars:= arg[2].chars;
  966.              cletter:= "Y";
  967.              cnr:= [1..Length(chars)];
  968.           elif IsVector(arg[2].chars) then
  969.              cnr:= arg[2].chars;
  970.              chars:= Sublist(chars, cnr);
  971.           elif IsInt(arg[2].chars) then
  972.              chars:= [chars[arg[2].chars]];
  973.              cnr:= [arg[2].chars];
  974.           fi;
  975.        fi;
  976.        if IsBound(arg[2].letter) and arg[2].letter in letters then
  977.           cletter:= arg[2].letter;
  978.        fi;
  979.        if IsBound(arg[2].classes) then
  980.           classes:= arg[2].classes;
  981.        fi;
  982.        if IsBound(arg[2].powermap) then
  983.           if IsInt(arg[2].powermap) then
  984.              powermap:= [arg[2].powermap];
  985.           elif IsList(arg[2].powermap) then
  986.              powermap:= arg[2].powermap;
  987.           elif arg[2].powermap = false then
  988.              powermap:= [];
  989.           fi;
  990.        fi;
  991.        if IsBound(arg[2].centralizers) and arg[2].centralizers = false then
  992.           centralizers:= false;
  993.        fi;
  994.        if IsBound(arg[2].indicator) and not (IsBound(arg[2].chars) and
  995.                                IsMat(arg[2].chars)) then
  996.           if arg[2].indicator = true then
  997.              indicator:= [2];
  998.           elif IsVector(arg[2].indicator) then
  999.              indicator:= Set(Filtered(arg[2].indicator,x->IsInt(x) and x>0));
  1000.           fi;
  1001.        fi;
  1002.     fi;
  1003.  
  1004.     # a chartable has a name
  1005.     Print(tbl.name, "\n\n");
  1006.  
  1007.     # prepare centralizers
  1008.     if centralizers then
  1009.        cen:= [];
  1010.        fak:= Factors(tbl.order);
  1011.        primes:= Set(fak);
  1012.        for prime in primes do
  1013.           cen[prime]:= [Length(Filtered(fak, x->x=prime))];
  1014.        od;
  1015.     fi;
  1016.  
  1017.     # prepare classnames
  1018.     if IsBound(tbl.classnames) then
  1019.        nam:= tbl.classnames;
  1020.     else
  1021.        nam:= ClassNamesCharTable(tbl);
  1022.     fi;
  1023.  
  1024.     # prepare indicator
  1025.     iw:= [0];
  1026.     if indicator <> [] and not IsBound(tbl.irredinfo) then
  1027.        indicator:= [];
  1028.     fi;
  1029.     if indicator <> [] then
  1030.        indic:= [];
  1031.        for i in indicator do
  1032.           indic[i]:= [];
  1033.           for j in cnr do
  1034.              if IsBound(tbl.irredinfo[j]) and
  1035.                 IsBound(tbl.irredinfo[j].indicator) and
  1036.                 IsBound(tbl.irredinfo[j].indicator[i]) then
  1037.                 indic[i][j]:= tbl.irredinfo[j].indicator[i];
  1038.              fi;
  1039.           od;
  1040.           if indic[i] = [] then
  1041.              Unbind(indic[i]);
  1042.           else
  1043.              if i = 2 then
  1044.                 iw[i]:= 2;
  1045.              else
  1046.                 iw[i]:= Maximum(LengthString(String(Maximum(Set(indic[i])))),
  1047.                        LengthString(String(Minimum(Set(indic[i])))),
  1048.                        LengthString(String(i)))+1;
  1049.              fi;
  1050.              iw[1]:= iw[1] + iw[i];
  1051.           fi;
  1052.        od;
  1053.        iw[1]:= iw[1] + 1;
  1054.        indicator:= Filtered(indicator, x-> IsBound(indic[x]));
  1055.     fi;
  1056.  
  1057.     prin:= [LengthString(String(Maximum(cnr)))+3];
  1058.     ncols:= Length(classes) + 1; # Number Of Columns
  1059.  
  1060.     col:= 1;             # Anzahl bereits gedruckter Spalten
  1061.     while col < ncols do
  1062.  
  1063.        # determine number of cols for next page
  1064.        acol:= 0;
  1065.        if indicator <> [] then
  1066.           prin[1]:= prin[1] + iw[1];
  1067.        fi;
  1068.        len:= prin[1];
  1069.        while col+acol < ncols and len < SizeScreen()[1] do
  1070.           acol:= acol + 1;
  1071.           if Length(prin) < col + acol then
  1072.              prin[col + acol]:= colWidth(classes[col + acol - 1]);
  1073.           fi;
  1074.           len:= len + prin[col+acol];
  1075.        od;
  1076.        if len >= SizeScreen()[1] then
  1077.           acol:= acol-1;
  1078.        fi;
  1079.  
  1080.        # centralizers
  1081.        if centralizers then
  1082.           for i in [col..col+acol-1] do
  1083.              fak:= Factors(tbl.centralizers[classes[i]]);
  1084.              for prime in Set(fak) do
  1085.                 cen[prime][i]:= Length(Filtered(fak, x->x=prime));
  1086.              od;
  1087.           od;
  1088.           for j in [1..Length(cen)] do
  1089.              if IsBound(cen[j]) then
  1090.                 for i in [col..col+acol-1] do
  1091.                    if not IsBound(cen[j][i]) then
  1092.                       cen[j][i]:= 0;
  1093.                    fi;
  1094.                 od;
  1095.              fi;
  1096.           od;
  1097.  
  1098.           for prime in primes do
  1099.              dispEntry(String(prime), prin[1]);
  1100.              for j in [1..acol] do
  1101.                 dispEntry(cen[prime][col+j-1], prin[col+j]);
  1102.              od;
  1103.              Print("\n");
  1104.           od;
  1105.           Print("\n");
  1106.        fi;
  1107.  
  1108.        # classnames
  1109.        dispEntry("", prin[1]);
  1110.        for i in [1..acol] do
  1111.           dispEntry(nam[classes[col+i-1]], prin[col+i]);
  1112.        od;
  1113.        Print("\n");
  1114.  
  1115.        # powermaps
  1116.        if powermap <> [] and IsBound(tbl.powermap) then
  1117.           for i in powermap do
  1118.              if IsBound(tbl.powermap[i]) then
  1119.                 dispEntry(ConcatenationString(String(i), "P"), prin[1]);
  1120.                 for j in [1..acol] do
  1121.                    q:= tbl.powermap[i][classes[col+j-1]];
  1122.                    if IsInt(q) then
  1123.                       dispEntry(nam[q],prin[col+j]);
  1124.                    else
  1125.                       dispEntry("?", prin[col+j]);
  1126.                    fi;
  1127.                 od;
  1128.                 Print("\n");
  1129.              fi;
  1130.           od;
  1131.        fi;
  1132.  
  1133.        # empty line resp. indicators
  1134.        if indicator <> [] then
  1135.           prin[1]:= prin[1] - iw[1];
  1136.           dispEntry("", prin[1]);
  1137.           for i in indicator do
  1138.              dispEntry(i, iw[i]);
  1139.           od;
  1140.        fi;
  1141.        Print("\n");
  1142.  
  1143.        # the characters
  1144.        for i in [1..Length(chars)] do
  1145.           dispEntry(ConcatenationString( cletter, ".",
  1146.                                          String(cnr[i])), -prin[1]);
  1147.  
  1148.           # indicators
  1149.           for j in indicator do
  1150.              if IsBound(indic[j][cnr[i]]) then
  1151.                 if j = 2 then
  1152.                    if indic[j][cnr[i]] = 0 then
  1153.                       dispEntry("o", iw[j]);
  1154.                    elif indic[j][cnr[i]] = 1 then
  1155.                       dispEntry("+", iw[j]);
  1156.                    elif indic[j][cnr[i]] = -1 then
  1157.                       dispEntry("-", iw[j]);
  1158.                    fi;
  1159.                 else
  1160.                    if indic[j][cnr[i]] = 0 then
  1161.                       dispEntry("0", iw[j]);
  1162.                    else
  1163.                       dispEntry(indic[j][cnr[i]], iw[j]);
  1164.                    fi;
  1165.                 fi;
  1166.              else
  1167.                 dispEntry("", iw[j]);
  1168.              fi;
  1169.           od;
  1170.           if indicator <> [] then
  1171.              Print(" ");
  1172.           fi;
  1173.           for j in [1..acol] do
  1174.              dispEntry(chars[i][classes[col+j-1]], prin[col+j]);
  1175.           od;
  1176.           Print("\n");
  1177.        od;
  1178.        col:= col + acol;
  1179.        Print("\n");
  1180.        indicator:= [];
  1181.     od;
  1182.  
  1183.     # print legend for cyclos
  1184.     for i in [1..Length(irrstack)] do
  1185.        Print(irrName(i), " = ", irrstack[i], "\n");
  1186.        q:= Quadratic(irrstack[i]);
  1187.        if IsRec(q) then
  1188.           if q.a <> 0 then
  1189.              q.t:= String(q.a);
  1190.           else
  1191.              q.t:= "";
  1192.           fi;
  1193.           if AbsInt(q.b) > 1 then
  1194.              if q.t = "" then
  1195.                 q.t:= String(q.b);
  1196.              elif q.b > 0 then
  1197.                 q.t:= ConcatenationString(q.t, "+", String(q.b));
  1198.              else
  1199.                 q.t:= ConcatenationString(q.t, String(q.b));
  1200.              fi;
  1201.           elif q.b = 1 and q.t <> "" then
  1202.              q.t:= ConcatenationString(q.t, "+");
  1203.           elif q.b = -1 then
  1204.              q.t:= ConcatenationString(q.t, "-");
  1205.           fi;
  1206.           q.t:= ConcatenationString(q.t, "ER(", String(q.root), ")");
  1207.           if q.d <> 1 then
  1208.              q.t:= ConcatenationString("(", q.t, ")/", String(q.d));
  1209.           fi;
  1210.           Print("  = ", q.t, " = ", q.ATLAS, "\n");
  1211.        fi;
  1212.     od;
  1213.  
  1214.     end;
  1215.  
  1216.  
  1217. #############################################################################
  1218. ##
  1219. #F ClassMultCoeffCharTable( <tbl>, <c1>, <c2>, <c3> ) . class mult coefficent
  1220. ##
  1221. ClassMultCoeffCharTable := function(tbl, c1 ,c2, c3)
  1222.  
  1223.     local char, res;
  1224.  
  1225.     res:= 0;
  1226.  
  1227.     for char in tbl.irreducibles do
  1228.        res:= res + char[c1] * char[c2] * GaloisCyc(char[c3], -1) / char[1];
  1229.     od;
  1230.  
  1231.     return tbl.classes[c1] * tbl.classes[c2] * res / tbl.order;
  1232.  
  1233.     end;
  1234.  
  1235.  
  1236. #############################################################################
  1237. ##
  1238. #F ClassStructureCharTable(<tbl>,<classes>) . . gener. class mult. coefficent
  1239. ##
  1240. ClassStructureCharTable := function( tbl, classes )
  1241.  
  1242.     local chi, res, exp, summand, cl;
  1243.  
  1244.     res:= 0;
  1245.     exp:= Length( classes ) - 2;
  1246.     if exp < 0 then
  1247.       Error( "length of <classes> must be at least 2" );
  1248.     fi;
  1249.  
  1250.     for chi in tbl.irreducibles do
  1251.       summand:= 1;
  1252.       for cl in classes do
  1253.         summand:= summand * chi[cl];
  1254.       od;
  1255.       res:= res + summand / ( chi[1] ^ exp );
  1256.     od;
  1257.  
  1258.     for cl in classes do
  1259.       res:= res * tbl.classes[cl];
  1260.     od;
  1261.     return res / tbl.order;
  1262.  
  1263.     end;
  1264.  
  1265.  
  1266. #############################################################################
  1267. ##
  1268. #F MatClassMultCoeffsCharTable( <tbl>, <class> )
  1269. #F                                     . . . matrix of class mult coefficents
  1270. ##
  1271. ##  returns a matrix <M> of structure constants where
  1272. ##  '<M>[j][k] = ClassMultCoeffCharTable( <tbl>, <class>, j, k )'
  1273. ##
  1274. MatClassMultCoeffsCharTable := function( tbl, class )
  1275.     local j, k, result, nccl, row;
  1276.     result:= [];
  1277.     nccl:= Length( tbl.centralizers );
  1278.     for j in [ 1 .. nccl ] do
  1279.       row:= [];
  1280.       for k in [ 1 .. nccl ] do
  1281.         row[k]:= ClassMultCoeffCharTable( tbl, class, j, k );
  1282.       od;
  1283.       result[j]:= row;
  1284.     od;
  1285.     return result;
  1286.     end;
  1287.  
  1288.  
  1289. #############################################################################
  1290. ##
  1291. #F RealClassesCharTable( <tbl> )  . . . .  the real-valued classes of a table
  1292. ##
  1293. ## An element $x$ is real iff it is conjugate with its inverse
  1294. ## $x^-1 = x^{o(x)-1}$.
  1295. ##
  1296. RealClassesCharTable := function(tbl)
  1297.     local i, p, k, oo, po, cla, nccl, powmap, res;
  1298.  
  1299.     res:= [];
  1300.     powmap:= tbl.powermap;
  1301.     nccl:= Length(tbl.orders);
  1302.  
  1303.     for i in [1..nccl] do
  1304.        # test x ~ x^-1
  1305.        oo:= tbl.orders[i];
  1306.        if oo <= 2 then
  1307.           Add(res, i);
  1308.        else
  1309.  
  1310.           po:= Factors(oo-1);
  1311.           cla:= i;
  1312.           for p in po do
  1313.              if not IsBound(powmap[p]) then
  1314.                 powmap[p]:= Powermap(tbl, p, rec( quick:= true ) );
  1315.              fi;
  1316.              cla:= powmap[p][cla];
  1317.           od;
  1318.           if cla = i then 
  1319.              Add(res, i);
  1320.           fi;
  1321.  
  1322.        fi;
  1323.     od;
  1324.  
  1325.     return res;
  1326.  
  1327.     end;
  1328.  
  1329.  
  1330. #############################################################################
  1331. ##
  1332. #F ClassOrbitCharTable( <tbl>, <cc> ) . . . . .  classes of a cyclic subgroup
  1333. ##
  1334. ClassOrbitCharTable := function(tbl, cc)
  1335.     local i, p, cla, oo, po, powmap, res;
  1336.  
  1337.     res:= [cc];
  1338.     powmap:= tbl.powermap;
  1339.     oo:= tbl.orders[cc];
  1340.  
  1341.     # find all generators of <cc>
  1342.     for i in [2..oo-1] do
  1343.        if GcdInt(i, oo) = 1 then
  1344.           po:= Factors(i);
  1345.           cla:= cc;
  1346.           for p in po do
  1347.              if not IsBound(powmap[p]) then
  1348.                 powmap[p]:= Powermap(tbl, p, rec( quick:= true ) );
  1349.                 if Length( powmap[p] ) = 1 then
  1350.                    powmap[p]:= powmap[p][1];
  1351.                 else
  1352.                    Print( "#I ClassOrbitCharTable: powermap not",
  1353.                           " uniquely determined\n" );
  1354.                    powmap[p]:= Parametrized( powmap[p] );
  1355.                 fi;
  1356.              fi;
  1357.              cla:= powmap[p][cla];
  1358.           od;
  1359.           AddSet(res, cla);
  1360.        fi;
  1361.     od;
  1362.  
  1363.     return res;
  1364.  
  1365.     end;
  1366.  
  1367.  
  1368. #############################################################################
  1369. ##
  1370. #F NrPolyhedralSubgroups( <tbl>, <c1>, <c2>, <c3>) . . # polyhedral subgroups
  1371. ##
  1372. NrPolyhedralSubgroups := function(tbl, c1, c2, c3)
  1373.     local res, ord;
  1374.  
  1375.     if tbl.orders[c1] = 2 then
  1376.        res:= ClassMultCoeffCharTable(tbl, c1, c2, c3) * tbl.classes[c3];
  1377.        if tbl.orders[c2] = 2 then
  1378.           if tbl.orders[c3] = 2 then   # V4
  1379.              ord:= Length(Set([c1, c2, c3]));
  1380.              if ord = 2 then
  1381.                 res:= res * 3;
  1382.              elif ord = 3 then
  1383.                 res:= res * 6;
  1384.              fi;
  1385.              res:= res / 6;
  1386.              if not IsInt(res) then
  1387.                 Error("noninteger result");
  1388.              fi;
  1389.              return rec(number:= res, type:= "V4");
  1390.           elif tbl.orders[c3] > 2 then   # D2n
  1391.              ord:= tbl.orders[c3];
  1392.              if c1 <> c2 then 
  1393.                 res:= res * 2;
  1394.              fi;
  1395.              res:= res * Length(ClassOrbitCharTable(tbl,c3))/(ord*Phi(ord));
  1396.              if not IsInt(res) then
  1397.                 Error("noninteger result");
  1398.              fi;
  1399.              return rec(number:= res, 
  1400.                         type:= ConcatenationString("D" ,String(2*ord)));
  1401.           fi;
  1402.        elif tbl.orders[c2] = 3 then
  1403.           if tbl.orders[c3] = 3 then   # A4
  1404.              res:= res * Length(ClassOrbitCharTable(tbl, c3)) / 24;
  1405.              if not IsInt(res) then
  1406.                 Error("noninteger result");
  1407.              fi;
  1408.              return rec(number:= res, type:= "A4");
  1409.           elif tbl.orders[c3] = 4 then   # S4
  1410.              res:= res / 24;
  1411.              if not IsInt(res) then
  1412.                 Error("noninteger result");
  1413.              fi;
  1414.              return rec(number:= res, type:= "S4");
  1415.           elif tbl.orders[c3] = 5 then   # A5
  1416.              res:= res * Length(ClassOrbitCharTable(tbl, c3)) / 120;
  1417.              if not IsInt(res) then
  1418.                 Error("noninteger result");
  1419.              fi;
  1420.              return rec(number:= res, type:= "A5");
  1421.           fi;
  1422.        fi;
  1423.     fi;
  1424.  
  1425.     end;
  1426.  
  1427.  
  1428. #############################################################################
  1429. ##
  1430. #F ClassRootsCharTable( <tbl> ) . . . . . . . . . nontrivial root of elements
  1431. ##
  1432. ClassRootsCharTable := function( tbl )
  1433.  
  1434.     local i, nccl, pmap, root;
  1435.  
  1436.     nccl:= Length(tbl.classes);
  1437.     root:= List([1..nccl], x->[]);
  1438.  
  1439.     for pmap in tbl.powermap do
  1440.        for i in [1..nccl] do
  1441.           if i <> pmap[i] and tbl.orders[i] <> tbl.orders[pmap[i]] then
  1442.              AddSet(root[pmap[i]], i);
  1443.           fi;
  1444.        od;
  1445.     od;
  1446.  
  1447.     return root;
  1448.  
  1449. end;
  1450.  
  1451.  
  1452. #############################################################################
  1453. ##
  1454. #F  'SortCharactersCharTable( <tbl> )'\\
  1455. #F  'SortCharactersCharTable( <tbl>, <permutation> )'\\
  1456. #F  'SortCharactersCharTable( <tbl>, <chars> )'\\
  1457. #F  'SortCharactersCharTable( <tbl>, <chars>, <permutation> )'\\
  1458. #F  'SortCharactersCharTable( <tbl>, <chars>, \"norm\" )'\\
  1459. #F  'SortCharactersCharTable( <tbl>, <chars>, \"degree\" )'
  1460. ##
  1461. ##  If no list <chars> of characters of the character table <tbl> is
  1462. ##  entered, 'SortCharactersCharTable' sorts '<tbl>.irreducibles'; then
  1463. ##  additionally the list '<tbl>.irredinfo' is permuted by the same
  1464. ##  permutation. Otherwise 'SortCharactersCharTable' sorts the list <chars>.
  1465. ##
  1466. ##  There are three possibilities to sort characters\:\ 
  1467. ##  They can be sorted according to ascending norms (parameter '\"norm\"'),
  1468. ##  to ascending degree (parameter '\"degree\"') or both (no third parameter),
  1469. ##  i.e.\ characters with same norm are sorted according to ascending degree,
  1470. ##  and characters with smaller norm precede those with bigger norm.
  1471. ##
  1472. ##  Rational characters always will precede other ones with same norm resp.\ 
  1473. ##  same degree afterwards. The trivial character, if contained in <chars>
  1474. ##  resp.\ <tbl>.irreducibles, will always be sorted to the first position.
  1475. ##
  1476. ##  'SortCharactersCharTable' returns the permutation that was applied to
  1477. ##  <chars>.
  1478. ##  If <list> is specified this permutation is applied to this list, too.
  1479. ##
  1480. ##  To apply a particular permutation to a list of characters, use "Permuted".
  1481. ##
  1482. SortCharactersCharTable := function( arg )
  1483.     local i, tbl, chars, listtosort, len, permutation, permuted, list, pos,
  1484.           entry;
  1485.     if not ( Length( arg ) in [ 1, 2, 3 ] and IsCharTable( arg[1] ) )
  1486.        or ( Length( arg ) = 2
  1487.           and not ( IsList( arg[2] ) or IsPerm( arg[2] )
  1488.                     or ( IsString( arg[2] )
  1489.                          and SubString( arg[2],1,3 ) in ["deg","nor"] ) ) )
  1490.        or ( Length( arg ) = 3
  1491.           and not ( IsList(arg[2]) and ( IsPerm(arg[3]) or ( IsString(arg[3])
  1492.                     and SubString( arg[3],1,3 ) in ["deg","nor"] ) ) ) ) then
  1493.       Error( "usage: SortCharactersCharTable( <tbl> )\n",
  1494.      "         resp. SortCharactersCharTable( <tbl>, <perm> )\n",
  1495.      "         resp. SortCharactersCharTable( <tbl>, <chars> )\n",
  1496.      "         resp. SortCharactersCharTable( <tbl>, <chars>, <perm> )\n",
  1497.      "         resp. SortCharactersCharTable( <tbl>, <chars>, \"norm\" )\n",
  1498.      "         resp. SortCharactersCharTable( <tbl>, <chars>, \"degree\" )" );
  1499.     fi;
  1500.     tbl:= arg[1];
  1501.     if Length( arg ) > 1 and not IsPerm( arg[2] )
  1502.        and ( not IsString( arg[2] ) or arg[2] = [] ) then
  1503.       chars:= arg[2];
  1504.     else
  1505.       chars:= tbl.irreducibles;
  1506.     fi;
  1507.     if chars = [] then return (); fi;
  1508.     listtosort:= [];
  1509.     if IsPerm( arg[ Length( arg ) ] ) then
  1510.                          # SortCharactersCharTable( tbl, perm )
  1511.                          # SortCharactersCharTable( tbl, chars, perm )
  1512.       permutation:= arg[ Length( arg ) ];
  1513.     else
  1514.       if Length( arg ) = 1 or ( Length( arg ) = 2 and
  1515.            IsList( arg[2] ) and not IsString( arg[2] ) ) then
  1516.                          # SortCharactersCharTable( tbl ) or
  1517.                          # SortCharactersCharTable( tbl, chars ) or
  1518.                          # (stable) sort according to norms and degrees
  1519.         len:= 4;
  1520.         for i in [ 1 .. Length( chars ) ] do
  1521.           listtosort[i]:=
  1522.                  [ tbl.operations.ScalarProduct(tbl,chars[i],chars[i]),
  1523.                    chars[i][1], ForAll( chars[i], IsRat ), i ];
  1524.         od;
  1525.       elif ( IsString( arg[2] ) and arg[2]{ [ 1..3 ] } = "nor" )
  1526.            or ( Length( arg ) = 3 and arg[3]{ [ 1..3 ] } = "nor" ) then
  1527.                        # SortCharacters( tbl, "norm" ) or
  1528.                        # SortCharacters( tbl, chars, "norm" ):
  1529.                        # (stable) sort according to norms
  1530.         len:= 3;
  1531.         for i in [ 1 .. Length( chars ) ] do
  1532.           listtosort[i]:=
  1533.                  [ tbl.operations.ScalarProduct(tbl,chars[i],chars[i]),
  1534.                    ForAll( chars[i], IsRat ), i ];
  1535.         od;
  1536.       else             # SortCharacters( tbl, "degree" ) or
  1537.                        # SortCharacters( tbl, chars, "degree" ):
  1538.                        # (stable) sort according to degrees
  1539.         len:= 3;
  1540.         for i in [ 1 .. Length( chars ) ] do
  1541.           listtosort[i]:= [ chars[i][1], ForAll( chars[i], IsRat ), i ];
  1542.         od;
  1543.       fi;
  1544.       Sort( listtosort );
  1545.       for i in [ 1 .. Length( chars ) ] do
  1546.         listtosort[i]:= listtosort[i][ len ];
  1547.       od;
  1548.       permutation:= PermList( listtosort )^(-1);
  1549.     fi;
  1550.     permuted:= Permuted( chars, permutation );
  1551.     for i in [ 1 .. Length( chars ) ] do chars[i]:= permuted[i]; od;
  1552.     if IsBound( tbl.irredinfo ) and ( Length( arg ) = 1 or IsPerm( arg[2] )
  1553.                     or IsString( arg[2] ) ) then   # adjust '<tbl>.irredinfo'
  1554.       permuted:= Permuted( tbl.irredinfo, permutation );
  1555.       for i in [ 1 .. Length( permuted ) ] do
  1556.         tbl.irredinfo[i]:= permuted[i];
  1557.       od;
  1558.     fi;
  1559.     entry:=  List( [ 1 .. Length( chars[1] ) ], x -> 1 );
  1560.     pos:= Position( chars, entry );
  1561.     if pos <> false and pos > 1 and not IsPerm( arg[ Length( arg ) ] ) then
  1562.                            # triv. char. is contained but not at position 1
  1563.       for i in Reversed( [ 1 .. pos-1 ] ) do chars[ i+1 ]:= chars[i]; od;
  1564.       chars[1]:= entry;
  1565.       if IsBound( tbl.irredinfo ) and ( Length( arg ) = 1
  1566.          or IsString( arg[2] ) ) then   # adjust '<tbl>.irredinfo'
  1567.         entry:= tbl.irredinfo[1];
  1568.         for i in Reversed( [ 1 .. pos-1 ] ) do
  1569.           tbl.irredinfo[ i+1 ]:= tbl.irredinfo[i];
  1570.         od;
  1571.         tbl.irredinfo[1]:= entry;
  1572.       fi;
  1573.       permutation:= permutation * PermList( Concatenation( [2..pos], [1] ) );
  1574.     fi;
  1575.     return permutation;
  1576.     end;
  1577.  
  1578.  
  1579. #############################################################################
  1580. ##
  1581. #F  SortClassesCharTable( <tbl> )
  1582. #F  SortClassesCharTable( <tbl>, \"centralizers\" )
  1583. #F  SortClassesCharTable( <tbl>, \"representatives\" )
  1584. #F  SortClassesCharTable( <tbl>, <permutation> )
  1585. #F  SortClassesCharTable( <chars>, <permutation> )
  1586. ##
  1587. ##  The last form simply permutes the classes of all elements of <chars>
  1588. ##  by <permutation>. All other forms take a character table <tbl> as
  1589. ##  parameter, and 'SortClassesCharTable' permutes the classes of <tbl>:
  1590. ##  'SortClassesCharTable( <tbl>, \"centralizers\" )
  1591. ##           sorts the classes according to descending centralizer orders,
  1592. ##  'SortClassesCharTable( <tbl>, \"representatives\" )
  1593. ##           sorts the classes according to ascending representative orders,
  1594. ##  'SortClassesCharTable( <tbl> )
  1595. ##           sorts the classes according to ascending representative orders,
  1596. ##           and classes with equal representative orders according to
  1597. ##           descending centralizer orders
  1598. ##  'SortClassesCharTable( <tbl>, <permutation> )
  1599. ##           sorts the classes by application of <permutation>
  1600. ##
  1601. ##  After having calculated the permutation, 'SortClassesCharTable' will
  1602. ##  adjust the following fields of <tbl>:
  1603. ##
  1604. ##  1. by application of the permutation: orders, centralizers, classes, print,
  1605. ##     irreducibles, classtext, classparam, all fusion maps, classnames,
  1606. ##     the 'chars' component of entries of 'projectives',
  1607. ##     the 'conjugacyClasses' component of 'group'
  1608. ##  2. the fields corresponding to <tbl>.classnames
  1609. ##  3. by conjugation with the permutation: all powermaps, automorphisms
  1610. ##  4. galoisfams.classes
  1611. ##  5. by multiplication with the permutation: <tbl>.permutation
  1612. ##
  1613. SortClassesCharTable := function( arg )
  1614.     local i, j, k, x, chars, permutation, listtosort, tbl, orders, classes,
  1615.           len, fusions, powermap, galoisfams, result, list, permmap, inverse;
  1616.     if not ( ( Length( arg ) = 1 and IsCharTable( arg[1] ) )
  1617.              or ( Length(arg) = 2 and ( ( IsList(arg[1]) and IsPerm(arg[2]) )
  1618.                 or ( IsCharTable( arg[1] ) and
  1619.                      ( IsString( arg[2] ) or IsPerm( arg[2] ) ) ) ) ) ) then
  1620.       Error( "usage: SortClassesCharTable( <tbl> )\n",
  1621.      "         resp. SortClassesCharTable( <tbl>, \"centralizers\" )\n",
  1622.      "         resp. SortClassesCharTable( <tbl>, \"representatives\" )\n",
  1623.      "         resp. SortClassesCharTable( <tbl>, <perm> )\n",
  1624.      "         resp. SortClassesCharTable( <chars>, <perm> )" );
  1625.     fi;
  1626.     if IsList( arg[1] ) then       # SortClassesCharTable( chars, perm )
  1627.       chars:= arg[1];
  1628.       permutation:= arg[2];
  1629.       for i in [ 1 .. Length( chars ) ] do
  1630.         chars[i]:= Permuted( chars[i], permutation );
  1631.       od;
  1632.       return permutation;
  1633.     fi;
  1634.     tbl:= arg[1];
  1635.     orders:= tbl.orders;
  1636.     classes:= tbl.classes;
  1637.     if Length( arg ) = 2 and IsPerm( arg[2] ) then
  1638.                                    # SortClassesCharTable( tbl, perm )
  1639.       permutation:= arg[2];  
  1640.     else
  1641.       listtosort:= [];
  1642.       if Length( arg ) = 1 then    # SortClassesCharTable( tbl ):
  1643.          # (stable) sort according to ascending orders and classes
  1644.         len:= 3;
  1645.         for i in [ 1 .. Length( orders ) ] do
  1646.           listtosort[i]:= [ orders[i], classes[i], i ];
  1647.         od;
  1648.       else                # SortClassesCharTable( tbl, string ):
  1649.                           # (stable) sort according to orders or centralizers
  1650.         len:= 2;
  1651.         if arg[2]{ [ 1..3 ] } = "cen" then
  1652.           for i in [ 1 .. Length( classes ) ] do
  1653.             listtosort[i]:= [ classes[i], i ];
  1654.           od;
  1655.         else
  1656.           for i in [ 1 .. Length( orders ) ] do
  1657.             listtosort[i]:= [ orders[i], i ];
  1658.           od;
  1659.         fi;
  1660.       fi;
  1661.       Sort( listtosort );
  1662.       for i in [ 1 .. Length( listtosort ) ] do
  1663.         listtosort[i]:= listtosort[i][ len ];
  1664.       od;
  1665.       permutation:= PermList( listtosort )^(-1);
  1666.     fi;
  1667.  
  1668.     if permutation = () then return (); fi;
  1669.  
  1670.     tbl.orders:=         Permuted( orders, permutation );
  1671.     tbl.centralizers:= Permuted( tbl.centralizers, permutation );
  1672.     tbl.classes:=      Permuted( classes, permutation );
  1673.     if IsBound( tbl.print ) then
  1674.       tbl.print:= Permuted( tbl.print, permutation );
  1675.     fi;
  1676.     if IsBound( tbl.irreducibles ) then
  1677.       SortClassesCharTable( tbl.irreducibles, permutation );
  1678.     fi;
  1679.     if IsBound( tbl.classtext ) then
  1680.       tbl.classtext:= Permuted( tbl.classtext, permutation );
  1681.     fi;
  1682.     if IsBound( tbl.classparam ) then
  1683.       tbl.classparam:= Permuted( tbl.classparam, permutation );
  1684.     fi;
  1685.     if IsBound( tbl.fusions ) then
  1686.       for i in tbl.fusions do
  1687.         i.map:= Permuted( i.map, permutation );
  1688.       od;
  1689.     fi;
  1690.     if IsBound( tbl.projectives ) then
  1691.       for i in tbl.projectives do
  1692.         SortClassesCharTable( i.chars, permutation );
  1693.       od;
  1694.     fi;
  1695.     if IsBound( tbl.group ) and IsBound(tbl.group.conjugacyClasses) then
  1696.       tbl.group.conjugacyClasses:=
  1697.                Permuted( tbl.group.conjugacyClasses, permutation );
  1698.     fi;
  1699.  
  1700.     if IsBound( tbl.classnames ) then
  1701.       tbl.classnames:= Permuted( tbl.classnames, permutation );
  1702.       for i in [ 1 .. Length( tbl.classnames ) ] do
  1703.         tbl.( tbl.classnames[i] ):= i;
  1704.       od;
  1705.     fi;
  1706.     if IsBound( tbl.powermap ) then
  1707.       permmap:= List( permutation );
  1708.       inverse:= List( permutation^(-1) );
  1709.       for k in [ Length(permmap)+1 .. Length(tbl.centralizers) ] do
  1710.         permmap[k]:= k;
  1711.         inverse[k]:= k;
  1712.       od;
  1713.       for k in [ 1 .. Length( tbl.powermap ) ] do
  1714.         if IsBound( tbl.powermap[k] ) then
  1715.           tbl.powermap[k]:= CompositionMaps( permmap,
  1716.                                CompositionMaps(tbl.powermap[k],inverse) );
  1717.         fi;
  1718.       od;
  1719.     fi;
  1720.     if IsBound( tbl.automorphisms ) then           # conjugate
  1721.       tbl.automorphisms:= Group( List( tbl.automorphisms.generators,
  1722.                                        x->x^permutation ), () );
  1723.     fi;
  1724.     if IsBound(tbl.permutation) then
  1725.       tbl.permutation:= tbl.permutation * permutation;
  1726.     else
  1727.       tbl.permutation:= permutation;
  1728.     fi;
  1729.     return permutation;
  1730.     end;
  1731.  
  1732.  
  1733. #############################################################################
  1734. ##
  1735. #F  SortCharTable( <tbl>, <kernel> )
  1736. #F  SortCharTable( <tbl>, <normalseries> )
  1737. #F  SortCharTable( <tbl>, <facttbl>, <kernel> )
  1738. ##
  1739. ##  sorts classes and 'irreducibles' of the character table <tbl>, and
  1740. ##  returns a record with components 'columns' and 'rows', which are the
  1741. ##  permutations applied to classes and characters.
  1742. ##
  1743. ##  The first form sorts the classes at positions contained in the list
  1744. ##  <kernel> to the beginning, and sorts all characters in
  1745. ##  '<tbl>.irreducibles' such that the first characters are those that
  1746. ##  contain <kernel> in their kernel.
  1747. ##
  1748. ##  The second form does the same successively for all kernels $k_i$ in
  1749. ##  the list $'normalseries' = [ k_1, k_2, \ldots, k_n ]$ where
  1750. ##  $k_i$ must be a sublist of $k_{i+1}$ for $1 \leq i \leq n-1$.
  1751. ##
  1752. ##  The third form computes the table <F> of the factor group of <tbl>
  1753. ##  modulo the normal subgroup formed by the classes whose positions are
  1754. ##  contained in the list <kernel>;
  1755. ##  <F> must be permutation equivalent to the table <facttbl> (in the
  1756. ##  sense of "TransformingPermutationsCharTables"), else 'false' is
  1757. ##  returned.  The classes of <tbl> are sorted such that the preimages
  1758. ##  of a class of <F> are consecutive, and that the succession of
  1759. ##  preimages is that of <facttbl>.  '<tbl>.irreducibles' is sorted as
  1760. ##  by 'SortCharTable( <tbl>, <kernel> )'.
  1761. ##  (*Note* that the transformation is only unique up to table automorphisms
  1762. ##  of <F>, and this need not be unique up to table automorphisms of <tbl>.)
  1763. ##
  1764. ##  All rearrangements of classes and characters are stable, i.e., the
  1765. ##  relative positions of classes and characters that are not distinguished
  1766. ##  by any relevant property is not changed.
  1767. ##
  1768. ##  The 'permutation' component of <tbl> is changed if necessary,
  1769. ##  see "Conventions for Character Tables".
  1770. ##
  1771. SortCharTable := function( arg )
  1772.      local i, j, tbl, kernels, list, columns, rows, chi, F, facttbl, kernel,
  1773.            trans, ker;
  1774.  
  1775.      # check the arguments
  1776.      if not ( Length( arg ) in [ 2, 3 ] and IsCharTable( arg[1] ) and
  1777.               IsList( arg[ Length( arg ) ] ) and
  1778.               ( Length( arg ) = 2 or IsCharTable( arg[2] ) ) ) then
  1779.        Error( "usage: SortCharTable( <tbl>, <kernel> ) resp.\n",
  1780.               "       SortCharTable( <tbl>, <normalseries> ) resp.\n",
  1781.               "       SortCharTable( <tbl>, <facttbl>, <kernel> )" );
  1782.      fi;
  1783.  
  1784.      tbl:= arg[1];
  1785.  
  1786.      if Length( arg ) = 2 then
  1787.  
  1788.        # sort w.r. to kernel or series of kernels
  1789.        kernels:= arg[2];
  1790.        if kernels = [] then
  1791.          return rec( columns:= (), rows:= () );
  1792.        fi;
  1793.  
  1794.        # regard single kernel as special case of normal series
  1795.        if IsInt( kernels[1] ) then kernels:= [ kernels ]; fi;
  1796.  
  1797.        # permutation of classes\:
  1798.        # 'list[i] = k' if 'i' is contained in 'kernels[k]' but not
  1799.        # in 'kernels[k-1]'; only the first position contains a zero
  1800.        # to ensure that the identity is not moved.
  1801.        # If class 'i' is not contained in any of the kernels we have
  1802.        # 'list[i] = ""'.
  1803.        list:= [ 0 ];
  1804.        for i in [ 2 .. Length( tbl.centralizers ) ] do
  1805.          list[i]:= "";
  1806.        od;
  1807.        for i in [ 1 .. Length( kernels ) ] do
  1808.          for j in kernels[i] do
  1809.            if not IsInt( list[j] ) then list[j]:= i; fi;
  1810.          od;
  1811.        od;
  1812.        columns:= Sortex( list );
  1813.  
  1814.        # permutation of characters
  1815.        # 'list[i] = -(k+1)' if '<tbl>.irreducibles[i]' has 'kernels[k]'
  1816.        # in its kernel but not 'kernels[k+1]'; if the 'i'--th irreducible
  1817.        # contains none of 'kernels' in its kernel we have 'list[i] = -1',
  1818.        # for an irreducible with kernel containing 'kernels[ Length( kernels ) ]
  1819.        # the value is '-(Length( kernels ) + 1)'.
  1820.        list:= [];
  1821.        if IsBound( tbl.irreducibles ) then
  1822.          for chi in tbl.irreducibles do
  1823.            i:= 1;
  1824.            while i <= Length( kernels ) and ForAll( kernels[i],
  1825.                                                     x -> chi[x] = chi[1] ) do
  1826.              i:= i+1;
  1827.            od;
  1828.            Add( list, -i );
  1829.          od;
  1830.          rows:= Sortex( list );
  1831.        else
  1832.          rows:= ();
  1833.        fi;
  1834.  
  1835.      else
  1836.  
  1837.        # sort w.r. to table of factor group
  1838.        facttbl:= arg[2];
  1839.        kernel:= arg[3];
  1840.        F:= CharTableFactorGroup( tbl, kernel );
  1841.        trans:= TransformingPermutationsCharTables( F, facttbl );
  1842.        if trans = false then
  1843.          InfoCharTable2( "#I SortCharTable:\n",
  1844.                          " tables of factor groups not compatible\n" );
  1845.          return false;
  1846.        fi;
  1847.  
  1848.        # permutation of classes\:
  1849.        # 'list[i] = k' if 'i' maps to the 'j'--th class of <F>, and
  1850.        # 'trans.columns[j] = i'
  1851.        list:= OnTuples( GetFusionMap( tbl, F ), trans.columns );
  1852.        columns:= Sortex( list );
  1853.  
  1854.        # permutation of characters\:
  1855.        # divide '<tbl>.irreducibles' into two parts, those containing
  1856.        # the kernel of the factor fusion in their kernel (value 0),
  1857.        # and the others (value 1); do not forget to permute characters
  1858.        # of the factor group with 'trans.rows'.
  1859.        if IsBound( tbl.irreducibles ) then
  1860.          ker:= KernelChar( GetFusionMap( tbl, F ) );
  1861.          list:= [];
  1862.          for chi in tbl.irreducibles do
  1863.            if ForAll( ker, x -> chi[x] = chi[1] ) then
  1864.              Add( list, 0 );
  1865.            else
  1866.              Add( list, 1 );
  1867.            fi;
  1868.          od;
  1869.          rows:= Sortex( list ) * trans.rows;
  1870.        else
  1871.          rows:= ();
  1872.        fi;
  1873.  
  1874.        # delete the fusion to 'F' on 'tbl'
  1875.        Unbind( tbl.fusions[ Length( tbl.fusions ) ] );
  1876.  
  1877.      fi;
  1878.  
  1879.      # sort and return
  1880.      SortClassesCharTable( tbl, columns );
  1881.      SortCharactersCharTable( tbl, rows );
  1882.      return rec( columns:= columns, rows:= rows );
  1883.  
  1884.      end;
  1885.  
  1886.