home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-05 | 35.9 KB | 1,092 lines |
- #############################################################################
- ##
- #A permhomo.g GAP library Martin Schoenert
- #A & Udo Polis
- ##
- #A @(#)$Id: permhomo.g,v 3.10 1992/06/23 12:08:47 martin Rel $
- ##
- #Y Copyright 1990-1992, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
- ##
- ## This file contains functions that implement homomorphisms for permgroups.
- ##
- #H $Log: permhomo.g,v $
- #H Revision 3.10 1992/06/23 12:08:47 martin
- #H fixed 'PGHBIO.CoKernel' to take the normal closure
- #H
- #H Revision 3.9 1992/06/04 12:50:57 martin
- #H changed 'GroupHomomorphismsByImages' to accept empty lists
- #H
- #H Revision 3.8 1992/06/03 17:26:20 martin
- #H improved 'GroupHomomorphismByImages'
- #H
- #H Revision 3.7 1992/03/27 11:14:51 martin
- #H changed mapping to general mapping and function to mapping
- #H
- #H Revision 3.6 1992/02/20 19:31:34 martin
- #H fixed a bug in 'BlocksHomOps.PreImagesSetStab', kernel may be trivial
- #H
- #H Revision 3.5 1992/02/20 15:58:50 martin
- #H added Udo to the list of authors
- #H
- #H Revision 3.4 1992/02/19 19:39:21 martin
- #H fixed 'TransConstHomOps.PreImagesSet', the generators of the preimage
- #H must contain the generators of the kernel
- #H
- #H Revision 3.3 1992/02/19 13:02:30 martin
- #H added 'TransConstHomomorphism' and 'BlocksHomomorphism'
- #H
- #H Revision 3.2 1992/02/10 15:14:35 martin
- #H added the domain 'Mappings'
- #H
- #H Revision 3.1 1992/01/20 15:54:47 martin
- #H initial revision under RCS
- #H
- ##
-
-
- #############################################################################
- ##
- #F PermGroupOps.GroupHomomormphismByImages(<G>,<H>,<gens>,<imgs>) . create
- #F a permutation group homomorphism by the images of a generating system
- ##
- PermGroupOps.GroupHomomorphismByImages := function ( G, H, gens, imgs )
- local hom; # homomorphism from <G> to <H>, result
-
- # make the homomorphism
- hom := rec( );
- hom.isGeneralMapping := true;
- hom.domain := Mappings;
-
- # enter the identifying information
- hom.source := G;
- hom.range := H;
- hom.generators := gens;
- hom.genimages := imgs;
-
- # enter usefull information (precious little)
- if IsEqualSet( gens, G.generators ) then
- hom.preimage := G;
- else
- hom.preimage := Parent(G).operations.Subgroup( Parent(G), gens );
- fi;
- if IsEqualSet( imgs, H.generators ) then
- hom.image := H;
- else
- hom.image := Parent(H).operations.Subgroup( Parent(H), imgs );
- fi;
-
- # enter the operations record
- hom.operations := PermGroupHomomorphismByImagesOps;
-
- # return the homomorphism
- return hom;
- end;
-
- PermGroupHomomorphismByImagesOps := Copy( GroupHomomorphismByImagesOps );
-
- PermGroupHomomorphismByImagesOps.MakeMapping := function ( hom )
- local rnd, # list of random elements of '<hom>.source'
- rne, # list of the images of the elements in <rnd>
- rni, # index of the next random element to consider
- elm, # one element in '<hom>.source'
- img, # its image
- size, # size of the stabilizer chain constructed so far
- stb, # stabilizer in '<hom>.source'
- orb, # orbit
- len, # length of the orbit before extension
- bpt, # base point
- i, j; # loop variables
-
- # handle trivial case
- if hom.generators = [] then
- return;
- fi;
-
- # start with the generators as random elements
- rnd := ShallowCopy( hom.generators );
- for i in [Length(rnd)..16] do
- Add( rnd, hom.source.identity );
- od;
- rne := ShallowCopy( hom.genimages );
- for i in [Length(rne)..16] do
- Add( rne, hom.range.identity );
- od;
- rni := 1;
-
- # initialize the top level
- bpt := 0;
- for elm in hom.generators do
- if elm <> elm^0
- and (bpt = 0 or SmallestMovedPointPerm( elm ) < bpt)
- then
- bpt := SmallestMovedPointPerm( elm );
- fi;
- od;
- if bpt = 0 then bpt := 1; fi;
- hom.orbit := [ bpt ];
- hom.transversal := [];
- hom.transversal[ bpt ] := hom.source.identity;
- hom.transimages := [];
- hom.transimages[ bpt ] := hom.range.identity;
- hom.stabilizer := rec();
- hom.stabilizer.identity := hom.source.identity;
- hom.stabilizer.generators := [];
- hom.stabilizer.genimages := [];
-
- # extend orbit and transversal
- orb := hom.orbit;
- i := 1;
- while i <= Length(orb) do
- for j in [1..Length(hom.generators)] do
- elm := hom.generators[j];
- img := hom.genimages[j];
- if not IsBound(hom.transversal[orb[i]/elm]) then
- hom.transversal[orb[i]/elm] := elm;
- hom.transimages[orb[i]/elm] := img;
- Add( orb, orb[i]/elm );
- fi;
- od;
- i := i + 1;
- od;
-
- # get the size of the stabilizer chain
- size := Length( hom.orbit );
-
- # create new elements until we have reached the size
- while size <> Size( hom.preimage ) do
-
- # make a new element from the generators
- elm := rnd[rni];
- img := rne[rni];
- i := RandomList( [ 1 .. Length( hom.generators ) ] );
- rnd[rni] := rnd[rni] * hom.generators[i];
- rne[rni] := rne[rni] * hom.genimages[i];
- rni := rni mod 16 + 1;
-
- # divide the element through the stabilizer chain
- stb := hom;
- while stb.generators <> []
- and IsBound(stb.transversal[stb.orbit[1]^elm]) do
- bpt := stb.orbit[1];
- while bpt ^ elm <> bpt do
- img := img * stb.transimages[bpt^elm];
- elm := elm * stb.transversal[bpt^elm];
- od;
- stb := stb.stabilizer;
- od;
-
- # if the element was not in the stabilizer chain
- if elm <> hom.source.identity then
-
- # if this stabilizer is trivial add an initial orbit
- if stb.generators = [] then
- bpt := SmallestMovedPointPerm( elm );
- stb.orbit := [ bpt ];
- stb.transversal := [];
- stb.transversal[ bpt ] := hom.source.identity;
- stb.transimages := [];
- stb.transimages[ bpt ] := hom.range.identity;
- stb.stabilizer := rec();
- stb.stabilizer.identity := hom.source.identity;
- stb.stabilizer.generators := [];
- stb.stabilizer.genimages := [];
- fi;
-
- # divide the size of stabilizer chain by the old orbit length
- size := size / Length( stb.orbit );
-
- # add the element to the generators
- Add( stb.generators, elm );
- Add( stb.genimages, img );
-
- # extend orbit and transversal
- orb := stb.orbit;
- len := Length(orb);
- i := 1;
- while i <= len do
- if not IsBound(stb.transversal[orb[i]/elm]) then
- stb.transversal[orb[i]/elm] := elm;
- stb.transimages[orb[i]/elm] := img;
- Add( orb, orb[i]/elm );
- fi;
- i := i + 1;
- od;
- while i <= Length(orb) do
- for j in [1..Length(stb.generators)] do
- elm := stb.generators[j];
- img := stb.genimages[j];
- if not IsBound(stb.transversal[orb[i]/elm]) then
- stb.transversal[orb[i]/elm] := elm;
- stb.transimages[orb[i]/elm] := img;
- Add( orb, orb[i]/elm );
- fi;
- od;
- i := i + 1;
- od;
-
- # multiply the size of stabilizer chain by the new orbit length
- size := size * Length( stb.orbit );
-
- fi;
-
- od;
-
- end;
-
- PermGroupHomomorphismByImagesOps.CoKernel := function ( hom )
- local C, # cokernel of <hom>, result
- stb, # stabilizer in the chain of <hom>
- bpt, # basepoint of stabilizer
- elm, # one schreier generator
- img, # image of <elm> under <hom>
- i, k; # loop variables
-
- # handle special case
- if IsBound( hom.isMapping ) and hom.isMapping then
- return TrivialSubgroup( hom.range );
- fi;
-
- # make sure we have a stabilizer chain for <hom>
- if not IsBound( hom.stabilizer ) then
- hom.operations.MakeMapping( hom );
- fi;
-
- # loop over the stabilizer chain
- C := TrivialSubgroup( hom.range );
- while hom.generators <> [] do
-
- # for all orbit points
- for i in hom.orbit do
-
- # and all generators
- for k in [ 1 .. Length(hom.generators) ] do
-
- # make the schreier generator and its image
- elm := hom.transversal[i] * hom.generators[k];
- img := hom.transimages[i] * hom.genimages[k];
-
- # divde the schreier generator through the stabilizer chain
- stb := hom;
- while stb.generators <> []
- and IsBound(stb.transversal[stb.orbit[1]^elm]) do
- bpt := stb.orbit[1];
- while bpt ^ elm <> bpt do
- img := img * stb.transimages[bpt^elm];
- elm := elm * stb.transversal[bpt^elm];
- od;
- stb := stb.stabilizer;
- od;
-
- # if the image is not trivial add it to the cokernel
- if not img in C then
- C := Closure( C, img );
- fi;
-
- od;
-
- od;
-
- # go down to the next stabilizer
- hom := hom.stabilizer;
-
- od;
-
- # return the cokernel
- return NormalClosure( Parent( C ), C );
- end;
-
- PermGroupHomomorphismByImagesOps.ImageElm := function ( hom, elm )
- if not IsMapping( hom ) then
- Error("<hom> must be a single valued mapping");
- fi;
- return hom.operations.ImagesRepresentative( hom, elm );
- end;
-
- PermGroupHomomorphismByImagesOps.ImagesElm := function ( hom, elm )
- local img, # image of <elm>, result
- stb, # stabilizer of <G>
- bpt; # basepoint of <stb>
-
- # make sure we have a stabilizer chain and the co kernel
- if not IsBound( hom.stabilizer ) then
- hom.operations.MakeMapping( hom );
- fi;
- if not IsBound( hom.coKernel ) then
- hom.coKernel := hom.operations.CoKernel( hom );
- fi;
-
- # go down the stabchain and reduce the permutation
- stb := hom;
- img := hom.range.identity;
- while stb.generators <> [] do
- bpt := stb.orbit[1];
-
- # if '<bpt>^<elm>' is not in the orbit then <elm> is not in <source>
- if not IsBound(stb.transversal[bpt^elm]) then
- return [];
- fi;
-
- # reduce <elm> into the stabilizer
- while bpt ^ elm <> bpt do
- img := img * stb.transimages[bpt^elm];
- elm := elm * stb.transversal[bpt^elm];
- od;
-
- # and test if the reduced <g> lies in the stabilizer
- stb := stb.stabilizer;
- od;
-
- # if <elm> is not the identity it did not lie in <source>
- if elm <> hom.source.identity then
- return [];
- fi;
-
- # return the image
- return hom.coKernel * img^-1;
- end;
-
- PermGroupHomomorphismByImagesOps.ImagesSet := function ( hom, elms )
- if IsGroup( elms ) and IsSubset( hom.source, elms ) then
- if hom.preimage <> hom.source then
- elms := Intersection( hom.preimage, elms );
- fi;
- if not IsBound( hom.coKernel ) then
- hom.coKernel := hom.operations.CoKernel( hom );
- fi;
- return Closure( hom.coKernel,
- Parent( hom.range ).operations.Subgroup(
- Parent( hom.range ),
- List( elms.generators,
- gen -> ImagesRepresentative( hom,
- gen ) )));
- else
- return GroupHomomorphismOps.ImagesSet( hom, elms );
- fi;
- end;
-
- PermGroupHomomorphismByImagesOps.ImagesRepresentative := function (hom,elm)
- local img, # image of <elm>, result
- stb, # stabilizer of <G>
- bpt; # basepoint of <stb>
-
- # make sure we have a stabilizer chain
- if not IsBound( hom.stabilizer ) then
- hom.operations.MakeMapping( hom );
- fi;
-
- # go down the stabchain and reduce the permutation
- stb := hom;
- img := hom.range.identity;
- while stb.generators <> [] do
- bpt := stb.orbit[1];
-
- # if '<bpt>^<elm>' is not in the orbit then <elm> is not in <source>
- if not IsBound(stb.transversal[bpt^elm]) then
- Error("<elm> must lie in the preimage of <hom>");
- fi;
-
- # reduce <elm> into the stabilizer
- while bpt ^ elm <> bpt do
- img := img * stb.transimages[bpt^elm];
- elm := elm * stb.transversal[bpt^elm];
- od;
-
- # and test if the reduced <g> lies in the stabilizer
- stb := stb.stabilizer;
- od;
-
- # if <elm> is not the identity it did not lie in <source>
- if elm <> hom.source.identity then
- Error("<elm> must lie in the preimage of <hom>");
- fi;
-
- # return the image
- return img^-1;
- end;
-
- PermGroupHomomorphismByImagesOps.CompositionMapping := function (hom1,hom2)
- local prd, # product of <hom1> and <hom2>, result
- stb, # stabilizer in the chain of <prd>
- gens, # strong generators of '<hom1>.source'
- imgs, # their images under <prd>
- i, k; # loop variables
-
- # product of a homomorphism by generator images
- if IsHomomorphism( hom2 ) and IsBound( hom2.genimages ) then
-
- # with another homomorphism
- if IsHomomorphism( hom1 ) then
-
- # make sure we have a stabilizer chain for the left homomorphism
- if not IsBound( hom2.stabilizer ) then
- hom1.operations.MakeMapping( hom2 );
- fi;
-
- # make the homomorphism
- prd := rec( );
- prd.isGeneralMapping := true;
- prd.domain := Mappings;
-
- # enter the identifying information
- prd.source := hom2.source;
- prd.range := hom1.range;
-
- # enter usefull information
- prd.isMapping := true;
- prd.isHomomorphism := true;
- prd.preimage := hom2.source;
-
- # copy the stabilizer chain and update the images of the sgs
- gens := [ prd.source.identity ];
- imgs := [ prd.range.identity ];
- stb := prd;
- stb.identity := hom2.source.identity;
- stb.generators := [];
- stb.genimages := [];
- while hom2.generators <> [] do
-
- # copy the generators and their images
- for i in [ 1 .. Length( hom2.generators ) ] do
- if not hom2.generators[i] in gens then
- Add( gens, hom2.generators[i] );
- Add( imgs, ImagesRepresentative( hom1,
- hom2.genimages[i] ) );
- fi;
- stb.generators[i] := hom2.generators[i];
- stb.genimages[i] := imgs[ Position( gens,
- hom2.generators[i] ) ];
- od;
-
- # copy the orbit and transversal
- stb.orbit := [];
- stb.transversal := [];
- stb.transimages := [];
- for i in [ 1 .. Length( hom2.orbit ) ] do
- k := hom2.orbit[i];
- stb.orbit[i] := k;
- stb.transversal[k] := hom2.transversal[k];
- stb.transimages[k] := imgs[ Position( gens,
- hom2.transversal[k] ) ];
- od;
-
- # on to the next stabilizer
- stb.stabilizer := rec();
- stb.stabilizer.identity := stb.identity;
- stb.stabilizer.generators := [];
- stb.stabilizer.genimages := [];
- stb := stb.stabilizer;
- hom2 := hom2.stabilizer;
-
- od;
-
- # enter the operations record
- prd.operations := PermGroupHomomorphismByImagesOps;
-
- # with another mapping
- else
-
- prd := MappingOps.CompositionMapping( hom1, hom2 );
-
- fi;
-
- # of something else
- else
- prd := MappingOps.CompositionMapping( hom1, hom2 );
- fi;
-
- # return the product
- return prd;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.OperationHomomorphism(<G>,<P>) . . . operation homomorphism
- #F for a perm group
- ##
- PermGroupOps.OperationHomomorphism := function ( G, P )
- local hom; # operation homomorphism from <G> into <P>, result
-
- # special case for transitive constituent homomorphism
- if P.operationOperation = OnPoints
- and ForAll( P.operationDomain, IsInt )
- then
- hom := PermGroupOps.TransConstHomomorphism( G, P );
-
- # special case for blocks homomorphism
- elif P.operationOperation = OnSets
- and ForAll( P.operationDomain, IsSet )
- and Size( Union(P.operationDomain) ) = Sum( P.operationDomain, Size )
- then
- hom := PermGroupOps.BlocksHomomorphism( G, P );
-
- # delegate other cases
- else
- hom := GroupOps.OperationHomomorphism( G, P );
-
- fi;
-
- # return the homomorphism
- return hom;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.TransConstHomomorphism(<G>,<P>) . . . transitive constituent
- #F homomorphism of <G> into <P>
- ##
- ## The reason that we specialize 'OperationHomomorphism' for this case
- ## is that we can map stabilizer chains when we take images of preimages
- ## of subgroups. Also taking images of elements can be made a litte bit
- ## faster.
- ##
- PermGroupOps.TransConstHomomorphism := function ( G, P )
- local hom; # homomorphism, result
-
- # make the homomorphism
- hom := rec(
-
- # tags
- isGeneralMapping := true,
- domain := Mappings,
-
- # source and range
- source := G,
- range := P,
-
- # permutation mapping <D> to the moved points of <P>
- conperm := MappingPermListList( P.operationDomain,
- [ 1 .. Length( P.operationDomain ) ] ),
-
- # usefull information
- isMapping := true,
- isHomomorphism := true,
- isGroupHomomorphism := true,
- isTransConstHom := true,
-
- # operations record
- operations := TransConstHomomorphismOps );
-
- # return the homomorphism
- return hom;
- end;
-
- TransConstHomomorphismOps := Copy( OperationHomomorphismOps );
-
- TransConstHomomorphismOps.ImageElm := function ( hom, elm )
- return RestrictedPerm(elm,hom.range.operationDomain) ^ hom.conperm;
- end;
-
- TransConstHomomorphismOps.ImagesElm := function ( hom, elm )
- return [ hom.operations.ImageElm( hom, elm ) ];
- end;
-
- TransConstHomomorphismOps.ImagesRepresentative
- := TransConstHomomorphismOps.ImageElm;
-
- TransConstHomomorphismOps.ImagesSet := function ( hom, H )
- local I, # image of <H>, result
- S, # stabilizer in <H>
- T, # corresponding stabilizer in <I>
- gens, # strong generators of <H>
- imgs, # their images in <I>
- top, # is 'true' if <T> is <I>
- gen, # one generator from <gens>
- pnt, # one point in the orbit <S>
- img; # the image of <pnt> in the orbit of <T>
-
- # handle special case that <H> is a subgroup of '<hom>.source'
- if IsDomain( H ) then
-
- # adapt the base of <H> to the subset of <D> that is in the base
- MakeStabChain( H, hom.range.operationDomain );
- Size( H );
- InfoPermGroup1("#I TransConstHomOps.ImagesSet called for ",
- GroupString(H,"H"),"\n");
-
- # initialize a list of strong gens of <H> and their images in <I>
- gens := [];
- imgs := [];
- for gen in H.generators do
- Add( gens, gen );
- Add( imgs, Image( hom, gen ) );
- od;
-
- # create the image group
- I := Subgroup( Parent( hom.range ), imgs );
- if IsBound( I.orbit ) then return I; fi;
-
- # loop over the points in the subset of <G> that is in the base
- S := H;
- T := I;
- top := true;
- while IsBound( S.orbit )
- and S.orbit[1] in hom.range.operationDomain
- do
-
- # make the generators for <T>
- if not top then
- T.generators := [];
- for gen in S.generators do
- if not gen in gens then
- Add( gens, gen );
- Add( imgs, Image( hom, gen ) );
- fi;
- if imgs[ Position( gens, gen ) ] <> T.identity then
- Add( T.generators, imgs[ Position( gens, gen ) ] );
- fi;
- od;
- fi;
-
- # make the orbit and the transversal for <T>
- T.orbit := [];
- T.transversal := [];
- for pnt in S.orbit do
- img := pnt ^ hom.conperm;
- Add( T.orbit, img );
- if pnt <> S.orbit[1] then
- gen := S.transversal[ pnt ];
- T.transversal[ img ] := imgs[ Position( gens, gen ) ];
- else
- T.transversal[ img ] := T.identity;
- fi;
- od;
-
- # add a trivial stabilizer
- T.stabilizer := rec(
- generators := [],
- identity := T.identity );
-
- # go down to the next step
- S := S.stabilizer;
- T := T.stabilizer;
- top := false;
-
- od;
-
- # give some information
- Size( I );
- InfoPermGroup1("#I TransConstHomOps.ImagesSet returns ",
- GroupString(I,"I"),"\n");
-
- # delegate set case
- else
- I := OperationHomomorphismOps.ImagesSet( hom, H );
-
- fi;
-
- # return the image
- return I;
- end;
-
- TransConstHomomorphismOps.PreImagesSet := function ( hom, I )
- local H, # preimage of <I>, result
- S, # stabilizer in <H>
- T, # corresponding stabilizer in <I>
- K, # kernel of <hom>
- gens, # strong generators of <I>
- pres, # their preimages in <H>
- top, # is 'true' if <S> is <H>
- gen, # one generator from <gens>
- pnt, # one point in the orbit <T>
- img; # the preimage of <pnt> in the orbit of <S>
-
- #N 18-Feb-92 <I> need not be a subset of 'Image( <hom> )'
-
- # handle special case that <I> is a subgroup of '<hom>.range'
- if IsDomain( I ) then
-
- # compute a stabilizer chain for <I>
- MakeStabChain( I );
- Size( I );
- InfoPermGroup1("#I TransConstHomOps.PreImagsSet called for ",
- GroupString(I,"I"),"\n");
-
- # initialize a list of strong gens of <I> and their preimages in <H>
- gens := [];
- pres := [];
- for gen in I.generators do
- Add( gens, gen );
- Add( pres, PreImagesRepresentative( hom, gen ) );
- od;
-
- # compute the kernel of <hom>
- K := Kernel( hom );
-
- # create the preimage group
- H := Subgroup(Parent(hom.source),Concatenation(pres,K.generators));
- if IsBound( H.orbit ) then return H; fi;
-
- # loop over the basepoints of <I>
- S := H;
- T := I;
- top := true;
- while IsBound( T.orbit ) do
-
- # make the generators for <S>
- if not top then
- S.generators := ShallowCopy( K.generators );
- for gen in T.generators do
- if not gen in gens then
- Add( gens, gen );
- Add( pres, PreImagesRepresentative( hom, gen ) );
- fi;
- Add( S.generators, pres[ Position( gens, gen ) ] );
- od;
- fi;
-
- # make the orbit and the transversal for <S>
- S.orbit := [];
- S.transversal := [];
- for pnt in T.orbit do
- img := pnt / hom.conperm;
- Add( S.orbit, img );
- if pnt <> T.orbit[1] then
- gen := T.transversal[ pnt ];
- S.transversal[ img ] := pres[ Position( gens, gen ) ];
- else
- S.transversal[ img ] := S.identity;
- fi;
- od;
-
- # add a trivial stabilizer
- S.stabilizer := rec(
- generators := [],
- identity := S.identity );
-
- # go down to the next step
- S := S.stabilizer;
- T := T.stabilizer;
- top := false;
-
- od;
-
- # append the kernel to the stabilizer chain of <H>
- #N 18-Feb-92 martin 'Copy' and 'ShallowCopy' should go away
- S.generators := ShallowCopy( K.generators );
- if IsBound( K.orbit ) then
- S.orbit := ShallowCopy( K.orbit );
- S.transversal := ShallowCopy( K.transversal );
- S.stabilizer := Copy( K.stabilizer );
- fi;
-
- # give some information
- Size( H );
- InfoPermGroup1("#I TransConstHomOps.PreImagesSet returns ",
- GroupString(H,"H"),"\n");
-
- # delegate set case
- else
- H := OperationHomomorphismOps.PreImagesSet( hom, I );
-
- fi;
-
- # return the preimage
- return H;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.BlocksHomomorphism(<G>,<P>) homomorphism for the operation
- #F of a permutation group on a block system
- ##
- PermGroupOps.BlocksHomomorphism := function ( G, P )
- local hom, # homomorphism, result
- i, k; # loop variables
-
- # make the homomorphism
- hom := rec(
-
- # tags
- isGeneralMapping := true,
- domain := Mappings,
-
- # source and range
- source := G,
- range := P,
-
- # get the blocks
- blocks := P.operationDomain,
-
- # usefull information
- isMapping := true,
- isHomomorphism := true,
- isGroupHomomorphism := true,
- isBlocksHomomorphism := true,
-
- # operations record
- operations := BlocksHomomorphismOps );
-
- # add also a list that says for each element which block it lies in
- hom.reps := [];
- for i in [ 1 .. Length( hom.blocks ) ] do
- for k in hom.blocks[i] do
- hom.reps[k] := i;
- od;
- od;
-
- # return the homomorphism
- return hom;
- end;
-
- BlocksHomomorphismOps := Copy( OperationHomomorphismOps );
-
- BlocksHomomorphismOps.ImageElm := function ( hom, elm )
- local img, # image of <elm> under <hom>, result
- i; # loop variable
-
- # make the image permutation as a list
- img := [];
- for i in [ 1 .. Length( hom.blocks ) ] do
- img[i] := hom.reps[ hom.blocks[i][1] ^ elm ];
- od;
-
- # return the image as a permutation
- return PermList( img );
- end;
-
- BlocksHomomorphismOps.ImagesElm := function ( hom, elm )
- return [ hom.operations.ImageElm( hom, elm ) ];
- end;
-
- BlocksHomomorphismOps.ImagesRepresentative
- := BlocksHomomorphismOps.ImageElm;
-
- BlocksHomomorphismOps.ImagesSet := function ( hom, H )
- local I, # image of <H>, result
- S, # block stabilizer in <H>
- T, # corresponding stabilizer in <I>
- R, # temporary stabilizer
- gens, # strong generators of <H>
- imgs, # their images in <I>
- top, # 'true' if <T> is <I>
- gen, # one generator from <gens>
- pnt, # one point in the orbit <S>
- img, # the image of <pnt> in the orbit of <T>
- blockStabsOrbit, # orbit of the block stabilizers
- blockStabsTransversal, # transversals of the block stabilizers
- i; # loop variable
-
- # handle the special case that <H> is a subgroup of '<hom>.source'
- if IsDomain( H ) then
-
- # compute the generators for the image
- gens := [];
- imgs := [];
- for gen in H.generators do
- Add( gens, gen );
- Add( imgs, Image( hom, gen ) );
- od;
-
- # initialize the image group
- I := Subgroup( Parent( hom.range ), imgs );
-
- blockStabsOrbit := [];
- blockStabsTransversal := [];
-
- # start with the group
- S := H;
- T := I;
- top := true;
-
- # loop over the blocks
- for i in [ 1 .. Length( hom.blocks ) ] do
-
- # make sure that <S> has the rep. of the block as basepoint
- MakeStabChain( S, [ hom.blocks[i][1] ] );
-
- # if <S> does not already stabilize this block
- if IsBound( S.orbit )
- and S.orbit[1] = hom.blocks[i][1]
- and not IsSubsetSet( hom.blocks[i], S.orbit )
- then
-
- # add orbit and transversal to the representative lists
- Add( blockStabsOrbit, S.orbit );
- Add( blockStabsTransversal, S.transversal );
-
- # make the generators for <T>
- if not top then
- T.generators := [];
- for gen in S.generators do
- if not gen in gens then
- Add( gens, gen );
- Add( imgs, Image( hom, gen ) );
- fi;
- if imgs[ Position( gens, gen ) ] <> T.identity then
- Add( T.generators, imgs[ Position(gens,gen) ] );
- fi;
- od;
- fi;
-
- # make the orbit and the transversal of <T>
- T.orbit := [ i ];
- T.transversal := [];
- T.transversal[i] := ();
- for pnt in S.orbit do
- img := hom.reps[ pnt ];
- if not img in T.orbit then
- Add( T.orbit, img );
- gen := S.transversal[ pnt ];
- T.transversal[ img ] := imgs[ Position(gens,gen) ];
- fi;
- od;
-
- # add a trivial stabilizer to <T>
- T.stabilizer := rec(
- identity := T.identity,
- generators := [] );
-
- # make <R> the stabilizer of the block in <S>
- #N 18-Feb-91 martin 'Copy' and 'ShallowCopy' should go away
- R := ShallowCopy( Subgroup( Parent( S ), [] ) );
- R.generators := ShallowCopy( S.stabilizer.generators );
- R.orbit := [ S.orbit[1] ];
- R.transversal := [];
- R.transversal[ R.orbit[1] ] := R.identity;
- for pnt in S.orbit do
- if pnt in hom.blocks[i] and not pnt in R.orbit then
- gen := R.identity;
- while R.orbit[1] ^ gen <> pnt do
- gen := LeftQuotient(S.transversal[pnt/gen],gen);
- od;
- PermGroupOps.AddGensExtOrb( R, [gen] );
- fi;
- od;
- R.stabilizer := Copy( S.stabilizer );
-
- # prepare for the next step
- S := R;
- T := T.stabilizer;
- top := false;
-
- fi;
-
- od;
-
- # if <H> is the full group this also gives us the kernel
- if H = hom.source and not IsBound( hom.kernel ) then
- hom.kernel := S;
- hom.blockStabsOrbit := blockStabsOrbit;
- hom.blockStabsTransversal := blockStabsTransversal;
- fi;
-
- # delegate the set case
- else
- I := OperationHomomorphismOps.ImagesSet( hom, H );
-
- fi;
-
- # return the images
- return I;
- end;
-
- BlocksHomomorphismOps.PreImagesRepresentative := function ( hom, elm )
- local pre, # preimage of <elm>, result
- pnt, # one point of a set stabilizer
- i; # loop variable
-
- # make sure that we know the iterated set stabilizers
- if not IsBound( hom.blockStabsOrbit ) then
- Image( hom );
- fi;
-
- # start with the identity as preimage
- pre := hom.source.identity;
-
- # loop over the blocks and their interated set stabilizers
- for i in [ 1 .. Length( hom.blockStabsOrbit ) ] do
-
- # find a rep. mapping 'blocks[<i>]' to 'blocks[<i>^<elm>]^(<pre>^-1)'
- pnt := First( hom.blocks[ hom.reps[hom.blockStabsOrbit[i][1]]^elm ],
- pnt -> pnt / pre in hom.blockStabsOrbit[i] );
- while hom.blockStabsOrbit[i][1] ^ pre <> pnt do
- pre := LeftQuotient(hom.blockStabsTransversal[i][pnt/pre],pre);
- od;
-
- od;
-
- # return the preimage
- return pre;
- end;
-
- BlocksHomomorphismOps.PreImagesSet := function ( hom, I )
- local H; # preimage of <I> under <hom>, result
-
- # make sure we know a stabilizer chain for <I>
- MakeStabChain( I );
-
- # now compute the preimage by iterating
- H := BlocksHomomorphismOps.PreImagesSetStab( hom, I );
-
- # return the preimage
- return H;
- end;
-
- BlocksHomomorphismOps.PreImagesSetStab := function ( hom, I )
- local H, # preimage of <I> under <hom>, result
- pnt, # rep. of the block that is the basepoint <I>
- gen, # one generator of <I>
- pre; # a representative of its preimages
-
- # if <I> is trivial is preimage is the kernel of <hom>
- if I.generators = [] then
- H := ShallowCopy( Kernel( hom ) );
- H.generators := ShallowCopy( H.generators );
- if IsBound( H.orbit ) then
- H.orbit := ShallowCopy( H.orbit );
- H.transversal := ShallowCopy( H.transversal );
- H.stabilizer := Copy( H.stabilizer );
- fi;
-
- # else begin with the preimage $H_{block[i]}$ of the stabilizer $I_{i}$,
- # adding preimages of the generators of $I$ to those of $H_{block[i]}$
- # gives us generators for $H$. Because $H_{block[i][1]} \<= H_{block[i]}$
- # the stabilizer chain below $H_{block[i][1]}$ is already complete, so we
- # only have to care about the top level with the basepoint $block[i][1]$.
- else
- H := BlocksHomomorphismOps.PreImagesSetStab( hom, I.stabilizer );
- pnt := hom.blocks[ I.orbit[1] ][1];
- MakeStabChain( H, [ pnt ] );
- ExtendStabChain( H, [ pnt ] );
- for gen in I.generators do
- pre := PreImagesRepresentative( hom, gen );
- if not IsBound( H.transversal[ pnt ^ pre ] ) then
- PermGroupOps.AddGensExtOrb( H, [ pre ] );
- fi;
- od;
-
- fi;
-
- # return the preimage
- return H;
- end;
-
- BlocksHomomorphismOps.KernelGroupHomomorphism := function ( hom )
-
- # when we compute the image we will also get the kernel
- Image( hom );
-
- # return the kernel
- return hom.kernel;
- end;
-
-
- #############################################################################
- ##
- #E Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
- ##
- ## Local Variables:
- ## mode: outline
- ## outline-regexp: "#F\\|#V\\|#E\\|#R"
- ## fill-column: 73
- ## fill-prefix: "## "
- ## eval: (hide-body)
- ## End:
- ##
-
-
-
-