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

  1. #############################################################################
  2. ##
  3. #A  grpctbl.g                   GAP library                  Alexander Hulpke
  4. ##
  5. #H  @(#)$Id: grpctbl.g,v 3.6 1993/02/19 11:57:30 gap Exp $
  6. ##
  7. #Y  Copyright (C)  1993,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  8. ##
  9. ##  This file contains  the Dixon-Schneider Algorithm for computing
  10. ##  character tables of groups
  11. ##
  12. #H  $Log: grpctbl.g,v $
  13. #H  Revision 3.6  1993/02/19  11:57:30  gap
  14. #H  fixed a bug in 'DxLinearCharacter'
  15. #H
  16. #H  Revision 3.5  1993/02/09  14:25:55  martin
  17. #H  made undefined globals local
  18. #H
  19. #H  Revision 3.4  1993/01/25  08:24:14  ahulpke
  20. #H  fixed a bug in SplitDegree
  21. #H
  22. #H  Revision 3.3  1993/01/21  14:45:35  ahulpke
  23. #H  worked around a bug in CharTablePGroup
  24. #H
  25. #H  Revision 3.2  1993/01/19  12:50:48  ahulpke
  26. #H  threw out some debugging stuff
  27. #H
  28. #H  Revision 3.1  1993/01/18  18:46:52  martin
  29. #H  initial revision under RCS
  30. #H
  31. ##
  32.  
  33.  
  34. #############################################################################
  35. ##
  36. #F  InfoCharTable1 . . . . . . . .  information function for character tables
  37. #F  InfoCharTable2 . . . . . . . .  information function for character tables
  38. ##
  39. if not IsBound(InfoCharTable1) then InfoCharTable1:=Ignore; fi;
  40. if not IsBound(InfoCharTable2) then InfoCharTable2:=Ignore; fi;
  41.  
  42. #############################################################################
  43. ##
  44. #G  USECTPGROUP . . . . . . . . . . indicates, whether CharTablePGroup may
  45. ##                                  be called
  46. USECTPGROUP := false;
  47.  
  48. #############################################################################
  49. ##
  50. #F  IsLargeGroup(<G>) . . . . . . . . . . . .  test, whether a group is small
  51. ##
  52. ##  If a group is small, we may use enumerations of the elements to speed up
  53. ##  the computations. The criterion is the size, compared to the global
  54. ##  variable LARGEGROUPORDER.
  55. ##
  56. if not IsBound(LARGEGROUPORDER) then
  57.   LARGEGROUPORDER:=10000;
  58. fi;
  59.  
  60. IsLargeGroup := function(G)
  61.   # note: if the size of a Group is <1000, ConjugacyClasses stores
  62.   # the elements. Thus the enumeration feature is unnecessary.
  63.   return G.size<1000 or G.size>LARGEGROUPORDER;
  64. end;
  65.  
  66. #############################################################################
  67. ##
  68. #F  CharTableDixonSchneider(<G>) . . . . .  character table of finite Group G
  69. ##
  70. ##  Compute the table of the irreducible characters of G, using the
  71. ##  Dixon/Schneider method.
  72. ##
  73. CharTableDixonSchneider := function(arg)
  74.   local G,k,C,D,Gi,opt;
  75.  
  76.   G:=arg[1];
  77.   if Length(arg)>1 then
  78.     opt:=arg[2];
  79.   else
  80.     opt:=rec();
  81.   fi;
  82.   if IsBound(G.charTable) and
  83.      not IsBound(G.conjugacyClasses) then
  84. Error("if characters are given, you must also provide the\nconjugacy Classes");
  85.   fi;
  86.  
  87.   D:=DixonInit(G,opt);
  88.   k:=D.klanz;
  89.   C:=D.charTable;
  90.  
  91.   # iterierte Schleife
  92.  
  93.   while Length(C.irreducibles)<k do
  94.  
  95.     DixonSplit(D);
  96.     OrbitSplit(D);
  97.  
  98.   od;
  99.  
  100.   G:=DixontinI(D);
  101.  
  102.   return G.charTable;
  103. end;
  104.  
  105. GroupOps.CharTable := CharTableDixonSchneider;
  106.  
  107.  
  108. #############################################################################
  109. ##
  110. #F  DixonRecord( <G> ) . . . . . . . . . .  prepare record .dixon and note it
  111. #F                                                               in the group
  112. ##
  113. DixonRecord := function(G)
  114.   local D,cl,pl;
  115.   D:=rec( group:=G, # workgroup
  116.           oldG:=G, # the group for which computation should take place
  117.           deg:=Size(G),
  118.           yetmats:=[],
  119.           modulars:=[],
  120.       operations:=DixonRecordOps);
  121.   if IsBound(G.name) then 
  122.     D.name:=ConcatenationString("DixonRecord(",G.name,")");
  123.   else
  124.     D.name:="DixonRecord of nameless group";
  125.   fi;
  126.   G.dixon:=D;
  127.   cl:=ShallowCopy(ConjugacyClasses(G));
  128.   D.klanz:=Length(ConjugacyClasses(G));
  129.  
  130.   pl:=[1..D.klanz];
  131.   SortParallel(cl,pl,ClassComparison);
  132.  
  133.   D.classPermutation:=PermList(pl);
  134.  
  135.   D.conjugacyClasses:=cl;
  136.  
  137.   # force computation of the derived Subgroup
  138.   G.isPerfect:=Size(G)=Size(DerivedSubgroup(G));
  139.   return D;
  140. end;
  141.  
  142.  
  143. #############################################################################
  144. ##
  145. #V  DixonRecordOps . . . . . . . . . . . . . . .  operations for DixonRecords
  146. ##
  147. DixonRecordOps := rec(Print:=function(r)
  148.                    Print(r.name);
  149.                  end);
  150.  
  151.  
  152. #############################################################################
  153. ##
  154. #F  DixonInit(<G>) . . . . . . . . . . . initialize Dixon-Schneider algorithm
  155. ##
  156. DixonInit := function(arg)
  157.   local k,z,exp,prime,C,M,cg,moli,m,f,r,pl,pa,ga,cpool,D,G,opt,i;
  158.  
  159.   G:=arg[1];
  160.   if Length(arg)>1 then
  161.     opt:=arg[2];
  162.   else
  163.     opt:=rec();
  164.   fi;
  165.   # force computation of the size of the group
  166.   Size(G);
  167.  
  168.   D:=G.operations.DxPreparation(G);
  169.   G:=D.group;
  170.  
  171.   k:=D.klanz;
  172.   InfoCharTable1("#I  ",k," classes\n");
  173.  
  174.   D.currentInverseClassNo:=0;
  175.  
  176.   exp:=Exponent(G);
  177.   prime:=exp+1;
  178.   while prime<100 do
  179.     prime:=prime+exp;
  180.   od;
  181.  
  182.   if IsBound(opt.maxdeg) then
  183.     z:=2*opt.maxdeg;
  184.     D.degreePool:=List(Filtered(DivisorsInt(G.size),i->i<=z),i->[i,k]);
  185.   else
  186.     z:=RootInt(G.size);
  187.     if z<30000 then
  188.       D.degreePool:=List(Filtered(DivisorsInt(G.size),i->i<=z),i->[i,k]);
  189.     else
  190.       # try to calculate approximate degrees
  191.       D.degreePool:=G.operations.CharacterDegreePool(G);
  192.     fi;
  193.     z:=2*Maximum(List(D.degreePool,i->i[1]));
  194.  
  195.   fi;
  196.   # throw away (unneeded) linear degrees!
  197.   D.degreePool:=Filtered(D.degreePool,i->i[1]>1 and i[1]<z/2);
  198.  
  199.   while prime<z do
  200.     prime:=prime+exp;
  201.   od;
  202.   while not IsPrime(prime) do
  203.     prime:=prime+exp;
  204.   od;
  205.   if prime>65535 then
  206.     Error("sorry, GAP does not support fields of sufficient size");
  207.   fi;
  208.   f:=GF(prime); # probably later IntegersModP
  209.   z:=PowerModInt(PrimitiveRootMod(prime),(prime-1)/exp,prime);
  210.   D.modularMap:=GeneratePrimeCyclotomic(exp,z*f.one);
  211.   D.num:=D.klanz;
  212.   D.prime:=prime;
  213.   D.field:=f;
  214.   D.fone:=f.one;
  215.   D.z:=z;
  216.   r:=RowSpace(k,f);
  217.   D.raeume:= [r];
  218.  
  219.   M:=IdentityMat(k);
  220.   for i in [1..k] do
  221.     M[i][i]:=Size(D.conjugacyClasses[i]) mod prime;
  222.   od;
  223.   D.projectionMat:=M*(D.fone/(Size(D.group) mod prime));
  224.  
  225.   if not IsBound(D.oldG.charTable) then
  226.     C:=rec(order := D.group.size,
  227.      centralizers:=List(D.conjugacyClasses,cl->D.group.size/Size(cl)),
  228.      orders := List(D.conjugacyClasses,
  229.             c->Order(D.group,c.representative)),
  230.      classes := List(D.conjugacyClasses,Size),
  231.      irreducibles:=[],
  232.      #group    := D.group,
  233.      operations := CharTableOps);
  234.  
  235.     if IsBound(D.group.name) then
  236.       C.name:=D.group.name;
  237.     else
  238.       Print("#W  Warning: Group has no name\n");
  239.       C.name:="";
  240.     fi;
  241.     cpool:=[];
  242.   else
  243.     C:=D.oldG.charTable;
  244.     Unbind(C.group); # don't mess with the classes when resorting
  245.     SortClassesCharTable(C,D.classPermutation^(-1));
  246.     C.group:=G;
  247.     m:=C.irreducibles;
  248.     C.irreducibles:=[];
  249.     cpool:=m;
  250.   fi;
  251.  
  252.   D.charTable:=C;
  253.  
  254.   if not IsBound(C.powermap) then
  255.     C.powermap:=[];
  256.   fi;
  257.  
  258.   if not IsBound(C.inversemap) then
  259.     C.inversemap:=[1];
  260.     for i in [2..k] do
  261.       C.inversemap[i]:=DxPowerClass(D,i,-1);
  262.     od;
  263.   fi;
  264.  
  265.   DxCalcPowerMap(D);
  266.  
  267.   # Galoisgroup operating on the columns
  268.   ga:=Group(Set(List(List(PrimeResidueClassGroup(Exponent(G)).generators,
  269.                            i->i.representative),
  270.        i->PermList(List([1..k],j->DxPowerClass(D,j,i))))),());
  271.   ga.maybeIncomplete:=true;
  272.   C.automorphisms:=ga;
  273.  
  274.   D.galoisOrbits:=List([1..k],i->Set(Orbit(ga,i)));
  275.  
  276.   D.matrices:=Difference(Set(List(D.galoisOrbits,i->i[1])),[1]);
  277.  
  278.   D.galOp:=[];
  279.  
  280.   IncludeIrreducibles(D,DxLinearCharacters(D));
  281.  
  282.   if USECTPGROUP  and IsBound(G.isAgGroup) and G.isAgGroup
  283.       then # Anfangscharaktere ausrechnen
  284.  
  285.     m:=List(CharTablePGroup(G,"meckere nicht").irreducibles,
  286.          i->Permuted(i,D.classPermutation^(-1)) );
  287.     if Length(m)<k then
  288.       C.irreducibles:=[];
  289.       IncludeIrreducibles(D,m);
  290.     fi;
  291.   fi;
  292.  
  293.   if Length(D.raeume)>0 then
  294.     # indicate Stabilizer of the whole orbit, simultaneously compute
  295.     # CharacterMorphisms.
  296.     D.raeume[1].stabilizer:=CharacterMorphismGroup(D);
  297.     m:=First(D.conjugacyClasses,i->Size(i)>1);
  298.     if Size(m)>8 then 
  299.       D.maycent:=true;
  300.     fi;
  301.   fi;
  302.  
  303.   if Length(cpool)>0 then
  304.     IncludeIrreducibles(D,cpool);
  305.   fi;
  306.  
  307.   return D;
  308. end;
  309.  
  310.  
  311. #############################################################################
  312. ##
  313. #F  RegisterNewCharacter( <D>, <c> )  . . . . .  note newly found irreducible
  314. #F                                                     character modulo prime
  315. ##
  316. RegisterNewCharacter := function(D,c)
  317.   local d,p;
  318.   # it may happen, that an irreducible character will be registered twice:
  319.   # 2-dim space, 1 Orbit, combinatoric split. Avoid this!
  320.   if not(c in D.modulars) then
  321.     Add(D.modulars,c);
  322.     d:=IntFFE2(c[1]);
  323.     D.deg:=D.deg-d^2;
  324.     D.num:=D.num-1;
  325.     p:=1;
  326.     while p<=Length(D.degreePool) do
  327.       if D.degreePool[p][1]=d then
  328.     D.degreePool[p][2]:=D.degreePool[p][2]-1;
  329.     # filter still possible character degrees:
  330.     p:=1;
  331.     d:=1;
  332.     # determinate smallest possible degree (nonlinear)
  333.     while p<=Length(D.degreePool) and d=1 do
  334.       if D.degreePool[p][2]>1 then
  335.         d:=D.degreePool[p][1];
  336.       fi;
  337.       p:=p+1;  
  338.     od;
  339.     # degreeBound
  340.     d:=RootInt(D.deg-(D.num-1)*d);
  341.     D.degreePool:=Filtered(D.degreePool,i->i[2]>0 and i[1]<=d);
  342.     p:=Length(D.degreePool)+1;
  343.       fi;
  344.       p:=p+1;
  345.     od;
  346.   fi;
  347. end;
  348.  
  349.  
  350. #############################################################################
  351. ##
  352. #F  DixontinI( <D> )  . . . . . . . . . . . . . . . .  reverse initialisation
  353. ##
  354. ##  Return everything modified by the Dixon-Algorithm to its former status.
  355. ##  the old group is returned, character table is sorted according to its 
  356. ##  classes
  357. ##
  358. DixontinI := function(D)
  359.   local C,p,u;
  360.  
  361.   if IsBound(D.shorttests) then
  362.     InfoCharTable2("#I  ",D.shorttests," shortened conjugation tests\n");
  363.   fi;
  364.   InfoCharTable1("#I  Total:",Length(D.yetmats)," matrices, ",
  365.                  D.yetmats,"\n");
  366.   C:=D.charTable;
  367.   C.text:="origin: Dixon's Algorithm";
  368.  
  369.   SortCharactersCharTable(C);
  370.  
  371.   Unbind(C.group);
  372.   p:=D.classPermutation;
  373.   SortClassesCharTable(C,p);
  374.   #C.inversemap:=Permuted(List(C.inversemap,i->i^p),p);
  375.   Unbind(C.inversemap);
  376.  
  377.   C.group:=D.oldG;
  378.   D.conjugacyClasses:=D.oldG.conjugacyClasses;
  379.   D.group:=D.oldG;
  380.  
  381.   # throw away not any longer used record fields
  382.   for u in Difference(RecFields(D),
  383.     ["ClassElement","centmulCandidates","charTable","classMap",
  384.     "facs","fingerprintCandidates",
  385.     "group","identification","ids","iscentral","klanz","name","operations",
  386.     "replist","shorttests","uniques"])
  387.     do
  388.     Unbind(D.(u));
  389.   od;
  390.   D.Permutation:=();
  391.   SortDixonRecord(D);
  392.   D.group.dixon:=D;
  393.  
  394.   D.group.charTable:=C;
  395.   return D.group;
  396. end;
  397.  
  398.  
  399. #############################################################################
  400. ##
  401. #F  SortDixonRecord( <D> )  . . . . . sort DixonRecord <D> to character table
  402. #F                                                                permutation
  403. ##
  404. SortDixonRecord := function(D)
  405.   local p,cp;
  406.   if IsBound(D.charTable.permutation) then
  407.     cp:=D.charTable.permutation;
  408.   else
  409.     cp:=();
  410.   fi;
  411.   p:=D.Permutation^(-1)*cp;
  412.   if not(p<>()) then
  413.     if IsBound(D.centmulCandidates) then
  414.       Apply(D.centmulCandidates,
  415.     function(l)
  416.     local m,i;
  417.       m:=[l[1]];
  418.       for i in [2..Length(l)] do
  419.         m[i]:=l[i]^p;
  420.       od;
  421.       return m;
  422.     end);
  423.     fi;
  424.     if IsBound(D.classMap) then
  425.       Apply(D.classMap,i->i^p);
  426.     fi;
  427.     D.ids:=Permuted(D.ids,p);
  428.     D.Permutation:=cp;
  429.   fi;
  430. end;
  431.  
  432.  
  433. #############################################################################
  434. ##
  435. #F  DixonSplit(<D>) . .  calculate matrix, split spaces and obtain characters
  436. ##
  437. DixonSplit := function(D)
  438.   local r,i,j,ch,ra;
  439.  
  440.   SplitStep(D,BestSplittingMatrix(D));
  441.  
  442.   for i in [1..Length(D.raeume)] do
  443.     r:=D.raeume[i];
  444.     if r.dim=1 then
  445.       InfoCharTable2("#I  lifting character no.",
  446.                       Length(D.charTable.irreducibles)+1,"\n");
  447.       if IsBound(r.char) then
  448.         ch:=r.char[1];
  449.       else
  450.     r.generators[1]:=r.generators[1]
  451.               *ModularCharacterDegree(D,r.generators[1]);
  452.     for j in Orbit(D.characterMorphisms,
  453.               r.generators[1],D.asCharacterMorphism) do
  454.       RegisterNewCharacter(D,j);
  455.     od;
  456.         ch:=DxLiftCharacter(D,r.generators[1]);
  457.       fi;
  458.       for j in Orbit(D.characterMorphisms,ch,D.asCharacterMorphism) do
  459.         Add(D.charTable.irreducibles,j);
  460.       od;
  461.       Unbind(D.raeume[i]);
  462.     fi;
  463.   od;
  464.   # Throw away lifted spaces
  465.   ra:=[];
  466.   for i in D.raeume do
  467.     Add(ra,i);
  468.   od;
  469.   D.raeume:=ra;
  470.   CombinatoricSplit(D);
  471. end;
  472.  
  473.  
  474. #############################################################################
  475. ##
  476. #F  OrbitSplit(<D>) . . . . . . . . . . . . . . try to split two-orbit-spaces
  477. ##
  478. OrbitSplit := function(D)
  479.   local i,j,s,ni,nm;
  480.   ni:=[];
  481.   nm:=[];
  482.   for i in D.raeume do
  483.     if i.dim=3 and not IsBound(i.twofail) and
  484.        CharacterMorphismOrbits(D,i).number=2 then
  485.       s:=SplitTwoSpace(D,i);
  486.       if Length(s)=2 and s[1].d=1 then
  487.         # character extracted
  488.         Add(ni,s[1].char[1]);
  489.         Add(nm,s[1].base[1]);
  490.       fi;
  491.     fi;
  492.   od;
  493.   if ni<>[] then
  494.     IncludeIrreducibles(D,ni,nm);
  495.   fi;
  496.   CombinatoricSplit(D);
  497. end;
  498.  
  499.  
  500. #############################################################################
  501. ##
  502. #F  CombinatoricSplit( <D> )  . . . . . . . . .  split two-dimensional spaces
  503. ##
  504. CombinatoricSplit := function(D)
  505.   local i,newRaeume,raum,neuer,j,ch,irrs,mods,incirrs,incmods,nb,rt,k,neuc;
  506.   newRaeume:=[];
  507.   incirrs:=[];
  508.   incmods:=[];
  509.   for i in [1..Length(D.raeume)] do
  510.     raum:=D.raeume[i];
  511.     if raum.dim=2 and not IsBound(raum.twofail) then
  512.       neuer:=SplitTwoSpace(D,raum);
  513.     else
  514.       neuer:=[];
  515.       if raum.dim=2 then
  516.     # next attempt might work due to fewer degrees
  517.     Unbind(raum.twofail);
  518.       fi;
  519.     fi;
  520.     if Length(neuer)=2 then
  521.       rt:=Difference(RightTransversal(D.characterMorphisms,
  522.            CharacterMorphismOrbits(D,raum).stabilizer),
  523.            [D.characterMorphisms.identity]);
  524.       mods:=[];
  525.       irrs:=[];
  526.       for j in [1,2] do
  527.         Add(mods,neuer[j].base[1]);
  528.     RegisterNewCharacter(D,neuer[j].base[1]);
  529.         InfoCharTable2("#I  lifting character no.",
  530.                         Length(D.charTable.irreducibles)+1,"\n");
  531.         if IsBound(neuer[j].char) then
  532.           ch:=neuer[j].char[1];
  533.         else
  534.           ch:=DxLiftCharacter(D,neuer[j].base[1]);
  535.         fi;
  536.         Add(irrs,ch);
  537.         Add(D.charTable.irreducibles,ch);
  538.       od;
  539.       for j in rt do
  540.         InfoCharTable1("#I  TwoDimSpace image\n");
  541.         nb:=D.asCharacterMorphism(raum.base[1],j);
  542.         neuc:=List(irrs,i->D.asCharacterMorphism(i,j));
  543.         if not ForAny([i+1..Length(D.raeume)],i->nb in D.raeume[i]) then
  544.           incirrs:=Union(incirrs,neuc);
  545.           incmods:=Union(incmods,List(mods,i->D.asCharacterMorphism(i,j)));
  546.         else
  547.           InfoCharTable1(
  548.             "#W strange spaces due to inclusion of irreducibles!");
  549.           Add(D.charTable.irreducibles,neuc[1]);
  550.           Add(D.charTable.irreducibles,neuc[2]);
  551.         fi;
  552.       od;
  553.     else
  554.       Add(newRaeume,raum);
  555.     fi;
  556.   od;
  557.   D.raeume:=newRaeume;
  558.   if Length(incirrs)>0 then
  559.     IncludeIrreducibles(D,incirrs,incmods);
  560.   fi;
  561. end;
  562.  
  563.  
  564. #############################################################################
  565. ##
  566. #F  SplitCharacters( <D>, <list> )   split characters according to the spaces
  567. ##
  568. SplitCharacters := function(D,l)
  569.   local ml,nu,ret,r,p,v,alo,ofs,i,j,inv,b;
  570.   b:=Filtered(l,i->(i[1]>1) and (i[1]<D.prime/2));
  571.   l:=Difference(l,b);
  572.   ml:=List(b,i->List(i,D.modularMap));
  573.   nu:=List(D.conjugacyClasses,i->D.field.zero);
  574.   ret:=[];
  575.   b:=ShallowCopy(D.modulars);
  576.   alo:=Length(b);
  577.   ofs:=[];
  578.   for r in D.raeume do
  579.     # recreate all images
  580.     for i in Orbit(D.characterMorphisms,r,D.asCharacterMorphism) do
  581.       b:=Concatenation(b,Base(i));
  582.       Add(ofs,[alo+1..Length(b)]);
  583.       alo:=Length(b);
  584.     od;
  585.   od;
  586.   inv:=b^(-1);
  587.   for i in ml do
  588.     v:=i*inv;
  589.     for r in [1..Length(D.raeume)] do
  590.       p:=ShallowCopy(nu);
  591.       for j in ofs[r] do
  592.         p[j]:=v[j];
  593.       od;
  594.       p:=p*b;
  595.       if p<>nu then
  596.         AddSet(ret,DxLiftCharacter(D,p));
  597.       fi;
  598.     od;
  599.   od;
  600.   return Union(ret,l);
  601. end;
  602.  
  603.  
  604. #############################################################################
  605. ##
  606. #F  IncludeIrreducibles(<D>,<new>,[<newmod>]) . . . . . handle (newly?) found
  607. #F                                                               irreducibles
  608. ##
  609. ##  This routine will do all handling, whenever characters have been found
  610. ##  by other means, than the Dixon/Schneider algorithm. First the routine
  611. ##  checks, which characters are not new (this allows, to include huge bulks
  612. ##  of irreducibles, got by tensoring). Then the characters are closed under
  613. ##  images of the CharacterMorphisms. Afterwards the character spaces are
  614. ##  stripped of the new characters, the characters are included as
  615. ##  irreducibles and possible degrees etc. are corrected. If the modular
  616. ##  images of the irreducibles are known, they may be given in newmod.
  617. ##
  618. IncludeIrreducibles := function(arg)
  619.   local i,pcomp,m,r,D,neue,tm,nm,news;
  620.   D:=arg[1];
  621.   # force computation of all images under $\cal T$. We will need this
  622.   # (among others), to be sure, that we can keep the stabilizers
  623.   neue:=arg[2];
  624.   if IsBound(D.characterMorphisms) then
  625.     tm:=D.characterMorphisms;
  626.     news:=Union(List(neue,i->Orbit(tm,i,D.asCharacterMorphism)));
  627.     if Length(news)>Length(neue) then
  628.       InfoCharTable1("#I  new Characters by CharacterMorphisms found\n");
  629.     fi;
  630.     neue:=news;
  631.   fi;
  632.   neue:=Difference(neue,D.charTable.irreducibles);
  633.   D.charTable.irreducibles:=Concatenation(D.charTable.irreducibles,neue);
  634.   if Length(arg)=3 then
  635.     m:=Difference(arg[3],D.modulars);
  636.     nm:=true;
  637.   else
  638.     m:=List(neue,i->List(i,D.modularMap));
  639.     nm:=false;
  640.   fi;
  641.   if nm and IsBound(D.characterMorphisms) then
  642.     m:=Union(List(m,i->Orbit(tm,i,D.asCharacterMorphism)));
  643.   fi;
  644.   for i in m do
  645.     RegisterNewCharacter(D,i);
  646.   od;
  647.  
  648.   pcomp:=RowSpace(NullspaceMat(D.projectionMat*TransposedMat(D.modulars)),
  649.                   D.field,List([1..D.klanz],i->D.field.zero));
  650.  
  651.   for i in [1..Length(D.raeume)] do
  652.     r:=D.raeume[i];
  653.     if ForAny(m,i->i in r) then
  654.       if Dimension(r)=Length(r.generators[1]) then
  655.         # trivial case: Intersection with full space in the beginning
  656.         r:=pcomp;
  657.       else
  658.         r:=Intersection(pcomp,r);
  659.       fi;
  660.       r.dim:=Dimension(r);
  661.       # note stabilizer
  662.       if IsBound(D.raeume[i].stabilizer) then
  663.         r.stabilizer:=D.raeume[i].stabilizer;
  664.       fi;
  665.       ActiveCols(r);
  666.       D.raeume[i]:=r;
  667.     fi;
  668.   od;
  669.   D.raeume:=Filtered(D.raeume,i->i.dim>0);
  670. end;
  671.  
  672.  
  673. #############################################################################
  674. ##
  675. #F  DxLinearCharacters( <D> ) . . . .   calculate characters of G of degree 1
  676. ##
  677. ##  These characters are computed as characters of G/G'. This can be done
  678. ##  easily by using the fact, that an abelian group is direct product of
  679. ##  cyclic groups. Thus we get the characters as "direct products" of the
  680. ##  characters of cyclic groups, which can be easily computed. They are
  681. ##  lifted afterwards back to G.
  682. ##
  683. DxLinearCharacters := function(D)
  684.   local H,T,c,a,e,f,i,j,k,l,m,p,ch,el,ur,s,hom,gens,onc,G;
  685.   G:=D.group;
  686.   onc:=List([1..D.klanz],i->1);
  687.   H:=CommutatorFactorGroup(G);
  688.   e:=ShallowCopy(Elements(H));
  689.   s:=Length(e); # Size(H)
  690.   if s=1 then # perfekter Fall
  691.     return [onc];
  692.   else
  693.     a:=Reversed(AbelianInvariants(H));
  694.     gens:=[];
  695.     T:=Subgroup(H,gens);
  696.     for i in a do
  697.       # was: m:=First(e,el->Order(H,el)=i);
  698.       m:=First(e,
  699.       el->Order(H,el)=i and ForAll([2..Order(H,el)-1],i->el^i in e));
  700.       T:=Closure(T,m);
  701.       e:=Difference(e,Elements(T));
  702.       Add(gens,m);
  703.     od;
  704.     e:=Elements(H);
  705.     f:=List(e,i->[]);
  706.     hom:=NaturalHomomorphism(G,H);
  707.     for i in [1..D.klanz] do # create classimages
  708.       Add(f[Position(e,Image(hom,D.conjugacyClasses[i].representative))],i);
  709.    od;
  710.  
  711.     m:=Length(a);
  712.     c:=List([1..m],i->[]);
  713.     i:=m;
  714.     # run through all Elements of H by trying every combination of the
  715.     # generators
  716.     p:=List([1..m],i->0);
  717.     while i>0 do
  718.       el:=H.identity; # Element berechnen
  719.       for j in [1..m] do
  720.         el:=el*gens[j]^p[j];
  721.       od;
  722.       ur:=f[Position(e,el)];
  723.       for j in [1..m] do # all character values for this element
  724.         ch:=E(a[j])^p[j];
  725.         for l in ur do
  726.           c[j][l]:=ch;
  727.         od;
  728.       od;
  729.       while (i>0) and (p[i]=a[i]-1) do
  730.         p[i]:=0;
  731.         i:=i-1;
  732.       od;
  733.       if i>0 then
  734.         p[i]:=p[i]+1;
  735.         i:=m;
  736.       fi;
  737.     od;
  738.  
  739.     ch:=[];
  740.     i:=m;
  741.     # run through all characters trying every combination of the generators
  742.     p:=List([1..m],i->0);
  743.     while i>0 do
  744.       # construct tensor product systematically
  745.       el:=ShallowCopy(onc);
  746.       for j in [1..m] do
  747.         for k in [1..D.klanz] do
  748.           el[k]:=el[k]*c[j][k]^p[j];
  749.         od;
  750.       od;
  751.       Add(ch,[ShallowCopy(p),el]);
  752.       while (i>0) and (p[i]=a[i]-1) do
  753.         p[i]:=0;
  754.         i:=i-1;
  755.       od;
  756.       if i>0 then
  757.         p[i]:=p[i]+1;
  758.         i:=m;
  759.       fi;
  760.     od;
  761.     D.tensorMorphisms:=rec(a:=a,
  762.                                  c:=c,
  763.                                  els:=ch);
  764.  
  765.     return List(ch,i->i[2]);
  766.   fi;
  767. end;
  768.  
  769.  
  770. #############################################################################
  771. ##
  772. #F  ClassComparison(<c>,<d>)  . . . . . . . . . . . . compare classes c and d
  773. ##
  774. ##  comparison is based first on the size of the class and afterwards on the
  775. ##  order of the representatives. Thus the 1-Class is in the first position,
  776. ##  as required. Since sorting is primary by the class sizes, smaller
  777. ##  classes are in earlier positions, making the active columns those to
  778. ##  smaller classes, reducing the work for calculating class matrices!
  779. ##  Additionally galois conjugated classes are together, thus increasing the
  780. ##  chance, that with one columns of them active to be several acitive,
  781. ##  reducing computation time !
  782. ##
  783. ClassComparison := function(c,d)
  784.   if Size(c)=Size(d) then
  785.     return Order(c.group,c.representative)<Order(d.group,d.representative);
  786.   else
  787.     return Size(c)<Size(d);
  788.   fi;
  789. end;
  790.  
  791.  
  792. #############################################################################
  793. ##
  794. #F  DxCalcPowerMap(<D>) . . . . . . .  calculate powermap for character table
  795. #F                                                                D.charTable
  796. ##
  797. DxCalcPowerMap := function(D)
  798.   local primes,classes,class,i,j,p,ex,primeClasses,cl,pi,C;
  799.   C:=D.charTable;
  800.   primes:=Set(Filtered([1..Maximum(C.orders)],IsPrime));
  801.   classes:=[1..D.klanz];
  802.   for pi in [1..Length(primes)] do
  803.     p:=primes[pi];
  804.     if not IsBound(C.powermap[p]) then
  805.       # calculate approximation of powermap
  806.       C.powermap[p]:=InitPowermap(C,p);
  807.       for i in classes do
  808.         if not IsInt(C.powermap[p][i]) then
  809.           cl:=i;
  810.           ex:=p mod C.orders[i];
  811.           if ex>C.orders[i]/2 then
  812.             # can we get it cheaper via the inverse
  813.             ex:=AbsInt(C.orders[i]-ex);
  814.             cl:=C.inversemap[i];
  815.           fi;
  816.           if ex<p or (ex=p and IsInt(C.powermap[p][cl])) then
  817.             C.powermap[p][i]:=DxPowerClass(D,cl,ex);
  818.           fi;
  819.         fi;
  820.       od;
  821.       for i in classes do
  822.         if not IsInt(C.powermap[p][i]) then
  823.             C.powermap[p][i]:=D.ClassElement(D,
  824.           D.conjugacyClasses[i].representative^(p mod C.orders[i]));
  825.           # note following powers: (x^a)^b=(x^b)^a
  826.           for j in [1..pi-1] do
  827.             cl:=C.powermap[primes[j]][i];
  828.             if cl>i then
  829.               C.powermap[p][cl]:=C.powermap[primes[j]][C.powermap[p][i]];
  830.             fi;
  831.           od;
  832.         fi;
  833.       od;
  834.     fi;
  835.   od;
  836.   primeClasses:=[];
  837.   for i in classes do
  838.     primeClasses[i]:=[];
  839.     class:=i;
  840.     j:=1;
  841.     while class>1 do
  842.       if class<>i then
  843.         Unbind(classes[class]);
  844.       fi;
  845.       primeClasses[i][j]:=class;
  846.       j:=j+1;
  847.       class:=DxPowerClass(D,i,j);
  848.     od;
  849.   od;
  850.   D.primeClasses:=[];
  851.   for i in classes do
  852.     Add(D.primeClasses,primeClasses[i]);
  853.   od;
  854.   D.primeClasses[1]:=[1];
  855. end;
  856.  
  857.  
  858. #############################################################################
  859. ##
  860. #F  DxPowerClass(<D>,<cl>,<pow>)  . . . . . . . . . . . . . evaluate powermap
  861. ##
  862. DxPowerClass := function(D,nu,power)
  863.   local p,primes,cl;
  864.   cl:=nu;
  865.   power:=power mod D.charTable.orders[cl];
  866.   if power=0 then
  867.     return 1;
  868.   elif power=1 then
  869.     return cl;
  870.   else
  871.     primes:=Factors(power);
  872.     for p in primes do
  873.       if not IsBound(D.charTable.powermap[p]) then
  874.         return D.ClassElement(D,
  875.           D.conjugacyClasses[nu].representative^power);
  876.       else
  877.         cl:=D.charTable.powermap[p][cl];
  878.       fi;
  879.     od;
  880.     return cl;
  881.   fi;
  882. end;
  883.  
  884.  
  885. #############################################################################
  886. ##
  887. #F  SplitStep(<D>,<bestMat>)  . . . . . .  calculate matrix bestMat as far as
  888. #F                                                    needed and split spaces
  889. ##
  890. SplitStep := function(D,bestMat)
  891.   local raeume,base,M,bestMatCol,bestMatSplit,i,j,k,N,row,col,Row,o,dim,
  892.         newRaeume,raum,ra,f,activeCols,eigenbase,eigen,v,vo,gens;
  893.  
  894.   if not bestMat in D.matrices then
  895.     Error("matrix <bestMat> not indicated for splitting");
  896.   fi;
  897.  
  898.   k:=D.klanz;
  899.  
  900.   f:=D.field;
  901.   o:=f.one;
  902.   raeume:=D.raeume;
  903.  
  904.   if ForAny(raeume,i->i.dim>1) then
  905.     bestMatCol:=D.requiredCols[bestMat];
  906.     bestMatSplit:=D.splitBases[bestMat];
  907.     M:=IdentityMat(k,1)*0;
  908.     InfoCharTable1("#I  Matrix ",bestMat,", Representative of Order ",
  909.        Order(D.group,D.conjugacyClasses[bestMat].representative),
  910.        ", Centralizer: ",Size(D.conjugacyClasses[bestMat].centralizer),
  911.        "\n");
  912.  
  913.     Add(D.yetmats,bestMat);
  914.     for col in bestMatCol do
  915.       InfoCharTable2("#I  Computing column ",col,": ");
  916.       D.ClassMatrixColumn(D,M,bestMat,col);
  917.       InfoCharTable2("\n");
  918.     od;
  919.  
  920.     M:=M*o;
  921.  
  922.     # note, that we will have calculated yet one!
  923.     D.maycent:=true;
  924.  
  925.     newRaeume:=[];
  926.     SubtractSet(D.matrices,[bestMat]);
  927.     for i in bestMatSplit do
  928.       raum:=raeume[i];
  929.       base:=Base(raum);
  930.       dim:=Length(base);
  931.       activeCols:=raum.activeCols;
  932.       N:=0*IdentityMat(dim,o);
  933.       for row in [1..dim] do
  934.         Row:=base[row]*M;
  935.         for col in [1..dim] do
  936.           N[row][col]:=Row[activeCols[col]];
  937.         od;
  938.       od;
  939.       eigen:=Eigenbase(N,f);
  940.       # Base umrechnen
  941.       eigenbase:=List(eigen.base,i->List(i,j->j*base));
  942.     #eigenvalues:=List(eigen.values,i->i/Size(D.conjugacyClasses[bestMat]));
  943.  
  944.       if Length(eigenbase)=1 then
  945.         InfoCharTable1("#W This can't happen !\n");
  946.         Add(newRaeume,raum);
  947.       else
  948.         ra:=List(eigenbase,i->RowSpace(i,f));
  949.  
  950.         # throw away Galois-images
  951.         for i in [1..Length(ra)] do
  952.           if IsBound(ra[i]) then
  953.             vo:=Orbit(raum.stabilizer,ra[i].generators[1],
  954.                      D.asCharacterMorphism);
  955.             for v in vo do
  956.               for j in [i+1..Length(ra)] do
  957.                 if IsBound(ra[j]) and Dimension(ra[i])=Dimension(ra[j])
  958.                   and v in ra[j] then
  959.                   Unbind(ra[j]);
  960.                 fi;
  961.               od;
  962.             od;
  963.           fi;
  964.         od;
  965.         for i in ra do
  966.           Base(i); # force computation of base
  967.           i.dim:=Dimension(i);
  968.           if IsBound(raum.stabilizer) then
  969.             i.approxStab:=raum.stabilizer;
  970.           fi;
  971.           Add(newRaeume,i);
  972.         od;
  973.       fi;
  974.     od;
  975.     for i in [1..Length(raeume)] do
  976.       if not i in bestMatSplit then
  977.         Add(newRaeume,raeume[i]);
  978.       fi;
  979.     od;
  980.     raeume:=newRaeume;
  981.   fi;
  982.  
  983.   for i in [1..Length(raeume)] do
  984.     if raeume[i].dim>1 then
  985.       ActiveCols(raeume[i]);
  986.     fi;
  987.   od;
  988.  
  989.   InfoCharTable1("#I  Dimensions: ",List(raeume,i->i.dim),"\n");
  990.   D.raeume:=raeume;
  991. end;
  992.  
  993.  
  994. #############################################################################
  995. ##
  996. #F  SplitTwoSpace(<D>,<raum>) . . . split two-dim space by combinatoric means
  997. ##
  998. ##  If the room is 2-dimensional, this is ment to be the standard split.
  999. ##  Otherwise, the two-dim invariant space of raum is to be split
  1000. ##
  1001. SplitTwoSpace := function(D,raum)
  1002.   local v1,v2,v1v1,v1v2,v2v1,v2v2,degrees,d1,d2,deg2,prime,o,f,d,degrees2,f,
  1003.         lift,root,p,q,n,char,char1,char2,a1,a2,i,j,NotFailed,k,l,m,test,ol,
  1004.         di,rp,mdeg2,mult;
  1005.  
  1006.   mult:=Index(D.characterMorphisms,CharacterMorphismOrbits(D,raum).stabilizer);
  1007.   f:=Dimension(raum)=2; # space or invariant space split indicator flag
  1008.   prime:=D.prime;
  1009.   rp:=Int(prime/2);
  1010.   o:=D.fone;
  1011.   if f then
  1012.     v1:=Base(raum)[1];
  1013.     v2:=raum.base[2];
  1014.     ol:=[1];
  1015.   else
  1016.     InfoCharTable1("#I  Attempt:",Dimension(raum),"\n");
  1017.     v1:=raum.invariantbase[1];
  1018.     v2:=raum.invariantbase[2];
  1019.     ol:=Filtered(DivisorsInt(Size(raum.stabilizer)),i->i<raum.dim/2+1);
  1020.   fi;
  1021.   v1v1:=ModProduct(D,v1,v1);
  1022.   v1v2:=ModProduct(D,v1,v2);
  1023.   v2v1:=ModProduct(D,v2,v1);
  1024.   v2v2:=ModProduct(D,v2,v2);
  1025.   char:=[];
  1026.   char2:=[];
  1027.   NotFailed:=true;
  1028.   di:=1;
  1029.   while di<=Length(ol) and NotFailed do
  1030.     d:=ol[di];
  1031.     degrees:=DegreeCandidates(D,d*mult);
  1032.     if f then
  1033.       degrees2:=degrees;
  1034.     else
  1035.       degrees2:=DegreeCandidates(D,(raum.dim-d)*mult);
  1036.     fi;
  1037.     mdeg2:=List(degrees2,i->i mod prime);
  1038.     i:=1;
  1039.     while i<=Length(degrees) and NotFailed do
  1040.       lift:=true;
  1041.       d1:=degrees[i];
  1042.       if d1*d>rp then
  1043.         lift:=false;
  1044.       fi;
  1045.       p:=(v2v1+v1v2)/v2v2;
  1046.       q:=(v1v1-o/(d*(d1^2) mod D.prime))/v2v2;
  1047.       for root in ModRoots((p/2)^2-q) do
  1048.         a1:=(-p/2+root);
  1049.         n:=v1v2+a1*v2v2;
  1050.         if (n=0*o) then
  1051.           # proceeding would force a division by zero
  1052.           NotFailed:=false;
  1053.         else
  1054.           a2:=-(v1v1+a1*v2v1)/n;
  1055.           n:=v1v1+a2*(v1v2+v2v1)+a2^2*v2v2;
  1056.           if n<>0*o then
  1057.             deg2:=List(ModRoots(o/(raum.dim-d)/n),IntFFE2);
  1058.             for d2 in deg2 do
  1059.               if d2 in mdeg2 then
  1060.                 if not d2 in degrees2 or d2*(raum.dim-d)>rp then
  1061.                   # degree is too big for lifting
  1062.                   lift:=false;
  1063.                 fi;
  1064.                 char1:=[d*d1*(v1+a1*v2),(raum.dim-d)*d2*(v1+a2*v2)];
  1065.  
  1066.                 if Length(char)>0 and
  1067.                   (char[1].base[1]=char1[2]) and
  1068.                   (char[2].base[1]=char1[1]) then
  1069.                     test:=false;
  1070.                 else
  1071.                   test:=true;
  1072.                 fi;
  1073.                 l:=1;
  1074.                 while (l<3) and test do
  1075.                   if f then
  1076.                     n:=1;
  1077.                   elif l=1 then
  1078.                     n:=d;
  1079.                   else
  1080.                     n:=raum.dim-d;
  1081.                   fi;
  1082.                   if not FrobSchurInd(D,char1[l]) in o*[-n..n]
  1083.                     then test:=false;
  1084.                   fi;
  1085.           m:=DxLiftCharacter(D,char1[l]);
  1086.           char2[l]:=m;
  1087.                   if test and lift then
  1088.                     for k in [2..Length(m)] do
  1089.                       if IsInt(m[k]) and AbsInt(m[k])>m[1] then
  1090.                         test:=false;
  1091.                       fi;
  1092.                     od;
  1093.                     if test and not IsInt(Sum(m)) then
  1094.                       test:=false;
  1095.                     fi;
  1096.                   fi;
  1097.                   l:=l+1;
  1098.                 od;
  1099.  
  1100.                 if test then
  1101.                   if Length(char)>0 then
  1102.                     NotFailed:=false;
  1103.                   else
  1104.                     char:=[rec(base:=[char1[1]],
  1105.                    char:=[char2[1]],
  1106.                                d:=d),
  1107.                            rec(base:=[char1[2]],
  1108.                    char:=[char2[2]],
  1109.                                d:=raum.dim-d)];
  1110.                   fi;
  1111.                 fi;
  1112.               fi;
  1113.             od;
  1114.           fi;
  1115.         fi;
  1116.       od;
  1117.       i:=i+1;
  1118.     od;
  1119.     di:=di+1;
  1120.   od;
  1121.   if f then
  1122.     InfoCharTable1("#I  Two-dim ");
  1123.   else
  1124.     InfoCharTable1("#I  Two orbit ");
  1125.   fi;
  1126.   if NotFailed then
  1127.     InfoCharTable1("space split\n");
  1128.     return char;
  1129.   else
  1130.     InfoCharTable1("split failed\n");
  1131.     raum.twofail:=true;
  1132.     return [];
  1133.   fi;
  1134. end;
  1135.  
  1136.  
  1137. #############################################################################
  1138. ##
  1139. #F  DxLiftCharacter(<D>,<modChi>) . recalculate character in characteristic 0
  1140. ##
  1141. DxLiftCharacter := function(D,modular)
  1142.   local modularChi,Chi,zeta,degree,sum,M,y,l,s,n,j,p,polynom,Chipolynom,
  1143.         family,prime;
  1144.   prime:=D.prime;
  1145.   modularChi:=List(modular,IntFFE2); #IntFFE(modular);
  1146.   degree:=modularChi[1];
  1147.   Chi:=[degree];
  1148.   for family in D.primeClasses do
  1149.     # we need to compute the polynomial only for prime classes. Powers are
  1150.     # obtained by simpy inserting powers in this polynomial
  1151.     j:=family[1];
  1152.     l:=Order(D.group,D.conjugacyClasses[j].representative);
  1153.     zeta:=E(l);
  1154.     polynom:=[degree,modularChi[j]];
  1155.     for n in [2..l-1] do
  1156.       s:=family[n];
  1157.       polynom[n+1]:=modularChi[s];
  1158.     od;
  1159.     Chipolynom:=[];
  1160.     s:=0;
  1161.     sum:=degree;
  1162.     while sum>0 do
  1163.       M:=ModularValuePol(polynom,
  1164.                          PowerModInt(D.z,-s*Exponent(D.group)/l,prime),
  1165.                          prime)/l mod prime;
  1166.       Add(Chipolynom,M);
  1167.       sum:=sum-M;
  1168.       s:=s+1;
  1169.     od;
  1170.     for n in [1..l-1] do
  1171.       s:=family[n];
  1172.       if not IsBound(Chi[s]) then
  1173.         Chi[s]:=ValuePol(Chipolynom,zeta^n);
  1174.       fi;
  1175.     od;
  1176.   od;
  1177.   return Chi;
  1178. end;
  1179.  
  1180.  
  1181. #############################################################################
  1182. ##
  1183. #F  GeneratePrimeCyclotomic( <e>, <r> ) . . . . . . . . .  ring homomorphisms
  1184. ##
  1185. ##  $\Q(\varepsilon_e)\to\F_p$. r is e-th root in F_p.
  1186. ##
  1187. GeneratePrimeCyclotomic := function(e,r) # exponent, Primitive Root
  1188.   return function(a)
  1189.   local l,n,w,s,i,o;
  1190.     l:=COEFFSCYC(a);
  1191.     n:=Length(l);
  1192.     o:=r^0;
  1193.     w:=0*o;
  1194.     s:=r^(e/n); # calculate corresponding power of modular root of unity
  1195.    for i in [1..n] do
  1196.       if i=1 then
  1197.         w:=w+l[i]*o;
  1198.       else
  1199.         w:=w+s^(i-1)*l[i];
  1200.       fi;
  1201.     od;
  1202.     return w;
  1203.   end;
  1204. end;
  1205.  
  1206.  
  1207. #############################################################################
  1208. ##
  1209. #F  ModProduct(<D>,<vector1>,<vector2>) . . . product of two characters mod p
  1210. ##
  1211. ModProduct := function(D,v1,v2)
  1212.   local prod,i;
  1213.   prod:=0*D.fone;
  1214.   for i in [1..D.klanz] do
  1215.     prod:=prod+ (Size(D.conjugacyClasses[i]) mod D.prime)*v1[i]
  1216.         *v2[D.charTable.inversemap[i]];
  1217.   od;
  1218.   prod:=prod/(D.group.size mod D.prime);
  1219.   return prod;
  1220. end;
  1221.  
  1222.  
  1223. #############################################################################
  1224. ##
  1225. #F  ModularCharacterDegree(<D>,<Chi>) . . . . . . . . .  degree of normalized
  1226. #F                                                         character modulo p
  1227. ##
  1228. ModularCharacterDegree := function(D,chi)
  1229.   local j,j1,d,sum,prime;
  1230.   prime:=D.prime;
  1231.   sum:=0*D.fone;
  1232.   for j in [1..D.klanz] do
  1233.     j1:=D.charTable.inversemap[j];
  1234.     sum:=sum+chi[j]*chi[j1]*(Size(D.conjugacyClasses[j]) mod prime);
  1235.   od;
  1236.   d:=RootMod(D.group.size/IntFFE2(sum) mod prime,prime);
  1237.   # take correct (smaller) root
  1238.   if 2*d>prime then
  1239.     d:=prime-d;
  1240.   fi;
  1241.   return d;
  1242. end;
  1243.  
  1244.  
  1245. #############################################################################
  1246. ##
  1247. #F  DegreeCandidates(<D>,[<anz>]) . . Potential degrees for anz characters of
  1248. #F     same degree, if num characters of total degree deg are yet to be found
  1249. ##
  1250. DegreeCandidates := function(arg)
  1251.   local D,anz,degrees,divisors,i,r;
  1252.   D:=arg[1];
  1253.   if Length(arg)>1 then
  1254.     anz:=arg[2];
  1255.     degrees:=[];
  1256.     r:=RootInt(Int((D.deg-(D.num-anz)*D.degreePool[1][1]^2)/anz));
  1257.     i:=1;
  1258.     while i<=Length(D.degreePool) and D.degreePool[i][1]<=r do
  1259.       if D.degreePool[i][2]>anz then
  1260.     Add(degrees,D.degreePool[i][1]);
  1261.       fi;
  1262.       i:=i+1;
  1263.     od;
  1264.     return degrees;
  1265.   else
  1266.     return List(D.degreePool,i->i[1]);
  1267.   fi;
  1268. end;
  1269.  
  1270.  
  1271. #############################################################################
  1272. ##
  1273. #F  FrobSchurInd( <D>, <char> ) . . . . . . modular Frobenius-Schur indicator
  1274. ##
  1275. FrobSchurInd := function(D,char)
  1276.   local FSInd,classes,l,ll,L,family;
  1277.   FSInd:=char[1];
  1278.   classes:=[2..D.klanz];
  1279.   for family in D.primeClasses do
  1280.     L:=Length(family)+1;
  1281.     for l in [1..L-1] do
  1282.       if family[l] in classes then
  1283.         ll:=2*l mod L;
  1284.         if ll=0 then
  1285.           FSInd:=FSInd+(Size(D.conjugacyClasses[family[l]]) mod D.prime)
  1286.                *char[1];
  1287.         else
  1288.           FSInd:=FSInd+(Size(D.conjugacyClasses[family[l]]) mod D.prime)
  1289.                *char[family[ll]];
  1290.        fi;
  1291.         SubtractSet(classes,[family[l]]);
  1292.       fi;
  1293.     od;
  1294.   od;
  1295.   return FSInd/(D.group.size mod D.prime);
  1296. end;
  1297.  
  1298.  
  1299. #############################################################################
  1300. ##
  1301. #F  BestSplittingMatrix(<D>) . number of the matrix, that will yield the best
  1302. #F                                                                      split
  1303. ##
  1304. ##  This routine calculates also all required columns etc. and stores the
  1305. ##  result in D
  1306. ##
  1307. BestSplittingMatrix := function(D)
  1308.   local n,dim,i,val,b,requiredCols,splitBases,wert,nu,r,rs,rc,bn,bw,split,
  1309.         orb,os;
  1310.  
  1311.   nu:=D.field.zero;
  1312.   requiredCols:=[];
  1313.   splitBases:=[];
  1314.   wert:=[];
  1315.   os:=ForAll(D.raeume,i->i.dim<20); #only small spaces left?
  1316.  
  1317.   for n in D.matrices do
  1318.     requiredCols[n]:=[];
  1319.     splitBases[n]:=[];
  1320.     wert[n]:=0;
  1321.     # dont start with central classes in small groups!
  1322.     if D.charTable.classes[n]>1 or IsBound(D.maycent) then
  1323.       for i in [1..Length(D.raeume)] do
  1324.         r:=D.raeume[i];
  1325.         if IsBound(r.splits) then
  1326.           rs:=r.splits;
  1327.         else
  1328.           rs:=[];
  1329.           r.splits:=rs;
  1330.         fi;
  1331.  
  1332.         if r.dim>1 then
  1333.  
  1334.           if IsBound(rs[n]) then
  1335.             split:=rs[n].split;
  1336.             val:=rs[n].val;
  1337.           else
  1338.             b:=Base(r);
  1339.             split:=ForAny(Sublist(b,[2..r.dim]),i->i[n]<>nu);
  1340.         if split then
  1341.           if r.dim<4 then
  1342.         # very small spaces will split nearly perfect
  1343.         val:=8;
  1344.           else
  1345.         bn:=SplitDegree(D,r,n);
  1346.         if os then
  1347.           if D.group.isPerfect then
  1348.             # G is perfect, no linear characters
  1349.             # we can't predict much about the splitting
  1350.             val:=Maximum(1,9-r.dim/bn);
  1351.           else
  1352.             val:=bn*Maximum(1,9-r.dim/bn);
  1353.           fi;
  1354.         else
  1355.           val:=bn;
  1356.         fi;
  1357.           fi;
  1358.           # note the images, which split as well
  1359.           val:=val*Index(D.characterMorphisms,
  1360.                  CharacterMorphismOrbits(D,r).stabilizer);
  1361.             else
  1362.           val:=0;
  1363.         fi;
  1364.             rs[n]:=rec(split:=split,val:=val);
  1365.           fi;
  1366.           if split then
  1367.             wert[n]:=wert[n]+val;
  1368.             Add(splitBases[n],i);
  1369.             requiredCols[n]:=Union(requiredCols[n],
  1370.                                     D.raeume[i].activeCols);
  1371.           fi;
  1372.         fi;
  1373.       od;
  1374.       if Length(splitBases[n])>0 then
  1375.         # can we use Galois-Conjugation
  1376.         orb:=GaloisOrbits(D,n);
  1377.         rc:=[];
  1378.         for i in requiredCols[n] do
  1379.           rc:=Union(rc,[orb.orbits[i][1]]);
  1380.         od;
  1381.  
  1382.         wert[n]:=wert[n]*Size(D.conjugacyClasses[n].centralizer) # *G/|K|
  1383.                  /(Length(rc)); # We count -mistakening - also the first
  1384.        # column, that is availiable for free. Its "costs" are ment to
  1385.        # compensate for the splitting process.
  1386.       fi;
  1387.     fi;
  1388.   od;
  1389.  
  1390.   for r in D.raeume do
  1391.     if Number(r.splits)=1 then
  1392.       # is room split by only ONE matrix?(then we need this sooner or later)
  1393.       n:=PositionProperty(r.splits,IsBound);
  1394.       wert[n]:=wert[n]*10; #arbitrary increase of value
  1395.     fi;
  1396.   od;
  1397.  
  1398.   bn:=D.matrices[1];
  1399.   bw:=0;
  1400.   InfoCharTable2("#I  ");
  1401.   for n in D.matrices do
  1402.     InfoCharTable2(n,":",Int(wert[n])," ");
  1403.     if wert[n]>=bw then
  1404.       bn:=n;
  1405.       bw:=wert[n];
  1406.     fi;
  1407.   od;
  1408.   InfoCharTable2("\n");
  1409.   D.requiredCols:=requiredCols;
  1410.   D.splitBases:=splitBases;
  1411.  
  1412.   return bn;
  1413. end;
  1414.  
  1415.  
  1416. #############################################################################
  1417. ##
  1418. #F  SplitDegree( <D>, <space>, <r> )  estimate number of parts when splitting
  1419. ##                space with matrix number r, according to charactermorphisms
  1420. ##
  1421. SplitDegree := function(D,space,r)
  1422.   local a,b,s,o,fix,k,l,i,j,gorb,v,w;
  1423.   # is perfect split guaranteed ?
  1424.   if IsBound(space.split) then
  1425.     return space.split;
  1426.   fi;
  1427.   o:=D.fone;
  1428.   a:=CharacterMorphismOrbits(D,space);
  1429.   if a.number=space.dim then
  1430.     return 2; #worst possible split
  1431.   fi;
  1432.   if a.number=1 and IsPrime(space.dim) then
  1433.     # spaces of prime dimension with one orbit must split perfectly
  1434.     space.split:=space.dim;
  1435.     return space.dim;
  1436.   fi;
  1437.   # both cases, but MultiOrbit is not as effective
  1438.   s:=a.stabilizer;
  1439.   b:=a.invariantbase;
  1440.   gorb:=D.galoisOrbits[r];
  1441.   fix:=Length(gorb)=1;
  1442.   if not fix then
  1443.     # Galoisgroup operates trivial ? (seen if constant values on 
  1444.     # rational class)
  1445.     i:=1;
  1446.     fix:=true;
  1447.     while fix and i<=Length(space.base) do
  1448.       v:=space.base[i];
  1449.       w:=v[r];
  1450.       for j in gorb do
  1451.         if v[j]<>w then
  1452.           fix:=false;
  1453.         fi;
  1454.       od;
  1455.       i:=i+1;
  1456.     od;
  1457.   fi;
  1458.   if fix then
  1459.     #l:=List(s.generators,i->i.tens[r]);
  1460.     l:=List(s.generators,i->D.asCharacterMorphism(1,i).tens[r]);
  1461.     v:=[o];
  1462.     for i in v do
  1463.       for j in l do
  1464.         w:=i*j;
  1465.         if not w in v then
  1466.           Add(v,w);
  1467.         fi;
  1468.       od;
  1469.     od;
  1470.     return Length(v); #Length(Set(List(Elements(s),i->i.tens[r])));
  1471.   else
  1472.     # nonfix
  1473.     # v is an element from the space with non-galois-fix parts.
  1474.     l:=Maximum(List(TransposedMat(List(Orbit(s,v,D.asCharacterMorphism),
  1475.                i->Sublist(i,D.galoisOrbits[r]))),i->Length(Set(i))));
  1476.     if a.number=1 then
  1477. # One orbit: number of resultant spaces must be a divisor of the dimension
  1478.       k:=DivisorsInt(space.dim);
  1479.       while l<space.dim and not l in k do
  1480.         l:=l+1;
  1481.       od;
  1482.     fi;
  1483.     return l;
  1484.   fi;
  1485. end;
  1486.  
  1487.  
  1488. #############################################################################
  1489. ##
  1490. #F  CharacterMorphismGroup( <D> ) . . . . create group of character morphisms
  1491. ##
  1492. ##  The group is stored in .characterMorphisms. It is an AgGroup,
  1493. ##  according to the decomposition K=tens:gal as semidirect product. The
  1494. ##  group works as linear mappings that permute characters via the operation
  1495. ##  .asCharacterMorphism.
  1496. ##
  1497. CharacterMorphismGroup := function(D)
  1498.   local C,e,gens,rels,p,gals,f,er,tm,tme,i,j,k,l,offset,op,ob,o,tl,komm,el,h;
  1499.   C:=D.charTable;
  1500.   p:=AgGroup(C.automorphisms);
  1501.   gals:=List(p.generators,i->Image(p.bijection,i));
  1502.   # obtain Ag presentation for galois part
  1503.   f:=AgGroupOps.FpGroup(p,"g");
  1504.   gens:=f.generators;
  1505.   rels:=f.relators;
  1506.  
  1507.   if IsBound(D.tensorMorphisms) then
  1508.     er:=[1..D.klanz];
  1509.     tm:=D.tensorMorphisms;
  1510.     tme:=tm.els;
  1511.     # create generators and decompose orders in prime powers
  1512.     for i in [1..Length(tm.a)] do
  1513.       op:=Factors(tm.a[i]);
  1514.       gens:=Concatenation(gens,List([1..Length(op)],j->AbstractGenerator(
  1515.               ConcatenationString(String(i),"t",String(j)))));
  1516.       ob:=op[1];
  1517.       for j in tme do
  1518.         j[1][i]:=Reversed(PadicInt(j[1][i],Length(op),ob));
  1519.       od;
  1520.     od;
  1521.     # remove iterated lists in the p-adic part
  1522.     for i in tme do
  1523.       e:=[];
  1524.       for j in i[1] do
  1525.         e:=Concatenation(e,j);
  1526.       od;
  1527.       i[1]:=e;
  1528.     od;
  1529.  
  1530.     tl:=Length(gens)-Length(gals);
  1531.  
  1532.     offset:=Length(gals);
  1533.     for i in [1..Length(tm.a)] do
  1534.       # decompose each generator (which has prime power order, since
  1535.       # obtained via 'AbelianInvariants') in power parts.
  1536.       o:=tm.a[i];
  1537.       e:=tm.c[i];
  1538.       op:=Factors(o);
  1539.       ob:=op[1];
  1540.       op:=Length(op);
  1541.       for j in [offset+1..offset+op] do
  1542.         # first generator is original tensor generator, the following ones
  1543.         # are its images
  1544.         if j<offset+op then
  1545.           Add(rels,gens[j]^ob/gens[j+1]);
  1546.         else
  1547.           Add(rels,gens[j]^ob);
  1548.         fi;
  1549.  
  1550.         # Add relators for operation of galois part on tensor part
  1551.         el:=[]; # compute representative for AgGenerator -> power
  1552.         for k in er do
  1553.           el[k]:=e[k]^(ob^(j-1-offset));
  1554.         od;
  1555.         for k in [1..Length(gals)] do
  1556.           h:=Permuted(ShallowCopy(el),gals[k]);
  1557.           for l in er do
  1558.             h[l]:=el[l]^(-1)*h[l];
  1559.           od;
  1560.           l:=1;
  1561.           while tme[l][2]<>h do
  1562.             l:=l+1;
  1563.           od;
  1564.           h:=tme[l][1];
  1565.           komm:=IdWord;
  1566.           for l in [1..tl] do
  1567.             komm:=komm*gens[Length(gals)+l]^h[l];
  1568.           od;
  1569.  
  1570.           Add(rels,Comm(gens[j],gens[k])/komm);
  1571.         od;
  1572.       od;
  1573.       offset:=offset+op;
  1574.     od;
  1575.     for i in tme do
  1576.       # store modular tensor part
  1577.       i[3]:=List(i[2],j->D.modularMap(j));
  1578.     od;
  1579.   else
  1580.     tme:=[[[],List(D.conjugacyClasses,i->1),
  1581.               List(D.conjugacyClasses,i->D.fone)]];
  1582.   fi;
  1583.   tm:=AgGroupFpGroup(rec(generators:=gens,
  1584.                          relators:=rels));
  1585.   D.characterMorphisms:=tm;
  1586.   D.asCharacterMorphism:=AsCharacterMorphismFunction(gals,tme);
  1587.   D.tensorMorphisms:=tme;
  1588.   return tm;
  1589. end;
  1590.  
  1591.  
  1592. #############################################################################
  1593. ##
  1594. #F  AsCharacterMorphismFunction( <gals>, <tensormorphisms>)  create operation
  1595. #F                               function for operation of charactermorphisms
  1596. ##
  1597. AsCharacterMorphismFunction := function(gals,tme)
  1598.   local i,j,k,x,g,c,lg;
  1599.   lg:=Length(gals);
  1600.   return function(p,e)
  1601.     x:=ExponentsAgWord(e);
  1602.     g:=();
  1603.     for i in [1..lg] do
  1604.       g:=g*gals[i]^x[i];
  1605.     od;
  1606.     x:=Sublist(x,[lg+1..Length(x)]);
  1607.     i:=1;
  1608.     while tme[i][1]<>x do
  1609.       i:=i+1;
  1610.     od;
  1611.     x:=tme[i][3];
  1612.     if IsInt(p) then # integer works only as indicator: return galois and
  1613.                      # tensor part
  1614.       return rec(gal:=g,
  1615.                  tens:=x);
  1616.     elif IsList(p) then
  1617.       if not IsFFE(p[1]) then
  1618.         # operation on characteristic 0 characters;
  1619.         x:=tme[i][2];
  1620.       fi;
  1621.       c:=[];
  1622.       for i in [1..Length(p)] do
  1623.         j:=i^g;
  1624.         c[j]:=p[i]*x[j];
  1625.       od;
  1626.       return c;
  1627.     else # RowSpace
  1628.       c:=List(p.generators,i->[]);
  1629.       for i in [1..Length(p.zero)] do
  1630.         j:=i^g;
  1631.         for k in [1..Length(p.generators)] do
  1632.           c[k][j]:=p.generators[k][i]*x[j];
  1633.         od;
  1634.       od;
  1635.  
  1636.     # simulate: RowSpace(gens,a.field);
  1637.       return rec(generators:=c,
  1638.                  field:=p.field,
  1639.                  zero:=p.zero,
  1640.                  isDomain:=true,
  1641.                  isVectorSpace:=true,
  1642.                  isRowSpace:=true,
  1643.                  isFinite:=true,
  1644.                  operations:=RowSpaceOps);
  1645.  
  1646.     fi;
  1647.   end;
  1648. end;
  1649.  
  1650.  
  1651. #############################################################################
  1652. ##
  1653. #F  CharacterMorphismOrbits( <D>, <space> ) . . stabilizer and invariantspace
  1654. ##
  1655. CharacterMorphismOrbits := function(D,space)
  1656.   local a,b,s,o,gen;
  1657.   if not IsBound(space.stabilizer) then
  1658.     if IsBound(space.approxStab) then
  1659.       a:=space.approxStab;
  1660.     else
  1661.       a:=D.characterMorphisms;
  1662.     fi;
  1663.     space.stabilizer:=Stabilizer(a,space,D.asCharacterMorphism);
  1664.   fi;
  1665.   if not IsBound(space.invariantbase) then
  1666.     o:=D.fone;
  1667.     s:=space.stabilizer;
  1668.     b:=Base(space);
  1669.     a:=ActiveCols(space);
  1670.     # calculate invariant space as intersection of E.S to E.V. 1
  1671.     for gen in s.generators do
  1672.       b:=NullspaceMat(List(b,i->Sublist(D.asCharacterMorphism(i,gen),a))
  1673.                        -IdentityMat(Length(b),o))*b;
  1674.       TriangulizeMat(b);
  1675.       a:=ActiveCols(b);
  1676.     od;
  1677.     space.invariantbase:=b;
  1678.   fi;
  1679.   return rec(invariantbase:=space.invariantbase,
  1680.              number:=Length(space.invariantbase),
  1681.              stabilizer:=space.stabilizer);
  1682. end;
  1683.  
  1684.  
  1685. #############################################################################
  1686. ##
  1687. #F  GaloisOrbits(<D>,<f>) .  orbits of Stab_Gal(f) when acting on the classes
  1688. ##
  1689. GaloisOrbits := function(D,f)
  1690.   local i,k,l,u,h,ga,galOp,p;
  1691.   k:=Length(D.conjugacyClasses);
  1692.   if not IsBound(D.galOp[f]) then
  1693.     galOp:=D.galOp;
  1694.     if f in PermGroupOps.MovedPoints(D.charTable.automorphisms) then
  1695.       ga:=Stabilizer(D.charTable.automorphisms,f);
  1696.     else
  1697.       ga:=D.charTable.automorphisms;
  1698.     fi;
  1699.     p:=true;
  1700.     i:=1;
  1701.     while p and i<=Length(galOp) do
  1702.       if IsBound(galOp[i]) and
  1703.          galOp[i].group=ga then
  1704.           galOp[f]:=galOp[i];
  1705.           p:=false;
  1706.       else
  1707.         i:=i+1;
  1708.       fi;
  1709.     od;
  1710.     if p then
  1711.       galOp[f]:=rec(group:=ga);
  1712.       l:=List([1..k],i->Set(Orbit(ga,i)));
  1713.       galOp[f].orbits:=l;
  1714.       u:=List(Filtered(Collected(
  1715.         List(Set(List(l,i->i[1])),j->D.rids[j])),n->n[2]=1),t->t[1]);
  1716.       galOp[f].uniqueIdentifications:=u;
  1717.       galOp[f].identifees:=Filtered([1..k],i->D.rids[i] in u);
  1718.     fi;
  1719.   fi;
  1720.   return D.galOp[f];
  1721. end;
  1722.  
  1723.  
  1724. #############################################################################
  1725. ##
  1726. #F  RootsOfPol(<pol>) . . . . . . . . . . . . . . . . . roots of a polynomial
  1727. ##
  1728. RootsOfPol := function(f)
  1729.   local roots,factor;
  1730.   roots:=[];
  1731.   for factor in Factors(f) do
  1732.     if EuclideanDegree(factor)=1 then
  1733.       # work around new representation of polynomials
  1734.       if factor.valuation=0 then
  1735.     Add(roots,-factor.coefficients[1]);
  1736.       else
  1737.     Add(roots,0*factor.coefficients[1]);
  1738.       fi;
  1739.     fi;
  1740.   od;
  1741.   return roots;
  1742. end;
  1743.  
  1744.  
  1745. #############################################################################
  1746. ##
  1747. #F  ModRoots(<n>) . . . . . . . . . computes, if possible, the roots of FFE n
  1748. ##
  1749. ModRoots := function(n)
  1750.   local r,f,e;
  1751.   if n=0*n then
  1752.     return [n];
  1753.   fi;
  1754.   e:=LogFFE(n)/2;
  1755.   if IsInt(e) then
  1756.     r:=Z(CharFFE(n)^DegreeFFE(n))^e;
  1757.     return Set([r,-r]);
  1758.   else
  1759.     return [];
  1760.   fi;
  1761. end;
  1762.  
  1763.  
  1764. #############################################################################
  1765. ##
  1766. #F  ModularValuePol( <f>, <x>, <p> )  . evaluate polynomial at a point, mod p
  1767. ##
  1768. ##  'ModularValuePol' returns the value of the polynomial <f> at <x>,
  1769. ##  regarding the result modulo p. <x> must be an integer number.
  1770. ##
  1771. ##  'ModularValuePol' uses Horners rule to evaluate the polynom.
  1772. ##
  1773. ModularValuePol := function ( f, x,p )
  1774.   local  value, i;
  1775.   value := 0;
  1776.   i := Length(f);
  1777.   while i > 0  do
  1778.     value := (value * x + f[i]) mod p;
  1779.     i := i-1;
  1780.   od;
  1781.   return value;
  1782. end;
  1783.  
  1784.  
  1785. ############################################################################
  1786. ##
  1787. #F  BMminpol(<seq>,<p>) . . . . . . . . . . . . .  Berlekamp-Massey Algorithm
  1788. ##
  1789. ##  calculate minimal polynomial of the linear homogenous recurring
  1790. ##  sequence <seq> modulo <p>
  1791. ##  Lit.: Lidl/Niederreiter: Finite Fields, Ch. 8
  1792. ##
  1793. BMminpol := function(seq,f)
  1794.   local M,newg,k,m,g,h,b,r,i,l,j,o,z,mi;
  1795.   k:=QuoInt(Length(seq),2);
  1796.   o:=f.one;
  1797.   z:=f.zero;
  1798.   g:=[o];
  1799.   h:=[z,o];
  1800.   m:=0;
  1801.   for i in [1..2*k] do
  1802.     b:=z;
  1803.     # compute coefficient in product without computing the product itself
  1804.     for j in [1..i] do
  1805.       if Length(g)>=i-j+1 then
  1806.         b:=b+seq[j]*g[i-j+1];
  1807.       fi;
  1808.     od;
  1809.     if b<>z then
  1810.       # newg:=limo(DifferencePol(g,b*h),prime);
  1811.       mi:=Minimum(Length(g),Length(h));
  1812.       newg:=[];
  1813.       newg[mi]:=z;
  1814.       for j in [1..mi] do
  1815.         newg[j]:=g[j]-b*h[j];
  1816.       od;
  1817.       if Length(g)>Length(h) then
  1818.         for j in [mi+1..Length(g)] do
  1819.           newg[j]:=g[j];
  1820.         od;
  1821.       elif Length(g)<Length(h) then
  1822.         for j in [mi+1..Length(h)] do
  1823.           newg[j]:=-b*h[j];
  1824.         od;
  1825.       else
  1826.         while newg[Length(newg)]=z do
  1827.           Unbind(newg[Length(newg)]);
  1828.         od;
  1829.       fi;
  1830.     else
  1831.       newg:=g;
  1832.     fi;
  1833.     if(b<>z)and(m>=0)then
  1834.       h:=Concatenation([z],b^(-1)*g);
  1835.       m:=-m;
  1836.     else
  1837.       h:=Concatenation([z],h);
  1838.       m:=m+1;
  1839.     fi;
  1840.     g:=newg;
  1841.   od;
  1842.   l:=Length(g);
  1843.   r:=QuoInt(2*k+1-m,2);
  1844.   M:=[];
  1845.   for i in [l..r] do
  1846.     Add(M,z);
  1847.   od;
  1848.   for i in [0..l-1] do
  1849.     Add(M,g[l-i]);
  1850.   od;
  1851.   return Polynomial(f,M);
  1852. end;
  1853.  
  1854.  
  1855. #############################################################################
  1856. ##
  1857. #F  KrylovSequence(<vec>,<mat>) . . . . . . . . list of images of <vec> under
  1858. #F                                                    multiplication by <mat>
  1859. ##
  1860. KrylovSequence := function(w,A)
  1861.   local i,l,k;
  1862.   k:=Length(A);
  1863.   l:=[w];
  1864.   for i in [1..2*k] do
  1865.     w:=w*A;
  1866.     Add(l,w);
  1867.   od;
  1868.   return l;
  1869. end;
  1870.  
  1871.  
  1872. #############################################################################
  1873. ##
  1874. #F  Eigenbase(<mat>,<base>,<o>) . . . . . components of Eigenvects resp. base
  1875. ##
  1876. Eigenbase := function(M,f)
  1877.   local dim,v,w,i,k,KS,scalarSeq,eigenvalues,base,minpol,bases;
  1878.   k:=Length(M);
  1879.   repeat
  1880.     repeat
  1881.       w:=List([1..k],x->Random(f));
  1882.     until w<>0*w;
  1883.     repeat
  1884.       v:=List([1..k],x->Random(f));
  1885.     until v<>0*v;
  1886.     KS:=KrylovSequence(w,M);
  1887.     scalarSeq:=[];
  1888.     for i in [1..2*k+1] do
  1889.       scalarSeq[i]:=KS[i]*v;
  1890.     od;
  1891.     minpol:=BMminpol(scalarSeq,f);
  1892.     eigenvalues:=Set(RootsOfPol(minpol));
  1893.     dim:=0;
  1894.     bases:=[];
  1895.     for i in eigenvalues do
  1896.       base:=NullspaceMat(M-i*M^0);
  1897.       if base=[] then
  1898.         Error("This can`t happen: Wrong Eigenvalue ???");
  1899.       else
  1900.         #TriangulizeMat(base);
  1901.         dim:=dim+Length(base);
  1902.         Add(bases,base);
  1903.       fi;
  1904.     od;
  1905.     if dim<k then
  1906.       InfoCharTable2("#I  Failed to calculate eigenspaces.\n");
  1907.     fi;
  1908.   until dim=k;
  1909.   return rec(base:=bases,
  1910.              values:=eigenvalues);
  1911. end;
  1912.  
  1913.  
  1914. #############################################################################
  1915. ##
  1916. #F  ActiveCols(<space|base>)  . . . . . . . . active columns of space or base
  1917. ##
  1918. ActiveCols := function(raum)
  1919.   local base,activeCols,j,n,l;
  1920.   activeCols:=[];
  1921.   if IsRec(raum) then
  1922.     n:=raum.field.zero;
  1923.     if IsBound(raum.activeCols) then
  1924.       return raum.activeCols;
  1925.     fi;
  1926.     base:=Base(raum);
  1927.   else
  1928.     n:=Field(raum[1]).zero;
  1929.     base:=raum;
  1930.   fi;
  1931.   l:=1;
  1932.   for j in [1..Length(base)] do
  1933.     while base[j][l]=n do
  1934.       l:=l+1;
  1935.     od;
  1936.     Add(activeCols,l);
  1937.   od;
  1938.   if IsRec(raum) then
  1939.     raum.activeCols:=activeCols;
  1940.   fi;
  1941.   return activeCols;
  1942. end;
  1943.  
  1944.  
  1945. #############################################################################
  1946. ##
  1947. #F  PadicInt( <n>, <len>, <b> ) . . . . . . . . . . . . . convert n to base b
  1948. ##
  1949. ##  n is converted in a list of exponents in base b, maximum length len
  1950. ##  (thus taking m mod b^len).
  1951. ##
  1952. PadicInt := function(n,l,b)
  1953.   local i,p;
  1954.   p:=[];
  1955.   for i in [1..l] do
  1956.     p[l-i+1]:=RemInt(n,b);
  1957.     n:=QuoInt(n,b);
  1958.   od;
  1959.   return p;
  1960. end;
  1961.  
  1962.  
  1963. #############################################################################
  1964. ##
  1965. #F  ClassElementLargeGroup(D,<el>)  . . . . . identify class of el in D.group
  1966. ##
  1967. ##  First, the (hopefully) cheap identification is used, to filter the
  1968. ##  possible classes. If still not unique, a hard conjugacy test is applied
  1969. ##
  1970. ClassElementLargeGroup := function(D,el)
  1971.   local possible,structure,i,id;
  1972.   id:=D.identification(D,el);
  1973.   possible:=Filtered([1..D.klanz],i->D.ids[i]=id);
  1974.   i:=1;
  1975.   while i<Length(possible) do
  1976.     if el in D.conjugacyClasses[possible[i]] then
  1977.       return possible[i];
  1978.     else
  1979.       i:=i+1;
  1980.     fi;
  1981.   od;
  1982.   return possible[i];
  1983. end;
  1984.  
  1985.  
  1986. #############################################################################
  1987. ##
  1988. #F  ClassElementSmallGroup( <D>, <el> ) . . . identify class of el in D.group
  1989. ##
  1990. ##  Since we have stored the complete classmap, this is done by simply
  1991. ##  looking the class number up in this list.
  1992. ##
  1993. ClassElementSmallGroup := function(D,el)
  1994.   return D.classMap[D.group.enumeration.number(D.group,el)];
  1995. end;
  1996.  
  1997.  
  1998. #############################################################################
  1999. ##
  2000. #F  DoubleCentralizerOrbit( <D>, <c1>, <c2> )
  2001. ##
  2002. ##  Let g_i be the representative of Class i.
  2003. ##  Compute orbits of C(g_2) on (g_1^(-1))^G. Since we want to evaluate
  2004. ##  x^(-1)*z for x\in Cl(g_1), and we only need the class of the result, we
  2005. ##  may conjugate with z-centralizing elements and still obtain the same
  2006. ##  results! The orbits are calculated either by simple orbit algorithms or
  2007. ##  whenever they might become bigger using double cosets of the
  2008. ##  centralizers.
  2009. ##
  2010. DoubleCentralizerOrbit := function(D,c1,c2)
  2011.   local often,trans,e,neu,i,inv,cent,l,s,s1,x;
  2012.   inv:=D.charTable.inversemap[c1];
  2013.   s1:=D.charTable.classes[c1];
  2014.   # criteria for using simple orbit part: only for small groups, note that
  2015.   # computing ascending chains can be very expensive.
  2016.   if s1<500 or
  2017.      (not IsBound(D.conjugacyClasses[inv].centralizer.ascendingChain)
  2018.         and s1<1000)
  2019.  
  2020.   then
  2021.     if D.currentInverseClassNo<>c1 then
  2022.       D.currentInverseClassNo:=c1;
  2023.       # compute (x^(-1))^G
  2024.       D.currentInverseClass:=Orbit(D.group,
  2025.                            D.conjugacyClasses[inv].representative);
  2026.     fi;
  2027.     trans:=[];
  2028.     cent:=D.conjugacyClasses[c2].centralizer;
  2029.     for e in D.currentInverseClass do
  2030.       neu:=true;
  2031.       i:=1;
  2032.       while neu and (i<=Length(trans)) do
  2033.         if e in trans[i] then neu:=false;
  2034.         fi;
  2035.         i:=i+1;
  2036.       od;
  2037.       if neu then
  2038.         Add(trans,Orbit(cent,e));
  2039.       fi;
  2040.     od;
  2041.     often:=List(trans,i->Length(i));
  2042.     return [List(trans,i->i[1]),often];
  2043.   else
  2044.     InfoCharTable2("using DoubleCosets; ");
  2045.     cent:=D.conjugacyClasses[inv].centralizer;
  2046.     l:=DoubleCosets(D.group,cent,D.conjugacyClasses[c2].centralizer);
  2047.     s1:=Size(cent);
  2048.     e:=[];
  2049.     s:=[];
  2050.     x:=D.conjugacyClasses[inv].representative;
  2051.     for i in l do
  2052.       Add(e,x^i.representative);
  2053.       Add(s,Size(i)/s1);
  2054.     od;
  2055.     return [e,s];
  2056.   fi;
  2057. end;
  2058.  
  2059.  
  2060. #############################################################################
  2061. ##
  2062. #F  StandardClassMatrixColumm(<D>,<mat>,<r>,<t>)  . calculate the t-th column
  2063. #F       of the r-th class matrix and store it in the appropriate column of M
  2064. ##
  2065. StandardClassMatrixColumn := function(D,M,r,t)
  2066.   local c,gt,s,z,i,T,w,e,j,p,orb;
  2067.   if t=1 then
  2068.     M[D.charTable.inversemap[r]][t]:=Size(D.conjugacyClasses[r]);
  2069.   else
  2070.     orb:=GaloisOrbits(D,r);
  2071.     z:=D.conjugacyClasses[t].representative;
  2072.     c:=orb.orbits[t][1];
  2073.     if c<>t then
  2074.       p:=RepresentativeOperation(orb.group,c,t);
  2075.       # was the first column of the galois class active?
  2076.       if ForAny(M,i->i[c]>0) then
  2077.     for i in [1..Length(D.conjugacyClasses)] do
  2078.       M[i^p][t]:=M[i][c];
  2079.     od;
  2080.     InfoCharTable2("by GaloisImage");
  2081.     return;
  2082.       fi;
  2083.     fi;
  2084.  
  2085.     T:=DoubleCentralizerOrbit(D,r,t);
  2086.     InfoCharTable2(Length(T[1])," instead of ",D.conjugacyClasses[r].size);
  2087.  
  2088.     if IsLargeGroup(D.group) then
  2089.       # if r and t are unique, the conjugation test can be weak (i.e. up to
  2090.       # galois automorphisms )
  2091.       w:=Length(orb.orbits[t])=1;
  2092.       for i in [1..Length(T[1])] do
  2093.         if w then
  2094.           e:=T[1][i]*z;
  2095.           c:=D.rationalidentification(D,e);
  2096.           if c in orb.uniqueIdentifications then
  2097.             s:=orb.orbits[
  2098.               First([1..D.klanz],j->D.rids[j]=c)][1];
  2099.           else
  2100.             s:=D.ClassElement(D,T[1][i] * z);
  2101.           fi;
  2102.         else # only strong test possible
  2103.           s:=D.ClassElement(D,T[1][i] * z);
  2104.         fi;
  2105.         M[s][t]:=M[s][t]+T[2][i];
  2106.       od;
  2107.       if w then # weak discrimination possible ?
  2108.         gt:=Set(Filtered(orb.orbits,i->Length(i)>1));
  2109.         for i in gt do
  2110.           if i[1] in orb.identifees then
  2111.             # were these classes detected weak ?
  2112.             e:=M[i[1]][t];
  2113.             if e>0 then
  2114.               InfoCharTable2("\n#I  GaloisIdentification ",i,": ",e);
  2115.             fi;
  2116.             for j in i do
  2117.               M[j][t]:=e/Length(i);
  2118.             od;
  2119.           fi;
  2120.         od;
  2121.       fi;
  2122.     else # Small Group
  2123.       for i in [1..Length(T[1])] do
  2124.         s:=D.ClassElement(D,T[1][i] * z);
  2125.         M[s][t]:=M[s][t]+T[2][i];
  2126.       od;
  2127.     fi;
  2128.   fi;
  2129. end;
  2130.  
  2131.  
  2132. #############################################################################
  2133. ##
  2134. #F  IdentificationGenericGroup( <D>, <el> ) . .  class invariants for el in G
  2135. ##
  2136. IdentificationGenericGroup := function(D,el)
  2137.   return Order(D.group,el);
  2138. end;
  2139.  
  2140.  
  2141. #############################################################################
  2142. ##
  2143. #F  GroupOps.DxPreparation(<G>) . . .  specific initialisation for groups not
  2144. #F                                              fitting in any other category
  2145. ##
  2146. GroupOps.DxPreparation := function(G)
  2147.   local D,i,j;
  2148.   InfoCharTable1("#W Warning: Generic Group Routines can be very slow\n");
  2149.   D:=DixonRecord(G);
  2150.   D.identification:=IdentificationGenericGroup;
  2151.   D.rationalidentification:=IdentificationGenericGroup;
  2152.   D.ClassMatrixColumn:=StandardClassMatrixColumn;
  2153.  
  2154.   D.ids:=[];
  2155.   for i in [1..D.klanz] do
  2156.     D.ids[i]:=D.identification(D,D.conjugacyClasses[i].representative);
  2157.   od;
  2158.   D.rids:=D.ids;
  2159.  
  2160.   if IsLargeGroup(G) then
  2161.     D.ClassElement:=ClassElementLargeGroup;
  2162.   else
  2163.     D.ClassElement:=ClassElementSmallGroup;
  2164.     Enumeration(G);
  2165.     D.classMap:=List([1..Size(G)],i->D.klanz);
  2166.     for j in [1..D.klanz-1] do
  2167.       for i in Orbit(G,D.conjugacyClasses[j].representative) do
  2168.         D.classMap[G.enumeration.number(G,i)]:=j;
  2169.       od;
  2170.     od;
  2171.   fi;
  2172.  
  2173.   return D;
  2174.  
  2175. end;
  2176.  
  2177.  
  2178. #############################################################################
  2179. ##
  2180. ##  CharacterDegreePool(G)  . . possible character degrees, using thm. of Ito
  2181. ##
  2182. GroupOps.CharacterDegreePool := function(G)
  2183.   local d,k,r,s;
  2184.   r:=RootInt(Size(G));
  2185.   s:=Lcm(List(AbelianNormalSubgroups(G),i->Index(G,i)));
  2186.   k:=Length(ConjugacyClasses(G));
  2187.   return List(Filtered(DivisorsInt(s),i->i<=r),i->[i,k]);
  2188. end;
  2189.  
  2190. #############################################################################
  2191. ##
  2192. ##  AbelianNormalSubgroups(G) . . . . . list of all abelian normal subgroups
  2193. ##  These subgroups are used by CharacterDegreePool to apply Ito's theorem.
  2194. ##
  2195. AbelianNormalSubgroups := function(G)
  2196. local ant,aunt,tant,onk,uncl,e,n,r,s,i,j,k,o,f,l;
  2197.   ant:=[];
  2198.   for r in List(Sublist(ConjugacyClasses(G),[2..Length(G.conjugacyClasses)]),
  2199.                 Representative) do
  2200.     s:=r^Random(G);
  2201.     if Comm(r,s)=G.identity then
  2202.       n:=Subgroup(G,Set([r,s]));
  2203.       f:=true;
  2204.       j:=1;
  2205.       while f and j<=Length(n.generators) do
  2206.         i:=1;
  2207.         while f and i<=Length(G.generators) do
  2208.           e:=n.generators[j]^G.generators[i];
  2209.           if not e in n then
  2210.             n:=Closure(n,e);
  2211.             if not IsAbelian(n) then
  2212.               f:=false;
  2213.             fi;
  2214.           else
  2215.             i:=i+1;
  2216.           fi;
  2217.         od;
  2218.         j:=j+1;
  2219.       od;
  2220.       if f then
  2221.         AddSet(ant,n);
  2222.       fi;
  2223.     fi;
  2224.   od;
  2225.  
  2226.   aunt:=[];
  2227.   for tant in [1..2^Length(ant)-1] do
  2228.     e:=LogInt(tant,2);
  2229.     onk:=tant-2^e;
  2230.     e:=e+1;
  2231.     if onk=0 then
  2232.       aunt[tant]:=ant[e];
  2233.     elif IsBound(aunt[onk]) then
  2234.       uncl:=aunt[onk];
  2235.       f:=true;
  2236.       k:=1;
  2237.       while f and k<=Length(ant[e].generators) do
  2238.         l:=1;
  2239.         while f and l<=Length(uncl.generators) do
  2240.           if Comm(ant[e].generators[k],uncl.generators[l])<>G.identity
  2241.             then
  2242.               f:=false;
  2243.           fi;
  2244.           l:=l+1;
  2245.         od;
  2246.         k:=k+1;
  2247.       od;
  2248.       if f then
  2249.         n:=Closure(uncl,ant[e]);
  2250.         if not (n in aunt) then
  2251.           aunt[tant]:=n;
  2252.         fi;
  2253.       fi;
  2254.     fi;
  2255.   od;
  2256.  
  2257.   ant:=[];
  2258.   for i in aunt do
  2259.     Add(ant,i);
  2260.   od;
  2261.  
  2262.   return ant;
  2263. end;
  2264.  
  2265.  
  2266. #############################################################################
  2267. ##
  2268. #E  Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
  2269. ##
  2270. ##  Local Variables:
  2271. ##  mode:               outline
  2272. ##  outline-regexp:     "#A\\|#F\\|#V\\|#E\\|#R"
  2273. ##  tab-width:          2
  2274. ##  fill-column:        73
  2275. ##  fill-prefix:        "##  "
  2276. ##  eval:               (hide-body)
  2277. ##  End:
  2278. ##
  2279.  
  2280.  
  2281.  
  2282.