Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346############################################################################# ## #W gp2obj.gi GAP4 package `XMod' Chris Wensley #W & Murat Alp #Y Copyright (C) 2001-2017, Chris Wensley et al, #Y School of Computer Science, Bangor University, U.K. ## ## This file contains generic methods for (pre-)crossed modules and ## (pre-)cat1-groups. ## ############################################################################## ## ## Global constants which determine whether to read cat1data.g ## CAT1_LIST_CLASS_SIZES for groups of size <= CAT1_LIST_MAX_SIZE ## CAT1_LIST_MAX_SIZE := 70; CAT1_LIST_CLASS_SIZES := List( [1..CAT1_LIST_MAX_SIZE], n -> NumberSmallGroups(n) ); CAT1_LIST_LOADED := false; CAT1_LIST := [ ]; ############################################################################## ## #M IsPerm2DimensionalGroup . . check whether source and range are perm groups #M IsFp2DimensionalGroup . . . check whether source and range are fp groups #M IsPc2DimensionalGroup . . . check whether source and range are pc groups ## InstallMethod( IsPerm2DimensionalGroup, "generic method for 2d-group objects", true, [ Is2DimensionalGroup ], 0, function( obj ) return ( IsPermGroup( Source( obj ) ) and IsPermGroup( Range( obj ) ) ); end ); InstallMethod( IsFp2DimensionalGroup, "generic method for 2d-group objects", true, [ Is2DimensionalGroup ], 0, function( obj ) return ( IsFpGroup( Source( obj ) ) and IsFpGroup( Range( obj ) ) ); end ); InstallMethod( IsPc2DimensionalGroup, "generic method for 2d-group objects", true, [ Is2DimensionalGroup ], 0, function( obj ) return ( IsPcGroup( Source( obj ) ) and IsPcGroup( Range( obj ) ) ); end ); ############################################################################# ## #M IsPreXMod . . . . . . . . check that the first crossed module axiom holds ## InstallMethod( IsPreXMod, "generic method for 2d-group", true, [ Is2DimensionalGroup ], 0, function( P ) local Xsrc, Xrng, bdy, a, aut, act, gensrc, ngsrc, genrng, ngrng, ssrc, x1, y1, z1, x2, y2, z2, w2; if not IsPreXModObj( P ) then return false; fi; Xrng := Range( P ); genrng := GeneratorsOfGroup( Xrng ); ngrng := Length( genrng ); Xsrc := Source( P ); gensrc := GeneratorsOfGroup( Xsrc ); ngsrc := Length( gensrc ); ssrc := Size( Xsrc ); bdy := Boundary( P ); # Check P.boundary: P.source -> P.range if not ( ( Source( bdy ) = Xsrc ) and ( Range( bdy ) = Xrng ) ) then Info( InfoXMod, 2, "Error: require X.boundary : X.source -> X.range" ); return false; fi; # checking IsHomomorphism(bdy) gives cokernel error when Xsrc = [ ] if ( ssrc > 1 ) then if not IsGroupHomomorphism( bdy ) then Info( InfoXMod, 2, "Error: the boundary map is NOT a homomorphism!" ); return false; fi; fi; act := XModAction( P ); aut := Range( act ); # Check X.aut is a group of automorphisms X.source -> X.source if not ( IsGroup( aut ) ) then Info( InfoXMod, 2, "Error: group of actions on X.source does not exist!" ); return false; fi; if ( aut = Group( IdentityMapping( Xsrc ) ) ) then SetIsTrivialAction2DimensionalGroup( P, true ); else a := GeneratorsOfGroup( aut )[1]; if not ( ( Source( a ) = Xsrc ) and ( Range( a ) = Xsrc ) and IsBijective( a ) ) then Info( InfoXMod, 2, "Require automorphism X.aut.1 on X.source" ); return false; fi; fi; # Check X.action: X.range -> X.aut if not ( ( Source( act ) = Xrng ) and ( Range( act ) = aut ) ) then Info( InfoXMod, 2, "Error: require X.action : X.range -> X.aut" ); return false; fi; if ( Size( aut ) = 1 ) then Info( InfoXMod, 2, "X.action trivial => not checking a homomorphism!" ); else if not IsGroupHomomorphism( act ) then Info( InfoXMod, 2, " X.action is not a homomorphism|" ); return false; fi; fi; Info( InfoXMod, 3, "Checking CM1) bdy(x2^x1) = (bdy(x2))^x1 " ); for x1 in genrng do for x2 in gensrc do # Print( "x1,x2 = ", x1, ", ", x2, "\n" ); y1 := ( x2 ^ ( x1^act ) ) ^ bdy; z1 := ( x2 ^ bdy ) ^ x1; if ( y1 <> z1 ) then Info( InfoXMod, 3, "CM1) fails at x1 = ", x1, ", x2 = ", x2, "\n", " bdy(x2^x1) = ", y1, "\n", "(bdy(x2))^x1 = ", z1 ); return false; fi; od; od; return true; end ); ############################################################################## ## #M \=( <P>, <Q> ) . . . . . . . . test if two pre-crossed modules are equal ## InstallMethod( \=, "generic method for two pre-crossed modules", IsIdenticalObj, [ IsPreXMod, IsPreXMod ], 0, function ( P, Q ) return ( ( Boundary(P) = Boundary(Q) ) and ( XModAction(P) = XModAction(Q) ) ); end ); ############################################################################## ## #M Size( <P> ) . . . . . . . . . . . . . . . . size for a pre-crossed module ## InstallOtherMethod( Size, "generic method for a 2d-object", [ Is2DimensionalDomain ], 20, function ( obj ) return [ Size( Source( obj ) ), Size( Range( obj ) ) ]; end ); ############################################################################# ## #M IsTrivialAction2DimensionalGroup . . . . check whether action is trivial ## InstallMethod( IsTrivialAction2DimensionalGroup, "generic method for pre-crossed modules", true, [ IsPreXMod ], 0, function( PM ) local act, genrng, onesrc; act := XModAction( PM ); genrng := GeneratorsOfGroup( Range( PM ) ); onesrc := IdentityMapping( Source( PM ) ); return ForAll( genrng, r -> ( Image( act, r ) = onesrc ) ); end ); ############################################################################## ## #M PreXModObj( <bdy>, <act> ) . . . . . . . . . . . make a pre-crossed module ## InstallMethod( PreXModObj, "for homomorphism and action", true, [ IsGroupHomomorphism, IsGroupHomomorphism ], 0, function( bdy, act ) local type, PM, ok, src, rng, aut, name; src := Source( bdy ); rng := Range( bdy ); if not ( rng = Source( act ) ) then Error( "require Range( bdy ) = Source( act )" ); fi; aut := Range( act ); if not IsGroupOfAutomorphisms( aut ) then Error( "Range( act ) must be a group of automorphisms" ); fi; if ( IsPermGroup( src ) and IsPermGroup( rng ) ) then type := PermPreXModObjType; elif ( IsPcGroup( src ) and IsPcGroup( rng ) ) then type := PcPreXModObjType; else type := PreXModObjType; fi; PM := rec(); ObjectifyWithAttributes( PM, type, Source, src, Range, rng, Boundary, bdy, XModAction, act, IsPreXModDomain, true, Is2DimensionalGroup, true ); if not IsPreXMod( PM ) then Info( InfoXMod, 1, "Warning: not a pre-crossed module." ); else ok := IsXMod( PM ); # for running properly the function AllXMods fi; # name := Name( PM ); ## check the types if ( IsPermGroup(src) and IsPermGroup(rng) ) then SetIsPerm2DimensionalGroup( PM, true ); elif ( IsPcGroup(src) and IsPcGroup(rng) ) then SetIsPc2DimensionalGroup( PM, true ); fi; return PM; end ); ############################################################################# ## #M ImageElmXModAction( <pxmod>, <r>, <s> ) pre-xmod module action of s on r ## InstallMethod( ImageElmXModAction, "method for a precrossed module", true, [ Is2DimensionalDomain, IsObject, IsObject ], 0, function( PM, s, r ) local actr; if ( HasIsPreXModWithObjects(PM) and IsPreXModWithObjects(PM) ) then actr := ImageElm( XModAction( PM ), r )![1]; return ImageElm( actr, s ); else return ImageElm( ImageElm( XModAction(PM), r ), s ); fi; end ); ############################################################################# ## #M ExternalSetXMod( <pxm> ) . . . . . . . source group as a range group set ## InstallMethod( ExternalSetXMod, "method for a precrossed module", true, [ IsPreXMod ], 0, function( PM ) local rng, genR, act; rng := Range( PM ); genR := GeneratorsOfGroup( rng ); act := XModAction( PM ); return ExternalSet( rng, Source(PM), genR, List( genR, g -> Image(act,g) ) ); end ); ############################################################################# ## #M String, ViewString, PrintString, ViewObj, PrintObj ## . . . . . . . . . . . . . . . . . . . . . . . for two-dimensional domains ## InstallMethod( String, "for a 2d-domain", true, [ Is2DimensionalDomain ], 0, function( g2d ) return( STRINGIFY( "[", String( Source(g2d) ), " -> ", String( Range(g2d) ), "]" ) ); end ); InstallMethod( ViewString, "for a 2d-domain", true, [ Is2DimensionalDomain ], 0, String ); InstallMethod( PrintString, "for a 2d-domain", true, [ Is2DimensionalDomain ], 0, String ); InstallMethod( ViewObj, "for a 2d-domain", true, [ Is2DimensionalDomain ], 0, function( g2d ) if HasName( g2d ) then Print( Name( g2d ), "\n" ); elif ( HasIsPreXModDomain( g2d ) and IsPreXModDomain( g2d ) ) then Print( "[", Source( g2d ), "->", Range( g2d ), "]" ); elif ( HasIsPreCat1Domain( g2d ) and IsPreCat1Domain( g2d ) ) then Print( "[", Source( g2d ), "=>", Range( g2d ), "]" ); else TryNextMethod(); fi; end ); InstallMethod( PrintObj, "for a 2d-domain", true, [ Is2DimensionalDomain ], 0, function( g2d ) if HasName( g2d ) then Print( Name( g2d ), "\n" ); elif ( HasIsPreXModDomain( g2d ) and IsPreXModDomain( g2d ) ) then Print( "[", Source( g2d ) ); if IsGroupoid( Source( g2d ) ) then Print( "\n-> " ); else Print( " -> " ); fi; Print( Range( g2d ), "]" ); elif ( HasIsPreCat1Domain( g2d ) and IsPreCat1Domain( g2d ) ) then Print( "[", Source( g2d ) ); if IsGroupoid( Source( g2d ) ) then Print( "\n=> " ); else Print( " => " ); fi; Print( Range( g2d ), "]" ); else TryNextMethod(); fi; end ); ############################################################################# ## #F Display( <g2d> ) . . . . . . . . . . . . . . print details of a 2d-group ## InstallMethod( Display, "method for prexmods and precat2groups", true, [ Is2DimensionalGroup ], 20, function( g2d ) local name, bdy, act, aut, len, i, ispar, src, rng, gensrc, genrng, ker, genker, mor, triv, imact, a, t, h, e, b, k, imt, imh, ime, imb, imk; src := Source( g2d ); rng := Range( g2d ); if ( HasName(src) and HasName(rng) ) then name := Name( g2d ); else name := "[??->??]"; fi; gensrc := GeneratorsOfGroup( src ); genrng := GeneratorsOfGroup( rng ); if ( HasIsPreXMod( g2d ) and IsPreXMod( g2d ) ) then if ( HasIsXMod( g2d ) and IsXMod( g2d ) ) then Print( "\nCrossed module " ); else Print( "\nPre-crossed module " ); fi; elif ( HasIsPreCat1Group( g2d ) and IsPreCat1Group( g2d ) ) then if ( HasIsCat1Group( g2d ) and IsCat1Group( g2d ) ) then Print( "\nCat1-group " ); else Print( "\nPre-cat1-group " ); fi; else Print( "WARNING: neither a PreXMod nor a PreCat1Group" ); fi; if HasName( g2d ) then Print( Name(g2d), " :- \n" ); else Print( ":- \n" ); fi; ispar := not HasParent( src ); if ( ispar and HasName( src ) ) then Print( ": Source group ", src ); elif ( ispar and HasName( Parent( src ) ) ) then Print( ": Source group has parent ( ", Parent( src), " ) and" ); else Print( ": Source group" ); fi; Print( " has generators:\n" ); Print( " ", gensrc, "\n" ); ispar := not HasParent( rng ); if ( ispar and HasName( rng ) ) then Print( ": Range group ", rng ); elif ( ispar and HasName( Parent( rng ) ) ) then Print( ": Range group has parent ( ", Parent( rng ), " ) and" ); else Print( ": Range group" ); fi; Print( " has generators:\n" ); Print( " ", genrng, "\n" ); if ( HasIsPreXMod( g2d ) and IsPreXMod( g2d ) ) then Print( ": Boundary homomorphism maps source generators to:\n" ); bdy := Boundary( g2d ); Print( " ", List( gensrc, s -> Image( bdy, s ) ), "\n" ); act := XModAction( g2d ); imact := List( genrng, r -> Image( act, r ) ); aut := Range( act ); triv := ( aut = Group( InclusionMappingGroups( src, src ) ) ); len := Length( genrng ); if ( len = 0 ) then triv := true; else for i in [1..len] do a := imact[i]; od; fi; if not triv then Print( ": Action homomorphism maps" ); Print( " range generators to automorphisms:\n" ); for i in [1..len] do Print( " ", genrng[i], " --> { source gens --> " ); Print( List( gensrc, s -> Image( imact[i], s ) ), " }\n" ); od; fi; if triv then Print( " The automorphism group is trivial\n" ); else if ( len = 1 ) then Print( " This automorphism generates" ); else Print( " These ", len, " automorphisms generate" ); fi; Print( " the group of automorphisms.\n" ); fi; else ## g2d is at least a PreCat1Group ker := Kernel( g2d ); genker := GeneratorsOfGroup( ker ); t := TailMap( g2d ); h := HeadMap( g2d ); e := RangeEmbedding( g2d ); b := Boundary( g2d ); k := KernelEmbedding( g2d ); imt := List( gensrc, x -> Image( t, x ) ); imh := List( gensrc, x -> Image( h, x ) ); ime := List( genrng, x -> Image( e, x ) ); imb := List( genker, x -> Image( b, x ) ); imk := List( genker, x -> Image( k, x ) ); Print( ": tail homomorphism maps source generators to:\n" ); Print( " ", imt, "\n" ); Print( ": head homomorphism maps source generators to:\n" ); Print( " ", imh, "\n" ); Print( ": range embedding maps range generators to:\n" ); Print( " ", ime, "\n" ); if ( Size( ker ) = 1 ) then Print( ": the kernel is trivial.\n" ); else Print( ": kernel has generators:\n" ); Print( " ", genker, "\n" ); Print( ": boundary homomorphism maps generators of kernel to:\n" ); Print( " ", imb, "\n" ); Print( ": kernel embedding maps generators of kernel to:\n" ); Print( " ", imk, "\n" ); fi; fi; if ( HasIsXMod( g2d ) and IsXMod( g2d ) and HasCat1GroupOfXMod( g2d ) ) then Print( ": associated cat1-group is ", Cat1GroupOfXMod( g2d ), "\n" ); elif ( HasIsCat1Group( g2d ) and IsCat1Group( g2d ) and HasXModOfCat1Group( g2d ) ) then Print( ": associated crossed module is ", XModOfCat1Group( g2d ), "\n" ); fi; Print( "\n" ); end ); ############################################################################# ## #M IdGroup . . . . . . . . . . . . . . . . . . . . for a 2Dimensional-domain #M StructureDescription . . . . . . . . . . . . . for a 2Dimensional-domain ## InstallOtherMethod( IdGroup, "method for a 2d-domain", true, [ Is2DimensionalDomain ], 0, function( dom ) return [ IdGroup( Source(dom) ), IdGroup( Range(dom) ) ]; end ); InstallOtherMethod( StructureDescription, "method for a 2d-domain", true, [ Is2DimensionalDomain ], 0, function( dom ) return [ StructureDescription( Source(dom) ), StructureDescription( Range(dom) ) ]; end ); ############################################################################# ## #M Name . . . . . . . . . . . . . . . . . . . . . for a 2Dimensional-domain ## InstallMethod( Name, "method for a 2d-domain", true, [ Is2DimensionalDomain ], 0, function( dom ) local nsrc, nrng, name, arrow; if HasName( Source( dom ) ) then nsrc := Name( Source( dom ) ); else nsrc := ".."; fi; if HasName( Range( dom ) ) then nrng := Name( Range( dom ) ); else nrng := ".."; fi; if ( HasIsPreXModDomain( dom ) and IsPreXModDomain( dom ) ) then arrow := "->"; elif ( HasIsPreCat1Domain( dom ) and IsPreCat1Domain( dom ) ) then arrow := "=>"; else arrow := "->-"; fi; name := Concatenation( "[", nsrc, arrow, nrng, "]" ); SetName( dom, name ); return name; end ); ############################################################################# ## #M PreXModByBoundaryAndAction ## InstallMethod( PreXModByBoundaryAndAction, "pre-crossed module from boundary and action maps", true, [ IsGroupHomomorphism, IsGroupHomomorphism ], 0, function( bdy, act ) local rng, src, genrng, gensrc, aut, genaut, imact, i, a0, ima, a; src := Source( bdy ); gensrc := GeneratorsOfGroup( src ); rng := Range( bdy ); genrng := GeneratorsOfGroup( rng ); if not ( Source( act ) = rng ) then Info( InfoXMod, 2, "The range group is not the source of the action." ); return fail; fi; aut := Range( act ); genaut := GeneratorsOfGroup( aut ); if not IsGroupOfAutomorphisms( aut ) then Info( InfoXMod, 2, "<aut> is not a group of automorphisms" ); return fail; fi; for a in genaut do if not ( ( Source( a ) = src ) and ( Range( a ) = src ) ) then Info( InfoXMod, 2, "error in source and range of automorphism" ); return fail; fi; od; if not ( One( aut ) = IdentityMapping( src ) ) then Info( InfoXMod, 2, "aut.identity <> IdentityMapping( src )" ); return fail; fi; imact := List( genrng, r -> Image( act, r ) ); for i in [ 1..Length( imact ) ] do a0 := imact[i]; ima := List( gensrc, s -> Image( a0, s ) ); a := GroupHomomorphismByImages( src, src, gensrc, ima ); imact[i] := a; od; return PreXModObj( bdy, act ); end ); ############################################################################# ## #M IsPreCat1Group check that the first pre-cat1-group axiom holds ## InstallMethod( IsPreCat1Group, "generic method for 2dim-group", true, [ Is2DimensionalGroup ], 0, function( C1G ) local Csrc, Crng, x, e, t, h, idrng, he, te, kert, kerh, kerth; if not IsPreCat1Obj( C1G ) then return false; fi; Crng := Range( C1G ); h := HeadMap( C1G ); t := TailMap( C1G ); e := RangeEmbedding( C1G ); # checking the first condition of cat-1 group idrng := IdentityMapping( Crng ); he := CompositionMapping( h, e ); te := CompositionMapping( t, e ); if not ( te = idrng ) then Print( "te <> range identity \n" ); return false; fi; if not ( he = idrng ) then Print( "he <> range identity \n" ); return false; fi; return true; end ); ############################################################################## ## #M \=( <C1>, <C2> ) . . . . . . . . . . test if two pre-cat1-groups are equal ## InstallMethod( \=, "generic method for pre-cat1-groups", IsIdenticalObj, [ IsPreCat1Group, IsPreCat1Group ], 0, function( C1, C2 ) return ( ( TailMap(C1) = TailMap(C2) ) and ( HeadMap(C1) = HeadMap(C2) ) and ( RangeEmbedding(C1) = RangeEmbedding(C2) ) ); end ); ############################################################################## ## #M SourceEmbedding . . . . . . . . . . . . . . . . . . . for a pre-cat1-group ## InstallMethod( SourceEmbedding, "for a pre-cat1-group", true, [ IsPreCat1Group ], 0, function( C1G ) local G, spi, dpi, info, emb, pxm, mgi, sc, sx, src, rng; G := Source( C1G ); spi := HasSemidirectProductInfo( G ); dpi := HasDirectProductInfo( G ); if spi then info := SemidirectProductInfo( G ); emb := info!.embeddings[2]; Print("case1: ", MappingGeneratorsImages(emb), "\n" ); elif dpi then info := DirectProductInfo( G ); emb := info!.embeddings[2]; Print("case2: ", MappingGeneratorsImages(emb), "\n" ); else pxm := PreXModOfPreCat1Group( C1G ); sc := Source( C1G ); sx := Source( pxm ); if IsSubgroup( sc, sx ) then emb := InclusionMappingGroups( sc, sx ); Print("case3: ", MappingGeneratorsImages(emb), "\n" ); else Error( "case still to be implemented" ); fi; fi; src := Source( emb ); rng := ImagesSource( emb ); mgi := MappingGeneratorsImages( emb ); return GroupHomomorphismByImages( src, rng, mgi[1], mgi[2] ); end ); ############################################################################## ## #M PreCat1Obj . . . . . . . . . . . . . . . . . . . . . make a pre-cat1-group ## InstallMethod( PreCat1Obj, "for tail, head, embedding", true, [ IsGroupHomomorphism, IsGroupHomomorphism, IsGroupHomomorphism ], 0, function( t, h, e ) local src, rng, type, C1G, ok, name; src := Source( h ); rng := Range( h ); if not ( ( src = Source( t ) ) and ( rng = Range( t ) ) ) then Error( "tail & head must have same source and range" ); fi; if not ( ( Source( e ) = rng ) and ( Range( e ) = src ) ) then Error( "tail, embedding must have opposite source and range" ); fi; if ( IsPermGroup( src ) and IsPermGroup( rng ) ) then type := PermPreCat1ObjType; elif ( IsPcGroup( src ) and IsPcGroup( rng ) ) then type := PcPreCat1ObjType; else type := PreCat1ObjType; fi; C1G := rec(); ObjectifyWithAttributes( C1G, type, Source, Source( t ), Range, Range( t ), TailMap, t, HeadMap, h, RangeEmbedding, e, IsPreCat1Domain, true, Is2DimensionalGroup, true ); ok := IsPreCat1Group( C1G ); # name := Name( C1G ); if not ok then Error( "not a pre-cat1-group" ); fi; ok := IsEndomorphismPreCat1Group( C1G ); ok := IsCat1Group( C1G ); return C1G; end ); ############################################################################## ## #M Elements( <P> ) . . . . . . . . . . . . elements for a pre-crossed module ## ## replaced by Enumerator ??? ############################################################################# ## #M ReverseCat1Group for a pre-cat1-group ## InstallMethod( ReverseCat1Group, "method for a cat1-group", true, [ IsPreCat1Group ], 0, function( C1G ) local rev; rev := PreCat1Group( HeadMap(C1G), TailMap(C1G), RangeEmbedding(C1G ) ); SetReverseCat1Group( rev, C1G ); return rev; end ); ############################################################################# ## #F PreCat1Group( <t>, <h>, <e> ) pre-cat1-group from given tail, head, embed #F PreCat1Group( <t>, <h> ) pre-cat1-group from tail, head endomorphisms ## InstallGlobalFunction( PreCat1Group, function( arg ) local nargs, usage, C1G; nargs := Length( arg ); usage := "standard usage: PreCat1Group( tail, head [,embed] );"; if not ForAll( arg, a -> IsGroupHomomorphism(a) ) then Error( usage ); fi; # one endomorphism if ( ( nargs=1 ) and IsEndoMapping( arg[1] ) ) then return PreCat1GroupByEndomorphisms( arg[1], arg[1] ); # two endomorphisms elif ( nargs=2 ) then if ( IsEndoMapping( arg[1] ) and IsEndoMapping( arg[2] ) ) then return PreCat1GroupByEndomorphisms( arg[1], arg[2] ); elif ( ImagesSource( arg[1] ) = Source( arg[2] ) ) then return PreCat1GroupByTailHeadEmbedding( arg[1], arg[1], arg[2] ); fi; # two homomorphisms and an embedding elif ( nargs=3 ) then return PreCat1GroupByTailHeadEmbedding( arg[1], arg[2], arg[3] ); fi; # other alternatives not allowed Error( usage ); end ); ############################################################################## ## #M PreCat1GroupOfPreXMod . . convert a pre-crossed module to a pre-cat1-group ## InstallMethod( PreCat1GroupOfPreXMod, "convert a pre-crossed module to a pre-cat1-group", true, [ IsPreXMod ], 0, function( XM ) local Xsrc, Xrng, Xact, Xbdy, gensrc, genrng, one, imbdy, info, G, genG, t, h, f, eR, eS, imeR, imeS, projS, imt, imh, ime, imf, C; if not ( IsPermPreXMod( XM ) or IsPcPreXMod( XM ) ) then Print( "#W: should be a perm-xmod or a pc-xmod\n" ); return fail; fi; Xsrc := Source( XM ); gensrc := GeneratorsOfGroup( Xsrc ); Xrng := Range( XM ); genrng := GeneratorsOfGroup( Xrng ); one := One( Xrng ); Xact := XModAction( XM ); Xbdy := Boundary( XM ); if IsTrivialAction2DimensionalGroup( XM ) then Info( InfoXMod, 2, "Using direct product: ", Xrng, " x ", Xsrc ); G := DirectProduct( Xrng, Xsrc ); info := DirectProductInfo( G ); if ( HasName( Xsrc ) and HasName( Xrng ) ) then SetName( G, Concatenation( Name( Xrng ), Name( Xsrc ) ) ); fi; genG := GeneratorsOfGroup( G ); gensrc := GeneratorsOfGroup( Xsrc ); genrng := GeneratorsOfGroup( Xrng ); imbdy := List( gensrc, s -> Image( Xbdy, s ) ); imt := Concatenation( genrng, List( gensrc, s -> one ) ); imh := Concatenation( genrng, imbdy ); t := GroupHomomorphismByImages( G, Xrng, genG, imt ); h := GroupHomomorphismByImages( G, Xrng, genG, imh ); eR := Embedding( G, 1 ); eR := AsGroupGeneralMappingByImages( eR ); else Info( InfoXMod, 2, "Using semidirect product: ", Xrng, " |X ", Xsrc ); G := SemidirectProduct( Xrng, Xact, Xsrc ); info := SemidirectProductInfo( G ); if ( HasName( Xsrc ) and HasName( Xrng ) ) then SetName( G, Concatenation ( Name(Xrng), " |X ", Name(Xsrc) ) ); else SetName( G, "..|X.." ); fi; genG := GeneratorsOfGroup( G ); eR := Embedding( G, 1 ); imeR := List( genrng, r -> Image( eR, r ) ); eS := Embedding( G, 2 ); imeS := List( gensrc, s -> Image( eS, s ) ); t := Projection( G ); imt := List( genG, g -> Image( t, g ) ); projS := List( imt, r -> Image( eR, r^-1 ) ); projS := List( [ 1..Length( genG ) ], i -> projS[i] * genG[i] ); projS := List( projS, x -> PreImagesRepresentative( eS, x ) ); imh := List( [ 1..Length( genG ) ], i -> imt[i] * Image( Xbdy, projS[i] ) ); h := GroupHomomorphismByImages( G, Xrng, genG, imh ); fi; SetSourceEmbedding( XM, eR ); C := PreCat1GroupByTailHeadEmbedding( t, h, eR ); if HasName( XM ) then SetName( C, Concatenation( "cat1(", Name( XM ), ")" ) ); fi; return C; end ); ############################################################################# ## #M IsXMod check that the second crossed module axiom holds ## InstallMethod( IsXMod, "generic method for pre-crossed modules", true, [ IsPreXMod ], 0, function( XM ) local gensrc, genrng, x2, y2, w2, z2, hom, act; hom := Boundary( XM ); act := XModAction( XM ); gensrc := GeneratorsOfGroup( Source( XM ) ); genrng := GeneratorsOfGroup( Range( XM ) ); for x2 in gensrc do for y2 in gensrc do # Print( "x2,y2 = ", x2, ", ", y2, "\n" ); z2 := x2 ^ ((y2 ^ hom) ^ act); w2 := x2 ^ y2; if ( z2 <> w2 ) then Info( InfoXMod, 2, "CM2) fails at x2 = ", x2, ", y2 = ", y2, "\n", "x2^(hom(y2)) = ", z2, "\n"," x2^y2 = ", w2, "\n" ); return false; fi; od; od; return true; end ); ############################################################################# ## #M XModByBoundaryAndAction ## InstallMethod( XModByBoundaryAndAction, "crossed module from boundary and action maps", true, [ IsGroupHomomorphism, IsGroupHomomorphism ], 0, function( bdy, act ) local PM; PM := PreXModByBoundaryAndAction( bdy, act ); if not IsXMod( PM ) then Error( "this boundary and action only defines a pre-crossed module" ); fi; return PM; end ); ############################################################################# ## #M XModByTrivialAction ## InstallMethod( XModByTrivialAction, "crossed module with trivial action", true, [ IsGroupHomomorphism ], 0, function( f ) local R, ZR, S, XM, aut, act, name; S := Source( f ); if not IsAbelian( S ) then Error( "the source of f must be abelian" ); fi; R := Range( f ); ZR := Centre( R ); if not IsSubgroup( ZR, Image( f, S ) ) then Error( "image of source must lie in the centre of range" ); fi; aut := Group( IdentityMapping( S ) ); act := MappingToOne( R, aut ); XM := XModByBoundaryAndAction( f, act ); SetIsTrivialAction2DimensionalGroup( XM, true ); return XM; end ); ############################################################################## ## #F XModByNormalSubgroup create a crossed module from normal N in G ## InstallMethod( XModByNormalSubgroup, "conjugation crossed module", true, [ IsGroup, IsGroup ], 0, function( G, N ) local XM, bdy, act, aut, genrng, gensrc, name, a, triv, idsrc, autgen, imautgen, phi, j, g, n, genN, f2pN, imgenN; if not IsNormal( G, N ) then return fail; fi; genrng := GeneratorsOfGroup( G ); gensrc := GeneratorsOfGroup( N ); bdy := GroupHomomorphismByImages( N, G, gensrc, gensrc ); autgen := [ ]; for g in genrng do imautgen := List( gensrc, n -> n^g ); a := GroupHomomorphismByImages( N, N, gensrc, imautgen ); Add( autgen, a ); od; if ( Length( genrng ) = 0 ) then idsrc := IdentityMapping( N ); aut := Group( idsrc ); Info( InfoXMod, 2, "Group of conjugations has size ", Size( aut ) ); else aut := Group( autgen ); fi; SetIsGroupOfAutomorphisms( aut, true ); act := GroupHomomorphismByImages( G, aut, genrng, autgen ); XM := PreXModObj( bdy, act ); SetIsNormalSubgroup2DimensionalGroup( XM, true ); if ( Length( autgen ) = 0 ) then SetIsTrivialAction2DimensionalGroup( XM, true ); fi; return XM; end ); ############################################################################# ## #F XModByCentralExtension xmod from surjection with central kernel ## InstallMethod( XModByCentralExtension, "central extension crossed module", true, [ IsGroupHomomorphism ], 0, function( hom ) local rng, src, Zsrc, ker, gensrc, ngsrc, imhom, genrng, autgen, j, imsrc, aut, act, XM, ok, idsrc; if not IsSurjective( hom ) then Error( "homomorphism must be surjective" ); fi; src := Source( hom ); rng := Range( hom ); Zsrc := Centre( src ); ker := Kernel( hom ); if not IsSubgroup( Zsrc, ker ) then Error( "Kernel of surjection is not central" ); fi; gensrc := GeneratorsOfGroup( src ); ngsrc := Length( gensrc ); imhom := List( gensrc, s -> Image( hom, s ) ); genrng := GeneratorsOfGroup( rng ); autgen := ListWithIdenticalEntries( ngsrc, 0 ); for j in [1..ngsrc] do imsrc := List( gensrc, s -> s^gensrc[j] ); autgen[j] := GroupHomomorphismByImages( src, src, gensrc, imsrc ); od; aut := Group( autgen ); SetIsGroupOfAutomorphisms( aut, true ); Info( InfoXMod, 2, "Group of conjugations has size ", Size(aut) ); act := GroupHomomorphismByImages( rng, aut, imhom, autgen ); if ( not IsGroupHomomorphism( act ) ) then Error( "action is not a homomorphism" ); fi; XM := PreXModObj( hom, act ); SetIsCentralExtension2DimensionalGroup( XM, true ); idsrc := IdentityMapping( src ); if ForAll( autgen, a -> ( a = idsrc ) ) then SetIsTrivialAction2DimensionalGroup( XM, true ); fi; ok := IsXMod( XM ); return XM; end ); ############################################################################# ## #M XModByAbelianModule( <abmod> ) crossed module [zero : abmod -> grp] ## InstallMethod( XModByAbelianModule, "abelian module crossed module", true, [ IsAbelianModule ], 0, function( abmod ) local aut, act, z; act := AbelianModuleAction( abmod ); z := MappingToOne( AbelianModuleGroup( abmod ), Source( act ) ); return XModByBoundaryAndAction( z, act ); end ); ############################################################################# ## #M XModByGroupOfAutomorphisms crossed module [G -> A] ## InstallMethod( XModByGroupOfAutomorphisms, "automorphism crossed module", true, [ IsGroup, IsGroupOfAutomorphisms ], 0, function( G, A ) local genA, ispc, a2p, p2a, a, ima, genG, oneP, P, genP, bdy, img, imbdy, g, idG, abelian, XM; ispc := IsPcGroup( G ); if ispc then a2p := IsomorphismPcGroup( A ); ispc := not ( a2p = fail ); else a2p := IsomorphismSmallPermGroup( A ); fi; P := ImagesSource( a2p ); if ( not HasName( P ) and HasName( A ) ) then SetName( P, Concatenation( "P", Name( A ) ) ); fi; genA := GeneratorsOfGroup( A ); genP := List( genA, a -> Image( a2p, a ) ); p2a := GroupHomomorphismByImages( P, A, genP, genA ); abelian := IsAbelian( G ); genG := GeneratorsOfGroup( G ); oneP := One( P ); if abelian then imbdy := List( genG, g -> oneP ); else imbdy := [ ]; for g in genG do ima := List( genG, h -> h^g ); a := GroupHomomorphismByImages( G, G, genG, ima ); img := Image( a2p, a ); Add( imbdy, img ); od; fi; bdy := GroupHomomorphismByImages( G, P, genG, imbdy ); XM := PreXModObj( bdy, p2a ); SetIsAutomorphismGroup2DimensionalGroup( XM, true ); if not IsXMod( XM ) then Error( "this boundary and action only defines a pre-crossed module" ); fi; return XM; end ); ############################################################################# ## #F XModByAutomorphismGroup( <G> ) crossed module [G -> Aut(G)] #F XModByAutomorphismGroup( <G>, <A> ) crossed module [G -> A] ## InstallGlobalFunction( XModByAutomorphismGroup, function( arg ) local nargs, G, A, innG, a; nargs := Length( arg ); # A not specified if ( ( nargs = 1 ) and IsGroup( arg[1] ) ) then G := arg[1]; A := AutomorphismGroup( G ); if ( not HasName( A ) and HasName( G ) ) then SetName( A, Concatenation( "Aut(", Name( G ), ")" ) ); fi; elif ( ( nargs = 2 ) and IsGroupOfAutomorphisms( arg[2] ) ) then G := arg[1]; A := arg[2]; innG := InnerAutomorphismsByNormalSubgroup( G, G ); for a in GeneratorsOfGroup( innG ) do if not ( a in A ) then Error( "arg[2] must include all inner automorphisms.\n" ); fi; od; else # alternatives not allowed Print( "usage: XModByAutomorphismGroup( G );\n" ); Print( " or: XModByAutomorphismGroup( G, A );\n" ); return fail; fi; SetIsGroupOfAutomorphisms( A, true ); return XModByGroupOfAutomorphisms( G, A ); end ); ############################################################################# ## #M XModByInnerAutomorphismGroup( <G> ) crossed module [G -> Inn(G)] ## InstallMethod( XModByInnerAutomorphismGroup, "inner automorphism xmod", true, [ IsGroup ], 0, function( G ) local A, innG, a; A := InnerAutomorphismsByNormalSubgroup( G, G ); if ( not HasName( A ) and HasName( G ) ) then SetName( A, Concatenation( "Inn(", Name( G ), ")" ) ); fi; SetIsGroupOfAutomorphisms( A, true ); return XModByGroupOfAutomorphisms( G, A ); end ); ############################################################################## ## #M XModOfCat1Group ## InstallMethod( XModOfCat1Group, "generic method for cat1-groups", true, [ IsCat1Group ], 0, function( C1 ) local X1; X1 := PreXModOfPreCat1Group( C1 ); SetIsXMod( X1, true ); SetXModOfCat1Group( C1, X1 ); SetCat1GroupOfXMod( X1, C1 ); return X1; end ); ############################################################################## ## #M Cat1GroupOfXMod ## InstallMethod( Cat1GroupOfXMod, "generic method for crossed modules", true, [ IsXMod ], 0, function( X1 ) local C1; C1 := PreCat1GroupOfPreXMod( X1 ); SetIsCat1Group( C1, true ); SetXModOfCat1Group( C1, X1 ); SetCat1GroupOfXMod( X1, C1 ); return C1; end ); ############################################################################## ## #M PeifferSubgroupPreXMod . . . . . normally generated by Peiffer commutators ## InstallMethod( PeifferSubgroupPreXMod, "generic method for pre-crossed xmods", true, [ IsPreXMod ], 0, function( PM ) local Pf, s1, s2, a1, src, gensrc, comm, bdy, act, ok, XPf; # this code mimics that of DerivedSubgroup src := Source( PM ); bdy := Boundary( PM ); act := XModAction( PM ); gensrc := GeneratorsOfGroup( src ); Pf := TrivialSubgroup( src ); for s1 in gensrc do a1 := Image( act, Image( bdy, s1 ) ); for s2 in gensrc do comm := (s2^-1)^s1 * Image( a1, s2 ); if not ( comm in Pf ) then Pf := ClosureSubgroup( Pf, comm ); fi; od; od; Pf := NormalClosure( src, Pf ); if ( Pf = src ) then Pf := src; fi; XPf := Sub2DimensionalGroup( PM, Pf, TrivialSubgroup( Range(PM) ) ); ok := IsNormal( PM, XPf ); SetPeifferSub2DimensionalGroup( PM, XPf ); return Pf; end ); ############################################################################## ## #M PeifferSubgroupPreCat1Group . . . . commutator of kernels of tail and head ## InstallMethod( PeifferSubgroupPreCat1Group, "generic method for pre-cat1-groups", true, [ IsPreCat1Group ], 0, function( PCG ) local src, kerh, kert, Pf; src := Source( PCG ); kert := Kernel( TailMap( PCG ) ); kerh := Kernel( HeadMap( PCG ) ); Pf := CommutatorSubgroup( kert, kerh ); if ( Pf = src ) then Pf := src; fi; return Pf; end ); ############################################################################## ## #M PeifferSubgroup . . . . . . . . ## InstallMethod( PeifferSubgroup, "generic method for 2d-groups", true, [ Is2DimensionalGroup ], 0, function( obj ) local P, ok, NP; if IsPreXModObj( obj ) then if IsXMod( obj ) then return Subgroup( Source( obj ), [ One( Source( obj ) ) ] ); else P := PeifferSubgroupPreXMod( obj ); NP := SubPreXMod( obj, P, TrivialSubgroup( Range(obj) ) ); ok := IsNormal( obj, NP ); return P; fi; elif IsPreCat1Obj( obj ) then if IsCat1Group( obj ) then return Subgroup( Source( obj ), [ One( Source( obj ) ) ] ); else P := PeifferSubgroupPreCat1Group( obj ); NP := SubPreCat1Group( obj, P, TrivialSubgroup( Range(obj) ) ); ok := IsNormal( obj, NP ); return P; fi; else return fail; fi; end ); ############################################################################## ## #F XModByPeifferQuotient xmod from prexmod and Peiffer subgroup ## InstallMethod( XModByPeifferQuotient, "crossed module from a pre-crossed module and Peiffer subgroup", true, [ IsPreXMod ], 0, function( PM ) local pfsub, pfxmod, name, nat, ok, FM; if IsXMod( PM ) then Info( InfoXMod, 1, "this object is already a crossed module!" ); return PM; fi; pfsub := PeifferSubgroup( PM ); if not IsNormal( Source( PM ), pfsub ) then Error( "Peiffer subgroup not normal in source group" ); fi; pfxmod := SubPreXMod( PM, pfsub, TrivialSubgroup( Range(PM) ) ); ok := IsNormal( PM, pfxmod ); if not ok then Error( "Peiffer precrossed module not normal!" ); fi; FM := FactorPreXMod( PM, pfxmod ); nat := ProjectionOfFactorPreXMod( FM ); if HasName( PM ) then name := Name( PM ); SetName( FM, Concatenation( "Peiffer(", name, ")" ) ); fi; return FM; end ); ############################################################################# ## #F XMod( <bdy>, <act> ) crossed module from given boundary & action #F XMod( <G>, <N> ) crossed module from a normal inclusion #F XMod( <surj> ) crossed module from a surjective hom #F XMod( <cat1> ) crossed module associated to a cat1-group #F XMod( <aut> ) crossed module from automorphism group #F XMod( <pxm> ) crossed module by Peiffer quotient ## InstallGlobalFunction( XMod, function( arg ) local nargs; nargs := Length( arg ); # two homomorphisms if ( ( nargs = 2 ) and IsGroupHomomorphism( arg[1] ) and IsGroupHomomorphism( arg[2] ) ) then return XModByBoundaryAndAction( arg[1], arg[2] ); # group and normal subgroup elif ( ( nargs = 2 ) and IsGroup( arg[1] ) and IsGroup( arg[2] ) and IsSubgroup( arg[1], arg[2] ) and IsNormal( arg[1], arg[2] ) ) then return XModByNormalSubgroup( arg[1], arg[2] ); # xmod plus list of objects plus boolean elif ( ( nargs = 3 ) and IsXMod( arg[1] ) and IsList( arg[2] ) and IsBool( arg[3] ) ) then return SinglePiecePreXModWithObjects( arg[1], arg[2], arg[3] ); # surjective homomorphism elif ( ( nargs = 1 ) and IsGroupHomomorphism( arg[1] ) and IsSurjective( arg[1] ) ) then return XModByCentralExtension( arg[1] ); # convert a cat1-group elif ( ( nargs = 1 ) and HasIsCat1Group( arg[1] ) and IsCat1Group( arg[1] ) ) then return PreXModOfPreCat1Group( arg[1] ); # group of automorphisms elif ( ( nargs = 1 ) and IsGroupOfAutomorphisms( arg[1] ) ) then return XModByAutomorphismGroup( arg[1] ); # just a group elif ( ( nargs = 1 ) and IsGroup( arg[1] ) ) then return XModByNormalSubgroup( arg[1], arg[1] ); # pre-crossed module elif ( ( nargs = 1 ) and IsPreXMod( arg[1] ) ) then return XModByPeifferQuotient( arg[1] ); fi; # alternatives not allowed Error( "usage: XMod( bdy, act ); or XMod( G, N );" ); end ); ############################################################################## ## #M IsSubPreXMod ## InstallMethod( IsSubPreXMod, "generic method for pre-crossed modules", true, [ Is2DimensionalGroup, Is2DimensionalGroup ], 0, function( PM, SM ) local ok, Ssrc, Srng, gensrc, genrng, s, r, r1, r2, im1, im2; if not ( IsPreXMod( PM ) and IsPreXMod( SM ) ) then return false; fi; if ( HasParent( SM ) and ( Parent( SM ) = PM ) ) then return true; fi; Ssrc := Source( SM ); Srng := Range( SM ); if not ( IsSubgroup( Source( PM ), Ssrc ) and IsSubgroup( Range( PM ), Srng ) ) then Info( InfoXMod, 3, "IsSubgroup failure in IsSubPreXMod" ); return false; fi; ok := true; gensrc := GeneratorsOfGroup( Ssrc ); genrng := GeneratorsOfGroup( Srng ); for s in gensrc do if ( Image( Boundary( PM ), s ) <> Image( Boundary( SM ), s ) ) then ok := false; fi; od; if not ok then Info( InfoXMod, 3, "boundary maps have different images" ); return false; fi; for r in genrng do r1 := Image( XModAction( PM ), r ); r2 := Image( XModAction( SM ), r ); for s in gensrc do im1 := Image( r1, s ); im2 := Image( r2, s ); if ( im1 <> im2 ) then ok := false; Info( InfoXMod, 3, "s,im1,im2 = ", [s,im1,im2] ); fi; od; od; if not ok then Info( InfoXMod, 3, "actions have different images" ); return false; fi; if ( PM <> SM ) then SetParent( SM, PM ); fi; return true; end ); ############################################################################## ## #M IsSubXMod( <XM>, <SM> ) ## InstallMethod( IsSubXMod, "generic method for crossed modules", true, [ Is2DimensionalGroup, Is2DimensionalGroup ], 0, function( XM, SM ) if not ( IsXMod( XM ) and IsXMod( SM ) ) then return false; fi; return IsSubPreXMod( XM, SM ); end ); ############################################################################## ## #M IsSubPreCat1Group ## InstallMethod( IsSubPreCat1Group, "generic method for pre-cat1-groups", true, [ Is2DimensionalGroup, Is2DimensionalGroup ], 0, function( C0, S0 ) local ok, Ssrc, Srng, gensrc, genrng, tc, hc, ec, ts, hs, es, s, r; if not ( IsPreCat1Group( C0 ) and IsPreCat1Group( S0 ) ) then return false; fi; if ( HasParent( S0 ) and ( Parent( S0 ) = C0 ) ) then return true; fi; Ssrc := Source( S0 ); Srng := Range( S0 ); if not ( IsSubgroup( Source( C0 ), Ssrc ) and IsSubgroup( Range( C0 ), Srng ) ) then Info( InfoXMod, 3, "IsSubgroup failure in IsSubPreCat1Group" ); return false; fi; ok := true; gensrc := GeneratorsOfGroup( Ssrc ); genrng := GeneratorsOfGroup( Srng ); tc := TailMap(C0); hc := HeadMap(C0); ec := RangeEmbedding(C0); ts := TailMap(S0); hs := HeadMap(S0); es := RangeEmbedding(S0); for s in gensrc do if ( Image( tc, s ) <> Image( ts, s ) ) then ok := false; fi; if ( Image( hc, s ) <> Image( hs, s ) ) then ok := false; fi; od; if not ok then Info( InfoXMod, 3, "tail/head maps have different images" ); return false; fi; for r in genrng do if ( Image( ec, r ) <> Image( es, r ) ) then ok := false; fi; od; if not ok then Info( InfoXMod, 3, "embeddingss have different images" ); return false; fi; if ( C0 <> S0 ) then SetParent( S0, C0 ); fi; return true; end ); ############################################################################## ## #M IsSubCat1Group( <C1>, <S1> ) ## InstallMethod( IsSubCat1Group, "generic method for cat1-groups", true, [ Is2DimensionalGroup, Is2DimensionalGroup ], 0, function( C1, S1 ) if not ( IsCat1Group( C1 ) and IsCat1Group( S1 ) ) then return false; fi; return IsSubPreCat1Group( C1, S1 ); end ); ############################################################################## ## #M Sub2DimensionalGroup . . creates Sub2bObject from Ssrc<=Osrc & Srng<=Orng ## InstallMethod( Sub2DimensionalGroup, "generic method for 2d-objects", true, [ Is2DimensionalGroup, IsGroup, IsGroup ], 0, function( obj, src, rng ) if ( HasIsXMod(obj) and IsXMod(obj) ) then return SubXMod( obj, src, rng ); elif ( HasIsPreXMod(obj) and IsPreXMod(obj) ) then return SubPreXMod( obj, src, rng ); elif ( HasIsCat1Group(obj) and IsCat1Group(obj) ) then return SubCat1Group( obj, src, rng ); elif ( HasIsPreCat1Group(obj) and IsPreCat1Group(obj) ) then return SubPreCat1Group( obj, src, rng ); else Error( "unknown type of 2d-object" ); fi; end ); ############################################################################## ## #M SubPreXMod creates SubPreXMod from Ssrc<=Psrc & Srng<=Prng ## InstallMethod( SubPreXMod, "generic method for pre-crossed modules", true, [ IsPreXMod, IsGroup, IsGroup ], 0, function( PM, Ssrc, Srng ) local Psrc, Prng, Pbdy, Pact, Paut, genSsrc, genSrng, Pname, Sname, SM, Sbdy, Saut, Sact, r, innaut, genPrng, genPsrc, ssrc, trivsrc, trivrng, incSsrc, idSsrc, imact, imgen, imbdy, imSsrc, imalpha, alpha; Psrc := Source( PM ); Prng := Range( PM ); Pbdy := Boundary( PM ); Pact := XModAction( PM ); Paut := Range( Pact ); if not IsSubgroup( Psrc, Ssrc ) then Print( "Ssrc is not a subgroup of Psrc\n" ); return fail; fi; if not ( IsSubgroup( Prng, Srng ) ) then Print( "Srng is not a subgroup of Prng\n" ); return fail; fi; ssrc := Size( Ssrc ); genPsrc := GeneratorsOfGroup( Psrc ); genPrng := GeneratorsOfGroup( Prng ); genSsrc := GeneratorsOfGroup( Ssrc ); genSrng := GeneratorsOfGroup( Srng ); incSsrc := InclusionMappingGroups( Psrc, Ssrc ); imgen := List( genSsrc, x -> Image( Pbdy, x ) ); imSsrc := Subgroup( Prng, imgen ); if not IsSubgroup( Srng, imSsrc ) then Info( InfoXMod, 2, "Pbdy(Ssrc) is not a subgroup of Srng" ); return fail; fi; trivsrc := ( Size( Ssrc ) = 1 ); trivrng := ( Size( Srng ) = 1 ); if ( trivrng or trivsrc ) then Sbdy := MappingToOne( Ssrc, Srng ); else Sbdy:= GroupHomomorphismByImages( Ssrc, Srng, genSsrc, imgen ); fi; innaut := [ ]; for r in genSrng do alpha := Image( Pact, r ); imgen := List( genSsrc, x -> Image( alpha, x ) ); if not ForAll( imgen, x -> ( x in Ssrc ) ) then return fail; fi; imalpha := Subgroup( Ssrc, imgen ); if not ( IsSubgroup( Ssrc, imalpha ) ) then Info( InfoXMod, 2, "Srng does not act correctly on Ssrc" ); return fail; fi; alpha:=GroupHomomorphismByImages( Ssrc, Ssrc, genSsrc, imgen ); Add( innaut, alpha ); od; idSsrc := IdentityMapping( Ssrc ); if ( ssrc = 1 ) then Saut := Group( idSsrc ); innaut := List( genSrng, s -> idSsrc ); else Saut := Group( innaut, idSsrc ); fi; Sact := GroupHomomorphismByImages( Srng, Saut, genSrng, innaut ); if ( not IsGroupHomomorphism( Sact ) ) then Print( "Sact is not a homomorphism\n" ); return fail; fi; SM := PreXModByBoundaryAndAction( Sbdy, Sact ); if HasParent( PM ) then SetParent( SM, Parent( PM ) ); else SetParent( SM, PM ); fi; return SM; end ); ############################################################################## ## #M SubXMod . . . . . . . . . . . creates SubXMod from Ssrc<=Psrc & Srng<=Prng ## InstallMethod( SubXMod, "generic method for crossed modules", true, [ IsXMod, IsGroup, IsGroup ], 0, function( XM, Ssrc, Srng ) local SM; SM := SubPreXMod( XM, Ssrc, Srng ); if ( SM = fail ) then return fail; fi; if not IsXMod( SM ) then Error( "the result is only a pre-crossed module" ); fi; return SM; end ); ############################################################################### ## #M SubPreCat1Group . . created from PreCat1Group and a subgroup of the source ## InstallMethod( SubPreCat1Group, "generic method for (pre-)cat1-groups", true, [ IsPreCat1Group, IsGroup, IsGroup ], 0, function( C, G, R ) local Csrc, Crng, Ct, Ch, Ce, t, h, e, SC, ok; Csrc := Source( C ); Crng := Range( C ); Ct := TailMap( C ); Ch := HeadMap( C ); Ce := RangeEmbedding( C ); ok := true; if not ( IsSubgroup( Csrc, G ) ) then Print( "G is not a subgroup of Csrc\n" ); ok := false; fi; if not ( ( R = Image( Ct, G ) ) and ( R = Image( Ch, G ) ) ) then Print( "restrictions of Ct, Ch to G must have common image R\n" ); ok := false; fi; t := GeneralRestrictedMapping( Ct, G, R ); h := GeneralRestrictedMapping( Ch, G, R ); e := GeneralRestrictedMapping( Ce, R, G ); SC := PreCat1GroupByTailHeadEmbedding( t, h, e ); if not ( C = SC ) then SetParent( SC, C ); fi; return SC; end ); ############################################################################## ## #M SubCat1Group . . creates SubCat1Group from Cat1Group and subgroup of source ## InstallMethod( SubCat1Group, "generic method for cat1-groups", true, [ IsCat1Group, IsGroup, IsGroup ], 0, function( C, G, R ) local S; S := SubPreCat1Group( C, G, R ); if not IsCat1Group( S ) then Error( "result is only a pre-cat1-group" ); fi; return S; end ); ############################################################################# ## #M IsCat1Group check that the second cat1-group axiom holds ## InstallMethod( IsCat1Group, "generic method for crossed modules", true, [ IsPreCat1Group ], 0, function( C1G ) local Csrc, Crng, h, t, e, f, kerC, kert, kerh, kerth; Csrc := Source( C1G ); Crng := Range( C1G ); h := HeadMap( C1G ); t := TailMap( C1G ); e := RangeEmbedding( C1G ); kerC := Kernel( C1G ); f := KernelEmbedding( C1G ); kert := Kernel( t ); kerh := Kernel( h ); kerth := CommutatorSubgroup( kert, kerh ); if not ( Size( kerth ) = 1 ) then Info( InfoXMod, 1, "condition [kert,kerh] = 1 is not satisfied"); return false; fi; if not ( ( Source( f ) = kerC ) and ( Range( f ) = Csrc ) ) then Print( "Warning: KernelEmbedding( C1G ) incorrectly defined?\n" ); fi; return true; end ); ############################################################################# ## #M IsIdentityCat1 #M IsEndomorphismPreCat1Group ## InstallMethod( IsEndomorphismPreCat1Group, "test a pre-cat1-group", true, [ IsPreCat1Group ], 0, function( obj ) return IsSubgroup( Source(obj), Range(obj) ); end ); InstallMethod( IsIdentityCat1Group, "test a cat1-group", true, [ IsCat1Group ], 0, function( C1G ) return ( ( TailMap( C1G ) = IdentityMapping( Source( C1G ) ) ) and ( HeadMap( C1G ) = IdentityMapping( Source( C1G ) ) ) ); end ); ############################################################################# ## #F Cat1Group( <size>, <gpnum>, <num> ) cat1-group from data in CAT1_LIST #F Cat1Group( <t>, <h>, <e> ) cat1-group from given t,h,e #F Cat1Group( <t>, <h> ) cat1-group from t,h endomorphisms ## InstallGlobalFunction( Cat1Group, function( arg ) local nargs, C1G, ok; nargs := Length( arg ); if ( ( nargs < 1 ) or ( nargs > 3 ) ) then Print( "standard usage: Cat1Group( tail, head [,embed] );\n" ); Print( " or: Cat1Group( size, gpnum, num );\n" ); return fail; elif not IsInt( arg[1] ) then if ( nargs = 1 ) then C1G := PreCat1Group( arg[1] ); elif ( nargs = 2 ) then C1G := PreCat1Group( arg[1], arg[2] ); elif ( nargs = 3 ) then C1G := PreCat1Group( arg[1], arg[2], arg[3] ); fi; ok := IsCat1Group( C1G ); if ok then return C1G; else Error( "quotient by Peiffer group is not yet implemented" ); return fail; fi; else ## arg[1] is an integer, so use the data in cat1data.g return Cat1Select( arg[1], arg[2], arg[3] ); fi; end ); ############################################################################# ## #F Cat1Select( <size>, <gpnum>, <num> ) cat1-group from data in CAT1_LIST ## InstallOtherMethod( Cat1Select, "construct a cat1-group using data in file", true, [ IsInt ], 0, function( size ) return Cat1Select( size, 0, 0 ); end ); InstallOtherMethod( Cat1Select, "construct a cat1-group using data in file", true, [ IsInt, IsInt ], 0, function( size, gpnum ) return Cat1Select( size, gpnum, 0 ); end ); InstallMethod( Cat1Select, "construct a cat1-group using data in file", true, [ IsInt, IsInt, IsInt ], 0, function( size, gpnum, num ) local ok, type, norm, usage, usage2, maxsize, start, iso, count, comm, pos, pos2, names, i, j, k, ncat1, G, genG, fam, M, L, genR, R, imt, t, kert, imh, h, C1G, XC, i0; maxsize := CAT1_LIST_MAX_SIZE; usage := "Usage: Cat1Select( size, gpnum, num );"; usage2 := " where size <= CAT1_LIST_MAX_SIZE = "; if not ( ( size > 0 ) and ( size <= maxsize ) ) then Print( usage, usage2, CAT1_LIST_MAX_SIZE, "\n" ); return fail; fi; if ( size = 1 ) then if ( num = 0 ) then Print( usage, "\nThere is only " ); Print( "the trivial cat1-structure on the trivial group.\n" ); Print( "(1) [ [ ], tail = head = zero mapping ]\n" ); return 1; elif ( num = 1 ) then G := SmallGroup( 1, 1 ); t := IdentityMapping( G ); return PreCat1GroupByEndomorphisms( t, t ); else return fail; fi; fi; if ( CAT1_LIST_LOADED = false ) then ReadPackage( "xmod", "lib/cat1data.g" ); fi; # find starting positions of iso classes of groups of size <= maxsize iso := CAT1_LIST_CLASS_SIZES; count := 1; start := [ 1 ]; for j in iso do count := count + j; Add( start, count ); od; Info( InfoXMod, 2, " iso = ", iso, "\n start = ", start ); if ( ( size < 1 ) or ( size > maxsize ) ) then Error( "only groups of order up to ", maxsize, " in CAT1_LIST"); return false; fi; pos := start[ size ]; if ( size < maxsize ) then pos2 := start[ size + 1 ] - 1; else pos2 := Length( CAT1_LIST ); fi; names := List( [ pos..pos2], n -> CAT1_LIST[n][3] ); if not ( gpnum > 0 ) then Print( usage, "\n" ); return names; fi; if ( gpnum > iso[size] ) then Print( "# isomorphism classes of groups of size ", size, " is ", iso[size], ", less than ", gpnum, "\n" ); Print( usage, "\n" ); return names; fi; j := pos + gpnum - 1; M := CAT1_LIST[j]; if not ( ( M[1] = size ) and ( M[2] = gpnum ) ) then Error( "M[1..2] <> [ size, gpnum ]" ); fi; G := SmallGroup( size, gpnum ); SetName( G, M[3] ); comm := IsCommutative( G ); if comm then ncat1 := Length( M[5] ) + 2; k := 2; else ncat1 := Length( M[5] ) + 1; k := 1; fi; if IsPermGroup( G ) then return PermCat1Select( size, gpnum, num ); fi; fam := FamilyObj( GeneratorsOfGroup( G )[1] ); genG := List( M[4], e -> ObjByExtRep( fam, e ) ); if not ( ( num >= 1 ) and ( num <= ncat1 ) ) then Print( usage, "\n" ); Print( "There are ", ncat1, " cat1-structures for the group "); Print( G, ".\n" ); Print( "Using small generating set ", genG, " for source of homs.\n" ); Print( "[ [range gens]," ); Print( " [tail genimages], [head genimages] ]" ); Print( " :-\n" ); if comm then Print("(1) [ ","[ ]",", tail = head = zero mapping ]\n"); fi; for i in [1..ncat1-k] do if comm then i0 := i+1; else i0 := i; fi; L := M[5][i]; genR := List( L[1], e -> ObjByExtRep( fam, e ) ); imt := List( L[2], e -> ObjByExtRep( fam, e ) ); imh := List( L[3], e -> ObjByExtRep( fam, e ) ); Print( "(", i0, ") ", [ genR, imt, imh ], "\n" ); od; Print("(",ncat1,") [ ",genG,", tail = head = identity mapping ]\n"); return ncat1; fi; if ( num = ncat1 ) then t := IdentityMapping( G ); h := ShallowCopy( t ); else if ( ( num = 1 ) and IsCommutative( G ) ) then R := TrivialSubgroup( G ); SetName( R, "triv" ); t := MappingToOne( G, R ); h := ShallowCopy( t ); else L := M[5][num-k+1]; genR := List( L[1], e -> ObjByExtRep( fam, e ) ); R := Subgroup( G, genR ); imt := List( L[2], e -> ObjByExtRep( fam, e ) ); t := GroupHomomorphismByImages( G, R, genG, imt ); imh := List( L[3], e -> ObjByExtRep( fam, e ) ); h := GroupHomomorphismByImages( G, R, genG, imh ); fi; SetIsEndoMapping( t, true ); SetIsEndoMapping( h, true ); kert := Kernel( t ); fi; C1G := PreCat1GroupByEndomorphisms( t, h ); ok := IsCat1Group( C1G ); if ok then XC := XModOfCat1Group( C1G ); fi; return C1G; end ); InstallMethod( PermCat1Select, "construct a cat1-group using data in file", true, [ IsInt, IsInt, IsInt ], 0, function( size, gpnum, num ) local ok, type, norm, maxsize, start, iso, count, pos, pos2, names, i, j, ncat1, G, genG, fam, M, L, genR, R, t, kert, h, C1G, XC; # find starting positions of iso classes of groups of size <= maxsize maxsize := CAT1_LIST_MAX_SIZE; iso := CAT1_LIST_CLASS_SIZES; count := 1; start := [ 1 ]; for j in iso do count := count + j; Add( start, count ); od; Info( InfoXMod, 2, " iso = ", iso, "\n start = ", start ); if ( ( size < 1 ) or ( size > maxsize ) ) then Error( "only groups of order up to ", maxsize, " in CAT1_LIST"); return false; fi; pos := start[ size ]; if ( size < maxsize ) then pos2 := start[ size + 1 ] - 1; else pos2 := Length( CAT1_LIST ); fi; names := List( [ pos..pos2], n -> CAT1_LIST[n][4] ); j := pos + gpnum - 1; M := CAT1_LIST[j]; G := Group(M[4], ( )); SetName( G, M[3] ); ncat1 := Length( M[5] ) + 1; genG := GeneratorsOfGroup( G ); if not ( ( num >= 1 ) and ( num <= ncat1 ) ) then Print( "\nThere are ", ncat1, " cat1-structures for the group "); Print( G, ".\n" ); Print( "[ [range gens], source & range names," ); Print( " [tail genimages], [head genimages] ]" ); Print( " :-\n" ); Print( "[ ", genG, ", tail = head = identity mapping ]\n" ); for i in [2..ncat1] do Print( M[5][i-1], "\n" ); od; Print( "Group has generators ", genG, "\n" ); return ncat1; fi; if ( num = ncat1 ) then L := [ genG, genG, genG ]; else L := M[5][num-1]; fi; genR := L[1]; R := Subgroup( G, genR ); if ( G = R ) then SetName( R, Name(G) ); fi; t := GroupHomomorphismByImages( G, R, genG, L[2] ); h := GroupHomomorphismByImages( G, R, genG, L[3] ); SetIsEndoMapping( t, true ); SetIsEndoMapping( h, true ); kert := Kernel( t ); C1G := PreCat1GroupByEndomorphisms( t, h ); ok := IsCat1Group( C1G ); if ok then XC := XModOfCat1Group( C1G ); fi; return C1G; end ); ############################################################################# ## #M PreCat1GroupByTailHeadEmbedding ## InstallMethod( PreCat1GroupByTailHeadEmbedding, "cat1-group from tail, head and embedding", true, [ IsGroupHomomorphism, IsGroupHomomorphism, IsGroupHomomorphism ], 0, function( t, h, e ) local genG, R, genR, imh, imt, ime, eR, hres, tres, eres, kert, kergen, bdy, imbdy, f, C1G, ok, G, PC; G := Source( t ); genG := GeneratorsOfGroup( G ); if IsSurjective( t ) then R := Range( t ); else R := Image( t ); fi; genR := SmallGeneratingSet( R ); eR := Image( e ); if not ( ( Source( h ) = G ) and ( Image( h ) = R ) and ( Source( e ) = R ) and IsInjective( e ) and IsSubgroup( G, eR ) ) then return fail; fi; imh := List( genG, x -> Image( h, x ) ); imt := List( genG, x -> Image( t, x ) ); ime := List( genR, x -> Image( e, x ) ); kert := Kernel( t ); f := InclusionMappingGroups( G, kert ); hres := GroupHomomorphismByImages( G, R, genG, imh ); tres := GroupHomomorphismByImages( G, R, genG, imt ); eres := GroupHomomorphismByImages( R, G, genR, ime ); kergen := GeneratorsOfGroup( kert ); imbdy := List( kergen, x -> Image( h, x) ); bdy := GroupHomomorphismByImages( kert, R, kergen, imbdy ); PC := PreCat1Obj( tres, hres, eres ); SetBoundary( PC, bdy ); SetKernelEmbedding( PC, f ); ## check the types if ( IsPermGroup(G) and IsPermGroup(R) ) then SetIsPerm2DimensionalGroup( PC, true ); elif ( IsPcGroup(G) and IsPcGroup(R) ) then SetIsPc2DimensionalGroup( PC, true ); fi; return PC; end ); ############################################################################# ## #M PreCat1GroupByEndomorphisms( <et>, <eh> ) #M EndomorphismPreCat1Group( <pcg> ) ## InstallMethod( PreCat1GroupByEndomorphisms, "cat1-group from tail and head endomorphisms", true, [ IsGroupHomomorphism, IsGroupHomomorphism ], 0, function( et, eh ) local G, gG, R, t, h, e; if not ( IsEndoMapping( et ) and IsEndoMapping( eh ) ) then Print( "et, eh must both be group endomorphisms \n" ); return fail; fi; if not ( Source( et ) = Source( eh ) ) then Info( InfoXMod, 2, "et and eh must have same source" ); return fail; fi; G := Source( et ); if not ( Image( et ) = Image( eh ) ) then Info( InfoXMod, 2, "et and eh must have same image" ); return fail; fi; R := Image( et ); gG := GeneratorsOfGroup( G ); t := GroupHomomorphismByImages( G, R, gG, List( gG, g->Image(et,g) ) ); h := GroupHomomorphismByImages( G, R, gG, List( gG, g->Image(eh,g) ) ); e := InclusionMappingGroups( G, R ); return PreCat1GroupByTailHeadEmbedding( t, h, e ); end ); InstallMethod( EndomorphismPreCat1Group, "convert cat1-group to one with endomorphisms", true, [ IsPreCat1Group ], 0, function( C1G ) local e, t, h; if IsEndomorphismPreCat1Group( C1G ) then return C1G; fi; e := RangeEmbedding( C1G ); t := TailMap( C1G ) * e; h := HeadMap( C1G ) * e; return PreCat1GroupByEndomorphisms( t, h ); end ); ############################################################################# ## #M PreXModOfPreCat1Group ## InstallMethod( PreXModOfPreCat1Group, true, [ IsPreCat1Group ], 0, function( C1G ) local Csrc, Crng, gensrc, genrng, genker, bdy, kert, innaut, autgen, imautgen, idkert, a, aut, act, phi, j, r, PM, Cek, Cer, name; if not ( IsPermPreCat1Group( C1G ) or IsPcPreCat1Group( C1G ) ) then Print( "#W: should be a perm-cat1- or a pc-cat1-group\n" ); return fail; fi; Csrc := Source( C1G ); Crng := Range( C1G ); bdy := Boundary( C1G ); Cer := RangeEmbedding( C1G ); Cek := KernelEmbedding( C1G ); kert := Kernel( C1G ); if ( Size( kert ) = 1 ) then SetName( kert, "triv" ); fi; if ( ( not HasName( kert ) ) and HasName( C1G ) ) then SetName( kert, Concatenation( "ker(", Name( C1G ), ")" ) ); fi; gensrc := GeneratorsOfGroup( Csrc ); genrng := GeneratorsOfGroup( Crng ); genker := GeneratorsOfGroup( kert ); if IsIdentityCat1Group( C1G ) then # X has trivial source and action aut := Group( IdentityMapping( kert ) ); SetName( aut, "triv_aut" ); act := MappingToOne( Crng, aut ); SetName( act, "mapto1" ); else autgen := [ ]; for r in genrng do imautgen := List( genker, s -> Image( Cek, s ) ); imautgen := List( imautgen, g -> g^( Image( Cer, r ) ) ); imautgen := List( imautgen, g -> PreImagesRepresentative( Cek, g ) ); a := GroupHomomorphismByImages( kert, kert, genker, imautgen ); Add( autgen, a ); od; idkert := IdentityMapping( kert ); aut := Group( autgen, idkert ); act := GroupHomomorphismByImages( Crng, aut, genrng, autgen ); if HasName( kert ) then SetName( aut, Concatenation( "innaut(", Name( kert ), ")" ) ); else SetName( aut, "aut" ); fi; if not IsGroupHomomorphism( act ) then Error( "act is not a homomorphism" ); fi; fi; PM := PreXModObj( bdy, act ); #? aded 30/04/08 - but is it really needed ?? if ( IsSubgroup( Crng, kert ) and IsNormal( Crng, kert ) ) then SetIsNormalSubgroup2DimensionalGroup( PM, true ); fi; if HasName( C1G ) then SetName( PM, Concatenation( "xmod(", Name( C1G ), ")" ) ); fi; return PM; end ); ############################################################################# ## #M Source( C1G ) . . . . . . . . . . . . . . . . . . . . for a cat1-group ## InstallOtherMethod( Source, "method for a pre-cat1-group", true, [ IsPreCat1Group ], 0, C1G -> Source( TailMap( C1G ) ) ); ############################################################################## ## #M Range( C1G ) . . . . . . . . . . . . . . . . . . . . . for a cat1-group ## InstallOtherMethod( Range, "method for a pre-cat1-group", true, [ IsPreCat1Group ], 0, C1G -> Range( TailMap( C1G ) ) ); ############################################################################## ## #M Kernel( C1G ) . . . . . . . . . . . . . . . . . . . for a pre-cat1-group ## InstallOtherMethod( Kernel, "method for a pre-cat1-group", true, [ IsPreCat1Group ], 0, C1G -> Kernel( TailMap( C1G ) ) ); ############################################################################# ## #M Boundary( C1G ) . . . . . . . . . . . . . . . . . . . for a cat1-group ## InstallOtherMethod( Boundary, "method for a pre-cat1-group", true, [ IsPreCat1Group ], 0, C1G -> GeneralRestrictedMapping( HeadMap(C1G), Kernel(C1G), Range(C1G) ) ); ############################################################################# ## #M KernelEmbedding( C1G ) . . . . . . . . . . . . . . . . for a cat1-group ## InstallMethod( KernelEmbedding, "method for a pre-cat1-group", true, [ IsPreCat1Group ], 0, C1G -> InclusionMappingGroups( Source( C1G ), Kernel( C1G ) ) ); ############################################################################## ## #M Cat1GroupByPeifferQuotient . . . . cat1 from pre-cat1 and Peiffer subgroup ## InstallMethod( Cat1GroupByPeifferQuotient, "cat1-group from a pre-cat1-group and Peiffer subgroup", true, [ IsPreCat1Group ], 0, function( PC ) local PCrng, PCsrc, PCt, PCh, PCe, genrng, gensrc, Pf, nat, quot, qgen, pqgen, tpqgen, hpqgen, tail, head, ime, embed, C1G; PCrng := Range( PC ) ; genrng := GeneratorsOfGroup( PCrng ); PCsrc := Source( PC ); gensrc := GeneratorsOfGroup( PCsrc ); PCt := TailMap( PC ); PCh := HeadMap( PC ); PCe := RangeEmbedding( PC ); # construct the quotient Pf := PeifferSubgroup( PC ); if not IsNormal( PCsrc, Pf ) then Error( "Peiffer subgroup not normal in source group" ); fi; nat := NaturalHomomorphismByNormalSubgroup( PCsrc, Pf ); quot := Image( nat ); qgen := GeneratorsOfGroup( quot ); # construct the head, tail and embedding pqgen := List( qgen, q -> PreImagesRepresentative( nat, q ) ); tpqgen := List( pqgen, p -> Image( PCt, p ) ); tail := GroupHomomorphismByImages( quot, PCrng, qgen, tpqgen ); hpqgen := List( pqgen, p -> Image( PCh, p ) ); head := GroupHomomorphismByImages( quot, PCrng, qgen, hpqgen ); ime := List( genrng, r -> Image( nat, Image( PCe, r ) ) ); embed := GroupHomomorphismByImages( PCrng, quot, genrng, ime ); C1G := PreCat1GroupByTailHeadEmbedding( tail, head, embed ); if not IsCat1Group( C1G ) then Error( "fails to be a cat1-group" ); fi; return C1G; end ); ############################################################################## ## #M DiagonalCat1Group . . . . . . cat1-group of the form (GxG => G) with t<>h ## InstallMethod( DiagonalCat1Group, "cat1-group from a list of generators", true, [ IsList ], 0, function( gen1 ) local m, lgen, gen2, genR, i, p, L1, len1, L2, j, G, R, genG, one, ids, t, h, e, C; m := Maximum( List( gen1, g -> LargestMovedPoint(g) ) ); lgen := Length( gen1 ); gen2 := ShallowCopy( gen1 ); genR := ShallowCopy( gen1 ); for i in [1..lgen] do p := gen1[i]; L1 := ListPerm( p ); len1 := Length( L1 ); L2 := [1..2*m]; for j in [1..len1] do L2[m+j] := L1[j]+m; od; gen2[i] := PermList( L2 ); for j in [1..len1] do L2[j] := L1[j]; od; genR[i] := PermList( L2 ); od; genG := Concatenation( gen1, gen2 ); G := Group( genG ); R := Group( genR ); one := One( G ); ids := ListWithIdenticalEntries( lgen, one ); t := GroupHomomorphismByImages( G, R, genG, Concatenation( genR, ids ) ); h := GroupHomomorphismByImages( G, R, genG, Concatenation( ids, genR ) ); e := GroupHomomorphismByImages( R, G, genR, genR ); C := PreCat1GroupByTailHeadEmbedding( t, h, e ); return C; end ); ############################################################################## ## #M AllCat1Groups . . . . . . . list of cat1-group structures on a given group ## InstallMethod( AllCat1Groups, "cat1-group structures on a given group", true, [ IsGroup ], 0, function( gp ) local L, homs, idem, num, i, j, C, ok; homs := AllHomomorphisms( gp, gp ); idem := Filtered( homs, i -> CompositionMapping(i,i) = i ); num := Length( idem ); L := [ ]; for i in [1..num] do for j in [1..num] do C := PreCat1GroupByEndomorphisms( idem[i], idem[j] ); if not ( C = fail ) then ok := IsCat1Group( C ); if ok then Add( L, C ); fi; fi; od; od; return L; end ); ############################################################################# ## #M DirectProductInfo( <obj> ) . . . . . . . . . . . . . . . . . for 2d-objects #M Coproduct2dInfo( <obj> ) . . . . . . . . . . . . . . . . . . for 2d-objects #M DirectProductOp( ) . . . . . . . (bdy1 x bdy2) : (S1 x S2) --> (R1 x R2) ## InstallOtherMethod( DirectProductInfo, "generic method for 2d-objects", true, [ Is2DimensionalDomain ], 0, function( obj ) return rec( objects := [ ], embeddings := [ ], projections := [ ] ); end ); InstallMethod( Coproduct2dInfo, "generic method for 2d-objects", true, [ Is2DimensionalDomain ], 0, function( obj ) return rec( objects := [ ], embeddings := [ ], projections := [ ] ); end ); #? (19/07/07) : allowed for case when one of Xsrc,Xrng,Ysrc,Yrng trivial ## #? using parameter list: spec(=[0,0,0,0] by default) ## InstallOtherMethod( DirectProductOp, "method for pre-crossed modules", true, [ IsList, IsPreXMod ], 0, function( list, X1 ) local Xsrc, Xrng, Y1, Ysrc, Yrng, genXrng, genYrng, genXsrc, genYsrc, XSpos, YSpos, XRpos, YRpos, Spos, imaut, autgen, aut, act, XY, S, R, genS, lenS, genR, lenR, imbdy, bdy, a, i, j, k, Xbdy, Ybdy, Xact, Yact, imXbdy, imYbdy, alpha, info, eXS, eYS, pXS, pYS, eXR, eYR, spec; if not ( Length( list ) = 2 ) then Error( "direct product not yet implemented for more than 2 terms" ); fi; if not ( list[1] = X1 ) then Error( "second argument should be first in first argument" ); fi; Y1 := list[2]; ## first the source group Xsrc := Source( X1 ); Ysrc := Source( Y1 ); genXsrc := GeneratorsOfGroup( Xsrc ); genYsrc := GeneratorsOfGroup( Ysrc ); spec := [false,false,false,false]; if ( Size( Xsrc ) = 1 ) then spec[1] := true; elif ( Size( Ysrc ) = 1 ) then spec[3] := true; fi; if spec[1] then S := Ysrc; eYS := IdentityMapping( S ); pYS := IdentityMapping( S ); elif spec[3] then S := Xsrc; eXS := IdentityMapping( S ); pXS := IdentityMapping( S ); else S := DirectProduct( Xsrc, Ysrc ); if ( not HasName( S ) and HasName( Xsrc ) and HasName( Ysrc ) ) then SetName( S, Concatenation( Name( Xsrc ), "x", Name( Ysrc ) ) ); fi; eXS := Embedding( S, 1 ); eYS := Embedding( S, 2 ); pXS := Projection( S, 1 ); pYS := Projection( S, 2 ); fi; genS := GeneratorsOfGroup( S ); lenS := Length( genS ); Spos := [ 1..lenS ]; if spec[1] then XSpos := [ ]; YSpos := [ 1..Length( genYsrc ) ]; elif spec[3] then XSpos := [ 1..Length( genXsrc ) ]; YSpos := [ ]; else XSpos := [ 1..Length( genXsrc ) ]; YSpos := [ 1+Length( genXsrc ) .. lenS ]; fi; ## now for the range group Xrng := Range( X1 ); Yrng := Range( Y1 ); genXrng := GeneratorsOfGroup( Xrng ); genYrng := GeneratorsOfGroup( Yrng ); if ( Size( Xrng ) = 1 ) then spec[2] := true; elif ( Size( Yrng ) = 1 ) then spec[4] := true; fi; if spec[2] then R := Yrng; eXR := MappingToOne( Xrng, Yrng ); eYR := IdentityMapping( R ); elif spec[4] then R := Xrng; eXR := IdentityMapping( R ); eYR := MappingToOne( Yrng, Xrng ); else R := DirectProduct( Xrng, Yrng ); if ( not HasName( R ) and HasName( Xrng ) and HasName( Yrng ) ) then SetName( R, Concatenation( Name( Xrng ), "x", Name( Yrng ) ) ); fi; eXR := Embedding( R, 1 ); eYR := Embedding( R, 2 ); fi; genR := GeneratorsOfGroup( R ); lenR := Length( genR ); if spec[2] then XRpos := [ ]; YRpos := [ 1..Length( genYrng ) ]; elif spec[4] then XRpos := [ 1..Length( genXrng ) ]; YRpos := [ ]; else XRpos := [ 1..Length( genXrng ) ]; YRpos := [ 1+Length( genXrng ) .. lenR ]; fi; ## now for the boundary Xbdy := Boundary( X1 ); Ybdy := Boundary( Y1 ); Xact := XModAction( X1 ); Yact := XModAction( Y1 ); imXbdy := List( genS{ XSpos }, s -> Image( eXR, Image( Xbdy, Image( pXS, s ) ) ) ); imYbdy := List( genS{ YSpos }, s -> Image( eYR, Image( Ybdy, Image( pYS, s ) ) ) ); imbdy := Concatenation( imXbdy, imYbdy ); bdy := GroupHomomorphismByImages( S, R, genS, imbdy ); autgen := 0 * [ 1..lenR ]; for i in XRpos do a := Image( Xact, genXrng[i] ); imaut := 0 * Spos; for j in YSpos do imaut[j] := genS[j]; od; for j in XSpos do imaut[j] := Image( eXS, Image( a, Image( pXS, genS[j] ) ) ); od; alpha := GroupHomomorphismByImages( S, S, genS, imaut ); autgen[i] := alpha; od; if spec[2] then k := 0; else k := Length( genXrng ); fi; for i in YRpos do a := Image( Yact, genYrng[i-k] ); imaut := 0 * Spos; for j in XSpos do imaut[j] := genS[j]; od; for j in YSpos do imaut[j] := Image( eYS, Image( a, Image( pYS, genS[j] ) ) ); od; alpha := GroupHomomorphismByImages( S, S, genS, imaut ); autgen[i] := alpha; od; aut := Group( autgen ); act := GroupHomomorphismByImages( R, aut, genR, autgen ); XY := PreXModByBoundaryAndAction( bdy, act ); if ( IsXMod( X1 ) and IsXMod( Y1 ) ) then SetIsXMod( XY, true ); fi; if ( HasName( X1 ) and HasName( Y1 ) ) then SetName( XY, Concatenation( Name( X1 ), "x", Name( Y1 ) ) ); fi; info := DirectProductInfo( XY ); info!.objects := [ X1, Y1 ]; return XY; end ); ############################################################################## ## #M Embedding . . . . for direct products of (pre-)xmods and (pre-)cat1-groups ## InstallOtherMethod( Embedding, "generic method for (pre-)xmods & (pre-)cat1s", true, [ Is2DimensionalGroup, IsPosInt ], 0, function( D, i ) local info, eS, eR, obj, mor; info := DirectProductInfo( D ); if IsBound( info!.embeddings[i] ) then return info!.embeddings[i]; fi; eS := Embedding( Source( D ), i ); eR := Embedding( Range( D ), i ); Info( InfoXMod, 3, "SourceEmbedding: ", eS ); Info( InfoXMod, 3, " RangeEmbedding: ", eR ); obj := info!.objects[i]; if IsPreXMod( D ) then mor := PreXModMorphism( obj, D, eS, eR ); elif IsPreCat1Group( D ) then mor := PreCat1Morphism( obj, D, eS, eR ); else mor := fail; fi; if not ( mor = fail ) then SetIsInjective( mor, true ); info!.embeddings[i] := mor; fi; return mor; end ); ############################################################################## ## #M Projection . . . for direct products of (pre-)xmods and (pre-)cat1-groups ## InstallOtherMethod( Projection, "generic method for (pre-)xmods & (pre-)cat1s", true, [ Is2DimensionalGroup, IsPosInt ], 0, function( D, i ) local G, info, pS, pR, mor; G := Source( D ); if HasDirectProductInfo( G ) then info := DirectProductInfo( D ); if not ( i in [1,2] ) then Error( "only two projections available" ); fi; else info := SemidirectProductInfo( G ); if not ( i = 1 ) then Error( "only the first projection is available" ); fi; fi; if IsBound( info!.projections[i] ) then return info!.projections[i]; fi; pS := Projection( G, i ); pR := Projection( Range( D ), i ); if IsPreXMod( D ) then mor := PreXModMorphism( info!.objects[i], D, pS, pR ); elif IsPreCat1Group( D ) then mor := PreCat1Morphism( info!.objects[i], D, pS, pR ); else mor := fail; fi; if not ( mor = fail ) then SetIsInjective( mor, true ); info!.projections[i] := mor; fi; return mor; end ); ############################################################################## ## #M TrivialSub2DimensionalGroup . . . . . . . . . . of a 2d-object #M TrivialSubPreXMod . . . . . . . . . . . . . . . of a pre-crossed module #M TrivialSubXMod . . . . . . . . . . . . . . . of a crossed module #M TrivialSubPreCat1Group . . . . . . . . . . . . . of a pre-cat1-group #M TrivialSubCat1Group . . . . . . . . . . . . . . of a cat1-group ## InstallMethod( TrivialSub2DimensionalGroup, "of a 2d-object", true, [ Is2DimensionalGroup ], 0, function( obj ) local idsrc, idrng; idsrc := TrivialSubgroup( Source( obj ) ); idrng := TrivialSubgroup( Range( obj ) ); if IsPreXMod( obj ) then return SubPreXMod( obj, idsrc, idrng ); elif IsPreCat1Group( obj ) then return SubPreCat1Group( obj, idsrc ); else Error( "<obj> must be a pre-crossed module or a pre-cat1-group" ); fi; end ); InstallMethod( TrivialSubPreXMod, "of a pre-crossed module", true, [ IsPreXMod ], 0, function( obj ) return TrivialSub2DimensionalGroup( obj ); end ); InstallMethod( TrivialSubXMod, "of a crossed module", true, [ IsXMod ], 0, function( obj ) return TrivialSub2DimensionalGroup( obj ); end ); InstallMethod( TrivialSubPreCat1Group, "of a pre-cat1-group", true, [ IsPreCat1Group ], 0, function( obj ) return TrivialSub2DimensionalGroup( obj ); end ); InstallMethod( TrivialSubCat1Group, "of a cat1-group", true, [ IsCat1Group ], 0, function( obj ) return TrivialSub2DimensionalGroup( obj ); end ); ############################################################################## ## #M IsNormalSubgroup2DimensionalGroup . . . . . . . . for 2Dimensional-objects ## InstallMethod( IsNormalSubgroup2DimensionalGroup, "for crossed modules and cat1-groups", [ Is2DimensionalGroup ], 0, function( obj ) local src, rng, gensrc, genrng; src := Source( obj ); rng := Range( obj ); gensrc := GeneratorsOfGroup( src ); if IsXMod( obj ) then return ( IsNormal(rng,src) and ( gensrc = List( gensrc, s -> Image( Boundary(obj), s ) ) ) ); elif IsCat1Group( obj ) then return IsNormalSubgroup2DimensionalGroup( XModOfCat1Group( obj ) ); else Error( "method not yet implemented" ); fi; end ); ############################################################################## ## #M IsNormal . . . . . . . . . . . . . . . . . . . . for 2Dimensional-objects ## InstallOtherMethod( IsNormal, "for precrossed modules", IsIdenticalObj, [ IsPreXMod, IsPreXMod ], 0, function( XM, SM ) local xr, a, ss, im, xs, sr, Ssrc, Xact, snat, rnat; if not IsSubPreXMod( XM, SM ) then return false; fi; Ssrc := Source( SM ); Xact := XModAction( XM ); for xr in GeneratorsOfGroup( Range( XM ) ) do a := Image( Xact, xr ); for ss in GeneratorsOfGroup( Ssrc ) do im := Image( a, ss ); if not ( im in Ssrc ) then Info( InfoXMod, 2, "ss,xr,ss^xr = ", [ss,xr,im] ); return false; fi; od; od; for sr in GeneratorsOfGroup( Range( SM ) ) do a := Image( Xact, sr ); for xs in GeneratorsOfGroup( Source( XM ) ) do im := xs^(-1) * Image( a, xs ); if not ( im in Ssrc ) then Info( InfoXMod, 3, "sr,xs,sr^(-1)*xs^sr = ", [sr,xs,im] ); return false; fi; od; od; return true; end ); ############################################################################## ## #M NormalSubXMods . . . . . . . . . . . . . . . . . . for a crossed module ## InstallMethod( NormalSubXMods, "for a crossed module", true, [ IsXMod ], 0, function( XM ) local Xsrc, Xrng, YM, i, j, slen, rlen, norm, normsrc, normrng, ok; Xsrc := Source( XM ); Xrng := Range( XM ); norm := [ ]; normsrc := NormalSubgroups( Xsrc ); normrng := NormalSubgroups( Xrng ); slen := Length( normsrc ); rlen := Length( normrng ); for i in [ 1..slen ] do for j in [ 1..rlen ] do if ( ( i = 1 ) and ( j = 1 ) ) then YM := TrivialSubXMod( XM ); elif ( ( i = slen ) and ( j = rlen ) ) then YM := XM; else YM := SubXMod( XM, normsrc[i], normrng[j] ); fi; ok := not ( YM = fail ); if ( ok and IsXMod( YM ) and IsNormal( XM, YM ) ) then Add( norm, YM ); fi; od; od; return norm; end );