home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-05 | 70.7 KB | 2,353 lines |
- #############################################################################
- ##
- #A lattgrp.g GAP library J\"urgen Mnich
- ##
- #A @(#)$Id: lattgrp.g,v 3.10 1993/02/09 15:46:04 martin Rel $
- ##
- #Y Copyright 1990-1992, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
- ##
- ## This file contains the program for calculating the lattice of subgroups.
- ##
- #H $Log: lattgrp.g,v $
- #H Revision 3.10 1993/02/09 15:46:04 martin
- #H changed argument test in 'TableOfMarks'
- #H
- #H Revision 3.9 1993/02/09 14:25:55 martin
- #H made undefined globals local
- #H
- #H Revision 3.8 1993/01/20 17:40:03 felsch
- #H removed overlong lines
- #H
- #H Revision 3.7 1993/01/20 17:35:28 felsch
- #H moved 'TableOfMarks' to "tom.g", changed 'Lattice' to sort classes
- #H
- #H Revision 3.6 1992/12/16 19:47:27 martin
- #H replaced quoted record names with escaped ones
- #H
- #H Revision 3.5 1992/08/18 09:30:20 fceller
- #H added Juergen's lattice print functions
- #H
- #H Revision 3.4 1992/08/12 14:07:37 martin
- #H changed 'Representative' to 'RepresentativeOperation'
- #H
- #H Revision 3.3 1992/03/17 12:31:20 jmnich
- #H minor style changes, more bug fixes
- #H
- #H Revision 3.2 1992/02/29 13:25:11 jmnich
- #H general library review, some bug fixes
- #H
- #H Revision 3.1 1992/02/12 15:37:22 martin
- #H initial revision under RCS
- #H
- ##
-
-
- #############################################################################
- ##
- #F InfoLattice1(...) . . . . . . . . . . . . . . . . . . package information
- #F InfoLattice2(...) . . . . . . . . . . . . . . . package debug information
- ##
- if not IsBound( InfoLattice1 ) then InfoLattice1 := Ignore; fi;
- if not IsBound( InfoLattice2 ) then InfoLattice2 := Ignore; fi;
-
-
- LatticeBreak := false;
-
-
- #############################################################################
- ##
- #F Zuppos( <group> ) . . . . . . . . . . . . . . . . . . . . compute zuppos
- ##
- ## This function computes the zuppos of <group>.
- ##
- Zuppos := function( D )
- local zuppos;
-
- if IsDomain( D ) and IsBound( D.zuppos ) then
- zuppos := D.zuppos;
- elif IsDomain( D ) and IsParent( D )
- and IsBound( D.operations.SylowZuppos ) then
- D.zuppos := D.operations.SylowZuppos( D );
- zuppos := D.zuppos;
- elif IsDomain( D ) and IsBound( D.operations.Zuppos ) then
- D.zuppos := D.operations.Zuppos( D );
- zuppos := D.zuppos;
- else
- Error( "sorry, can't compute zuppos for domain" );
- fi;
- return zuppos;
- end;
-
-
- #############################################################################
- ##
- #F ZuppoBlist( <group> ) . . . . . . . . . . . . . . compute blist of zuppos
- ##
- ## This function computes the blist of zuppos of <group> relative to those
- ## of its parent group.
- ##
- ZuppoBlist := function( D )
- local zuppob;
-
- if IsDomain( D ) and IsBound( D.zuppoBlist ) then
- zuppob := D.zuppoBlist;
- elif IsDomain( D ) and IsBound( D.operations.ZuppoBlist ) then
- D.zuppoBlist := D.operations.ZuppoBlist( D );
- zuppob := D.zuppoBlist;
- else
- Error( "sorry, can't compute zuppo blist for domain" );
- fi;
- return zuppob;
- end;
-
-
- #############################################################################
- ##
- #F GeneratorZuppos( <group> ) . . . . . . . . compute zuppos for generators
- ##
- ## This function computes the zuppos for the generators of <group>.
- ##
- GeneratorZuppos := function( D )
- local zuppos;
-
- if IsDomain( D ) and IsBound( D.generatorZuppos ) then
- zuppos := D.generatorZuppos;
- elif IsDomain( D ) and IsBound( D.operations.GeneratorZuppos ) then
- D.generatorZuppos := D.operations.GeneratorZuppos( D );
- zuppos := D.generatorZuppos;
- else
- Error( "sorry, can't compute generator zuppos for domain" );
- fi;
- return zuppos;
- end;
-
-
- #############################################################################
- ##
- #F GeneratorZuppoBlist( <group> ) . compute blist of zuppos for generators
- ##
- ## This function computes the blist of zuppos for the generators of <group>
- ## relative to those of its parent group.
- ##
- GeneratorZuppoBlist := function( D )
- local zuppob;
-
- if IsDomain( D ) and IsBound( D.generatorZuppoBlist ) then
- zuppob := D.generatorZuppoBlist;
- elif IsDomain( D ) and IsBound( D.operations.GeneratorZuppoBlist ) then
- D.generatorZuppoBlist := D.operations.GeneratorZuppoBlist( D );
- zuppob := D.generatorZuppoBlist;
- else
- Error( "sorry, can't compute generator zuppo blist for domain" );
- fi;
- return zuppob;
- end;
-
-
- #############################################################################
- ##
- #F ConjugateZuppos( <group>, <subgroup>, <conjugand> ) . . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . . . . . . . . . compute conjugate zuppos
- ##
- ##
- ##
- ConjugateZuppos := function( H, g )
- local zuppos;
-
- if IsDomain( H ) and IsBound( H.operations.ConjugateZuppos ) then
- zuppos := H.operations.ConjugateZuppos( H, g );
- else
- Error( "sorry, can't compute conjugate zuppos for domain" );
- fi;
- return zuppos;
- end;
-
-
- #############################################################################
- ##
- #F ConjugateZuppoBlist( <group>, <conjugand> ) . . . . . . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . . . . . compute blist of conjugate zuppos
- ##
- ##
- ##
- ConjugateZuppoBlist := function( H, g )
- local zuppob;
-
- if IsDomain( H ) and IsBound( H.operations.ConjugateZuppos ) then
- zuppob := H.operations.ConjugateZuppoBlist( H, g );
- else
- Error( "sorry, can't compute conjugate zuppos for domain" );
- fi;
- return zuppob;
- end;
-
-
- #############################################################################
- ##
- #F SetLatticeStatus( <lattice>, <subgroup>, <status> ) . . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . . . . . . . set a lattice subgroup status
- ##
- ##
- ##
- SetLatticeStatus := function( L, H, status )
-
- if IsDomain( H ) and IsBound( H.operations.SetLatticeStatus ) then
- return H.operations.SetLatticeStatus( L, H, status );
- elif IsConjugacyClassSubgroups( H )
- and IsBound( H.representative.operations.SetLatticeStatus ) then
- return H.representative.operations.SetLatticeStatus( L, H, status );
- else
- Error( "sorry, can't set lattice status for group or class" );
- fi;
- end;
-
-
- #############################################################################
- ##
- #F IsLattice( <object> ) . . . . . . . . . . . test if a record is a lattice
- ##
- IsLattice := x -> IsRec( x ) and IsBound( x.isLattice ) and x.isLattice;
-
-
- #############################################################################
- ##
- #F IsSubgroupLattice( <object> ) . . test if a record is a subgroup lattice
- ##
- IsSubgroupLattice := x -> IsRec( x ) and IsBound( x.isSubgroupLattice )
- and x.isSubgroupLattice;
-
-
- #############################################################################
- ##
- #F Lattice( <domain> ) . . . . . . . . . . . . . . . . . lattice of a domain
- ##
- Lattice := function( obj )
- local lattice;
-
- if IsRec( obj ) and IsBound( obj.lattice ) then
- lattice := obj.lattice;
- elif IsRec( obj ) and IsBound( obj.operations )
- and IsBound( obj.operations.Lattice ) then
- obj.lattice := obj.operations.Lattice( obj );
- lattice := obj.lattice;
- else
- Error( "sorry, can't compute a lattice for <domain>" );
- fi;
- return lattice;
- end;
-
-
- #############################################################################
- ##
- #F StopLattice() . . . . . . . . . . . . . . terminate a lattice calculation
- ##
- StopLattice := function()
- LatticeBreak := true;
- end;
-
-
- #############################################################################
- ##
- #F ClearLatticeQueue( <domain> ) . . . . . . . . . clear queue of a lattice
- ##
- ClearLatticeQueue := function( obj )
-
- if IsRec( obj ) and IsBound( obj.operations )
- and IsBound( obj.operations.ClearLatticeQueue ) then
- obj.operations.ClearLatticeQueue( obj );
- else
- Error( "sorry, can't clear lattice queue for <domain>" );
- fi;
- end;
-
-
- #############################################################################
- ##
- #F RightTransversal( <G>, <H> ) . . . . . . . determine a right transversal
- ##
- ## returns
- ##
- ## <list>
- ##
- RightTransversal := function( G, H )
- local rt;
-
- if IsBound( H.rightTransversal ) and IsParent( G ) then
- rt := H.rightTransversal;
- elif IsDomain( G ) and IsBound( G.operations.RightTransversal ) then
- rt := G.operations.RightTransversal( G, H );
- if IsBound( G.elements ) then
- rt := ListBlist( G.elements, BlistList( G.elements, rt ) );
- fi;
- if IsParent( G ) then
- H.rightTransversal := rt;
- fi;
- fi;
- return rt;
- end;
-
-
- #############################################################################
- ##
- #F PerfectSubgroups( <group> ) . . . . . . . determine all perfect subgroups
- ##
- ## returns
- ##
- ## <list>
- ##
- PerfectSubgroups := function( obj )
- local pg;
-
- if IsDomain( obj ) and IsBound( obj.perfectSubgroups ) then
- pg := obj.perfectSubgroups;
- elif IsDomain( obj ) and IsBound( obj.operations.PerfectSubgroups ) then
- obj.perfectSubgroups := obj.operations.PerfectSubgroups( obj );
- pg := obj.perfectSubgroups;
- else
- Error( "sorry, can't compute perfect subgroups for <domain>" );
- fi;
- return pg;
- end;
-
-
- #############################################################################
- ##
- #F IsConjugacyClassSubgroups( <C> ) . . . . . . . . . . . . . . . . . . . .
- #F . . . . . . . test if an object is a conjugacy class of subgroups record
- ##
- IsConjugacyClassSubgroups := function ( C )
- return IsRec( C )
- and IsBound( C.isConjugacyClassSubgroups )
- and C.isConjugacyClassSubgroups;
- end;
-
-
- #############################################################################
- ##
- #F ConjugacyClassSubgroups(<G>,<H>) . . . . . . . . . . . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . . conjugacy class of subgroups in a group
- ##
- ConjugacyClassSubgroups := function ( G, H )
- if not IsSubgroup( G, H ) then
- Error( "sorry, <H> must be a subgroup of <G>" );
- fi;
- if IsDomain( G ) and IsBound( G.operations.ConjugacyClassSubgroups ) then
- return G.operations.ConjugacyClassSubgroups( G, H );
- else
- Error( "sorry, can't create conjugacy class of subgroups for <G>" );
- fi;
- end;
-
-
- #############################################################################
- ##
- #F ConjugacyClassesSubgroups( <G> ) . . . . . . . . . . . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . conjugacy classes of subgroups of a group
- ##
- ConjugacyClassesSubgroups := function ( G )
- local cc;
-
- if IsDomain( G ) and IsBound( G.conjugacyClassesSubgroups ) then
- cc := G.conjugacyClassesSubgroups;
- elif IsDomain( G ) and IsBound( G.operations.ConjugacyClassesSubgroups )
- then
- G.conjugacyClassesSubgroups :=
- G.operations.ConjugacyClassesSubgroups( G );
- cc := G.conjugacyClassesSubgroups;
- else
- Error(
- "sorry, can't compute a conjugacy classes of subgroups for <domain>"
- );
- fi;
- return cc;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.Zuppos( <group> ) . . . . . . . . . . . . . . . compute zuppos
- ##
- ## This function handles the general case for zuppo calculation.
- ## The calculation of the zuppos for a parent group differs from that for a
- ## subgroup as some more data is to be allocated for parent groups in order
- ## to ensure efficient work with zuppos.
- ## This data consists of the list of zuppo-generators (zuppos), for each
- ## element of the group the canonical zuppo-generator (zuppo_generator), for
- ## each zuppo-generator the zuppo-generator of its prime-power (zuppo_power)
- ## and for each zuppo-generator the corresponding prime (zuppo_prime) and
- ## exponent (zuppo_exponent).
- ## Additionally the function itself will bound all the data to the record.
- ##
- GroupOps.Zuppos := function( group )
- local zuppos, zuppo_gens, zuppo_powers, zuppo_primes, zuppo_exponents,
- nz, zg, elems, pos, cyc, g, known, order, forder, sorder,
- good, bad, x, p, parent;
-
- if IsParent( group ) then
-
- # initialize the calculated data
-
- nz := 0;
- zuppos := [];
- zuppo_gens := [ false ];
- zuppo_powers := [];
- zuppo_primes := [];
- zuppo_exponents := [];
-
- # remember good and bad orders
-
- good := [];
- bad := [];
-
- # sorry, but we will loop over all elements
-
- elems := Elements( group );
- known := BlistList( elems, [ group.identity ] );
- pos := Position( known, false );
- while pos <> false do
-
- # determine the next cyclic subgroup
-
- cyc := [ group.identity ];
- g := elems[pos];
- order := 1;
- while g <> group.identity do
- order := order + 1;
- cyc[order] := g;
- g := g * elems[pos];
- od;
-
- # check whether it yields a zuppo
-
- forder := Factors( order );
- sorder := Set( forder );
-
- if not (order in good or order in bad) then
- if Length( sorder ) = 1 then
- AddSet( good, order );
- else
- AddSet( bad, order );
- fi;
- fi;
-
- if order in good then
-
- # we have found a new zuppo.
- # now behave like this: the actual generator will be our
- # new zuppo-generator. this will ensure that the resulting
- # zuppo-list is in fact a set. all other zuppo-generators
- # in 'cyclic' are marked as known. this is done below.
- # remember to take elements from 'elems' to save memory.
- # we do not need to do that for 'zuppo_power' here, this
- # list is rewritten at the end of the function.
-
- nz := nz + 1;
- zg := nz;
- zuppos[nz] := elems[pos];
- zuppo_primes[nz] := forder[1];
- zuppo_exponents[nz] := Length( forder );
- if zuppo_exponents[nz] = 1 then
- zuppo_powers[nz] := false;
- else
- zuppo_powers[nz] := Position(
- elems, cyc[zuppo_primes[nz]+1] );
- fi;
-
- else
- zg := false;
- fi;
-
- # mark all generators of the cyclic group as known and put
- # the canonical generator in zuppo_gen.
- # remark: this is also done for non-zuppos (who cares ?)
-
- for p in sorder do
- for x in [0..order/p-1] do
- Unbind( cyc[x*p+1] );
- od;
- od;
- for x in cyc do
- p := Position( elems, x );
- zuppo_gens[p] := zg;
- known[p] := true;
- od;
-
- pos := Position( known, false, pos );
- od;
-
- # now convert 'zuppos' to a set
-
- if not IsSet( zuppos ) then
- Error( "fatal error, zuppo list is no set" );
- fi;
-
- # correct the values in zuppo_powers to contain 'zuppos' elements
-
- for x in [1..nz] do
- if zuppo_powers[x] <> false then
- zuppo_powers[x] := zuppo_gens[zuppo_powers[x]];
- fi;
- od;
-
- group.zuppos := zuppos;
- group.zuppo_generators := zuppo_gens;
- group.zuppo_powers := zuppo_powers;
- group.zuppo_primes := zuppo_primes;
- group.zuppo_exponents := zuppo_exponents;
-
- else
-
- parent := Parent( group );
- zuppos := ListBlist( Zuppos( parent ),
- BlistList( Zuppos( parent ), Elements( group ) ) );
-
- fi;
- return zuppos;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.ZuppoBlist( <group> ) . . . . . . . . . compute blist of zuppos
- ##
- ## This functions computes the zuppos of a group represented as a blist on
- ## the zuppos of the parent group.
- ##
- GroupOps.ZuppoBlist := function( group )
- local zuppob, rng;
-
- if IsParent( group ) then
- rng := [1 .. Length( Zuppos( group ) )];
- zuppob := BlistList( rng, rng );
- else
- zuppob := BlistList( Zuppos( Parent( group ) ), Elements( group ) );
- fi;
-
- return zuppob;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.GeneratorZuppos . . . . . . . . determine zuppos for generators
- ##
- GroupOps.GeneratorZuppos := function( H )
- local g, facord, prm, coprm, p, gzup, zuppos, parent;
-
- parent := Parent( H );
- zuppos := Zuppos( parent );
- gzup := [];
- for g in H.generators do
- facord := Factors( Order( H, g ) );
- for prm in Set( facord ) do
- coprm := 1;
- for p in facord do if p <> prm then coprm := coprm * p; fi; od;
- Add( gzup, zuppos[parent.zuppo_generators[Position(
- parent.elements, g ^ coprm )]] );
- od;
- od;
- return gzup;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.GeneratorZuppoBlist . . . . determine zuppoblist for generators
- ##
- GroupOps.GeneratorZuppoBlist := function( H )
- local g, facord, prm, coprm, p, gzup, zuppos, parent;
-
- parent := Parent( H );
- zuppos := Zuppos( parent );
- gzup := BlistList( zuppos, [] );
- for g in H.generators do
- facord := Factors( Order( H, g ) );
- for prm in Set( facord ) do
- coprm := 1;
- for p in facord do if p <> prm then coprm := coprm * p; fi; od;
- gzup[parent.zuppo_generators[Position(
- parent.elements, g ^ coprm )]] := true;
- od;
- od;
- return gzup;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.ConjugateZuppos( <group>, <conjugand> ) . . . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . . . . . compute blist of conjugate zuppos
- ##
- ##
- ##
- GroupOps.ConjugateZuppos := function( H, g )
- local zuppos, zuppop, parent, x, i;
-
- parent := Parent( H );
- zuppop := Zuppos( parent );
- zuppos := ShallowCopy( Zuppos( H ) );
- for i in [1..Length( zuppos )] do
- x := zuppos[i];
- x := parent.zuppo_generators[Position( parent.elements, x ^ g )];
- zuppos[i] := zuppop[x];
- od;
-
- return Set( zuppos );
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.ConjugateZuppoBlist( <group>, <conjugand> ) . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . . . . . compute blist of conjugate zuppos
- ##
- ##
- ##
- GroupOps.ConjugateZuppoBlist := function( H, g )
- local zuppob, zuppop, parent, x;
-
- parent := Parent( H );
- zuppop := Zuppos( parent );
- zuppob := BlistList( [1..Length( zuppop )], [] );
- for x in Zuppos( H ) do
- x := parent.zuppo_generators[Position( parent.elements, x ^ g )];
- zuppob[x] := true;
- od;
-
- return zuppob;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.SetLatticeStatus( <L>, <object>, <status> ) . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . . . . . . . set status of lattice objects
- ##
- ## returns
- ##
- ## [ <class>, <conjugand>, <isnew> ]
- ##
- ##
- GroupOps.SetLatticeStatus := function( L, H, status )
- local G, CH, N, CN, C, CC, T, equals, qequals, subs, sups,
- hzup, czup, gzup, isnew, issup, size, nelem, pos, t, i, x;
-
-
- G := L.group;
-
- # the first step is to convert H to a conjugacy class of subgroups
- # if it is a group.
-
- if IsGroup( H ) then
-
- # determine its layer
-
- CH := ConjugacyClassSubgroups( G, H );
- size := Size( H );
-
- if size = 1 then CH.layer := 0;
- else CH.layer := Length( Factors( size ) );
- fi;
-
- CH.status := "0 new";
-
- else
-
- CH := H;
- H := CH.representative;
- size := Size( H );
-
- if not IsBound( CH.status ) then
- if size = 1 then CH.layer := 0;
- else CH.layer := Length( Factors( size ) );
- fi;
-
- CH.status := "0 new";
- fi;
-
- fi;
-
- InfoLattice2( "#I setstatus ", H, ", size ", size, " to ", status,
- "in layer ", CH.layer, "\n" );
-
- # if the status of the class is higher than the requested one,
- # return it itself.
-
- if CH.status >= status then
- return [ CH, G.identity, false ];
- fi;
-
- # find list of possibly equal classes
-
- if IsBound( CH.equalClasses ) then
-
- # this has been done already
-
- equals := CH.equalClasses;
-
- elif CH.status >= "2 class" then
-
- # there is no need to test for equality if the class has already
- # been added to the lattice.
-
- equals := [];
-
- else
-
- # o.k. now, go through the list of classes and have a look.
-
- gzup := GeneratorZuppoBlist( H );
- equals := [];
- for CC in L.classes do
- C := CC.representative;
- if C.size = size then
- if IsSubsetBlist( ZuppoBlist( C ), gzup ) then
-
- # we were able to identify the representative
-
- L.statistics.equalGroups := L.statistics.equalGroups + 1;
- if IsBound( CH.normalsubgroups ) then
- for x in CH.normalsubgroups do
- x.normalizerLattice := [ CC, G.identity ];
- od;
- fi;
- InfoLattice2( "#I ...found in lattice\n" );
- return [ CC, G.identity, false ];
-
- else
- Add( equals, CC );
- fi;
- fi;
- od;
- fi;
-
- # now go on and improve the objects status one by one.
- # first: shall we add the group to the queue ?
-
- if status = "1 group" then
-
- # make sure H is not already in the queue
-
- gzup := GeneratorZuppoBlist( H );
-
- for i in [1..Length( L.queue )] do
- if IsBound( L.queue[i] ) then
- CC := L.queue[i];
- C := CC.representative;
- if C.size = size then
- if IsSubsetBlist( ZuppoBlist( C ), gzup ) then
-
- # oh, yes. there is a queue group equal to ours.
-
- L.statistics.equalGroups :=
- L.statistics.equalGroups + 1;
- if IsBound( CH.normalsubgroups ) then
- if not IsBound( CC.normalsubgroups ) then
- CC.normalsubgroups := [];
- fi;
- for x in CH.normalsubgroups do
- x.normalizerLattice := [ CC, G.identity ];
- Add( CC.normalsubgroups, x );
- od;
- fi;
- InfoLattice2( "#I ...found in queue\n" );
- return [ CC, G.identity, false ];
-
- fi;
- fi;
- fi;
- od;
-
- InfoLattice1( "#I ...added to queue\n" );
-
- CH.status := "1 group";
- CH.equalClasses := equals;
-
- Add( L.queue, CH );
-
- return [ CH, G.identity, false ];
- fi;
-
- # the class will have higher status than being a queue group so
- # remove the list of possibly equal classes.
-
- Unbind( CH.equalClasses );
-
- # second: shall we add the group to the lattice ?
-
- if CH.status < "2 class" and status >= "2 class" then
-
- # if we have to create the class we need the normalizer of H
- # and its (right) transversal in G.
-
- InfoLattice2( "#I calculating normalizer of H\n" );
-
- N := G.operations.Normalizer( G, H );
- CN := ConjugacyClassSubgroups( G, N );
- T := G.operations.RightTransversal( G, N );
-
- L.statistics.normalizers := L.statistics.normalizers + 1;
-
- CN.normalsubgroups := [ CH ];
- CH.normalizerLattice := [ CN, G.identity ];
- CH.conjugands := T;
- CH.size := Length( T );
-
- if Size( N ) <> size then
-
- InfoLattice2( "#I handling normalizer\n" );
-
- isnew := SetLatticeStatus( L, CN, L.calculatedGroups );
- CH.normalizerLattice := [ isnew[1], isnew[2] ];
- isnew := isnew[3];
-
- else
-
- InfoLattice2( "#I group is selfnormal -- no handling\n" );
-
- CH.normalizerLattice := [ CH, G.identity ];
- isnew := false;
-
- fi;
-
- # if H's normalizer wasn't known before, H itself must be new.
-
- if isnew then
- equals := [];
- fi;
-
- # we continue with the determination of possible subgroups...
-
- subs := [];
- for CC in L.classes do
- C := CC.representative;
- if CC.layer = CH.layer - 1 and CC.status = "3 extending"
- and size mod C.size = 0 then
- Add( subs, CC );
- fi;
- od;
-
- # ... and the possibly equal queue groups
-
- gzup := GeneratorZuppoBlist( H );
- qequals := [];
- for i in [1..Length( L.queue )] do
- if IsBound( L.queue[i] ) then
- CC := L.queue[i];
- C := CC.representative;
- if C.size = size then
- if IsSubsetBlist( ZuppoBlist( C ), gzup ) then
-
- # oh, there is a group in the queue equal to ours.
-
- L.statistics.equalGroups :=
- L.statistics.equalGroups + 1;
- if IsBound( CC.normalsubgroups ) then
- if not IsBound( CH.normalsubgroups ) then
- CH.normalsubgroups := [];
- fi;
- for x in CC.normalsubgroups do
- x.normalizerLattice := [ CH, G.identity ];
- Add( CH.normalsubgroups, x );
- od;
- fi;
- InfoLattice2( "#I ...found in queue\n" );
- Unbind( L.queue[i] );
-
- else
- Add( qequals, i );
- fi;
- fi;
- fi;
- od;
-
- # is there anything to do with the conjugates so far ?
-
- if equals = [] and qequals = [] and subs = [] then
- T := [];
- fi;
-
- # generate each conjugate, i.e. its zuppos one after the other,
- # performing all necessary actions with each zuppo blist right
- # here.
-
- InfoLattice2( "#I conjugating H\n" );
-
- for t in T do
-
- czup := H.operations.ConjugateZuppoBlist( H, t );
- L.statistics.conjugateZuppos := L.statistics.conjugateZuppos + 1;
-
- # first check whether this conjugate is the representative of a
- # known class of subgroups
-
- for CC in equals do
- C := CC.representative;
- if ZuppoBlist( C ) = czup then
-
- # in fact there is a class that contains the conjugate
-
- L.statistics.equalGroups := L.statistics.equalGroups + 1;
- if IsBound( CH.normalsubgroups ) then
- for x in CH.normalsubgroups do
- x.normalizerLattice :=
- [ CC, t^-1 * x.normalizerLattice[2] ];
- od;
- fi;
- InfoLattice2( "#I ...found in lattice\n" );
- return [ CC, t^-1, false ];
-
- fi;
- od;
-
- # next check whether this group is a member of the queue
-
- for i in qequals do
- if IsBound( L.queue[i] ) then
- CC := L.queue[i];
- C := CC.representative;
- if ZuppoBlist( C ) = czup then
-
- # bingo, we found a group in the queue equal to the
- # conjugate of H.
-
- L.statistics.equalGroups :=
- L.statistics.equalGroups + 1;
- if IsBound( CC.normalsubgroups ) then
- if not IsBound( CH.normalsubgroups ) then
- CH.normalsubgroups := [];
- fi;
- for x in CC.normalsubgroups do
- x.normalizerLattice := [ CH, t ];
- Add( CH.normalsubgroups, x );
- od;
- fi;
- InfoLattice2( "#I identified queue group\n" );
- Unbind( L.queue[i] );
-
- fi;
- fi;
- od;
-
- # next reduce the extendingZuppos blists of those classes that
- # are yet to be extended and whose representative may be a
- # subgroup of this conjugate.
-
- for CC in subs do
- C := CC.representative;
- if IsSubsetBlist( czup, ZuppoBlist( C ) ) then
- InfoLattice2( "#I found a subgroup\n" );
- SubtractBlist( CC.extendingZuppos, czup );
- fi;
- od;
- od;
-
- # the group survived this step, so it is new
-
- CH.status := "2 class";
-
- Unbind( CH.normalsubgroups );
- Add( L.classes, CH );
-
- InfoLattice1( "#I Class of size ", size, " and length ", CH.size,
- " added\n" );
- fi;
-
- # third: shall the extendingZuppos blist of the class be created ?
-
- if CH.status < "3 extending" and status >= "3 extending"
- and not LatticeBreak then
-
- # initialize the extendingZuppos blist
-
- CH.extendingZuppos := ShallowCopy( CH.normalizerLattice[1].
- representative.operations.ConjugateZuppoBlist(
- CH.normalizerLattice[1].representative,
- CH.normalizerLattice[2]
- )
- );
- SubtractBlist( CH.extendingZuppos, ZuppoBlist( H ) );
- L.statistics.conjugateZuppos := L.statistics.conjugateZuppos + 1;
-
- # change it to reflect the proper list of extending zuppos.
-
- gzup := GeneratorZuppos( H );
-
- for CC in L.classes do
- C := CC.representative;
- if CC.layer = CH.layer + 1 and C.size mod size = 0 then
- T := CC.conjugands;
- czup := ZuppoBlist( C );
- for t in T do
- issup := true;
- i := Length( gzup );
- x := t ^ -1;
- while issup and i > 0 do
- issup := czup[G.zuppo_generators[Position(
- G.elements, gzup[i]^x )]];
- i := i - 1;
- od;
- if issup then
- InfoLattice2( "#I supergroup found\n" );
- SubtractBlist( CH.extendingZuppos,
- C.operations.ConjugateZuppoBlist( C, t ) );
- L.statistics.conjugateZuppos :=
- L.statistics.conjugateZuppos + 1;
- fi;
- od;
- fi;
- od;
-
- CH.status := "3 extending";
- fi;
-
- # fourth: shall we calculate all cyclic extensions of H ?
-
- if CH.status < "4 extended" and status >= "4 extended"
- and not LatticeBreak then
-
- InfoLattice2( "#I calculating extensions of H\n" );
-
- hzup := ZuppoBlist( H );
- pos := Position( CH.extendingZuppos, true );
-
- while pos <> false and not LatticeBreak do
-
- # is the zuppo generator of prime index over H ?
-
- if G.zuppo_powers[pos] = false or hzup[G.zuppo_powers[pos]] then
-
- # put everything we know into N
-
- N := G.operations.Subgroup( G, Concatenation( H.generators,
- [ G.zuppos[pos] ] ) );
- CN := ConjugacyClassSubgroups( G, N );
-
- CN.equalClasses := [];
-
- # finally, add it to the lattice
-
- SetLatticeStatus( L, CN, L.extensionGroups );
- L.statistics.extensions := L.statistics.extensions + 1;
- fi;
-
- CH.extendingZuppos[pos] := false;
- pos := Position( CH.extendingZuppos, true, pos );
- od;
-
- if not LatticeBreak then
-
- # cleanup H
-
- CH.status := "4 extended";
- Unbind( CH.extendingZuppos );
- Unbind( H.generatorZuppos );
- Unbind( H.generatorZuppoBlist );
-
- if not IsParent( H ) then
- Unbind( H.elements );
- Unbind( H.zuppos );
- fi;
-
- InfoLattice2( "#I extensions of H done\n" );
- fi;
- fi;
-
- return [ CH, G.identity, true ];
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.Lattice( <group> ) . . . . . . . . . . compute subgroup lattice
- ##
- ## This function determines the lattice of subgroups.
- ##
- GroupOps.Lattice := function( group )
- local L, C, layers, p, g, cp, qp, i, j;
-
- if IsGroup( group ) then
- L := rec(
- group := group,
- classes := [],
- queue := [],
-
- externalGroups := "1 group",
- calculatedGroups := "1 group",
- extensionGroups := "2 class",
- queueGroups := "3 extending",
- classGroups := "4 extended",
-
- #T method := "b-t",
- method := "l-r",
-
- statistics := rec(
- normalizers := 0,
- conjugateZuppos := 0,
- extensions := 0,
- queueGroups := 0,
- classGroups := 0,
- equalGroups := 0
- ),
-
- isLattice := true,
- isSubgroupLattice := true,
-
- operations := SubgroupLatticeOps
- );
-
- # make sure that the zuppos are known
-
- Zuppos( group );
- else
- L := group;
- group := L.group;
- fi;
-
- # if the lattice is empty, add the perfect groups, the identity
- # and the group itself.
-
- if L.classes = [] and L.queue = [] then
- SetLatticeStatus( L, TrivialSubgroup( group ), L.externalGroups );
- SetLatticeStatus( L, group, L.externalGroups );
- for p in PerfectSubgroups( group ) do
- SetLatticeStatus( L, p, L.externalGroups );
- od;
- fi;
-
- if L.method = "b-t" then
-
- # the first method is to extend every class, and insert every
- # group in chronological order
- qp := 1;
- cp := 1;
-
- while (qp <= Length( L.queue ) or cp <= Length( L.classes ))
- and not LatticeBreak do
-
- while qp <= Length( L.queue ) and not LatticeBreak do
- if IsBound( L.queue[qp] ) then
- C := L.queue[qp];
- Unbind( L.queue[qp] );
- SetLatticeStatus( L, C, L.queueGroups );
- fi;
- qp := qp + 1;
- od;
- qp := Length( L.queue ) + 1;
-
- while cp <= Length( L.classes ) and not LatticeBreak do
- C := L.classes[cp];
- SetLatticeStatus( L, C, L.classGroups );
- cp := cp + 1;
- od;
-
- od;
-
- elif L.method = "l-r" then
-
- # the second method is to extend classes and handle groups
- # layerwise.
-
- layers := Length( Factors( Size( group ) ) );
-
- for i in [0..layers] do
-
- # first set all classes to the layer below to "3 extending"
-
- if i > 0 then
- for C in L.classes do
- if LatticeBreak then return L; fi;
- if C.layer = i-1 then
- SetLatticeStatus( L, C, "3 extending" );
- fi;
- od;
- fi;
-
- # now insert all groups in the queue belonging to the
- # current layer
-
- for j in [1..Length( L.queue )] do
- if LatticeBreak then return L; fi;
- if IsBound( L.queue[j] ) then
- C := L.queue[j];
- if C.layer = i then
- Unbind( L.queue[j] );
- SetLatticeStatus( L, C, L.queueGroups );
- fi;
- fi;
- od;
-
- # extend all classes in the layer below
-
- if i > 0 then
- for C in L.classes do
- if LatticeBreak then return L; fi;
- if C.layer = i-1 then
- SetLatticeStatus( L, C, L.classGroups );
- fi;
- od;
- fi;
- od;
-
- fi;
-
- # sort the conjugacy classes by increasing subgroup orders.
- Sort( L.classes,
- function( x, y )
- return x.representative.size < y.representative.size;
- end );
-
- return L;
-
- LatticeBreak := false;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.ConjugacyClassSubgroups(<G>,<H>) . . . . . . . . . . . . . . . .
- ##
- GroupOps.ConjugacyClassSubgroups := function ( G, H )
- local C;
-
- # make the domain
- C := rec( );
- C.isDomain := true;
- C.isConjugacyClassSubgroups := true;
-
- # enter the identifying information
- C.group := G;
- C.representative := H;
-
- # enter the operations record
- C.operations := ConjugacyClassSubgroupsGroupOps;
-
- # return the conjugacy class
- return C;
-
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.ConjugacyClassesSubgroups( <G> ) . . . . . . . . . . . . . . . .
- ##
- GroupOps.ConjugacyClassesSubgroups := function ( G )
- return Lattice( G ).classes;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.TableOfMarks( <group>[, <classes>]
- #F [, "full"|"upper"][, "unweighted"][, "compressed"] )
- ##
- ## returns
- ##
- ## <matrix>
- ##
- ## or
- ##
- ## <compressed matrix>
- ##
- ##
- ## may be it should better be
- ##
- ## rec(
- ## group := <group>,
- ## matrix := <matrix> or <compressed matrix>,
- ## classes := <list>,
- ## modes := <list>
- ## )
- ##
- GroupOps.TableOfMarks := function( arg )
- local usage, group, classes, reps, dim, m, count, zuppos, left, right,
- lreps, rreps, vargs, t, i, j;
-
- usage := ConcatenationString(
- "usage: TableOfMarks( <group>[, <classes>]",
- "[, \"full\"|\"upper\"][, \"unweighted\"][, \"compressed\"] )"
- );
-
- vargs := [ "full", "upper", "unweighted", "compressed" ];
-
- if Length( arg ) = 0 then Error( usage ); fi;
- group := arg[1];
-
- if Length( arg ) = 1 then
- classes := ShallowCopy( ConjugacyClassesSubgroups( group ) );
-
- # ensure that the classes are sorted by increasing subgroup
- # orders.
- for i in [ 2 .. Length( classes ) ] do
- if classes[i].representative.size <
- classes[i-1].representative.size then
- Error( "classes of subgroups are not sorted" );
- fi;
- od;
- #T Sort( classes,
- #T function( x, y )
- #T return x.representative.size < y.representative.size;
- #T end );
-
- elif IsList( arg[2] ) and not IsString( arg[2] ) then
- if not IsSubset( vargs, Sublist( arg, [3..Length( arg )] ) ) then
- Error( "sorry, unkown argument options" );
- fi;
-
- classes := arg[2];
- else
- if not IsSubset( vargs, Sublist( arg, [2..Length( arg )] ) ) then
- Error( "sorry, unkown argument options" );
- fi;
-
- classes := ShallowCopy( ConjugacyClassesSubgroups( group ) );
-
- # ensure that the classes are sorted by increasing subgroup
- # orders.
- for i in [ 2 .. Length( classes ) ] do
- if classes[i].representative.size <
- classes[i-1].representative.size then
- Error( "classes of subgroups are not sorted" );
- fi;
- od;
- #T Sort( classes,
- #T function( x, y )
- #T return x.representative.size < y.representative.size;
- #T end );
-
- fi;
-
- reps := List( classes, x -> x.representative );
- dim := Length( classes );
- left := "full" in arg or not "upper" in arg;
- right := "full" in arg or "upper" in arg;
-
- if "compressed" in arg then
- m := [ List( classes, x -> [] ), List( classes, x -> [] ) ];
- if "unweighted" in arg then
- for i in [1..dim] do
- Add( m[1][i], i );
- Add( m[2][i], 1 );
- od;
- else
- for i in [1..dim] do
- Add( m[1][i], i );
- Add( m[2][i], classes[i].normalizerLattice[1].
- representative.size / reps[i].size );
- od;
- fi;
- for i in [1..dim] do
- if reps[i].size = 1 and right then
- for j in [i+1..dim] do
- Add( m[1][i], j );
- Add( m[2][i], m[2][i][1] );
- od;
- elif reps[i].size = Size( group ) and left then
- for j in [1..i-1] do
- Add( m[1][i], j );
- Add( m[2][i], m[2][i][1] );
- od;
- else
- lreps := [];
- rreps := [];
- count := List( classes, x -> 0 );
- if left then
- for j in [1..i-1] do
- if reps[i].size mod reps[j].size = 0 then
- Add( lreps, j );
- fi;
- od;
- fi;
- if right then
- for j in [i+1..dim] do
- if reps[j].size mod reps[i].size = 0 then
- Add( rreps, j );
- fi;
- od;
- fi;
-
- for t in classes[i].conjugands do
- if t = group.identity then
- zuppos := ZuppoBlist( reps[i] );
- else
- zuppos := ConjugateZuppoBlist( reps[i], t );
- fi;
-
- for j in lreps do
- if IsSubsetBlist( zuppos, reps[j].zuppoBlist ) then
- count[j] := count[j] + 1;
- fi;
- od;
- for j in rreps do
- if IsSubsetBlist( reps[j].zuppoBlist, zuppos ) then
- count[j] := count[j] + 1;
- fi;
- od;
- od;
-
- for j in lreps do
- if count[j] <> 0 then
- Add( m[1][i], j );
- Add( m[2][i], count[j] * m[2][i][1] );
- fi;
- od;
- for j in rreps do
- if count[j] <> 0 then
- Add( m[1][i], j );
- Add( m[2][i], count[j] * m[2][i][1] );
- fi;
- od;
- fi;
- od;
- else
- m := List( classes, x -> List( classes, x -> 0 ) );
- if "unweighted" in arg then
- for i in [1..dim] do
- m[i][i] := 1;
- od;
- else
- for i in [1..dim] do
- m[i][i] := classes[i].normalizerLattice[1].representative.size
- / reps[i].size;
- od;
- fi;
- for i in [1..dim] do
- if reps[i].size = 1 and right then
- for j in [i+1..dim] do m[i][j] := m[i][i]; od;
- elif reps[i].size = Size( group ) and left then
- for j in [1..i-1] do m[i][j] := m[i][i]; od;
- else
- lreps := [];
- rreps := [];
- if left then
- for j in [1..i-1] do
- if reps[i].size mod reps[j].size = 0 then
- Add( lreps, j );
- fi;
- od;
- fi;
- if right then
- for j in [i+1..dim] do
- if reps[j].size mod reps[i].size = 0 then
- Add( rreps, j );
- fi;
- od;
- fi;
-
- for t in classes[i].conjugands do
- if t = group.identity then
- zuppos := ZuppoBlist( reps[i] );
- else
- zuppos := ConjugateZuppoBlist( reps[i], t );
- fi;
-
- for j in lreps do
- if IsSubsetBlist( zuppos, reps[j].zuppoBlist ) then
- m[i][j] := m[i][j] + m[i][i];
- fi;
- od;
- for j in rreps do
- if IsSubsetBlist( reps[j].zuppoBlist, zuppos ) then
- m[i][j] := m[i][j] + m[i][i];
- fi;
- od;
- od;
- fi;
- od;
- fi;
-
- return m;
-
- #T return rec(
- #T group := group,
- #T matrix := m,
- #T classes := classes,
- #T modes := Intersection( arg, vargs )
- #T );
-
- end;
-
-
- #############################################################################
- ##
- #V ConjugacyClassSubgroupsGroupOps . . . . . . . . . . . . . . . . . . . . .
- #V . . . . . . . . . . operations record for conjugacy classes of subgroups
- ##
- ConjugacyClassSubgroupsGroupOps := Copy( DomainOps );
-
-
- #############################################################################
- ##
- #F ConjugacyClassSubgroupsGroupOps.Elements( <C> ) . . . . . . . . . . . . .
- ##
- ConjugacyClassSubgroupsGroupOps.Elements := function ( C )
- return Set( Orbit( C.group, C.representative ) );
- end;
-
-
- #############################################################################
- ##
- #F ConjugacyClassSubgroupsGroupOps.Size( <C> ) . . . . . . . . . . . . . . .
- ##
- ConjugacyClassSubgroupsGroupOps.Size := function ( C )
- if not IsBound( C.normalizerLattice ) then
- C.normalizerLattice := [
- ConjugacyClassSubgroups( C.group, Normalizer( C.group,
- C.representative ) ),
- C.group.identity
- ];
- fi;
- return Index( C.group, C.normalizerLattice[1].representative );
- end;
-
-
- #############################################################################
- ##
- #F ConjugacyClassSubgroupsGroupOps.\=( <C>, <D> ) . . . . . . . . . . . . .
- ##
- ConjugacyClassSubgroupsGroupOps.\= := function ( C, D )
- local isEql;
-
- if IsRec( C ) and IsBound( C.isConjugacyClassSubgroups )
- and IsRec( D ) and IsBound( D.isConjugacyClassSubgroups )
- and C.group = D.group
- then
- isEql := Size( C ) = Size( D )
- and Size( C.representative ) = Size( D.representative )
- and RepresentativeOperation( C.group,
- D.representative,
- C.representative ) <> false;
- else
- isEql := DomainOps.\=( C, D );
- fi;
- return isEql;
-
- end;
-
-
- #############################################################################
- ##
- #F ConjugacyClassSubgroupsGroupOps.\in( <H>, <C> ) . . . . . . . . . . . .
- ##
- ConjugacyClassSubgroupsGroupOps.\in := function ( H, C )
- return Size( H ) = Size( C.representative )
- and RepresentativeOperation( C.group,
- H,
- C.representative ) <> false;
- end;
-
-
- #############################################################################
- ##
- #F ConjugacyClassSubgroupsGroupOps.Random( <C> ) . . . . . . . . . . . . . .
- ##
- ConjugacyClassSubgroupsGroupOps.Random := function ( C )
- return C.representative ^ Random( C.group );
- end;
-
-
- #############################################################################
- ##
- #F ConjugacyClassGroupOps.\*( <C>, <D> ) . . . . . . . . . . . . . . . . .
- ##
- ConjugacyClassGroupOps.\* := function ( C, D )
- if IsConjugacyClass( C ) then
- return Elements( C ) * D;
- elif IsConjugacyClass( D ) then
- return C * Elements( D );
- else
- Error(
- "panic, neither <C> nor <D> is a conjugacy class of subgroups" );
- fi;
- end;
-
-
- #############################################################################
- ##
- #F ConjugacyClassSubgroupsGroupOps.Print( <C> ) . . . . . . . . . . . . . .
- ##
- ConjugacyClassSubgroupsGroupOps.Print := function ( C )
- Print( "ConjugacyClassSubgroups( ", C.group, ", ", C.representative, " )"
- );
- end;
-
-
- #############################################################################
- ##
- #V SubgroupLatticeOps . . . . . . . operations record for subgroup lattices
- ##
- SubgroupLatticeOps := rec();
-
-
- #############################################################################
- ##
- #F SubgroupLatticeOps.Lattice( <lattice> ) . . resume an aborted calculation
- ##
- SubgroupLatticeOps.Lattice := GroupOps.Lattice;
-
-
- #############################################################################
- ##
- #F SubgroupLatticeOps.TableOfMarks( <lattice> ) . . . . . . table of marks
- ##
- SubgroupLatticeOps.TableOfMarks := function( L )
- return TableOfMarks( L.group );
- end;
-
-
- #############################################################################
- ##
- #F SubgroupLatticeOps.ClearLatticeQueue( <lattice> ) . . . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . . . . . . . move queue groups to lattice
- ##
- SubgroupLatticeOps.ClearLatticeQueue := function( L )
- local C, i;
-
- for i in [1..Length( L.queue )] do
- if IsBound( L.queue[i] ) then
- C := L.queue[i];
- Unbind( L.queue[i] );
- SetLatticeStatus( L, C, L.queueGroups );
- fi;
- od;
- end;
-
-
- #############################################################################
- ##
- #F SubgroupLatticeOps.Information( <lattice>[, <topics>] ) . . . . . . . . .
- ##
- ## returns
- ##
- ## rec(
- ## classes := <integer>,
- ## groups := <integer>,
- ## layers := <integer>,
- ## groupsizes := <list>,
- ## classizes := <list>,
- ## classlayers := <list>,
- ## queuelayers := <list>,
- ## queuegroups := <integer>,
- ## queuesizes := <list>,
- ## items := <record>,
- ## queueitems := <record>
- ## )
- ##
- SubgroupLatticeOps.Information := function( arg )
- local L, topics, info, tmp, rep, layers, fld, x, i;
-
- if Length( arg ) = 1 then
- L := arg[1];
- topics := [ "classes", "groups" ];
- elif Length( arg ) = 2 then
- L := arg[1];
- topics := arg[2];
- else
- Error( "usage: Information( <lattice>[, <topics>] )" );
- fi;
-
- if not IsLattice( L ) or not IsList( topics ) then
- Error( "usage: Information( <lattice>[, <topics>] )" );
- fi;
-
- layers := Length( Factors( Size( L.group ) ) );
-
- info := rec();
-
- if "classes" in topics then
- info.classes := Length( L.classes );
- fi;
-
- if "groups" in topics then
- tmp := 0;
- for x in L.classes do
- tmp := tmp + x.size;
- od;
- info.groups := tmp;
- fi;
-
- if "layers" in topics then
- info.layers := layers;
- fi;
-
- if "groupsizes" in topics then
- tmp := ShallowCopy( L.classes );
- for i in [1..Length( tmp )] do
- tmp[i] := tmp[i].representative.size;
- od;
- info.sizes := tmp;
- fi;
-
- if "classizes" in topics then
- tmp := ShallowCopy( L.classes );
- for i in [1..Length( tmp )] do
- tmp[i] := tmp[i].size;
- od;
- info.classizes := tmp;
- fi;
-
- if "classlayers" in topics then
- tmp := [1..layers+1];
- for i in [1..layers+1] do
- tmp[i] := [];
- od;
- for x in L.classes do
- Add( tmp[x.layer+1], x );
- od;
- info.classlayers := tmp;
- fi;
-
- if "queuelayers" in topics then
- tmp := [1..layers+1];
- for i in [1..layers+1] do
- tmp[i] := [];
- od;
- for x in L.queue do
- Add( tmp[x.layer+1], x );
- od;
- info.queuelayers := tmp;
- fi;
-
- if "queuegroups" in topics then
- tmp := 0;
- for x in L.queue do
- tmp := tmp + 1;
- od;
- info.queuegroups := tmp;
- fi;
-
- if "queuesizes" in topics then
- tmp := [];
- for x in L.queue do
- Add( tmp, x.representative.size );
- od;
- info.queuesizes := tmp;
- fi;
-
- if "items" in topics then
-
- tmp := rec(
- elements := 0,
- zuppos := 0,
- zuppoBlist := 0
- );
-
- for x in L.classes do
- rep := x.representative;
- if IsBound( rep.elements ) then
- tmp.elements := tmp.elements + 1;
- fi;
- if IsBound( rep.zuppos ) then
- tmp.zuppos := tmp.zuppos + 1;
- fi;
- if IsBound( rep.zuppoBlist ) then
- tmp.zuppoBlist := tmp.zuppoBlist + 1;
- fi;
- od;
-
- info.items := tmp;
- fi;
-
- if "queueitems" in topics then
-
- tmp := rec(
- elements := 0,
- zuppos := 0,
- zuppoBlist := 0
- );
-
- for x in L.queue do
- rep := x.representative;
- if IsBound( rep.elements ) then
- tmp.elements := tmp.elements + 1;
- fi;
- if IsBound( rep.zuppos ) then
- tmp.zuppos := tmp.zuppos + 1;
- fi;
- if IsBound( rep.zuppoBlist ) then
- tmp.zuppoBlist := tmp.zuppoBlist + 1;
- fi;
- od;
-
- info.queueitems := tmp;
- fi;
-
- if "memory" in topics then
- tmp := rec( representative := rec() );
- for x in L.classes do
- rep := x.representative;
- for fld in RecFields( x ) do
- if not fld in [ "group", "representative", "operations" ]
- then
- if IsRec( x.( fld ) ) then
- Print( "#I Warning: ignoring field '", fld, "'\n" );
- else
- if not IsBound( tmp.( fld ) ) then
- tmp.( fld ) := 0;
- fi;
- tmp.( fld ) := (tmp.( fld )) + SIZE( x.( fld ) );
- fi;
- fi;
- od;
- for fld in RecFields( rep ) do
- if not fld in [ "parent", "operations" ] then
- if IsRec( rep.( fld ) ) then
- Print( "#I Warning: ignoring field '", fld, "'\n" );
- else
- if not IsBound( tmp.representative.( fld ) ) then
- tmp.representative.( fld ) := 0;
- fi;
- tmp.representative.( fld ) := (tmp.representative.(
- fld )) + SIZE( rep.( fld ) );
- fi;
- fi;
- od;
- od;
-
- info.memory := tmp;
- fi;
-
- return info;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.RightTransversal( <G>, <H> ) . . . determine a right transversal
- ##
- ## returns
- ##
- ## <list>
- ##
- GroupOps.RightTransversal := function( G, H )
- return List( G.operations.RightCosets( G, H ), x -> x.representative );
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.CheckPerfectGroupType( <group>, <cat_entry> ) . . . . . . . . .
- ##
- GroupOps.CheckPerfectGroupType := function( G, CG )
- local type, cc, list;
-
-
- InfoLattice2( "#I PerfectSubgroups: checking group types\n" );
-
- # make sure the conjugacy classes of G have '.size' bounded
-
- for cc in ConjugacyClasses( G ) do
- Size( cc );
- od;
-
- # now check all types specified in CG.grouptype
-
- for type in CG.grouptype do
-
- InfoLattice2( "#I checking group type ", type, "\n" );
-
- if type[1] = 1 then
- list := Filtered( ConjugacyClasses( G ),
- x -> Order( G, x.representative ) = type[2] );
- if Sum( List( list, Size ) ) <> type[3] then
- InfoLattice2( "#I type test 1 failed\n" );
- return false;
- fi;
- elif type[1] = 2 then
- InfoLattice2("#I perfect group type check 2 not implemented\n");
- elif type[1] = 3 then
- list := Filtered( ConjugacyClasses( G ),
- x -> x.size = type[3]
- and Order( G, x.representative ) = type[2] );
- if Length( list ) <> type[4] then
- InfoLattice2( "#I type test 3 failed\n" );
- return false;
- fi;
- elif type[1] = 4 then
- InfoLattice2("#I perfect group type check 4 not implemented\n");
- fi;
- od;
-
- InfoLattice2( "#I group is of correct type\n" );
-
- return true;
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.FindPerfectGenerator( <group>, <cat_entry>, <C>, <gens> ) . . .
- ##
- GroupOps.FindPerfectGenerator := function( G, CG, U, gens )
- local k, cc, cclist, cyc, g, cent, w, type, list, orb, sum;
-
-
- k := Length( gens ) + 1;
-
- if k > Length( CG.generators ) then
-
- InfoLattice2( "#I PerfectSubgroups: testing (anti)relations\n" );
-
- # now check if the (anti)relations are obeyed.
-
- for w in CG.relations do
- if MappedWord( w, CG.generators, gens ) <> G.identity then
- InfoLattice2( "#I relations are not fulfilled\n" );
- return false;
- fi;
- od;
-
- for w in CG.antirelations do
- if MappedWord( w, CG.generators, gens ) = G.identity then
- InfoLattice2( "#I antirelations are not fulfilled\n" );
- return false;
- fi;
- od;
-
- InfoLattice2( "#I group is identified\n" );
- return true;
- else
-
- InfoLattice2("#I PerfectSubgroups: searching generator ", k, "\n");
-
- # O.K. we have to find the k-th generator
-
- type := CG.generatortype[k];
-
- # type specifications 1 and 4 may be tested for full classes
-
- list := Filtered( ConjugacyClasses( G ),
- x -> Order( G, x.representative ) = type[1] );
- list := Filtered( list,
- x -> x.size = type[4] );
-
- # now try to find a generator in one of the remaining classes
-
- for cc in list do
-
- cclist := ShallowCopy( Elements( cc ) );
-
- while cclist <> [] do
-
- g := cclist[1];
- orb := Orbit( U, g );
- gens[k] := g;
-
- if Length( orb ) = type[2] then
- cyc := Elements( Group( g ) );
- cyc := Filtered( cyc, x -> Order( G, x ) = type[1] );
- sum := 1;
- SubtractSet( cyc, orb );
- while cyc <> [] do
- SubtractSet( cyc, Orbit( U, cyc[1] ) );
- sum := sum + 1;
- od;
- if sum = type[3] then
- cent := Centralizer( U, g );
- if G.operations.FindPerfectGenerator( G, CG, cent,
- gens ) then
- return true;
- fi;
- fi;
- fi;
-
- SubtractSet( cclist, orb );
- od;
- od;
-
- Unbind( gens[k] );
- return false;
- fi;
- end;
-
-
- #############################################################################
- ##
- #F SubgroupLatticeOps.SetPrintLevel( <L>, <lev> ) . . change amount of info
- ##
- SubgroupLatticeOps.SetPrintLevel := function( L, lev )
- if IsInt( lev ) then
- if lev = 0 then lev := [ 0, 0, 0, 0, 0 ];
- elif lev = 1 then lev := [ 1, 0, 0, 0, 0 ];
- elif lev = 2 then lev := [ 2, 1, 0, 1, 0 ];
- elif lev = 3 then lev := [ 3, 2, 0, 1, 0 ];
- elif lev = 4 then lev := [ 4, 2, 1, 2, 0 ];
- elif lev = 5 then lev := [ 4, 2, 1, 2, 2 ];
- else
- Error( "sorry, <integer> must lie between 0 and 5" );
- fi;
- elif IsList( lev ) then
- if Length( lev ) <> 5 then
- Error( "sorry, <list> must hold 5 integers" );
- fi;
- else
- Error( "usage: SetPrintLevel( <lattice>, <integer>|<list> )" );
- fi;
- L.printLevel := lev;
- end;
-
-
- #############################################################################
- ##
- #F SubgroupLatticeOps.Print( <lattice> ) . . . . . print a subgroup lattice
- ##
- SubgroupLatticeOps.Print := function( L )
- local c;
- if not IsBound( L.printLevel ) then
- L.operations.SetPrintLevel( L, 0 );
- fi;
- if Set( L.printLevel ) <> [ 0 ] then
- for c in [1..Length( L.classes )] do
- PrintClassSubgroupLattice( L, c );
- od;
- fi;
- Print( "Lattice( ", L.group, " )" );
- end;
-
-
- PrintClassSubgroupLattice := function( L, cl )
- local i;
-
- if L.printLevel[1] >= 1 then
- Print( "#I Class number ", String(cl,3), ", Length ",
- String(Size(L.classes[cl] ),4), ", Order ",
- Size( L.classes[cl].representative ), "\n" );
- fi;
- if L.printLevel[1] >= 2 then
- PrintGroupSubgroupLattice( L, cl, 1 );
- PrintMinSubgroupLattice( L, cl, 1 );
- PrintMaxSubgroupLattice( L, cl, 1 );
- fi;
- if L.printLevel[1] >= 3 then
- for i in [2..Size( L.classes[cl] )] do
- PrintGroupSubgroupLattice( L, cl, i );
- PrintMinSubgroupLattice( L, cl, i );
- PrintMaxSubgroupLattice( L, cl, i );
- od;
- fi;
- end;
-
-
- PrintGroupSubgroupLattice := function( L, cl, co )
- local c, g;
-
- c := L.classes[cl];
-
- if co = 1 then
- Print( "#I Representative " );
- else
- Print( "#I Conjugate ", co, " by ", c.conjugands[co], " is " );
- fi;
-
- if L.printLevel[2] >= 1 and co = 1 then
- Print( c.representative.generators );
- fi;
- if L.printLevel[2] >= 2 and co <> 1 then
- g := c.representative ^ c.conjugands[co];
- Print( g.generators );
- fi;
- Print( "\n" );
- end;
-
-
- PrintMaxSubgroupLattice := function( L, cl, co )
- local classes, count, i, id, k, mmlr, rep, repi, tinv, tt, zuppos;
-
- classes := L.classes;
- rep := classes[cl].representative;
- if rep.size = 1 then return; fi;
-
- # compute (and save) a list of the maximal subgroups and the minimal
- # supergroups of all class representative subgroups, if not yet done.
- mmlr := MinMaxLatticeRelation( L.group );
-
- if L.printLevel[4] >= 1 and co = 1 then
- # print the maximal subgroups of the given class representative
- # subgroup.
- Print( "#I Max " );
- for i in [ 1 .. cl-1 ] do
- for k in mmlr[i][cl] do
- Print( " [", i, ",", k, "]" );
- od;
- od;
- Print( "\n" );
-
- elif L.printLevel[4] >= 2 and co <> 1 then
- # print the maximal subgroups of the given class non representative
- # subgroup.
- Print( "#I Max " );
- id := L.group.identity;
- tinv := classes[cl].conjugands[co]^-1;
- for i in [ 1 .. cl-1 ] do
- count := Length( mmlr[i][cl] );
- if count > 0 then
- repi := classes[i].representative;
- k := 0;
- while count > 0 do
- k := k + 1;
- tt := classes[i].conjugands[k] * tinv;
- if tt = id then
- zuppos := ZuppoBlist( repi );
- else
- zuppos := ConjugateZuppoBlist( repi, tt );
- fi;
- if IsSubsetBlist( rep.zuppoBlist, zuppos ) then
- Print( " [", i, ",", k, "]" );
- count := count - 1;
- fi;
- od;
- fi;
- od;
- Print( "\n" );
- fi;
- end;
-
-
- PrintMinSubgroupLattice := function( L, cl, co )
- local classes, count, i, id, k, mmlr, rep, repi, t, tt, zuppos;
-
- classes := L.classes;
- rep := classes[cl].representative;
- if rep.size = Size( L.group ) then return; fi;
-
- # compute (and save) a list of the maximal subgroups and the minimal
- # supergroups of all class representative subgroups, if not yet done.
- mmlr := MinMaxLatticeRelation( L.group );
-
- if L.printLevel[5] >= 1 and co = 1 then
- # print the minimal supergroups of the given class representative
- # subgroup.
- Print( "#I Min " );
- for i in [ cl+1 .. Length( classes ) ] do
- for k in mmlr[i][cl] do
- Print( " [", i, ",", k, "]" );
- od;
- od;
- Print( "\n" );
-
- elif L.printLevel[5] >= 2 and co <> 1 then
- # print the minimal supergroups of the given class non representative
- # subgroup.
- Print( "#I Min " );
- id := L.group.identity;
- t := classes[cl].conjugands[co];
- for i in [ cl+1 .. Length( classes ) ] do
- count := Length( mmlr[i][cl] );
- if count > 0 then
- repi := classes[i].representative;
- k := 0;
- while count > 0 do
- k := k + 1;
- tt := t * classes[i].conjugands[k]^-1;
- if tt = id then
- zuppos := ZuppoBlist( rep );
- else
- zuppos := ConjugateZuppoBlist( rep, tt );
- fi;
- if IsSubsetBlist( repi.zuppoBlist, zuppos ) then
- Print( " [", i, ",", k, "]" );
- count := count - 1;
- fi;
- od;
- fi;
- od;
- Print( "\n" );
- fi;
- end;
-
-
- MinMaxLatticeRelation := function( D )
- local rel;
-
- if IsDomain(D) and IsBound(D.minMaxLatticeRelation) then
- rel := D.minMaxLatticeRelation;
- elif IsDomain(D) and IsBound(D.operations.MinMaxLatticeRelation) then
- D.minMaxLatticeRelation := D.operations.MinMaxLatticeRelation( D );
- rel := D.minMaxLatticeRelation;
- else
- Error( "sorry, can't compute lattice relation for domain" );
- fi;
- return rel;
- end;
-
-
- GroupOps.MinMaxLatticeRelation := function( arg )
-
- local group, classes, reps, dim, m, count, zuppos, left, right,
- lreps, rreps, vargs, t, i, j, k;
-
- # check the arguments
- vargs := [ "min", "max" ];
- group := arg[1];
-
- if Length( arg ) = 1 then
- classes := ConjugacyClassesSubgroups( group );
- Append( arg, [ "min", "max" ] );
- elif IsList( arg[2] ) then
- if not IsSubset( vargs, Sublist( arg, [3..Length( arg )] ) ) then
- Error( "sorry, unkown argument options" );
- fi;
- classes := arg[2];
- else
- if not IsSubset( vargs, Sublist( arg, [2..Length( arg )] ) ) then
- Error( "sorry, unkown argument options" );
- fi;
-
- classes := ConjugacyClassesSubgroups( group );
- fi;
-
- # ensure that the classes are sorted by increasing subgroup
- # orders.
- for i in [ 2 .. Length( classes ) ] do
- if classes[i].representative.size <
- classes[i-1].representative.size then
- Error( "classes of subgroups are not sorted" );
- fi;
- od;
- #T Sort( classes,
- #T function( x, y )
- #T return x.representative.size < y.representative.size;
- #T end );
-
- reps := List( classes, x -> x.representative );
- dim := Length( classes );
- left := "min" in arg;
- right := "max" in arg;
-
- m := List( classes, x -> List( classes, x -> [] ) );
- for i in [1..dim] do
- m[i][i] := [ 1 ];
- od;
-
- for i in [1..dim] do
- if reps[i].size = 1 and right then
- for j in [i+1..dim] do m[i][j] := ShallowCopy( m[i][i] ); od;
- elif reps[i].size = Size( group ) and left then
- for j in [1..i-1] do m[i][j] := ShallowCopy( m[i][i] ); od;
- else
- lreps := [];
- rreps := [];
- if left then
- for j in [1..i-1] do
- if reps[i].size mod reps[j].size = 0 then
- Add( lreps, j );
- fi;
- od;
- fi;
- if right then
- for j in [i+1..dim] do
- if reps[j].size mod reps[i].size = 0 then
- Add( rreps, j );
- fi;
- od;
- fi;
- for k in [1..Length( classes[i].conjugands )] do
- t := classes[i].conjugands[k];
- if t = group.identity then
- zuppos := ZuppoBlist( reps[i] );
- else
- zuppos := ConjugateZuppoBlist( reps[i], t );
- fi;
- for j in lreps do
- if IsSubsetBlist( zuppos, reps[j].zuppoBlist ) then
- Add( m[i][j], k );
- fi;
- od;
- for j in rreps do
- if IsSubsetBlist( reps[j].zuppoBlist, zuppos ) then
- Add( m[i][j], k );
- fi;
- od;
- od;
- fi;
- od;
- for i in [1..dim] do
- for j in [1..dim] do
- if m[i][j] <> [] then
- if i > j then
- for k in [i+1..dim] do
- if m[k][i] <> [] then
- m[k][j] := [];
- fi;
- od;
- elif i < j then
- for k in [1..i-1] do
- if m[k][i] <> [] then
- m[k][j] := [];
- fi;
- od;
- fi;
- fi;
- od;
- od;
-
- return m;
-
- end;
-
-
- #############################################################################
- ##
- #F GroupOps.PerfectSubgroups( <group> ) . . . . . . . . . . . . . . . . . .
- ##
- GroupOps.PerfectSubgroups := function( group )
- local list, gens, pergrp, catgrp, solres;
-
-
- # compute the solvable residuum of the group
-
- solres := DerivedSeries( group );
- solres := solres[Length( solres )];
-
- if Size( solres ) = 1 then
- return [];
- fi;
-
- for catgrp in PerfectGroupsCatalogue do
- if catgrp.size = solres.size then
- gens := [];
- if solres.operations.CheckPerfectGroupType( solres, catgrp )
- and solres.operations.FindPerfectGenerator( solres,
- catgrp,
- solres,
- gens )
- then
- list := [ solres ];
- for pergrp in catgrp.subgroups do
- Add( list, Subgroup( Parent( group ),
- List( pergrp.generators,
- x -> MappedWord( x, catgrp.generators, gens ) ) ) );
- od;
- FreePerfectGroupsCatalogue();
- return list;
- fi;
- fi;
- od;
-
- Error( "sorry, can' t identify the group's solvable residuum" );
- end;
-
-
- #############################################################################
- ##
- #F FreePerfectGroupsCatalogue() . . unload the catalogue of perfect groups
- ##
- FreePerfectGroupsCatalogue := function()
- AUTO( ReadLib( "lattperf" ), PerfectGroupsCatalogue );
- end;
-
-
- #############################################################################
- ##
- #E Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
- ##
- ## Local Variables:
- ## mode: outline
- ## outline-regexp: "#F\\|#V\\|#E"
- ## fill-column: 73
- ## fill-prefix: "## "
- ## eval: (hide-body)
- ## End:
- ##
-