1############################################################################# 2## 3#W gp2obj.gi GAP4 package `XMod' Chris Wensley 4#W & Murat Alp 5#Y Copyright (C) 2001-2019, Chris Wensley et al, 6#Y School of Computer Science, Bangor University, U.K. 7## 8## This file contains generic methods for (pre-)crossed modules and 9## (pre-)cat1-groups. 10## 11 12############################################################################## 13## 14## Global constants which determine whether to read cat1data.g 15## CAT1_LIST_CLASS_SIZES for groups of size <= CAT1_LIST_MAX_SIZE 16## 17 18CAT1_LIST_MAX_SIZE := 70; 19CAT1_LIST_CLASS_SIZES := 20 List( [1..CAT1_LIST_MAX_SIZE], n -> NumberSmallGroups(n) ); 21CAT1_LIST_LOADED := false; 22CAT1_LIST := [ ]; 23 24############################################################################## 25## 26#M IsPerm2DimensionalGroup . . check whether source and range are perm groups 27#M IsFp2DimensionalGroup . . . check whether source and range are fp groups 28#M IsPc2DimensionalGroup . . . check whether source and range are pc groups 29## 30InstallMethod( IsPerm2DimensionalGroup, "generic method for 2d-group objects", 31 true, [ Is2DimensionalGroup ], 0, 32function( obj ) 33 return ( IsPermGroup( Source( obj ) ) and IsPermGroup( Range( obj ) ) ); 34end ); 35 36InstallMethod( IsFp2DimensionalGroup, "generic method for 2d-group objects", 37 true, [ Is2DimensionalGroup ], 0, 38function( obj ) 39 return ( IsFpGroup( Source( obj ) ) and IsFpGroup( Range( obj ) ) ); 40end ); 41 42InstallMethod( IsPc2DimensionalGroup, "generic method for 2d-group objects", 43 true, [ Is2DimensionalGroup ], 0, 44function( obj ) 45 return ( IsPcGroup( Source( obj ) ) and IsPcGroup( Range( obj ) ) ); 46end ); 47 48############################################################################# 49## 50#M IsPreXMod . . . . . . . . check that the first crossed module axiom holds 51## 52InstallMethod( IsPreXMod, "generic method for 2d-group", 53 true, [ Is2DimensionalGroup ], 0, 54function( P ) 55 56 local Xsrc, Xrng, bdy, a, aut, act, gensrc, ngsrc, genrng, ngrng, 57 ssrc, x1, y1, z1, x2, y2, z2, w2; 58 59 if not IsPreXModObj( P ) then 60 return false; 61 fi; 62 Xrng := Range( P ); 63 genrng := GeneratorsOfGroup( Xrng ); 64 ngrng := Length( genrng ); 65 Xsrc := Source( P ); 66 gensrc := GeneratorsOfGroup( Xsrc ); 67 ngsrc := Length( gensrc ); 68 ssrc := Size( Xsrc ); 69 bdy := Boundary( P ); 70 # Check P.boundary: P.source -> P.range 71 if not ( ( Source( bdy ) = Xsrc ) and ( Range( bdy ) = Xrng ) ) then 72 Info( InfoXMod, 2, 73 "Error: require X.boundary : X.source -> X.range" ); 74 return false; 75 fi; 76 # checking IsHomomorphism(bdy) gives cokernel error when Xsrc = [ ] 77 if ( ssrc > 1 ) then 78 if not IsGroupHomomorphism( bdy ) then 79 Info( InfoXMod, 2, 80 "Error: the boundary map is NOT a homomorphism!" ); 81 return false; 82 fi; 83 fi; 84 act := XModAction( P ); 85 aut := Range( act ); 86 # Check X.aut is a group of automorphisms X.source -> X.source 87 if not ( IsGroup( aut ) ) then 88 Info( InfoXMod, 2, 89 "Error: group of actions on X.source does not exist!" ); 90 return false; 91 fi; 92 if ( aut = Group( IdentityMapping( Xsrc ) ) ) then 93 SetIsTrivialAction2DimensionalGroup( P, true ); 94 else 95 a := GeneratorsOfGroup( aut )[1]; 96 if not ( ( Source( a ) = Xsrc ) and ( Range( a ) = Xsrc ) 97 and IsBijective( a ) ) then 98 Info( InfoXMod, 2, 99 "Require automorphism X.aut.1 on X.source" ); 100 return false; 101 fi; 102 fi; 103 # Check X.action: X.range -> X.aut 104 if not ( ( Source( act ) = Xrng ) and ( Range( act ) = aut ) ) then 105 Info( InfoXMod, 2, 106 "Error: require X.action : X.range -> X.aut" ); 107 return false; 108 fi; 109 if ( Size( aut ) = 1 ) then 110 Info( InfoXMod, 2, 111 "X.action trivial => not checking a homomorphism!" ); 112 else 113 if not IsGroupHomomorphism( act ) then 114 Info( InfoXMod, 2, " X.action is not a homomorphism|" ); 115 return false; 116 fi; 117 fi; 118 Info( InfoXMod, 3, 119 "Checking CM1) bdy(x2^x1) = (bdy(x2))^x1 " ); 120 for x1 in genrng do 121 for x2 in gensrc do 122 # Print( "x1,x2 = ", x1, ", ", x2, "\n" ); 123 y1 := ( x2 ^ ( x1^act ) ) ^ bdy; 124 z1 := ( x2 ^ bdy ) ^ x1; 125 if ( y1 <> z1 ) then 126 Info( InfoXMod, 3, 127 "CM1) fails at x1 = ", x1, ", x2 = ", x2, "\n", 128 " bdy(x2^x1) = ", y1, "\n", "(bdy(x2))^x1 = ", z1 ); 129 return false; 130 fi; 131 od; 132 od; 133 return true; 134end ); 135 136############################################################################## 137## 138#M \=( <P>, <Q> ) . . . . . . . . test if two pre-crossed modules are equal 139## 140InstallMethod( \=, "generic method for two pre-crossed modules", 141 IsIdenticalObj, [ IsPreXMod, IsPreXMod ], 0, 142function ( P, Q ) 143 return ( ( Boundary(P) = Boundary(Q) ) 144 and ( XModAction(P) = XModAction(Q) ) ); 145end ); 146 147############################################################################## 148## 149#M Size( <P> ) . . . . . . . . . . . . . . . . size for a pre-crossed module 150## 151InstallOtherMethod( Size, "generic method for a 2d-object", 152 [ Is2DimensionalDomain ], 20, 153function ( obj ) 154 return [ Size( Source( obj ) ), Size( Range( obj ) ) ]; 155end ); 156 157############################################################################# 158## 159#M IsTrivialAction2DimensionalGroup . . . . check whether action is trivial 160## 161InstallMethod( IsTrivialAction2DimensionalGroup, 162 "generic method for pre-crossed modules", true, [ IsPreXMod ], 0, 163function( PM ) 164 165 local act, genrng, onesrc; 166 167 act := XModAction( PM ); 168 genrng := GeneratorsOfGroup( Range( PM ) ); 169 onesrc := IdentityMapping( Source( PM ) ); 170 return ForAll( genrng, r -> ( ImageElm( act, r ) = onesrc ) ); 171end ); 172 173############################################################################### 174## 175#M IsCentralExtension2DimensionalGroup( <xmod> ) . . . . . . check the axioms 176## 177InstallMethod( IsCentralExtension2DimensionalGroup, "for an xmod", 178 true, [ IsXMod ], 0, 179function( X0 ) 180 181 local S, R, bdy, act, genS, genR, preR, len, i, r, pr, actr, s; 182 183 S := Source( X0 ); 184 R := Range( X0 ); 185 bdy := Boundary( X0 ); 186 if not IsSurjective( bdy ) then 187 return false; 188 fi; 189 if not IsSubgroup( Centre( S ), Kernel( bdy ) ) then 190 return false; 191 fi; 192 act := XModAction( X0 ); 193 genS := GeneratorsOfGroup( S ); 194 genR := GeneratorsOfGroup( R ); 195 preR := List( genR, r -> PreImagesRepresentative( bdy, r ) ); 196 len := Length( genR ); 197 for i in [1..len] do 198 r := genR[i]; 199 pr := preR[i]; 200 actr := ImageElm( act, r ); 201 for s in genS do 202 if not ( ImageElm( actr, s ) = s^pr ) then 203 return false; 204 fi; 205 od; 206 od; 207 return true; 208end ); 209 210############################################################################## 211## 212#M PreXModObj( <bdy>, <act> ) . . . . . . . . . . . make a pre-crossed module 213## 214InstallMethod( PreXModObj, "for homomorphism and action", true, 215 [ IsGroupHomomorphism, IsGroupHomomorphism ], 0, 216function( bdy, act ) 217 218 local type, PM, ok, src, rng, aut, name; 219 220 src := Source( bdy ); 221 rng := Range( bdy ); 222 if not ( rng = Source( act ) ) then 223 Error( "require Range( bdy ) = Source( act )" ); 224 fi; 225 aut := Range( act ); 226 if not IsGroupOfAutomorphisms( aut ) then 227 Error( "Range( act ) must be a group of automorphisms" ); 228 fi; 229 if ( IsPermGroup( src ) and IsPermGroup( rng ) ) then 230 type := PermPreXModObjType; 231 elif ( IsPcGroup( src ) and IsPcGroup( rng ) ) then 232 type := PcPreXModObjType; 233 else 234 type := PreXModObjType; 235 fi; 236 PM := rec(); 237 ObjectifyWithAttributes( PM, type, 238 Source, src, 239 Range, rng, 240 Boundary, bdy, 241 XModAction, act, 242 IsPreXModDomain, true, 243 Is2DimensionalGroup, true ); 244 if not IsPreXMod( PM ) then 245 Info( InfoXMod, 1, "Warning: not a pre-crossed module." ); 246 else 247 ok := IsXMod( PM ); # for running properly the function AllXMods 248 fi; 249 # name := Name( PM ); 250 ## check the types 251 if ( IsPermGroup(src) and IsPermGroup(rng) ) then 252 SetIsPerm2DimensionalGroup( PM, true ); 253 elif ( IsPcGroup(src) and IsPcGroup(rng) ) then 254 SetIsPc2DimensionalGroup( PM, true ); 255 fi; 256 return PM; 257end ); 258 259############################################################################# 260## 261#M ImageElmXModAction( <pxmod>, <s>, <r> ) pre-xmod module action of s on r 262## 263InstallMethod( ImageElmXModAction, "method for a precrossed module", true, 264 [ Is2DimensionalDomain, IsObject, IsObject ], 0, 265function( PM, s, r ) 266 267 local actr; 268 269 if ( HasIsPreXModWithObjects(PM) and IsPreXModWithObjects(PM) ) then 270 ## this is the crossed module of groupoids case 271 actr := ImageElm( XModAction( PM ), r )![1]; 272 return ImageElm( actr, s ); 273 else 274 return ImageElm( ImageElm( XModAction(PM), r ), s ); 275 fi; 276end ); 277 278############################################################################# 279## 280#M ExternalSetXMod( <pxm> ) . . . . . . . source group as a range group set 281## 282InstallMethod( ExternalSetXMod, "method for a precrossed module", true, 283 [ IsPreXMod ], 0, 284function( PM ) 285 286 local rng, genR, act; 287 288 rng := Range( PM ); 289 genR := GeneratorsOfGroup( rng ); 290 act := XModAction( PM ); 291 return ExternalSet( rng, Source(PM), genR, 292 List( genR, g -> ImageElm( act, g ) ) ); 293end ); 294 295############################################################################# 296## 297#M String, ViewString, PrintString, ViewObj, PrintObj 298## . . . . . . . . . . . . . . . . . . . . . . . for two-dimensional domains 299## 300InstallMethod( String, "for a 2d-domain", true, [ Is2DimensionalDomain ], 0, 301function( g2d ) 302 return( STRINGIFY( "[", String( Source(g2d) ), " -> ", 303 String( Range(g2d) ), "]" ) ); 304end ); 305 306InstallMethod( ViewString, "for a 2d-domain", true, [ Is2DimensionalDomain ], 307 0, String ); 308 309InstallMethod( PrintString, "for a 2d-domain", true, [ Is2DimensionalDomain ], 310 0, String ); 311 312InstallMethod( ViewObj, "for a 2d-domain", true, [ Is2DimensionalDomain ], 313 0, 314function( g2d ) 315 if HasName( g2d ) then 316 Print( Name( g2d ), "\n" ); 317 elif ( HasIsPreXModDomain( g2d ) and IsPreXModDomain( g2d ) ) then 318 Print( "[", Source( g2d ), "->", Range( g2d ), "]" ); 319 elif ( HasIsPreCat1Domain( g2d ) and IsPreCat1Domain( g2d ) ) then 320 Print( "[", Source( g2d ), "=>", Range( g2d ), "]" ); 321 else 322 TryNextMethod(); 323 fi; 324end ); 325 326InstallMethod( PrintObj, "for a 2d-domain", true, [ Is2DimensionalDomain ], 0, 327function( g2d ) 328 if HasName( g2d ) then 329 Print( Name( g2d ), "\n" ); 330 elif ( HasIsPreXModDomain( g2d ) and IsPreXModDomain( g2d ) ) then 331 Print( "[", Source( g2d ) ); 332 if IsGroupoid( Source( g2d ) ) then 333 Print( "\n-> " ); 334 else 335 Print( " -> " ); 336 fi; 337 Print( Range( g2d ), "]" ); 338 elif ( HasIsPreCat1Domain( g2d ) and IsPreCat1Domain( g2d ) ) then 339 Print( "[", Source( g2d ) ); 340 if IsGroupoid( Source( g2d ) ) then 341 Print( "\n=> " ); 342 else 343 Print( " => " ); 344 fi; 345 Print( Range( g2d ), "]" ); 346 else 347 TryNextMethod(); 348 fi; 349end ); 350 351############################################################################# 352## 353#F Display( <g2d> ) . . . . . . . . . . . . . . print details of a 2d-group 354## 355InstallMethod( Display, "method for prexmods and precat2groups", true, 356 [ Is2DimensionalGroup ], 20, 357function( g2d ) 358 359 local name, bdy, act, aut, len, i, ispar, src, rng, 360 gensrc, genrng, ker, genker, mor, triv, imact, a, 361 t, h, e, b, k, imt, imh, ime, imb, imk; 362 363 src := Source( g2d ); 364 rng := Range( g2d ); 365 if ( HasName(src) and HasName(rng) ) then 366 name := Name( g2d ); 367 else 368 name := "[??->??]"; 369 fi; 370 gensrc := GeneratorsOfGroup( src ); 371 genrng := GeneratorsOfGroup( rng ); 372 if ( HasIsPreXMod( g2d ) and IsPreXMod( g2d ) ) then 373 if ( HasIsXMod( g2d ) and IsXMod( g2d ) ) then 374 Print( "\nCrossed module " ); 375 else 376 Print( "\nPre-crossed module " ); 377 fi; 378 elif ( HasIsPreCat1Group( g2d ) and IsPreCat1Group( g2d ) ) then 379 if ( HasIsCat1Group( g2d ) and IsCat1Group( g2d ) ) then 380 Print( "\nCat1-group " ); 381 else 382 Print( "\nPre-cat1-group " ); 383 fi; 384 else 385 Print( "WARNING: neither a PreXMod nor a PreCat1Group" ); 386 fi; 387 if HasName( g2d ) then 388 Print( Name(g2d), " :- \n" ); 389 else 390 Print( ":- \n" ); 391 fi; 392 ispar := not HasParent( src ); 393 if ( ispar and HasName( src ) ) then 394 Print( ": Source group ", src ); 395 elif ( ispar and HasName( Parent( src ) ) ) then 396 Print( ": Source group has parent ( ", Parent( src), " ) and" ); 397 else 398 Print( ": Source group" ); 399 fi; 400 Print( " has generators:\n" ); 401 Print( " ", gensrc, "\n" ); 402 ispar := not HasParent( rng ); 403 if ( ispar and HasName( rng ) ) then 404 Print( ": Range group ", rng ); 405 elif ( ispar and HasName( Parent( rng ) ) ) then 406 Print( ": Range group has parent ( ", Parent( rng ), " ) and" ); 407 else 408 Print( ": Range group" ); 409 fi; 410 Print( " has generators:\n" ); 411 Print( " ", genrng, "\n" ); 412 if ( HasIsPreXMod( g2d ) and IsPreXMod( g2d ) ) then 413 Print( ": Boundary homomorphism maps source generators to:\n" ); 414 bdy := Boundary( g2d ); 415 Print( " ", List( gensrc, s -> ImageElm( bdy, s ) ), "\n" ); 416 act := XModAction( g2d ); 417 imact := List( genrng, r -> ImageElm( act, r ) ); 418 aut := Range( act ); 419 triv := ( aut = Group( InclusionMappingGroups( src, src ) ) ); 420 len := Length( genrng ); 421 if ( len = 0 ) then 422 triv := true; 423 else 424 for i in [1..len] do 425 a := imact[i]; 426 od; 427 fi; 428 if not triv then 429 Print( ": Action homomorphism maps" ); 430 Print( " range generators to automorphisms:\n" ); 431 for i in [1..len] do 432 Print( " ", genrng[i], " --> { source gens --> " ); 433 Print( List( gensrc, s -> ImageElm( imact[i], s ) ), " }\n" ); 434 od; 435 fi; 436 if triv then 437 Print( " The automorphism group is trivial\n" ); 438 else 439 if ( len = 1 ) then 440 Print( " This automorphism generates" ); 441 else 442 Print( " These ", len, " automorphisms generate" ); 443 fi; 444 Print( " the group of automorphisms.\n" ); 445 fi; 446 else ## g2d is at least a PreCat1Group 447 ker := Kernel( g2d ); 448 genker := GeneratorsOfGroup( ker ); 449 t := TailMap( g2d ); 450 h := HeadMap( g2d ); 451 e := RangeEmbedding( g2d ); 452 b := Boundary( g2d ); 453 k := KernelEmbedding( g2d ); 454 imt := List( gensrc, x -> ImageElm( t, x ) ); 455 imh := List( gensrc, x -> ImageElm( h, x ) ); 456 ime := List( genrng, x -> ImageElm( e, x ) ); 457 imb := List( genker, x -> ImageElm( b, x ) ); 458 imk := List( genker, x -> ImageElm( k, x ) ); 459 Print( ": tail homomorphism maps source generators to:\n" ); 460 Print( " ", imt, "\n" ); 461 Print( ": head homomorphism maps source generators to:\n" ); 462 Print( " ", imh, "\n" ); 463 Print( ": range embedding maps range generators to:\n" ); 464 Print( " ", ime, "\n" ); 465 if ( Size( ker ) = 1 ) then 466 Print( ": the kernel is trivial.\n" ); 467 else 468 Print( ": kernel has generators:\n" ); 469 Print( " ", genker, "\n" ); 470 Print( ": boundary homomorphism maps generators of kernel to:\n" ); 471 Print( " ", imb, "\n" ); 472 Print( ": kernel embedding maps generators of kernel to:\n" ); 473 Print( " ", imk, "\n" ); 474 fi; 475 fi; 476 if ( HasIsXMod( g2d ) and IsXMod( g2d ) and HasCat1GroupOfXMod( g2d ) ) then 477 Print( ": associated cat1-group is ", 478 Cat1GroupOfXMod( g2d ), "\n" ); 479 elif ( HasIsCat1Group( g2d ) and IsCat1Group( g2d ) 480 and HasXModOfCat1Group( g2d ) ) then 481 Print( ": associated crossed module is ", 482 XModOfCat1Group( g2d ), "\n" ); 483 fi; 484 Print( "\n" ); 485end ); 486 487############################################################################# 488## 489#M IdGroup . . . . . . . . . . . . . . . . . . . . for a 2Dimensional-domain 490#M StructureDescription . . . . . . . . . . . . . for a 2Dimensional-domain 491## 492InstallOtherMethod( IdGroup, "method for a 2d-domain", true, 493 [ Is2DimensionalDomain ], 0, 494function( dom ) 495 return [ IdGroup( Source(dom) ), IdGroup( Range(dom) ) ]; 496end ); 497 498InstallOtherMethod( StructureDescription, "method for a 2d-domain", true, 499 [ Is2DimensionalDomain ], 0, 500function( dom ) 501 return [ StructureDescription( Source(dom) ), 502 StructureDescription( Range(dom) ) ]; 503end ); 504 505############################################################################# 506## 507#M Name . . . . . . . . . . . . . . . . . . . . . for a 2Dimensional-domain 508## 509InstallMethod( Name, "method for a 2d-domain", true, 510 [ Is2DimensionalDomain ], 0, 511function( dom ) 512 513 local nsrc, nrng, name, arrow; 514 515 if HasName( Source( dom ) ) then 516 nsrc := Name( Source( dom ) ); 517 else 518 nsrc := ".."; 519 fi; 520 if HasName( Range( dom ) ) then 521 nrng := Name( Range( dom ) ); 522 else 523 nrng := ".."; 524 fi; 525 if ( HasIsPreXModDomain( dom ) and IsPreXModDomain( dom ) ) then 526 arrow := "->"; 527 elif ( HasIsPreCat1Domain( dom ) and IsPreCat1Domain( dom ) ) then 528 arrow := "=>"; 529 else 530 arrow := "->-"; 531 fi; 532 name := Concatenation( "[", nsrc, arrow, nrng, "]" ); 533 SetName( dom, name ); 534 return name; 535end ); 536 537############################################################################# 538## 539#M PreXModByBoundaryAndAction 540## 541InstallMethod( PreXModByBoundaryAndAction, 542 "pre-crossed module from boundary and action maps", 543 true, [ IsGroupHomomorphism, IsGroupHomomorphism ], 0, 544function( bdy, act ) 545 546 local rng, src, genrng, gensrc, aut, genaut, imact, i, a0, ima, a, PX; 547 548 src := Source( bdy ); 549 gensrc := GeneratorsOfGroup( src ); 550 rng := Range( bdy ); 551 genrng := GeneratorsOfGroup( rng ); 552 if not ( Source( act ) = rng ) then 553 Info( InfoXMod, 2, 554 "The range group is not the source of the action." ); 555 return fail; 556 fi; 557 aut := Range( act ); 558 genaut := GeneratorsOfGroup( aut ); 559 if not IsGroupOfAutomorphisms( aut ) then 560 Info( InfoXMod, 2, "<aut> is not a group of automorphisms" ); 561 return fail; 562 fi; 563 for a in genaut do 564 if not ( ( Source( a ) = src ) and ( Range( a ) = src ) ) then 565 Info( InfoXMod, 2, "error in source and range of automorphism" ); 566 return fail; 567 fi; 568 od; 569 if not ( One( aut ) = IdentityMapping( src ) ) then 570 Info( InfoXMod, 2, 571 "aut.identity <> IdentityMapping( src )" ); 572 return fail; 573 fi; 574 imact := List( genrng, r -> ImageElm( act, r ) ); 575 for i in [ 1..Length( imact ) ] do 576 a0 := imact[i]; 577 ima := List( gensrc, s -> ImageElm( a0, s ) ); 578 a := GroupHomomorphismByImages( src, src, gensrc, ima ); 579 imact[i] := a; 580 od; 581 PX := PreXModObj( bdy, act ); 582 if not IsPreXMod( PX ) then 583 Error( "PX fails to be a pre-crossed module" ); 584 fi; 585 return PX; 586end ); 587 588############################################################################# 589## 590#M IsPreCat1Group check that the first pre-cat1-group axiom holds 591## 592InstallMethod( IsPreCat1Group, "generic method for 2dim-group", true, 593 [ Is2DimensionalGroup ], 0, 594function( C1G ) 595 596 local Csrc, Crng, x, e, t, h, idrng, he, te, kert, kerh, kerth; 597 598 if not IsPreCat1Obj( C1G ) then 599 return false; 600 fi; 601 Crng := Range( C1G ); 602 h := HeadMap( C1G ); 603 t := TailMap( C1G ); 604 e := RangeEmbedding( C1G ); 605 # checking the first condition of cat-1 group 606 idrng := IdentityMapping( Crng ); 607 he := CompositionMapping( h, e ); 608 te := CompositionMapping( t, e ); 609 if not ( te = idrng ) then 610 Print( "te <> range identity \n" ); 611 return false; 612 fi; 613 if not ( he = idrng ) then 614 Print( "he <> range identity \n" ); 615 return false; 616 fi; 617 return true; 618end ); 619 620############################################################################## 621## 622#M \=( <C1>, <C2> ) . . . . . . . . . . test if two pre-cat1-groups are equal 623## 624InstallMethod( \=, "generic method for pre-cat1-groups", 625 IsIdenticalObj, [ IsPreCat1Group, IsPreCat1Group ], 0, 626function( C1, C2 ) 627 return ( ( TailMap(C1) = TailMap(C2) ) and ( HeadMap(C1) = HeadMap(C2) ) 628 and ( RangeEmbedding(C1) = RangeEmbedding(C2) ) ); 629end ); 630 631############################################################################## 632## 633#M PreCat1Obj . . . . . . . . . . . . . . . . . . . . . make a pre-cat1-group 634## 635InstallMethod( PreCat1Obj, "for tail, head, embedding", true, 636 [ IsGroupHomomorphism, IsGroupHomomorphism, IsGroupHomomorphism ], 0, 637function( t, h, e ) 638 639 local src, rng, type, C1G, ok, name; 640 641 src := Source( t ); 642 rng := Range( t ); 643 if not ( ( src = Source( h ) ) and ( rng = Range( h ) ) ) then 644 Error( "tail & head must have same source and range" ); 645 fi; 646 if not ( ( Source( e ) = rng ) and ( Range( e ) = src ) ) then 647 Error( "tail, embedding must have opposite source and range" ); 648 fi; 649 if ( IsPermGroup( src ) and IsPermGroup( rng ) ) then 650 type := PermPreCat1ObjType; 651 elif ( IsPcGroup( src ) and IsPcGroup( rng ) ) then 652 type := PcPreCat1ObjType; 653 else 654 type := PreCat1ObjType; 655 fi; 656 C1G := rec(); 657 ObjectifyWithAttributes( C1G, type, 658 Source, src, 659 Range, rng, 660 TailMap, t, 661 HeadMap, h, 662 RangeEmbedding, e, 663 IsPreCat1Domain, true, 664 Is2DimensionalGroup, true ); 665 ok := IsPreCat1Group( C1G ); 666 if not ok then 667 Error( "not a pre-cat1-group" ); 668 fi; 669 ok := IsPreCat1GroupByEndomorphisms( C1G ); 670 ok := IsCat1Group( C1G ); 671 ## check the types 672 if ( IsPermGroup( src ) and IsPermGroup( rng ) ) then 673 SetIsPerm2DimensionalGroup( C1G, true ); 674 elif ( IsPcGroup( src ) and IsPcGroup( rng ) ) then 675 SetIsPc2DimensionalGroup( C1G, true ); 676 fi; 677 if ( HasName( src ) and HasName( rng ) ) then 678 name := Name( C1G ); 679 fi; 680 return C1G; 681end ); 682 683############################################################################## 684## 685#M Elements( <P> ) . . . . . . . . . . . . elements for a pre-crossed module 686## 687## replaced by Enumerator ??? 688 689############################################################################# 690## 691#M ReverseCat1Group for a pre-cat1-group 692## 693InstallMethod( ReverseCat1Group, "method for a cat1-group", true, 694 [ IsPreCat1Group ], 0, 695function( C1G ) 696 local rev; 697 rev := PreCat1Group( HeadMap(C1G), TailMap(C1G), RangeEmbedding(C1G ) ); 698 SetReverseCat1Group( rev, C1G ); 699 return rev; 700end ); 701 702############################################################################# 703## 704#F PreCat1Group( <t>, <h>, <e> ) pre-cat1-group from given tail, head, embed 705#F PreCat1Group( <t>, <h> ) pre-cat1-group from tail, head endomorphisms 706## 707InstallGlobalFunction( PreCat1Group, function( arg ) 708 709 local nargs, usage, C1G; 710 711 nargs := Length( arg ); 712 usage := "standard usage: PreCat1Group( tail, head [,embed] );"; 713 if not ForAll( arg, a -> IsGroupHomomorphism(a) ) then 714 Error( usage ); 715 fi; 716 # one endomorphism 717 if ( ( nargs=1 ) and IsEndoMapping( arg[1] ) ) then 718 return PreCat1GroupByEndomorphisms( arg[1], arg[1] ); 719 # two endomorphisms 720 elif ( nargs=2 ) then 721 if ( IsEndoMapping( arg[1] ) and IsEndoMapping( arg[2] ) ) then 722 return PreCat1GroupByEndomorphisms( arg[1], arg[2] ); 723 elif ( Image( arg[1] ) = Source( arg[2] ) ) then 724 return PreCat1GroupByTailHeadEmbedding( arg[1], arg[1], arg[2] ); 725 fi; 726 # two homomorphisms and an embedding 727 elif ( nargs=3 ) then 728 return PreCat1GroupByTailHeadEmbedding( arg[1], arg[2], arg[3] ); 729 fi; 730 # other alternatives not allowed 731 Error( usage ); 732end ); 733 734############################################################################## 735## 736#M PreCat1GroupOfPreXMod . . convert a pre-crossed module to a pre-cat1-group 737## 738InstallMethod( PreCat1GroupOfPreXMod, 739 "convert a pre-crossed module to a pre-cat1-group", true, [ IsPreXMod ], 0, 740function( X0 ) 741 742 local S0, genS0, R0, genR0, iso, Xact, Xbdy, one, imbdy, info, G, genG, 743 t, h, f, eR, eS, imeR, imeS, projS, imt, imh, ime, imf, C, pcrec; 744 745 S0 := Source( X0 ); 746 genS0 := GeneratorsOfGroup( S0 ); 747 R0 := Range( X0 ); 748 genR0 := GeneratorsOfGroup( R0 ); 749 genS0 := GeneratorsOfGroup( S0 ); 750 genR0 := GeneratorsOfGroup( R0 ); 751 one := One( R0 ); 752 Xact := XModAction( X0 ); 753 Xbdy := Boundary( X0 ); 754 if IsTrivialAction2DimensionalGroup( X0 ) then 755 Info( InfoXMod, 2, "Using direct product: ", R0, " x ", S0 ); 756 G := DirectProduct( R0, S0 ); 757 info := DirectProductInfo( G ); 758 if ( HasName( S0 ) and HasName( R0 ) ) then 759 SetName( G, Concatenation( Name( R0 ), "x", Name( S0 ) ) ); 760 fi; 761 genG := GeneratorsOfGroup( G ); 762 imbdy := List( genS0, s -> ImageElm( Xbdy, s ) ); 763 imt := Concatenation( genR0, List( genS0, s -> one ) ); 764 imh := Concatenation( genR0, imbdy ); 765 t := GroupHomomorphismByImages( G, R0, genG, imt ); 766 h := GroupHomomorphismByImages( G, R0, genG, imh ); 767 eR := Embedding( G, 1 ); 768 eR := AsGroupGeneralMappingByImages( eR ); 769 eS := Embedding( G, 2 ); 770 eS := AsGroupGeneralMappingByImages( eS ); 771 else 772 Info( InfoXMod, 2, "Using semidirect product: ", R0, " |X ", S0 ); 773 G := SemidirectProduct( R0, Xact, S0 ); 774 info := SemidirectProductInfo( G ); 775 if ( HasName( S0 ) and HasName( R0 ) ) then 776 SetName( G, 777 Concatenation( "(", Name(R0), " |X ", Name(S0), ")" ) ); 778 else 779 SetName( G, "(..|X..)" ); 780 fi; 781 genG := GeneratorsOfGroup( G ); 782 eR := Embedding( G, 1 ); 783 imeR := List( genR0, r -> ImageElm( eR, r ) ); 784 eS := Embedding( G, 2 ); 785 imeS := List( genS0, s -> ImageElm( eS, s ) ); 786 t := Projection( G ); 787 imt := List( genG, g -> ImageElm( t, g ) ); 788 t := GroupHomomorphismByImages( G, R0, genG, imt ); 789 projS := List( imt, r -> ImageElm( eR, r^-1 ) ); 790 projS := List( [ 1..Length( genG ) ], i -> projS[i] * genG[i] ); 791 projS := List( projS, x -> PreImagesRepresentative( eS, x ) ); 792 imh := List( [ 1..Length( genG ) ], 793 i -> imt[i] * ImageElm( Xbdy, projS[i] ) ); 794 h := GroupHomomorphismByImages( G, R0, genG, imh ); 795 fi; 796 C := PreCat1GroupByTailHeadEmbedding( t, h, eR ); 797 if HasName( X0 ) then 798 SetName( C, Concatenation( "cat1(", Name( X0 ), ")" ) ); 799 fi; 800 pcrec := rec( precat1 := C, 801 xmodRangeEmbedding := Image( eR ), 802 xmodRangeEmbeddingIsomorphism := eR, 803 xmodSourceEmbedding := Image( eS ), 804 xmodSourceEmbeddingIsomorphism := eS ); 805 if HasIsXMod( X0 ) and IsXMod( X0 ) then 806 pcrec.iscat1 := true; 807 fi; 808 return pcrec; 809end ); 810 811############################################################################# 812## 813#M IsXMod . . . . . . . . . check that the second crossed module axiom holds 814## 815InstallMethod( IsXMod, "generic method for pre-crossed modules", 816 true, [ IsPreXMod ], 0, 817function( XM ) 818 819 local gensrc, genrng, x2, y2, w2, z2, hom, act; 820 821 hom := Boundary( XM ); 822 act := XModAction( XM ); 823 gensrc := GeneratorsOfGroup( Source( XM ) ); 824 genrng := GeneratorsOfGroup( Range( XM ) ); 825 for x2 in gensrc do 826 for y2 in gensrc do 827 # Print( "x2,y2 = ", x2, ", ", y2, "\n" ); 828 z2 := x2 ^ ((y2 ^ hom) ^ act); 829 w2 := x2 ^ y2; 830 if ( z2 <> w2 ) then 831 Info( InfoXMod, 2, 832 "CM2) fails at x2 = ", x2, ", y2 = ", y2, "\n", 833 "x2^(hom(y2)) = ", z2, "\n"," x2^y2 = ", w2, "\n" ); 834 return false; 835 fi; 836 od; 837 od; 838 return true; 839end ); 840 841############################################################################# 842## 843#M XModByBoundaryAndAction 844## 845InstallMethod( XModByBoundaryAndAction, 846 "crossed module from boundary and action maps", true, 847 [ IsGroupHomomorphism, IsGroupHomomorphism ], 0, 848function( bdy, act ) 849 850 local PM; 851 852 PM := PreXModByBoundaryAndAction( bdy, act ); 853 if not IsXMod( PM ) then 854 Error( "this boundary and action only defines a pre-crossed module" ); 855 fi; 856 return PM; 857end ); 858 859############################################################################# 860## 861#M XModByTrivialAction 862## 863InstallMethod( XModByTrivialAction, "crossed module with trivial action", 864 true, [ IsGroupHomomorphism ], 0, 865function( f ) 866 local R, ZR, S, XM, aut, act, name; 867 S := Source( f ); 868 if not IsAbelian( S ) then 869 Error( "the source of f must be abelian" ); 870 fi; 871 R := Range( f ); 872 ZR := Centre( R ); 873 if not IsSubgroup( ZR, Image( f, S ) ) then 874 Error( "image of source must lie in the centre of range" ); 875 fi; 876 aut := Group( IdentityMapping( S ) ); 877 act := MappingToOne( R, aut ); 878 XM := XModByBoundaryAndAction( f, act ); 879 SetIsTrivialAction2DimensionalGroup( XM, true ); 880 return XM; 881end ); 882 883############################################################################## 884## 885#F XModByNormalSubgroup create a crossed module from normal N in G 886## 887InstallMethod( XModByNormalSubgroup, "conjugation crossed module", 888 true, [ IsGroup, IsGroup ], 0, 889function( G, N ) 890 891 local XM, bdy, act, aut, genrng, gensrc, name, a, triv, idsrc, 892 autgen, imautgen, phi, j, g, n, genN, f2pN, imgenN; 893 894 if not IsNormal( G, N ) then 895 return fail; 896 fi; 897 genrng := GeneratorsOfGroup( G ); 898 gensrc := GeneratorsOfGroup( N ); 899 bdy := GroupHomomorphismByImages( N, G, gensrc, gensrc ); 900 autgen := [ ]; 901 for g in genrng do 902 imautgen := List( gensrc, n -> n^g ); 903 a := GroupHomomorphismByImages( N, N, gensrc, imautgen ); 904 Add( autgen, a ); 905 od; 906 if ( Length( genrng ) = 0 ) then 907 idsrc := IdentityMapping( N ); 908 aut := Group( idsrc ); 909 Info( InfoXMod, 2, 910 "Group of conjugations has size ", Size( aut ) ); 911 else 912 aut := Group( autgen ); 913 fi; 914 SetIsGroupOfAutomorphisms( aut, true ); 915 act := GroupHomomorphismByImages( G, aut, genrng, autgen ); 916 XM := PreXModObj( bdy, act ); 917 SetIsNormalSubgroup2DimensionalGroup( XM, true ); 918 if ( Length( autgen ) = 0 ) then 919 SetIsTrivialAction2DimensionalGroup( XM, true ); 920 fi; 921 return XM; 922end ); 923 924############################################################################# 925## 926#F XModByCentralExtension xmod from surjection with central kernel 927## 928InstallMethod( XModByCentralExtension, "central extension crossed module", 929 true, [ IsGroupHomomorphism ], 0, 930function( hom ) 931 932 local rng, src, Zsrc, ker, gensrc, ngsrc, imhom, genrng, autgen, 933 j, imsrc, aut, act, XM, ok, idsrc; 934 935 if not IsSurjective( hom ) then 936 Error( "homomorphism must be surjective" ); 937 fi; 938 src := Source( hom ); 939 rng := Range( hom ); 940 Zsrc := Centre( src ); 941 ker := Kernel( hom ); 942 if not IsSubgroup( Zsrc, ker ) then 943 Error( "Kernel of surjection is not central" ); 944 fi; 945 gensrc := GeneratorsOfGroup( src ); 946 ngsrc := Length( gensrc ); 947 imhom := List( gensrc, s -> ImageElm( hom, s ) ); 948 genrng := GeneratorsOfGroup( rng ); 949 autgen := ListWithIdenticalEntries( ngsrc, 0 ); 950 for j in [1..ngsrc] do 951 imsrc := List( gensrc, s -> s^gensrc[j] ); 952 autgen[j] := GroupHomomorphismByImages( src, src, gensrc, imsrc ); 953 od; 954 aut := Group( autgen ); 955 SetIsGroupOfAutomorphisms( aut, true ); 956 Info( InfoXMod, 2, "Group of conjugations has size ", Size(aut) ); 957 act := GroupHomomorphismByImages( rng, aut, imhom, autgen ); 958 if ( not IsGroupHomomorphism( act ) ) then 959 Error( "action is not a homomorphism" ); 960 fi; 961 XM := PreXModObj( hom, act ); 962 SetIsCentralExtension2DimensionalGroup( XM, true ); 963 idsrc := IdentityMapping( src ); 964 if ForAll( autgen, a -> ( a = idsrc ) ) then 965 SetIsTrivialAction2DimensionalGroup( XM, true ); 966 fi; 967 ok := IsXMod( XM ); 968 return XM; 969end ); 970 971############################################################################# 972## 973#M XModByAbelianModule( <abmod> ) crossed module [zero : abmod -> grp] 974## 975InstallMethod( XModByAbelianModule, "abelian module crossed module", true, 976 [ IsAbelianModule ], 0, 977function( abmod ) 978 979 local aut, act, z; 980 act := AbelianModuleAction( abmod ); 981 z := MappingToOne( AbelianModuleGroup( abmod ), Source( act ) ); 982 return XModByBoundaryAndAction( z, act ); 983end ); 984 985############################################################################# 986## 987#M XModByGroupOfAutomorphisms crossed module [G -> A] 988## 989InstallMethod( XModByGroupOfAutomorphisms, "automorphism crossed module", 990 true, [ IsGroup, IsGroup ], 0, 991function( G, A ) 992 993 local genA, autG, innG, abelian, genG, oneA, imbdy, g, ima, a, bdy, act, 994 iso1, A1, bdy1, act1, iso2, iso12, bdy2, act2, XM; 995 996 if not IsGroupOfAutomorphisms( A ) then 997 Error( "A is not a group of automorphisms" ); 998 fi; 999 genA := GeneratorsOfGroup( A ); 1000 autG := AutomorphismGroup( G ); 1001 if not IsSubgroup( autG, A ) then 1002 Error( "A is not a group of automorphisms of G" ); 1003 fi; 1004 innG := InnerAutomorphismsAutomorphismGroup( autG ); 1005 if not IsSubgroup( A, innG ) then 1006 Error( "the inner automorphism group of G is not a subgroup of A" ); 1007 fi; 1008 abelian := IsAbelian( G ); 1009 genG := GeneratorsOfGroup( G ); 1010 oneA := One( A ); 1011 if abelian then 1012 imbdy := List( genG, g -> oneA ); 1013 else 1014 imbdy := [ ]; 1015 for g in genG do 1016 ima := List( genG, h -> h^g ); 1017 a := GroupHomomorphismByImages( G, G, genG, ima ); 1018 Add( imbdy, a ); 1019 od; 1020 fi; 1021 bdy := GroupHomomorphismByImages( G, A, genG, imbdy ); 1022 XM := PreXModObj( bdy, IdentityMapping( A ) ); 1023 SetIsAutomorphismGroup2DimensionalGroup( XM, true ); 1024 if not IsXMod( XM ) then 1025 Error( "this boundary and action only defines a pre-crossed module" ); 1026 fi; 1027 return XM; 1028end ); 1029 1030############################################################################# 1031## 1032#M XModByAutomorphismGroup( <G> ) crossed module [G -> Aut(G)] 1033#M XModByInnerAutomorphismGroup( <G> ) crossed module [G -> Inn(G)] 1034## 1035InstallMethod( XModByAutomorphismGroup, "automorphism xmod of a group", 1036 true, [ IsGroup ], 0, 1037function( G ) 1038 1039 local autG, innG, a; 1040 1041 autG := AutomorphismGroup( G ); 1042 if ( not HasName( autG ) and HasName( G ) ) then 1043 SetName( autG, Concatenation( "Aut(", Name( G ), ")" ) ); 1044 fi; 1045 SetIsGroupOfAutomorphisms( autG, true ); 1046 return XModByGroupOfAutomorphisms( G, autG ); 1047end ); 1048 1049InstallMethod( XModByInnerAutomorphismGroup, "inner automorphism xmod", 1050 true, [ IsGroup ], 0, 1051function( G ) 1052 local A, innG, a; 1053 1054 A := InnerAutomorphismsByNormalSubgroup( G, G ); 1055 if ( not HasName( A ) and HasName( G ) ) then 1056 SetName( A, Concatenation( "Inn(", Name( G ), ")" ) ); 1057 fi; 1058 SetIsGroupOfAutomorphisms( A, true ); 1059 return XModByGroupOfAutomorphisms( G, A ); 1060end ); 1061 1062############################################################################## 1063## 1064#M XModOfCat1Group 1065## 1066InstallMethod( XModOfCat1Group, "generic method for cat1-groups", 1067 true, [ IsCat1Group ], 0, 1068function( C1 ) 1069 1070 local X1; 1071 X1 := PreXModOfPreCat1Group( C1 ); 1072 SetIsXMod( X1, true ); 1073 SetXModOfCat1Group( C1, X1 ); 1074 SetCat1GroupOfXMod( X1, C1 ); 1075 return X1; 1076end ); 1077 1078############################################################################## 1079## 1080#M Cat1GroupOfXMod 1081## 1082InstallMethod( Cat1GroupOfXMod, "generic method for crossed modules", 1083 true, [ IsXMod ], 0, 1084function( X1 ) 1085 1086 local PC1, C1; 1087 1088 PC1 := PreCat1GroupOfPreXMod( X1 ); 1089 C1 := PC1.precat1; 1090 SetXModOfCat1Group( C1, X1 ); 1091 return C1; 1092end ); 1093 1094############################################################################## 1095## 1096#M PeifferSubgroupPreXMod . . . . . normally generated by Peiffer commutators 1097## 1098InstallMethod( PeifferSubgroupPreXMod, "generic method for pre-crossed xmods", 1099 true, [ IsPreXMod ], 0, 1100function( PM ) 1101 1102 local Pf, s1, s2, a1, src, gensrc, comm, bdy, act, ok, XPf; 1103 1104 # this code mimics that of DerivedSubgroup 1105 src := Source( PM ); 1106 bdy := Boundary( PM ); 1107 act := XModAction( PM ); 1108 gensrc := GeneratorsOfGroup( src ); 1109 Pf := TrivialSubgroup( src ); 1110 for s1 in gensrc do 1111 a1 := ImageElm( act, ImageElm( bdy, s1 ) ); 1112 for s2 in gensrc do 1113 comm := (s2^-1)^s1 * ImageElm( a1, s2 ); 1114 if not ( comm in Pf ) then 1115 Pf := ClosureSubgroup( Pf, comm ); 1116 fi; 1117 od; 1118 od; 1119 Pf := NormalClosure( src, Pf ); 1120 if ( Pf = src ) then 1121 Pf := src; 1122 fi; 1123 XPf := Sub2DimensionalGroup( PM, Pf, TrivialSubgroup( Range(PM) ) ); 1124 ok := IsNormal( PM, XPf ); 1125 SetPeifferSub2DimensionalGroup( PM, XPf ); 1126 return Pf; 1127end ); 1128 1129############################################################################## 1130## 1131#M PeifferSubgroupPreCat1Group . . . . commutator of kernels of tail and head 1132## 1133InstallMethod( PeifferSubgroupPreCat1Group, 1134 "generic method for pre-cat1-groups", true, [ IsPreCat1Group ], 0, 1135function( PCG ) 1136 1137 local src, kerh, kert, Pf; 1138 1139 src := Source( PCG ); 1140 kert := Kernel( TailMap( PCG ) ); 1141 kerh := Kernel( HeadMap( PCG ) ); 1142 Pf := CommutatorSubgroup( kert, kerh ); 1143 if ( Pf = src ) then 1144 Pf := src; 1145 fi; 1146 return Pf; 1147end ); 1148 1149############################################################################## 1150## 1151#M PeifferSubgroup . . . . . . . . 1152## 1153InstallMethod( PeifferSubgroup, "generic method for 2d-groups", 1154 true, [ Is2DimensionalGroup ], 0, 1155function( obj ) 1156 local P, ok, NP; 1157 if IsPreXModObj( obj ) then 1158 if IsXMod( obj ) then 1159 return Subgroup( Source( obj ), [ One( Source( obj ) ) ] ); 1160 else 1161 P := PeifferSubgroupPreXMod( obj ); 1162 NP := SubPreXMod( obj, P, TrivialSubgroup( Range(obj) ) ); 1163 ok := IsNormal( obj, NP ); 1164 return P; 1165 fi; 1166 elif IsPreCat1Obj( obj ) then 1167 if IsCat1Group( obj ) then 1168 return Subgroup( Source( obj ), [ One( Source( obj ) ) ] ); 1169 else 1170 P := PeifferSubgroupPreCat1Group( obj ); 1171 NP := SubPreCat1Group( obj, P, TrivialSubgroup( Range(obj) ) ); 1172 ok := IsNormal( obj, NP ); 1173 return P; 1174 fi; 1175 else 1176 return fail; 1177 fi; 1178end ); 1179 1180############################################################################## 1181## 1182#A XModByPeifferQuotient . . . . . . . xmod from prexmod and Peiffer subgroup 1183## 1184InstallMethod( XModByPeifferQuotient, 1185 "crossed module from a pre-crossed module and Peiffer subgroup", true, 1186 [ IsPreXMod ], 0, 1187function( PM ) 1188 1189 local pfsub, pfxmod, name, nat, ok, FM; 1190 1191 if IsXMod( PM ) then 1192 Info( InfoXMod, 1, "this object is already a crossed module!" ); 1193 return PM; 1194 fi; 1195 pfsub := PeifferSubgroup( PM ); 1196 if not IsNormal( Source( PM ), pfsub ) then 1197 Error( "Peiffer subgroup not normal in source group" ); 1198 fi; 1199 pfxmod := SubPreXMod( PM, pfsub, TrivialSubgroup( Range(PM) ) ); 1200 ok := IsNormal( PM, pfxmod ); 1201 if not ok then 1202 Error( "Peiffer precrossed module not normal!" ); 1203 fi; 1204 FM := FactorPreXMod( PM, pfxmod ); 1205 nat := ProjectionOfFactorPreXMod( FM ); 1206 if HasName( PM ) then 1207 name := Name( PM ); 1208 SetName( FM, Concatenation( "Peiffer(", name, ")" ) ); 1209 fi; 1210 return FM; 1211end ); 1212 1213############################################################################## 1214## 1215#O XModByPullback . . . . . . . . xmod from an xmod and a group homomorphism 1216## 1217InstallMethod( XModByPullback, 1218 "crossed module from a crossed module and a group homomorphism", true, 1219 [ IsXMod, IsGroupHomomorphism ], 0, 1220function( X0, nu ) 1221 1222 local M, P, act0, N, L, genL, lenL, info, dp, emb1, emb2, lambda, 1223 kappa, genLN, genLM, autL, genN, lenN, imact1, i, n, an, 1224 actLN, actLM, prod, act1, X1, mor; 1225 1226 M := Source( X0 ); 1227 P := Range( X0 ); 1228 if not ( Range( nu ) = P ) then 1229 Error( "Range(hom) <> Range(X0)" ); 1230 fi; 1231 act0 := XModAction( X0 ); 1232 N := Source( nu ); 1233 L := Pullback( Boundary( X0 ), nu ); 1234 genL := GeneratorsOfGroup( L ); 1235 lenL := Length( genL ); 1236 info := PullbackInfo( L ); 1237 dp := info!.directProduct; 1238 emb1 := Embedding( dp, 1 ); 1239 emb2 := Embedding( dp, 2 ); 1240 kappa := info!.projections[1]; 1241 lambda := info!.projections[2]; 1242 genLN := List( genL, g -> ImageElm( lambda, g ) ); 1243 genLM := List( genL, g -> ImageElm( kappa, g ) ); 1244 autL := AutomorphismGroup( L ); 1245 genN := GeneratorsOfGroup( N ); 1246 lenN := Length( genN ); 1247 imact1 := ListWithIdenticalEntries( lenN, 0 ); 1248 for i in [1..lenN] do 1249 n := genN[i]; 1250 an := ImageElm( act0, ImageElm( nu, n ) ); 1251 actLN := List( genLN, g -> g^n ); 1252 actLM := List( genLM, g -> ImageElm( an, g ) ); 1253 prod := List( [1..lenL], j -> ImageElm( emb1, actLM[j] ) 1254 * ImageElm( emb2, actLN[j] ) ); 1255 imact1[i] := GroupHomomorphismByImages( L, L, genL, prod ); 1256 od; 1257 act1 := GroupHomomorphismByImages( N, autL, genN, imact1 ); 1258 X1 := XMod( lambda, act1 ); 1259 mor := XModMorphismByGroupHomomorphisms( X1, X0, kappa, nu ); 1260 SetMorphismOfPullback( X1, mor ); 1261 return X1; 1262end ); 1263 1264############################################################################## 1265## 1266#A KernelCokernelXMod . . . . . ( ker(bdy) -> range/image(bdy) ) for an xmod 1267## 1268InstallMethod( KernelCokernelXMod, "kernel -> cokernel for an xmod", true, 1269 [ IsXMod ], 0, 1270function( X0 ) 1271 1272 local S, R, bdy, act, K, J, nat, F, iso, mgi, inv, C, genK, imres, res, 1273 genC, preC, imact, i, g, p, ap, im, autK, actC; 1274 1275 S := Source( X0 ); 1276 R := Range( X0 ); 1277 bdy := Boundary( X0 ); 1278 act := XModAction( X0 ); 1279 K := Kernel( bdy ); 1280 J := Image( bdy ); 1281 if ( J = R ) then ## trivial cokernel 1282 C := Group( () ); 1283 res := MappingToOne( K, C ); 1284 return XModByTrivialAction( res ); 1285 fi; 1286 nat := NaturalHomomorphismByNormalSubgroup( R, J ); 1287 F := FactorGroup( R, J ); 1288 iso := IsomorphismPermGroup( F ); 1289 C := Image( iso ); 1290 mgi := MappingGeneratorsImages( iso ); 1291 inv := GroupHomomorphismByImages( C, F, mgi[2], mgi[1] ); 1292 genK := GeneratorsOfGroup( K ); 1293 imres := List( genK, g -> Image( iso, Image( nat, Image( bdy, g ) ) ) ); 1294 res := GroupHomomorphismByImages( K, C, genK, imres ); 1295 genC := GeneratorsOfGroup( C ); 1296 preC := List( genC, 1297 g -> PreImagesRepresentative( nat, ImageElm( inv, g ) ) ); 1298 imact := ShallowCopy( genC ); 1299 for i in [1..Length( genC )] do 1300 g := genC[i]; 1301 p := preC[i]; 1302 ap := ImageElm( act, p ); 1303 im := List( genK, k -> ImageElm( ap, k ) ); 1304 imact[i] := GroupHomomorphismByImages( K, K, genK, im ); 1305 od; 1306 autK := Group( imact ); 1307 SetIsGroupOfAutomorphisms( autK, true ); 1308 actC := GroupHomomorphismByImages( C, autK, genC, imact ); 1309 return XModByBoundaryAndAction( res, actC ); 1310end ); 1311 1312############################################################################# 1313## 1314#F XMod( <bdy>, <act> ) crossed module from given boundary & action 1315#F XMod( <G>, <N> ) crossed module from a normal inclusion 1316#F XMod( <surj> ) crossed module from a surjective hom 1317#F XMod( <cat1> ) crossed module associated to a cat1-group 1318#F XMod( <aut> ) crossed module from automorphism group 1319#F XMod( <pxm> ) crossed module by Peiffer quotient 1320## 1321InstallGlobalFunction( XMod, function( arg ) 1322 1323 local nargs; 1324 nargs := Length( arg ); 1325 1326 # two homomorphisms 1327 if ( ( nargs = 2 ) and IsGroupHomomorphism( arg[1] ) 1328 and IsGroupHomomorphism( arg[2] ) ) then 1329 return XModByBoundaryAndAction( arg[1], arg[2] ); 1330 1331 # group and normal subgroup 1332 elif ( ( nargs = 2 ) and IsGroup( arg[1] ) and IsGroup( arg[2] ) 1333 and IsSubgroup( arg[1], arg[2] ) and IsNormal( arg[1], arg[2] ) ) then 1334 return XModByNormalSubgroup( arg[1], arg[2] ); 1335 1336 # xmod plus list of objects plus boolean 1337 elif ( ( nargs = 3 ) and IsXMod( arg[1] ) 1338 and IsList( arg[2] ) and IsBool( arg[3] ) ) then 1339 return SinglePiecePreXModWithObjects( arg[1], arg[2], arg[3] ); 1340 1341 # surjective homomorphism 1342 elif ( ( nargs = 1 ) and IsGroupHomomorphism( arg[1] ) 1343 and IsSurjective( arg[1] ) ) then 1344 return XModByCentralExtension( arg[1] ); 1345 1346 # convert a cat1-group 1347 elif ( ( nargs = 1 ) and HasIsCat1Group( arg[1] ) 1348 and IsCat1Group( arg[1] ) ) then 1349 return PreXModOfPreCat1Group( arg[1] ); 1350 1351 # group of automorphisms 1352 elif ( ( nargs = 1 ) and IsGroupOfAutomorphisms( arg[1] ) ) then 1353 return XModByAutomorphismGroup( arg[1] ); 1354 1355 # just a group 1356 elif ( ( nargs = 1 ) and IsGroup( arg[1] ) ) then 1357 return XModByNormalSubgroup( arg[1], arg[1] ); 1358 1359 # pre-crossed module 1360 elif ( ( nargs = 1 ) and IsPreXMod( arg[1] ) ) then 1361 return XModByPeifferQuotient( arg[1] ); 1362 1363 fi; 1364 # alternatives not allowed 1365 Error( "usage: XMod( bdy, act ); or XMod( G, N );" ); 1366end ); 1367 1368############################################################################## 1369## 1370#M IsSubPreXMod 1371## 1372InstallMethod( IsSubPreXMod, "generic method for pre-crossed modules", true, 1373 [ Is2DimensionalGroup, Is2DimensionalGroup ], 0, 1374function( PM, SM ) 1375 1376 local ok, Ssrc, Srng, gensrc, genrng, s, r, r1, r2, im1, im2; 1377 1378 if not ( IsPreXMod( PM ) and IsPreXMod( SM ) ) then 1379 return false; 1380 fi; 1381 if ( HasParent( SM ) and ( Parent( SM ) = PM ) ) then 1382 return true; 1383 fi; 1384 Ssrc := Source( SM ); 1385 Srng := Range( SM ); 1386 if not ( IsSubgroup( Source( PM ), Ssrc ) 1387 and IsSubgroup( Range( PM ), Srng ) ) then 1388 Info( InfoXMod, 3, "IsSubgroup failure in IsSubPreXMod" ); 1389 return false; 1390 fi; 1391 ok := true; 1392 gensrc := GeneratorsOfGroup( Ssrc ); 1393 genrng := GeneratorsOfGroup( Srng ); 1394 for s in gensrc do 1395 if ( ImageElm( Boundary(PM), s ) <> ImageElm( Boundary(SM), s ) ) then 1396 ok := false; 1397 fi; 1398 od; 1399 if not ok then 1400 Info( InfoXMod, 3, "boundary maps have different images" ); 1401 return false; 1402 fi; 1403 for r in genrng do 1404 r1 := ImageElm( XModAction( PM ), r ); 1405 r2 := ImageElm( XModAction( SM ), r ); 1406 for s in gensrc do 1407 im1 := ImageElm( r1, s ); 1408 im2 := ImageElm( r2, s ); 1409 if ( im1 <> im2 ) then 1410 ok := false; 1411 Info( InfoXMod, 3, "s,im1,im2 = ", [s,im1,im2] ); 1412 fi; 1413 od; 1414 od; 1415 if not ok then 1416 Info( InfoXMod, 3, "actions have different images" ); 1417 return false; 1418 fi; 1419 if ( PM <> SM ) then 1420 SetParent( SM, PM ); 1421 fi; 1422 return true; 1423end ); 1424 1425############################################################################## 1426## 1427#M IsSubXMod( <XM>, <SM> ) 1428## 1429InstallMethod( IsSubXMod, "generic method for crossed modules", true, 1430 [ Is2DimensionalGroup, Is2DimensionalGroup ], 0, 1431function( XM, SM ) 1432 1433 if not ( IsXMod( XM ) and IsXMod( SM ) ) then 1434 return false; 1435 fi; 1436 return IsSubPreXMod( XM, SM ); 1437end ); 1438 1439############################################################################## 1440## 1441#M IsSubPreCat1Group 1442## 1443InstallMethod( IsSubPreCat1Group, "generic method for pre-cat1-groups", true, 1444 [ Is2DimensionalGroup, Is2DimensionalGroup ], 0, 1445function( C0, S0 ) 1446 1447 local ok, Ssrc, Srng, gensrc, genrng, tc, hc, ec, ts, hs, es, s, r; 1448 1449 if not ( IsPreCat1Group( C0 ) and IsPreCat1Group( S0 ) ) then 1450 return false; 1451 fi; 1452 if ( HasParent( S0 ) and ( Parent( S0 ) = C0 ) ) then 1453 return true; 1454 fi; 1455 Ssrc := Source( S0 ); 1456 Srng := Range( S0 ); 1457 if not ( IsSubgroup( Source( C0 ), Ssrc ) 1458 and IsSubgroup( Range( C0 ), Srng ) ) then 1459 Info( InfoXMod, 3, "IsSubgroup failure in IsSubPreCat1Group" ); 1460 return false; 1461 fi; 1462 ok := true; 1463 gensrc := GeneratorsOfGroup( Ssrc ); 1464 genrng := GeneratorsOfGroup( Srng ); 1465 tc := TailMap(C0); hc := HeadMap(C0); ec := RangeEmbedding(C0); 1466 ts := TailMap(S0); hs := HeadMap(S0); es := RangeEmbedding(S0); 1467 for s in gensrc do 1468 if ( ImageElm( tc, s ) <> ImageElm( ts, s ) ) then 1469 ok := false; 1470 fi; 1471 if ( ImageElm( hc, s ) <> ImageElm( hs, s ) ) then 1472 ok := false; 1473 fi; 1474 od; 1475 if not ok then 1476 Info( InfoXMod, 3, "tail/head maps have different images" ); 1477 return false; 1478 fi; 1479 for r in genrng do 1480 if ( ImageElm( ec, r ) <> ImageElm( es, r ) ) then 1481 ok := false; 1482 fi; 1483 od; 1484 if not ok then 1485 Info( InfoXMod, 3, "embeddingss have different images" ); 1486 return false; 1487 fi; 1488 if ( C0 <> S0 ) then 1489 SetParent( S0, C0 ); 1490 fi; 1491 return true; 1492end ); 1493 1494############################################################################## 1495## 1496#M IsSubCat1Group( <C1>, <S1> ) 1497## 1498InstallMethod( IsSubCat1Group, "generic method for cat1-groups", true, 1499 [ Is2DimensionalGroup, Is2DimensionalGroup ], 0, 1500function( C1, S1 ) 1501 1502 if not ( IsCat1Group( C1 ) and IsCat1Group( S1 ) ) then 1503 return false; 1504 fi; 1505 return IsSubPreCat1Group( C1, S1 ); 1506end ); 1507 1508############################################################################## 1509## 1510#M IsNormalSub2DimensionalDomain( <XM>, <SM> ) 1511## 1512InstallMethod( IsNormalSub2DimensionalDomain, "for xmod and subxmod etc.", 1513 true, [ Is2DimensionalGroup, Is2DimensionalGroup ], 0, 1514function( X0, X1 ) 1515 1516 local ispx, ok, S0, R0, S1, R1, r0, s0, r1, s1; 1517 1518 ispx := IsPreXMod( X0 ); 1519 if ispx then 1520 ok := IsSubPreXMod( X0, X1 ); 1521 else 1522 ok := IsSubPreCat1Group( X0, X1 ); 1523 fi; 1524 if not ok then 1525 return false; 1526 fi; 1527 if not ispx then 1528 Error( "not yet installed for cat1-groups" ); 1529 fi; 1530 S0 := Source( X0 ); 1531 R0 := Range( X0 ); 1532 S1 := Source( X1 ); 1533 R1 := Range( X1 ); 1534 if not IsNormal( R0, R1 ) then 1535 return false; 1536 fi; 1537 ## apparently no requirement for S1 to be normal in S0 1538 for r0 in GeneratorsOfGroup( R0 ) do 1539 for s1 in GeneratorsOfGroup( S1 ) do 1540 if not ImageElmXModAction( X0, s1, r0 ) in S1 then 1541 return false; 1542 fi; 1543 od; 1544 od; 1545 for r1 in GeneratorsOfGroup( R1 ) do 1546 for s0 in GeneratorsOfGroup( S0 ) do 1547 if not s0^-1 * ImageElmXModAction( X0, s0, r1 ) in S1 then 1548 return false; 1549 fi; 1550 od; 1551 od; 1552 return true; 1553end ); 1554 1555############################################################################## 1556## 1557#M Sub2DimensionalGroup . . creates Sub2bObject from Ssrc<=Osrc & Srng<=Orng 1558## 1559InstallMethod( Sub2DimensionalGroup, "generic method for 2d-objects", true, 1560 [ Is2DimensionalGroup, IsGroup, IsGroup ], 0, 1561function( obj, src, rng ) 1562 if ( HasIsXMod(obj) and IsXMod(obj) ) then 1563 return SubXMod( obj, src, rng ); 1564 elif ( HasIsPreXMod(obj) and IsPreXMod(obj) ) then 1565 return SubPreXMod( obj, src, rng ); 1566 elif ( HasIsCat1Group(obj) and IsCat1Group(obj) ) then 1567 return SubCat1Group( obj, src, rng ); 1568 elif ( HasIsPreCat1Group(obj) and IsPreCat1Group(obj) ) then 1569 return SubPreCat1Group( obj, src, rng ); 1570 else 1571 Error( "unknown type of 2d-object" ); 1572 fi; 1573end ); 1574 1575############################################################################## 1576## 1577#M SubPreXMod creates SubPreXMod from Ssrc<=Psrc & Srng<=Prng 1578## 1579InstallMethod( SubPreXMod, "generic method for pre-crossed modules", true, 1580 [ IsPreXMod, IsGroup, IsGroup ], 0, 1581function( PM, Ssrc, Srng ) 1582 1583 local Psrc, Prng, Pbdy, Pact, Paut, genSsrc, genSrng, Pname, Sname, 1584 SM, Sbdy, Saut, Sact, r, innaut, genPrng, genPsrc, ssrc, 1585 trivsrc, trivrng, incSsrc, idSsrc, imact, imgen, imbdy, imSsrc, 1586 imalpha, alpha; 1587 1588 Psrc := Source( PM ); 1589 Prng := Range( PM ); 1590 Pbdy := Boundary( PM ); 1591 Pact := XModAction( PM ); 1592 Paut := Range( Pact ); 1593 if not IsSubgroup( Psrc, Ssrc ) then 1594 Print( "Ssrc is not a subgroup of Psrc\n" ); 1595 return fail; 1596 fi; 1597 if not ( IsSubgroup( Prng, Srng ) ) then 1598 Print( "Srng is not a subgroup of Prng\n" ); 1599 return fail; 1600 fi; 1601 ssrc := Size( Ssrc ); 1602 genPsrc := GeneratorsOfGroup( Psrc ); 1603 genPrng := GeneratorsOfGroup( Prng ); 1604 genSsrc := GeneratorsOfGroup( Ssrc ); 1605 genSrng := GeneratorsOfGroup( Srng ); 1606 incSsrc := InclusionMappingGroups( Psrc, Ssrc ); 1607 imgen := List( genSsrc, x -> ImageElm( Pbdy, x ) ); 1608 imSsrc := Subgroup( Prng, imgen ); 1609 if not IsSubgroup( Srng, imSsrc ) then 1610 Info( InfoXMod, 2, "Pbdy(Ssrc) is not a subgroup of Srng" ); 1611 return fail; 1612 fi; 1613 trivsrc := ( Size( Ssrc ) = 1 ); 1614 trivrng := ( Size( Srng ) = 1 ); 1615 if ( trivrng or trivsrc ) then 1616 Sbdy := MappingToOne( Ssrc, Srng ); 1617 else 1618 Sbdy:= GroupHomomorphismByImages( Ssrc, Srng, genSsrc, imgen ); 1619 fi; 1620 innaut := [ ]; 1621 for r in genSrng do 1622 alpha := ImageElm( Pact, r ); 1623 imgen := List( genSsrc, x -> ImageElm( alpha, x ) ); 1624 if not ForAll( imgen, x -> ( x in Ssrc ) ) then 1625 return fail; 1626 fi; 1627 imalpha := Subgroup( Ssrc, imgen ); 1628 if not ( IsSubgroup( Ssrc, imalpha ) ) then 1629 Info( InfoXMod, 2, "Srng does not act correctly on Ssrc" ); 1630 return fail; 1631 fi; 1632 alpha:=GroupHomomorphismByImages( Ssrc, Ssrc, genSsrc, imgen ); 1633 Add( innaut, alpha ); 1634 od; 1635 idSsrc := IdentityMapping( Ssrc ); 1636 if ( ssrc = 1 ) then 1637 Saut := Group( idSsrc ); 1638 innaut := List( genSrng, s -> idSsrc ); 1639 else 1640 Saut := Group( innaut, idSsrc ); 1641 fi; 1642 Sact := GroupHomomorphismByImages( Srng, Saut, genSrng, innaut ); 1643 if ( not IsGroupHomomorphism( Sact ) ) then 1644 Print( "Sact is not a homomorphism\n" ); 1645 return fail; 1646 fi; 1647 SM := PreXModByBoundaryAndAction( Sbdy, Sact ); 1648 if HasParent( PM ) then 1649 SetParent( SM, Parent( PM ) ); 1650 else 1651 SetParent( SM, PM ); 1652 fi; 1653 return SM; 1654end ); 1655 1656############################################################################## 1657## 1658#M SubXMod . . . . . . . . . . . creates SubXMod from Ssrc<=Psrc & Srng<=Prng 1659## 1660InstallMethod( SubXMod, "generic method for crossed modules", true, 1661 [ IsXMod, IsGroup, IsGroup ], 0, 1662function( XM, Ssrc, Srng ) 1663 1664 local SM; 1665 SM := SubPreXMod( XM, Ssrc, Srng ); 1666 if ( SM = fail ) then 1667 return fail; 1668 fi; 1669 if not IsXMod( SM ) then 1670 Error( "the result is only a pre-crossed module" ); 1671 fi; 1672 return SM; 1673end ); 1674 1675############################################################################### 1676## 1677#M SubPreCat1Group . . created from PreCat1Group and a subgroup of the source 1678## 1679InstallMethod( SubPreCat1Group, "generic method for (pre-)cat1-groups", true, 1680 [ IsPreCat1Group, IsGroup, IsGroup ], 0, 1681function( C, G, R ) 1682 1683 local Csrc, Crng, Ct, Ch, Ce, t, h, e, SC, ok; 1684 1685 Csrc := Source( C ); 1686 Crng := Range( C ); 1687 Ct := TailMap( C ); 1688 Ch := HeadMap( C ); 1689 Ce := RangeEmbedding( C ); 1690 ok := true; 1691 if not ( IsSubgroup( Csrc, G ) ) then 1692 Print( "G is not a subgroup of Csrc\n" ); 1693 ok := false; 1694 fi; 1695 if not ( ( R = Image( Ct, G ) ) and 1696 ( R = Image( Ch, G ) ) ) then 1697 Print( "restrictions of Ct, Ch to G must have common image R\n" ); 1698 ok := false; 1699 fi; 1700 t := GeneralRestrictedMapping( Ct, G, R ); 1701 h := GeneralRestrictedMapping( Ch, G, R ); 1702 e := GeneralRestrictedMapping( Ce, R, G ); 1703 SC := PreCat1GroupByTailHeadEmbedding( t, h, e ); 1704 if not ( C = SC ) then 1705 SetParent( SC, C ); 1706 fi; 1707 return SC; 1708end ); 1709 1710############################################################################## 1711## 1712#M SubCat1Group . . creates SubCat1Group from Cat1Group and subgroup of source 1713## 1714InstallMethod( SubCat1Group, "generic method for cat1-groups", true, 1715 [ IsCat1Group, IsGroup, IsGroup ], 0, 1716function( C, G, R ) 1717 1718 local S; 1719 S := SubPreCat1Group( C, G, R ); 1720 if not IsCat1Group( S ) then 1721 Error( "result is only a pre-cat1-group" ); 1722 fi; 1723 return S; 1724end ); 1725 1726############################################################################# 1727## 1728#M IsCat1Group check that the second cat1-group axiom holds 1729## 1730InstallMethod( IsCat1Group, "generic method for crossed modules", true, 1731 [ IsPreCat1Group ], 0, 1732function( C1G ) 1733 1734 local Csrc, Crng, h, t, e, f, kerC, kert, kerh, kerth; 1735 1736 Csrc := Source( C1G ); 1737 Crng := Range( C1G ); 1738 h := HeadMap( C1G ); 1739 t := TailMap( C1G ); 1740 e := RangeEmbedding( C1G ); 1741 kerC := Kernel( C1G ); 1742 f := KernelEmbedding( C1G ); 1743 kert := Kernel( t ); 1744 kerh := Kernel( h ); 1745 kerth := CommutatorSubgroup( kert, kerh ); 1746 if not ( Size( kerth ) = 1 ) then 1747 Info( InfoXMod, 1, "condition [kert,kerh] = 1 is not satisfied"); 1748 return false; 1749 fi; 1750 if not ( ( Source( f ) = kerC ) and ( Range( f ) = Csrc ) ) then 1751 Print( "Warning: KernelEmbedding( C1G ) incorrectly defined?\n" ); 1752 fi; 1753 return true; 1754end ); 1755 1756############################################################################# 1757## 1758#M IsIdentityPreCat1Group 1759#M IsPreCat1GroupByEndomorphisms 1760## 1761InstallMethod( IsIdentityPreCat1Group, "test a pre-cat1-group", true, 1762 [ IsPreCat1Group ], 0, 1763function( C1G ) 1764 return ( ( TailMap( C1G ) = IdentityMapping( Source( C1G ) ) ) and 1765 ( HeadMap( C1G ) = IdentityMapping( Source( C1G ) ) ) ); 1766end ); 1767 1768InstallMethod( IsPreCat1GroupByEndomorphisms, "test a pre-cat1-group", true, 1769 [ IsPreCat1Group ], 0, 1770function( obj ) 1771 return IsSubgroup( Source(obj), Range(obj) ); 1772end ); 1773 1774############################################################################# 1775## 1776#F Cat1Group( <size>, <gpnum>, <num> ) cat1-group from data in CAT1_LIST 1777#F Cat1Group( <t>, <h>, <e> ) cat1-group from given t,h,e 1778#F Cat1Group( <t>, <h> ) cat1-group from t,h endomorphisms 1779## 1780InstallGlobalFunction( Cat1Group, function( arg ) 1781 1782 local nargs, C1G, ok; 1783 1784 nargs := Length( arg ); 1785 if ( ( nargs < 1 ) or ( nargs > 3 ) ) then 1786 Print( "standard usage: Cat1Group( tail, head [,embed] );\n" ); 1787 Print( " or: Cat1Group( size, gpnum, num );\n" ); 1788 return fail; 1789 elif not IsInt( arg[1] ) then 1790 if ( nargs = 1 ) then 1791 C1G := PreCat1Group( arg[1] ); 1792 elif ( nargs = 2 ) then 1793 C1G := PreCat1Group( arg[1], arg[2] ); 1794 elif ( nargs = 3 ) then 1795 C1G := PreCat1Group( arg[1], arg[2], arg[3] ); 1796 fi; 1797 ok := IsCat1Group( C1G ); 1798 if ok then 1799 return C1G; 1800 else 1801 Error( "quotient by Peiffer group is not yet implemented" ); 1802 return fail; 1803 fi; 1804 else ## arg[1] is an integer, so use the data in cat1data.g 1805 return Cat1Select( arg[1], arg[2], arg[3] ); 1806 fi; 1807end ); 1808 1809############################################################################# 1810## 1811#F Cat1Select( <size>, <gpnum>, <num> ) cat1-group from data in CAT1_LIST 1812## 1813InstallMethod( Cat1Select, "construct a cat1-group using data in file", 1814 true, [ IsInt ], 0, 1815function( size ) 1816 return Cat1Select( size, 0, 0 ); 1817end ); 1818 1819InstallMethod( Cat1Select, "construct a cat1-group using data in file", 1820 true, [ IsInt, IsInt ], 0, 1821function( size, gpnum ) 1822 return Cat1Select( size, gpnum, 0 ); 1823end ); 1824 1825InstallMethod( Cat1Select, "construct a cat1-group using data in file", true, 1826 [ IsInt, IsInt, IsInt ], 0, 1827function( size, gpnum, num ) 1828 1829 local ok, type, norm, usage, usage2, maxsize, start, iso, count, comm, 1830 pos, pos2, names, i, j, k, ncat1, G, genG, fam, M, L, genR, R, 1831 imt, t, kert, imh, h, C1G, XC, i0; 1832 1833 maxsize := CAT1_LIST_MAX_SIZE; 1834 usage := "Usage: Cat1Select( size, gpnum, num );"; 1835 usage2 := " where size <= CAT1_LIST_MAX_SIZE = "; 1836 if not ( ( size > 0 ) and ( size <= maxsize ) ) then 1837 Print( usage, usage2, CAT1_LIST_MAX_SIZE, "\n" ); 1838 return fail; 1839 fi; 1840 if ( size = 1 ) then 1841 if ( num = 0 ) then 1842 Print( usage, "\nThere is only " ); 1843 Print( "the trivial cat1-structure on the trivial group.\n" ); 1844 Print( "(1) [ [ ], tail = head = zero mapping ]\n" ); 1845 return 1; 1846 elif ( num = 1 ) then 1847 G := SmallGroup( 1, 1 ); 1848 t := IdentityMapping( G ); 1849 return PreCat1GroupByEndomorphisms( t, t ); 1850 else 1851 return fail; 1852 fi; 1853 fi; 1854 if ( CAT1_LIST_LOADED = false ) then 1855 ReadPackage( "xmod", "lib/cat1data.g" ); 1856 fi; 1857 # find starting positions of iso classes of groups of size <= maxsize 1858 iso := CAT1_LIST_CLASS_SIZES; 1859 count := 1; 1860 start := [ 1 ]; 1861 for j in iso do 1862 count := count + j; 1863 Add( start, count ); 1864 od; 1865 Info( InfoXMod, 2, " iso = ", iso, "\n start = ", start ); 1866 if ( ( size < 1 ) or ( size > maxsize ) ) then 1867 Error( "only groups of order up to ", maxsize, " in CAT1_LIST"); 1868 return false; 1869 fi; 1870 pos := start[ size ]; 1871 if ( size < maxsize ) then 1872 pos2 := start[ size + 1 ] - 1; 1873 else 1874 pos2 := Length( CAT1_LIST ); 1875 fi; 1876 names := List( [ pos..pos2], n -> CAT1_LIST[n][3] ); 1877 if not ( gpnum > 0 ) then 1878 Print( usage, "\n" ); 1879 return names; 1880 fi; 1881 if ( gpnum > iso[size] ) then 1882 Print( "# isomorphism classes of groups of size ", size, 1883 " is ", iso[size], ", less than ", gpnum, "\n" ); 1884 Print( usage, "\n" ); 1885 return names; 1886 fi; 1887 j := pos + gpnum - 1; 1888 M := CAT1_LIST[j]; 1889 if not ( ( M[1] = size ) and ( M[2] = gpnum ) ) then 1890 Error( "M[1..2] <> [ size, gpnum ]" ); 1891 fi; 1892 G := SmallGroup( size, gpnum ); 1893 SetName( G, M[3] ); 1894 comm := IsCommutative( G ); 1895 if comm then 1896 ncat1 := Length( M[5] ) + 2; 1897 k := 2; 1898 else 1899 ncat1 := Length( M[5] ) + 1; 1900 k := 1; 1901 fi; 1902 if IsPermGroup( G ) then 1903 return PermCat1Select( size, gpnum, num ); 1904 fi; 1905 fam := FamilyObj( GeneratorsOfGroup( G )[1] ); 1906 genG := List( M[4], e -> ObjByExtRep( fam, e ) ); 1907 if not ( ( num >= 1 ) and ( num <= ncat1 ) ) then 1908 Print( usage, "\n" ); 1909 Print( "There are ", ncat1, " cat1-structures for the group "); 1910 Print( G, ".\n" ); 1911 Print( "Using small generating set ", genG, " for source of homs.\n" ); 1912 Print( "[ [range gens]," ); 1913 Print( " [tail genimages], [head genimages] ]" ); 1914 Print( " :-\n" ); 1915 if comm then 1916 Print("(1) [ ","[ ]",", tail = head = zero mapping ]\n"); 1917 fi; 1918 for i in [1..ncat1-k] do 1919 if comm then i0 := i+1; else i0 := i; fi; 1920 L := M[5][i]; 1921 genR := List( L[1], e -> ObjByExtRep( fam, e ) ); 1922 imt := List( L[2], e -> ObjByExtRep( fam, e ) ); 1923 imh := List( L[3], e -> ObjByExtRep( fam, e ) ); 1924 Print( "(", i0, ") ", [ genR, imt, imh ], "\n" ); 1925 od; 1926 Print("(",ncat1,") [ ",genG,", tail = head = identity mapping ]\n"); 1927 return ncat1; 1928 fi; 1929 if ( num = ncat1 ) then 1930 t := IdentityMapping( G ); 1931 h := ShallowCopy( t ); 1932 else 1933 if ( ( num = 1 ) and IsCommutative( G ) ) then 1934 R := TrivialSubgroup( G ); 1935 SetName( R, "triv" ); 1936 t := MappingToOne( G, R ); 1937 h := ShallowCopy( t ); 1938 else 1939 L := M[5][num-k+1]; 1940 genR := List( L[1], e -> ObjByExtRep( fam, e ) ); 1941 R := Subgroup( G, genR ); 1942 imt := List( L[2], e -> ObjByExtRep( fam, e ) ); 1943 t := GroupHomomorphismByImages( G, R, genG, imt ); 1944 imh := List( L[3], e -> ObjByExtRep( fam, e ) ); 1945 h := GroupHomomorphismByImages( G, R, genG, imh ); 1946 fi; 1947 SetIsEndoMapping( t, true ); 1948 SetIsEndoMapping( h, true ); 1949 kert := Kernel( t ); 1950 fi; 1951 C1G := PreCat1GroupByEndomorphisms( t, h ); 1952 ok := IsCat1Group( C1G ); 1953 if ok then 1954 XC := XModOfCat1Group( C1G ); 1955 fi; 1956 return C1G; 1957end ); 1958 1959InstallMethod( PermCat1Select, "construct a cat1-group using data in file", 1960 true, [ IsInt, IsInt, IsInt ], 0, 1961function( size, gpnum, num ) 1962 1963 local ok, type, norm, maxsize, start, iso, count, pos, pos2, names, 1964 i, j, ncat1, G, genG, fam, M, L, genR, R, t, kert, h, C1G, XC; 1965 1966 # find starting positions of iso classes of groups of size <= maxsize 1967 maxsize := CAT1_LIST_MAX_SIZE; 1968 iso := CAT1_LIST_CLASS_SIZES; 1969 count := 1; 1970 start := [ 1 ]; 1971 for j in iso do 1972 count := count + j; 1973 Add( start, count ); 1974 od; 1975 Info( InfoXMod, 2, " iso = ", iso, "\n start = ", start ); 1976 if ( ( size < 1 ) or ( size > maxsize ) ) then 1977 Error( "only groups of order up to ", maxsize, " in CAT1_LIST"); 1978 return false; 1979 fi; 1980 pos := start[ size ]; 1981 if ( size < maxsize ) then 1982 pos2 := start[ size + 1 ] - 1; 1983 else 1984 pos2 := Length( CAT1_LIST ); 1985 fi; 1986 names := List( [ pos..pos2], n -> CAT1_LIST[n][4] ); 1987 j := pos + gpnum - 1; 1988 M := CAT1_LIST[j]; 1989 G := Group(M[4], ( )); 1990 SetName( G, M[3] ); 1991 ncat1 := Length( M[5] ) + 1; 1992 genG := GeneratorsOfGroup( G ); 1993 if not ( ( num >= 1 ) and ( num <= ncat1 ) ) then 1994 Print( "\nThere are ", ncat1, " cat1-structures for the group "); 1995 Print( G, ".\n" ); 1996 Print( "[ [range gens], source & range names," ); 1997 Print( " [tail genimages], [head genimages] ]" ); 1998 Print( " :-\n" ); 1999 Print( "[ ", genG, ", tail = head = identity mapping ]\n" ); 2000 for i in [2..ncat1] do 2001 Print( M[5][i-1], "\n" ); 2002 od; 2003 Print( "Group has generators ", genG, "\n" ); 2004 return ncat1; 2005 fi; 2006 if ( num = ncat1 ) then 2007 L := [ genG, genG, genG ]; 2008 else 2009 L := M[5][num-1]; 2010 fi; 2011 genR := L[1]; 2012 R := Subgroup( G, genR ); 2013 if ( G = R ) then 2014 SetName( R, Name(G) ); 2015 fi; 2016 t := GroupHomomorphismByImages( G, R, genG, L[2] ); 2017 h := GroupHomomorphismByImages( G, R, genG, L[3] ); 2018 SetIsEndoMapping( t, true ); 2019 SetIsEndoMapping( h, true ); 2020 kert := Kernel( t ); 2021 C1G := PreCat1GroupByEndomorphisms( t, h ); 2022 ok := IsCat1Group( C1G ); 2023 if ok then 2024 XC := XModOfCat1Group( C1G ); 2025 fi; 2026 return C1G; 2027end ); 2028 2029############################################################################# 2030## 2031#M PreCat1GroupByTailHeadEmbedding 2032## 2033InstallMethod( PreCat1GroupByTailHeadEmbedding, 2034 "cat1-group from tail, head and embedding", true, 2035 [ IsGroupHomomorphism, IsGroupHomomorphism, IsGroupHomomorphism ], 0, 2036function( t, h, e ) 2037 2038 local genG, R, genR, imh, imt, ime, eR, kert, kergen, bdy, imbdy, 2039 f, C1G, ok, G, PC; 2040 2041 G := Source( t ); 2042 genG := GeneratorsOfGroup( G ); 2043 R := Range( t ); 2044 genR := SmallGeneratingSet( R ); 2045 eR := Image( e ); 2046 if not ( ( Source( h ) = G ) 2047 and ( Image( h ) = R ) and ( Source( e ) = R ) 2048 and IsInjective( e ) and IsSubgroup( G, eR ) ) then 2049 return fail; 2050 fi; 2051 imh := List( genG, x -> ImageElm( h, x ) ); 2052 imt := List( genG, x -> ImageElm( t, x ) ); 2053 ime := List( genR, x -> ImageElm( e, x ) ); 2054 kert := Kernel( t ); 2055 f := InclusionMappingGroups( G, kert ); 2056 ## hres := GroupHomomorphismByImages( G, R, genG, imh ); 2057 ## tres := GroupHomomorphismByImages( G, R, genG, imt ); 2058 ## eres := GroupHomomorphismByImages( R, G, genR, ime ); 2059 kergen := GeneratorsOfGroup( kert ); 2060 imbdy := List( kergen, x -> ImageElm( h, x) ); 2061 bdy := GroupHomomorphismByImages( kert, R, kergen, imbdy ); 2062 PC := PreCat1Obj( t, h, e ); 2063 SetBoundary( PC, bdy ); 2064 SetKernelEmbedding( PC, f ); 2065 return PC; 2066end ); 2067 2068############################################################################# 2069## 2070#M IsPreCat1GroupByEndomorphisms( <pcg> ) 2071#M PreCat1GroupByEndomorphisms( <et>, <eh> ) 2072#M EndomorphismPreCat1Group( <pcg> ) 2073## 2074InstallMethod( IsPreCat1GroupByEndomorphisms, "tail & head are endomorphisms", 2075 true, [ IsPreCat1Group ], 0, 2076function( C1G ) 2077 return IsSubgroup( Source( C1G ), Range( C1G ) ); 2078end ); 2079 2080InstallMethod( PreCat1GroupByEndomorphisms, 2081 "cat1-group from tail and head endomorphisms", true, 2082 [ IsGroupHomomorphism, IsGroupHomomorphism ], 0, 2083function( et, eh ) 2084 2085 local G, gG, R, t, h, e; 2086 2087 if not ( IsEndoMapping( et ) and IsEndoMapping( eh ) ) then 2088 Print( "et, eh must both be group endomorphisms \n" ); 2089 return fail; 2090 fi; 2091 if not ( Source( et ) = Source( eh ) ) then 2092 Info( InfoXMod, 2, "et and eh must have same source" ); 2093 return fail; 2094 fi; 2095 G := Source( et ); 2096 if not ( Image( et ) = Image( eh ) ) then 2097 Info( InfoXMod, 2, "et and eh must have same image" ); 2098 return fail; 2099 fi; 2100 R := Image( et ); 2101 gG := GeneratorsOfGroup( G ); 2102 t := GroupHomomorphismByImages( G, R, gG, List( gG, g->ImageElm(et,g) ) ); 2103 h := GroupHomomorphismByImages( G, R, gG, List( gG, g->ImageElm(eh,g) ) ); 2104 e := InclusionMappingGroups( G, R ); 2105 return PreCat1GroupByTailHeadEmbedding( t, h, e ); 2106end ); 2107 2108InstallMethod( EndomorphismPreCat1Group, 2109 "convert cat1-group to one with endomorphisms", true, [ IsPreCat1Group ], 0, 2110function( C1G ) 2111 2112 local e, t, h; 2113 2114 if IsPreCat1GroupByEndomorphisms( C1G ) then 2115 return C1G; 2116 fi; 2117 e := RangeEmbedding( C1G ); 2118 t := TailMap( C1G ) * e; 2119 h := HeadMap( C1G ) * e; 2120 return PreCat1GroupByEndomorphisms( t, h ); 2121end ); 2122 2123############################################################################# 2124## 2125#M PreXModOfPreCat1Group 2126## 2127InstallMethod( PreXModOfPreCat1Group, true, [ IsPreCat1Group ], 0, 2128function( C1G ) 2129 2130 local Csrc, Crng, gensrc, genrng, genker, bdy, kert, innaut, autgen, 2131 imautgen, idkert, a, aut, act, phi, j, r, PM, Cek, Cer, name; 2132 2133 Csrc := Source( C1G ); 2134 Crng := Range( C1G ); 2135 bdy := Boundary( C1G ); 2136 Cer := RangeEmbedding( C1G ); 2137 Cek := KernelEmbedding( C1G ); 2138 kert := Kernel( C1G ); 2139 if ( Size( kert ) = 1 ) then 2140 SetName( kert, "triv" ); 2141 fi; 2142 gensrc := GeneratorsOfGroup( Csrc ); 2143 genrng := GeneratorsOfGroup( Crng ); 2144 genker := GeneratorsOfGroup( kert ); 2145 if IsIdentityPreCat1Group( C1G ) then 2146 # X has trivial source and action 2147 aut := Group( IdentityMapping( kert ) ); 2148 SetName( aut, "triv_aut" ); 2149 act := MappingToOne( Crng, aut ); 2150 SetName( act, "mapto1" ); 2151 else 2152 autgen := [ ]; 2153 for r in genrng do 2154 imautgen := List( genker, s -> ImageElm( Cek, s ) ); 2155 imautgen := List( imautgen, g -> g^( ImageElm( Cer, r ) ) ); 2156 imautgen := List( imautgen, 2157 g -> PreImagesRepresentative( Cek, g ) ); 2158 a := GroupHomomorphismByImages( kert, kert, genker, imautgen ); 2159 Add( autgen, a ); 2160 od; 2161 idkert := IdentityMapping( kert ); 2162 aut := Group( autgen, idkert ); 2163 act := GroupHomomorphismByImages( Crng, aut, genrng, autgen ); 2164 if HasName( kert ) then 2165 SetName( aut, Concatenation( "innaut(", Name( kert ), ")" ) ); 2166 else 2167 SetName( aut, "aut" ); 2168 fi; 2169 if not IsGroupHomomorphism( act ) then 2170 Error( "act is not a homomorphism" ); 2171 fi; 2172 fi; 2173 PM := PreXModObj( bdy, act ); 2174 #? aded 30/04/08 - but is it really needed ?? 2175 if ( IsSubgroup( Crng, kert ) and IsNormal( Crng, kert ) ) then 2176 SetIsNormalSubgroup2DimensionalGroup( PM, true ); 2177 fi; 2178 if ( HasName( Source( bdy ) ) and HasName( Range( bdy ) ) ) then 2179 name := Name( PM ); 2180 elif HasName( C1G ) then 2181 SetName( PM, Concatenation( "xmod(", Name( C1G ), ")" ) ); 2182 fi; 2183 SetPreCat1GroupOfPreXMod( PM, rec( 2184 precat1 := C1G, 2185 xmodSourceEmbedding := kert, 2186 xmodSourceEmbedddingIsomorphism := Cek, 2187 xmodRangeEmbedding := Image( Cer ), 2188 xmodRangeEmbeddingIsomorphism := Cer ) ); 2189 return PM; 2190end ); 2191 2192############################################################################# 2193## 2194#M Source( C1G ) . . . . . . . . . . . . . . . . . . . . for a cat1-group 2195## 2196InstallOtherMethod( Source, 2197 "method for a pre-cat1-group", 2198 true, 2199 [ IsPreCat1Group ], 0, 2200 C1G -> Source( TailMap( C1G ) ) ); 2201 2202############################################################################## 2203## 2204#M Range( C1G ) . . . . . . . . . . . . . . . . . . . . . for a cat1-group 2205## 2206InstallOtherMethod( Range, 2207 "method for a pre-cat1-group", 2208 true, 2209 [ IsPreCat1Group ], 0, 2210 C1G -> Range( TailMap( C1G ) ) ); 2211 2212############################################################################## 2213## 2214#M Kernel( C1G ) . . . . . . . . . . . . . . . . . . . for a pre-cat1-group 2215## 2216InstallOtherMethod( Kernel, 2217 "method for a pre-cat1-group", true, [ IsPreCat1Group ], 0, 2218 C1G -> Kernel( TailMap( C1G ) ) ); 2219 2220############################################################################# 2221## 2222#M Boundary( C1G ) . . . . . . . . . . . . . . . . . . . for a cat1-group 2223## 2224InstallOtherMethod( Boundary, 2225 "method for a pre-cat1-group", true, [ IsPreCat1Group ], 0, 2226 C1G -> GeneralRestrictedMapping( HeadMap(C1G), Kernel(C1G), Range(C1G) ) ); 2227 2228############################################################################# 2229## 2230#M KernelEmbedding( C1G ) . . . . . . . . . . . . . . . . for a cat1-group 2231## 2232InstallMethod( KernelEmbedding, 2233 "method for a pre-cat1-group", true, [ IsPreCat1Group ], 0, 2234 C1G -> InclusionMappingGroups( Source( C1G ), Kernel( C1G ) ) ); 2235 2236############################################################################## 2237## 2238#M Cat1GroupByPeifferQuotient . . . . cat1 from pre-cat1 and Peiffer subgroup 2239## 2240InstallMethod( Cat1GroupByPeifferQuotient, 2241 "cat1-group from a pre-cat1-group and Peiffer subgroup", 2242 true, [ IsPreCat1Group ], 0, 2243function( PC ) 2244 2245 local PCrng, PCsrc, PCt, PCh, PCe, genrng, gensrc, Pf, nat, quot, 2246 qgen, pqgen, tpqgen, hpqgen, tail, head, ime, embed, C1G; 2247 2248 PCrng := Range( PC ) ; 2249 genrng := GeneratorsOfGroup( PCrng ); 2250 PCsrc := Source( PC ); 2251 gensrc := GeneratorsOfGroup( PCsrc ); 2252 PCt := TailMap( PC ); 2253 PCh := HeadMap( PC ); 2254 PCe := RangeEmbedding( PC ); 2255 # construct the quotient 2256 Pf := PeifferSubgroupPreCat1Group( PC ); 2257 if not IsNormal( PCsrc, Pf ) then 2258 Error( "Peiffer subgroup not normal in source group" ); 2259 fi; 2260 nat := NaturalHomomorphismByNormalSubgroup( PCsrc, Pf ); 2261 quot := Image( nat ); 2262 qgen := GeneratorsOfGroup( quot ); 2263 # construct the head, tail and embedding 2264 pqgen := List( qgen, q -> PreImagesRepresentative( nat, q ) ); 2265 tpqgen := List( pqgen, p -> ImageElm( PCt, p ) ); 2266 tail := GroupHomomorphismByImages( quot, PCrng, qgen, tpqgen ); 2267 hpqgen := List( pqgen, p -> ImageElm( PCh, p ) ); 2268 head := GroupHomomorphismByImages( quot, PCrng, qgen, hpqgen ); 2269 ime := List( genrng, r -> ImageElm( nat, ImageElm( PCe, r ) ) ); 2270 embed := GroupHomomorphismByImages( PCrng, quot, genrng, ime ); 2271 C1G := PreCat1GroupByTailHeadEmbedding( tail, head, embed ); 2272 if not IsCat1Group( C1G ) then 2273 Error( "fails to be a cat1-group" ); 2274 fi; 2275 return C1G; 2276end ); 2277 2278############################################################################## 2279## 2280#M DiagonalCat1Group . . . . . . cat1-group of the form (GxG => G) with t<>h 2281## 2282InstallMethod( DiagonalCat1Group, "cat1-group from a list of generators", 2283 true, [ IsList ], 0, 2284function( gen1 ) 2285 2286 local m, lgen, gen2, genR, i, p, L1, len1, L2, j, 2287 G, R, genG, one, ids, t, h, e, C; 2288 2289 m := Maximum( List( gen1, g -> LargestMovedPoint(g) ) ); 2290 lgen := Length( gen1 ); 2291 gen2 := ShallowCopy( gen1 ); 2292 genR := ShallowCopy( gen1 ); 2293 for i in [1..lgen] do 2294 p := gen1[i]; 2295 L1 := ListPerm( p ); 2296 len1 := Length( L1 ); 2297 L2 := [1..2*m]; 2298 for j in [1..len1] do 2299 L2[m+j] := L1[j]+m; 2300 od; 2301 gen2[i] := PermList( L2 ); 2302 for j in [1..len1] do 2303 L2[j] := L1[j]; 2304 od; 2305 genR[i] := PermList( L2 ); 2306 od; 2307 genG := Concatenation( gen1, gen2 ); 2308 G := Group( genG ); 2309 R := Group( genR ); 2310 one := One( G ); 2311 ids := ListWithIdenticalEntries( lgen, one ); 2312 t := GroupHomomorphismByImages( G, R, genG, Concatenation( genR, ids ) ); 2313 h := GroupHomomorphismByImages( G, R, genG, Concatenation( ids, genR ) ); 2314 e := GroupHomomorphismByImages( R, G, genR, genR ); 2315 C := PreCat1GroupByTailHeadEmbedding( t, h, e ); 2316 return C; 2317end ); 2318 2319############################################################################## 2320## 2321#M AllCat1GroupsWithImage . . . . . . cat1-group structures with given range 2322#O AllCat1GroupsWithImageIterator( <gp> ) . . iterator for the previous list 2323#F NextIterator_AllCat1GroupsWithImage( <iter> ) 2324#F IsDoneIterator_AllCat1GroupsWithImage( <iter> ) 2325#F ShallowCopy_AllCat1GroupsWithImage( <iter> ) 2326#M AllCat1GroupsWithImageUpToIsomorphism . . . . . iso class reps for G => R 2327## 2328BindGlobal( "NextIterator_AllCat1GroupsWithImage", function ( iter ) 2329 2330 local C, post, pair, t, posh, h, ok; 2331 2332 ok := false; 2333 while ( not ok ) and ( not IsDoneIterator( iter!.pairsIterator ) ) do 2334 pair := NextIterator( iter!.pairsIterator ); 2335 ## could attempt to be clever and not calculate t every time 2336 t := GroupHomomorphismByImages( iter!.group, iter!.group, 2337 iter!.gens, iter!.images[ pair[1] ] ); 2338 h := GroupHomomorphismByImages( iter!.group, iter!.group, 2339 iter!.gens, iter!.images[ pair[2] ] ); 2340 C := PreCat1GroupByEndomorphisms( t, h ); 2341 if ( not ( C = fail ) and IsCat1Group( C ) ) then 2342 ok := true; 2343 return C; 2344 fi; 2345 if IsDoneIterator( iter!.pairsIterator ) then 2346 return fail; 2347 fi; 2348 od; 2349end ); 2350 2351BindGlobal( "IsDoneIterator_AllCat1GroupsWithImage", 2352 iter -> IsDoneIterator( iter!.pairsIterator ) 2353); 2354 2355BindGlobal( "ShallowCopy_AllCat1GroupsWithImage", 2356 iter -> rec( group := iter!.group, 2357 gens := iter!.gens, 2358 images := iter!.images, 2359 pairsIterator := ShallowCopy( iter!.pairsIterator ) 2360 ) 2361); 2362 2363InstallGlobalFunction( "DoAllCat1GroupsWithImageIterator", 2364function( G, R ) 2365 2366 local data, genG, images, found, len, i, lenIterator, pairsIterator, iter; 2367 2368 data := IdempotentEndomorphismsData( G ); 2369 genG := data.gens; 2370 images := data.images; 2371 found := false; 2372 len := Length( images ); 2373 i := 0; 2374 while ( not found ) and ( i < len ) do 2375 i := i+1; 2376 if ( R = Subgroup( G, images[i][1] ) ) then 2377 found := true; 2378 images := images[i]; 2379 fi; 2380 od; 2381 if not found then 2382 ## there are no idempotent endomorphisms with image R 2383 return IteratorList( [ ] ); 2384 fi; 2385 lenIterator := IteratorList( [1..Length(images)] ); 2386 pairsIterator := CartesianIterator( lenIterator, lenIterator ); 2387 iter := IteratorByFunctions( 2388 rec( group := G, 2389 gens := genG, 2390 images := images, 2391 pairsIterator := ShallowCopy( pairsIterator ), 2392 NextIterator := NextIterator_AllCat1GroupsWithImage, 2393 IsDoneIterator := IsDoneIterator_AllCat1GroupsWithImage, 2394 ShallowCopy := ShallowCopy_AllCat1GroupsWithImage ) ); 2395 return iter; 2396end ); 2397 2398InstallMethod( AllCat1GroupsWithImageIterator, "for a group and a subgroup", 2399 [ IsGroup, IsGroup ], 0, 2400function( G, R ) 2401 if not IsSubgroup( G, R ) then 2402 Error( "R is not a subgroup of G" ); 2403 fi; 2404 return DoAllCat1GroupsWithImageIterator( G, R ); 2405end ); 2406 2407InstallMethod( AllCat1GroupsWithImage, "for a group and a subgroup", 2408 [ IsGroup, IsGroup ], 0, 2409function( G, R ) 2410 2411 local L, C; 2412 2413 L := [ ]; 2414 for C in AllCat1GroupsWithImageIterator( G, R ) do 2415 if not ( C = fail ) then 2416 Add( L, C ); 2417 fi; 2418 od; 2419 return L; 2420end ); 2421 2422InstallMethod( AllCat1GroupsWithImageNumber, "for a group and a subgroup", 2423 [ IsGroup, IsGroup ], 0, 2424function( G, R ) 2425 2426 local n, C; 2427 2428 n := 0; 2429 for C in AllCat1GroupsWithImageIterator( G, R ) do 2430 if not ( C = fail ) then 2431 n := n+1; 2432 fi; 2433 od; 2434 return n; 2435end ); 2436 2437############################################################################## 2438## 2439#M AllCat1Groups . . . . . . . list of cat1-group structures on a given group 2440#O AllCat1GroupsIterator( <gp> ) . . . . . . . iterator for the previous list 2441#F NextIterator_AllCat1Groups( <iter> ) 2442#F IsDoneIterator_AllCat1Groups( <iter> ) 2443#F ShallowCopy_AllCat1Groups( <iter> ) 2444#A AllCat1GroupsNumber( <gp> ) . . . . . . . . . number of these cat1-groups 2445#M AllCat1GroupsUpToIsomorphism . . . iso class reps of cat1-group structures 2446## 2447BindGlobal( "NextIterator_AllCat1Groups", function ( iter ) 2448 local R, C; 2449 if IsDoneIterator( iter!.imagesIterator ) then 2450 R := NextIterator( iter!.subsIterator ); 2451 iter!.imagesIterator := 2452 AllCat1GroupsWithImageIterator( iter!.group, R ); 2453 ## but this iterator might be empty, so: 2454 if IsDoneIterator( iter!.imagesIterator ) then 2455 return fail; 2456 fi; 2457 fi; 2458 return NextIterator( iter!.imagesIterator ); 2459end ); 2460 2461BindGlobal( "IsDoneIterator_AllCat1Groups", 2462 iter -> ( IsDoneIterator( iter!.subsIterator ) 2463 and IsDoneIterator( iter!.imagesIterator ) ) 2464); 2465 2466BindGlobal( "ShallowCopy_AllCat1Groups", 2467 iter -> rec( group := iter!.group, 2468 subsIterator := ShallowCopy( iter!.subsIterator ), 2469 imagesIterator := ShallowCopy( iter!.imagesIterator ) 2470 ) 2471); 2472 2473InstallGlobalFunction( "DoAllCat1GroupsIterator", 2474function( G ) 2475 2476 local subsIterator, imagesIterator, iter; 2477 2478 subsIterator := AllSubgroupsIterator( G ); 2479 imagesIterator := IteratorList( [ ] ); 2480 iter := IteratorByFunctions( 2481 rec( group := G, 2482 subsIterator := ShallowCopy( subsIterator ), 2483 imagesIterator := ShallowCopy( imagesIterator ), 2484 NextIterator := NextIterator_AllCat1Groups, 2485 IsDoneIterator := IsDoneIterator_AllCat1Groups, 2486 ShallowCopy := ShallowCopy_AllCat1Groups ) ); 2487 return iter; 2488end ); 2489 2490InstallMethod( AllCat1GroupsIterator, "for a group", [ IsGroup ], 0, 2491 G -> DoAllCat1GroupsIterator( G ) ); 2492 2493InstallMethod( AllCat1Groups, "for a group", [ IsGroup ], 0, 2494function( G ) 2495 2496 local L, C, images, lens; 2497 2498 InitCatnGroupRecords( G ); 2499 L := [ ]; 2500 for C in AllCat1GroupsIterator( G ) do 2501 if not ( C = fail ) then 2502 Add( L, C ); 2503 fi; 2504 od; 2505 if not IsBound( CatnGroupNumbers( G ).idem ) then 2506 images := IdempotentEndomorphismsData( G ).images; 2507 lens := List( images, L -> Length( L ) ); 2508 CatnGroupNumbers( G ).idem := Sum( lens ); 2509 fi; 2510 if not IsBound( CatnGroupNumbers( G ).cat1 ) then 2511 CatnGroupNumbers( G ).cat1 := Length( L ); 2512 fi; 2513 return L; 2514end ); 2515 2516InstallMethod( AllCat1GroupsNumber, "for a group", [ IsGroup ], 0, 2517function( G ) 2518 2519 local n, C, all; 2520 2521 InitCatnGroupRecords( G ); 2522 if IsBound( CatnGroupNumbers( G ).cat1 ) then 2523 return CatnGroupNumbers( G ).cat1; 2524 fi; 2525 ## not already known, so perform the calculation 2526 all := AllCat1Groups( G ); 2527 return CatnGroupNumbers( G ).cat1; 2528end ); 2529 2530InstallMethod( AllCat1GroupsUpToIsomorphism, "iso class reps of cat1-groups", 2531 true, [ IsGroup ], 0, 2532function( G ) 2533 2534 local L, numL, i, k, C, ok, found, iso, images, lens; 2535 2536 InitCatnGroupRecords( G ); 2537 L := [ ]; 2538 i := 0; 2539 numL := 0; 2540 for C in AllCat1GroupsIterator( G ) do 2541 if not ( C = fail ) then 2542 i := i+1; 2543 k := 0; 2544 found := false; 2545 while ( not found ) and ( k < numL ) do 2546 k := k+1; 2547 iso := IsomorphismCat1Groups( C, L[k] ); 2548 if ( iso <> fail ) then 2549 found := true; 2550 fi; 2551 od; 2552 if not found then 2553 Add( L, C ); 2554 numL := numL + 1; 2555 fi; 2556 fi; 2557 od; 2558 if not IsBound( CatnGroupNumbers( G ).idem ) then 2559 images := IdempotentEndomorphismsData( G ).images; 2560 lens := List( images, L -> Length( L ) ); 2561 CatnGroupNumbers( G ).idem := Sum( lens ); 2562 fi; 2563 if not IsBound( CatnGroupNumbers( G ).cat1 ) then 2564 CatnGroupNumbers( G ).cat1 := i; 2565 fi; 2566 if not IsBound( CatnGroupNumbers( G ).iso1 ) then 2567 CatnGroupNumbers( G ).iso1 := numL; 2568 fi; 2569 return L; 2570end ); 2571 2572############################################################################# 2573## 2574#M DirectProductInfo( <obj> ) . . . . . . . . . . . . . . . . for 2d-objects 2575#M Coproduct2dInfo( <obj> ) . . . . . . . . . . . . . . . . . for 2d-objects 2576#M DirectProductOp( ) . . . . . . (bdy1 x bdy2) : (S1 x S2) --> (R1 x R2) 2577## 2578InstallOtherMethod( DirectProductInfo, "generic method for 2d-objects", true, 2579 [ Is2DimensionalDomain ], 0, 2580function( obj ) 2581 return rec( objects := [ ], 2582 embeddings := [ ], 2583 projections := [ ] ); 2584end ); 2585 2586InstallMethod( Coproduct2dInfo, "generic method for 2d-objects", true, 2587 [ Is2DimensionalDomain ], 0, 2588function( obj ) 2589 return rec( objects := [ ], 2590 embeddings := [ ], 2591 projections := [ ] ); 2592end ); 2593 2594#? (19/07/07) : allowed for case when one of Xsrc,Xrng,Ysrc,Yrng trivial ## 2595#? using parameter list: spec(=[0,0,0,0] by default) ## 2596 2597InstallOtherMethod( DirectProductOp, 2598 "method for pre-crossed modules", true, [ IsList, IsPreXMod ], 0, 2599function( list, X1 ) 2600 2601 local Xsrc, Xrng, Y1, Ysrc, Yrng, genXrng, genYrng, genXsrc, genYsrc, 2602 XSpos, YSpos, XRpos, YRpos, Spos, imaut, autgen, aut, act, 2603 XY, S, R, genS, lenS, genR, lenR, imbdy, bdy, a, i, j, k, 2604 Xbdy, Ybdy, Xact, Yact, imXbdy, imYbdy, alpha, info, 2605 eXS, eYS, pXS, pYS, eXR, eYR, spec; 2606 2607 if not ( Length( list ) = 2 ) then 2608 Error( "direct product not yet implemented for more than 2 terms" ); 2609 fi; 2610 if not ( list[1] = X1 ) then 2611 Error( "second argument should be first entry in first argument list" ); 2612 fi; 2613 Y1 := list[2]; 2614 ## first the source group 2615 Xsrc := Source( X1 ); 2616 Ysrc := Source( Y1 ); 2617 genXsrc := GeneratorsOfGroup( Xsrc ); 2618 genYsrc := GeneratorsOfGroup( Ysrc ); 2619 spec := [false,false,false,false]; 2620 if ( Size( Xsrc ) = 1 ) then 2621 spec[1] := true; 2622 elif ( Size( Ysrc ) = 1 ) then 2623 spec[3] := true; 2624 fi; 2625 if spec[1] then 2626 S := Ysrc; 2627 eYS := IdentityMapping( S ); 2628 pYS := IdentityMapping( S ); 2629 elif spec[3] then 2630 S := Xsrc; 2631 eXS := IdentityMapping( S ); 2632 pXS := IdentityMapping( S ); 2633 else 2634 S := DirectProduct( Xsrc, Ysrc ); 2635 if ( not HasName( S ) and HasName( Xsrc ) and HasName( Ysrc ) ) then 2636 SetName( S, Concatenation( Name( Xsrc ), "x", Name( Ysrc ) ) ); 2637 fi; 2638 eXS := Embedding( S, 1 ); 2639 eYS := Embedding( S, 2 ); 2640 pXS := Projection( S, 1 ); 2641 pYS := Projection( S, 2 ); 2642 fi; 2643 genS := GeneratorsOfGroup( S ); 2644 lenS := Length( genS ); 2645 Spos := [ 1..lenS ]; 2646 if spec[1] then 2647 XSpos := [ ]; 2648 YSpos := [ 1..Length( genYsrc ) ]; 2649 elif spec[3] then 2650 XSpos := [ 1..Length( genXsrc ) ]; 2651 YSpos := [ ]; 2652 else 2653 XSpos := [ 1..Length( genXsrc ) ]; 2654 YSpos := [ 1+Length( genXsrc ) .. lenS ]; 2655 fi; 2656 ## now for the range group 2657 Xrng := Range( X1 ); 2658 Yrng := Range( Y1 ); 2659 genXrng := GeneratorsOfGroup( Xrng ); 2660 genYrng := GeneratorsOfGroup( Yrng ); 2661 if ( Size( Xrng ) = 1 ) then 2662 spec[2] := true; 2663 elif ( Size( Yrng ) = 1 ) then 2664 spec[4] := true; 2665 fi; 2666 if spec[2] then 2667 R := Yrng; 2668 eXR := MappingToOne( Xrng, Yrng ); 2669 eYR := IdentityMapping( R ); 2670 elif spec[4] then 2671 R := Xrng; 2672 eXR := IdentityMapping( R ); 2673 eYR := MappingToOne( Yrng, Xrng ); 2674 else 2675 R := DirectProduct( Xrng, Yrng ); 2676 if ( not HasName( R ) and HasName( Xrng ) and HasName( Yrng ) ) then 2677 SetName( R, Concatenation( Name( Xrng ), "x", Name( Yrng ) ) ); 2678 fi; 2679 eXR := Embedding( R, 1 ); 2680 eYR := Embedding( R, 2 ); 2681 fi; 2682 genR := GeneratorsOfGroup( R ); 2683 lenR := Length( genR ); 2684 if spec[2] then 2685 XRpos := [ ]; 2686 YRpos := [ 1..Length( genYrng ) ]; 2687 elif spec[4] then 2688 XRpos := [ 1..Length( genXrng ) ]; 2689 YRpos := [ ]; 2690 else 2691 XRpos := [ 1..Length( genXrng ) ]; 2692 YRpos := [ 1+Length( genXrng ) .. lenR ]; 2693 fi; 2694 ## now for the boundary 2695 Xbdy := Boundary( X1 ); 2696 Ybdy := Boundary( Y1 ); 2697 Xact := XModAction( X1 ); 2698 Yact := XModAction( Y1 ); 2699 imXbdy := List( genS{ XSpos }, 2700 s -> ImageElm( eXR, ImageElm( Xbdy, ImageElm( pXS, s ) ) ) ); 2701 imYbdy := List( genS{ YSpos }, 2702 s -> ImageElm( eYR, ImageElm( Ybdy, ImageElm( pYS, s ) ) ) ); 2703 imbdy := Concatenation( imXbdy, imYbdy ); 2704 bdy := GroupHomomorphismByImages( S, R, genS, imbdy ); 2705 autgen := 0 * [ 1..lenR ]; 2706 for i in XRpos do 2707 a := ImageElm( Xact, genXrng[i] ); 2708 imaut := 0 * Spos; 2709 for j in YSpos do 2710 imaut[j] := genS[j]; 2711 od; 2712 for j in XSpos do 2713 imaut[j] := ImageElm( eXS, ImageElm( a, ImageElm(pXS,genS[j] ) ) ); 2714 od; 2715 alpha := GroupHomomorphismByImages( S, S, genS, imaut ); 2716 autgen[i] := alpha; 2717 od; 2718 if spec[2] then 2719 k := 0; 2720 else 2721 k := Length( genXrng ); 2722 fi; 2723 for i in YRpos do 2724 a := ImageElm( Yact, genYrng[i-k] ); 2725 imaut := 0 * Spos; 2726 for j in XSpos do 2727 imaut[j] := genS[j]; 2728 od; 2729 for j in YSpos do 2730 imaut[j] := ImageElm( eYS, ImageElm( a, ImageElm(pYS,genS[j] ) ) ); 2731 od; 2732 alpha := GroupHomomorphismByImages( S, S, genS, imaut ); 2733 autgen[i] := alpha; 2734 od; 2735 aut := Group( autgen ); 2736 act := GroupHomomorphismByImages( R, aut, genR, autgen ); 2737 XY := PreXModByBoundaryAndAction( bdy, act ); 2738 if ( IsXMod( X1 ) and IsXMod( Y1 ) ) then 2739 SetIsXMod( XY, true ); 2740 fi; 2741 if ( HasName( X1 ) and HasName( Y1 ) ) then 2742 SetName( XY, Concatenation( Name( X1 ), "x", Name( Y1 ) ) ); 2743 elif ( HasName( Source(XY) ) and HasName( Range(XY) ) ) then 2744 SetName( XY, Concatenation( "[", Name( Source(XY ) ), 2745 "->", Name( Range(XY) ), "]" ) ); 2746 fi; 2747 info := DirectProductInfo( XY ); 2748 info!.objects := [ X1, Y1 ]; 2749 return XY; 2750end ); 2751 2752############################################################################## 2753## 2754#M Embedding . . . . for direct products of (pre-)xmods and (pre-)cat1-groups 2755## 2756InstallOtherMethod( Embedding, "generic method for (pre-)xmods & (pre-)cat1s", 2757 true, [ Is2DimensionalGroup, IsPosInt ], 0, 2758function( D, i ) 2759 local info, eS, eR, obj, mor; 2760 2761 info := DirectProductInfo( D ); 2762 if IsBound( info!.embeddings[i] ) then 2763 return info!.embeddings[i]; 2764 fi; 2765 eS := Embedding( Source( D ), i ); 2766 eR := Embedding( Range( D ), i ); 2767 Info( InfoXMod, 3, "SourceEmbedding: ", eS ); 2768 Info( InfoXMod, 3, " RangeEmbedding: ", eR ); 2769 obj := info!.objects[i]; 2770 if IsPreXMod( D ) then 2771 mor := PreXModMorphism( obj, D, eS, eR ); 2772 elif IsPreCat1Group( D ) then 2773 mor := PreCat1GroupMorphism( obj, D, eS, eR ); 2774 else 2775 mor := fail; 2776 fi; 2777 if not ( mor = fail ) then 2778 SetIsInjective( mor, true ); 2779 info!.embeddings[i] := mor; 2780 fi; 2781 return mor; 2782end ); 2783 2784############################################################################## 2785## 2786#M Projection . . . for direct products of (pre-)xmods and (pre-)cat1-groups 2787## 2788InstallOtherMethod( Projection, "generic method for (pre-)xmods & (pre-)cat1s", 2789 true, [ Is2DimensionalGroup, IsPosInt ], 0, 2790function( D, i ) 2791 local G, info, pS, pR, mor; 2792 2793 G := Source( D ); 2794 if HasDirectProductInfo( G ) then 2795 info := DirectProductInfo( D ); 2796 if not ( i in [1,2] ) then 2797 Error( "only two projections available" ); 2798 fi; 2799 else 2800 info := SemidirectProductInfo( G ); 2801 if not ( i = 1 ) then 2802 Error( "only the first projection is available" ); 2803 fi; 2804 fi; 2805 if IsBound( info!.projections[i] ) then 2806 return info!.projections[i]; 2807 fi; 2808 pS := Projection( G, i ); 2809 pR := Projection( Range( D ), i ); 2810 if IsPreXMod( D ) then 2811 mor := PreXModMorphism( info!.objects[i], D, pS, pR ); 2812 elif IsPreCat1Group( D ) then 2813 mor := PreCat1GroupMorphism( info!.objects[i], D, pS, pR ); 2814 else 2815 mor := fail; 2816 fi; 2817 if not ( mor = fail ) then 2818 SetIsInjective( mor, true ); 2819 info!.projections[i] := mor; 2820 fi; 2821 return mor; 2822end ); 2823 2824############################################################################## 2825## 2826#M TrivialSub2DimensionalGroup . . . . . . . . . . of a 2d-object 2827#M TrivialSubPreXMod . . . . . . . . . . . . . . . of a pre-crossed module 2828#M TrivialSubXMod . . . . . . . . . . . . . . . of a crossed module 2829#M TrivialSubPreCat1Group . . . . . . . . . . . . . of a pre-cat1-group 2830#M TrivialSubCat1Group . . . . . . . . . . . . . . of a cat1-group 2831## 2832InstallMethod( TrivialSub2DimensionalGroup, "of a 2d-object", true, 2833 [ Is2DimensionalGroup ], 0, 2834function( obj ) 2835 2836 local idsrc, idrng; 2837 2838 idsrc := TrivialSubgroup( Source( obj ) ); 2839 idrng := TrivialSubgroup( Range( obj ) ); 2840 if IsPreXMod( obj ) then 2841 return SubPreXMod( obj, idsrc, idrng ); 2842 elif IsPreCat1Group( obj ) then 2843 return SubPreCat1Group( obj, idsrc ); 2844 else 2845 Error( "<obj> must be a pre-crossed module or a pre-cat1-group" ); 2846 fi; 2847end ); 2848 2849InstallMethod( TrivialSubPreXMod, "of a pre-crossed module", true, 2850 [ IsPreXMod ], 0, 2851function( obj ) 2852 return TrivialSub2DimensionalGroup( obj ); 2853end ); 2854 2855InstallMethod( TrivialSubXMod, "of a crossed module", true, [ IsXMod ], 0, 2856function( obj ) 2857 return TrivialSub2DimensionalGroup( obj ); 2858end ); 2859 2860InstallMethod( TrivialSubPreCat1Group, "of a pre-cat1-group", true, 2861 [ IsPreCat1Group ], 0, 2862function( obj ) 2863 return TrivialSub2DimensionalGroup( obj ); 2864end ); 2865 2866InstallMethod( TrivialSubCat1Group, "of a cat1-group", true, [ IsCat1Group ], 0, 2867function( obj ) 2868 return TrivialSub2DimensionalGroup( obj ); 2869end ); 2870 2871############################################################################## 2872## 2873#M IsNormalSubgroup2DimensionalGroup . . . . . . . . for 2Dimensional-objects 2874## 2875InstallMethod( IsNormalSubgroup2DimensionalGroup, 2876 "for crossed modules and cat1-groups", [ Is2DimensionalGroup ], 0, 2877function( obj ) 2878 local src, rng, gensrc, genrng; 2879 src := Source( obj ); 2880 rng := Range( obj ); 2881 gensrc := GeneratorsOfGroup( src ); 2882 if IsXMod( obj ) then 2883 return ( IsNormal(rng,src) and 2884 ( gensrc = List( gensrc, s -> ImageElm( Boundary(obj), s ) ) ) ); 2885 elif IsCat1Group( obj ) then 2886 return IsNormalSubgroup2DimensionalGroup( XModOfCat1Group( obj ) ); 2887 else 2888 Error( "method not yet implemented" ); 2889 fi; 2890end ); 2891 2892############################################################################## 2893## 2894#M IsNormal . . . . . . . . . . . . . . . . . . . . for 2Dimensional-objects 2895## 2896InstallOtherMethod( IsNormal, "for precrossed modules", IsIdenticalObj, 2897 [ IsPreXMod, IsPreXMod ], 0, 2898function( XM, SM ) 2899 2900 local xr, a, ss, im, xs, sr, Ssrc, Xact, snat, rnat; 2901 2902 if not IsSubPreXMod( XM, SM ) then 2903 return false; 2904 fi; 2905 Ssrc := Source( SM ); 2906 Xact := XModAction( XM ); 2907 for xr in GeneratorsOfGroup( Range( XM ) ) do 2908 a := ImageElm( Xact, xr ); 2909 for ss in GeneratorsOfGroup( Ssrc ) do 2910 im := ImageElm( a, ss ); 2911 if not ( im in Ssrc ) then 2912 Info( InfoXMod, 2, "ss,xr,ss^xr = ", [ss,xr,im] ); 2913 return false; 2914 fi; 2915 od; 2916 od; 2917 for sr in GeneratorsOfGroup( Range( SM ) ) do 2918 a := ImageElm( Xact, sr ); 2919 for xs in GeneratorsOfGroup( Source( XM ) ) do 2920 im := xs^(-1) * ImageElm( a, xs ); 2921 if not ( im in Ssrc ) then 2922 Info( InfoXMod, 3, "sr,xs,sr^(-1)*xs^sr = ", [sr,xs,im] ); 2923 return false; 2924 fi; 2925 od; 2926 od; 2927 return true; 2928end ); 2929 2930############################################################################## 2931## 2932#M NormalSubXMods . . . . . . . . . . . . . . . . . . for a crossed module 2933## 2934InstallMethod( NormalSubXMods, "for a crossed module", true, [ IsXMod ], 0, 2935function( XM ) 2936 2937 local Xsrc, Xrng, YM, i, j, slen, rlen, norm, normsrc, normrng, ok; 2938 2939 Xsrc := Source( XM ); 2940 Xrng := Range( XM ); 2941 norm := [ ]; 2942 normsrc := NormalSubgroups( Xsrc ); 2943 normrng := NormalSubgroups( Xrng ); 2944 slen := Length( normsrc ); 2945 rlen := Length( normrng ); 2946 for i in [ 1..slen ] do 2947 for j in [ 1..rlen ] do 2948 if ( ( i = 1 ) and ( j = 1 ) ) then 2949 YM := TrivialSubXMod( XM ); 2950 elif ( ( i = slen ) and ( j = rlen ) ) then 2951 YM := XM; 2952 else 2953 YM := SubXMod( XM, normsrc[i], normrng[j] ); 2954 fi; 2955 ok := not ( YM = fail ); 2956 if ( ok and IsXMod( YM ) and IsNormal( XM, YM ) ) then 2957 Add( norm, YM ); 2958 fi; 2959 od; 2960 od; 2961 return norm; 2962end ); 2963 2964############################################################################## 2965## 2966#M InitCatnGroupRecords . . . . . . . . . . . . . . . . . . . . . for a group 2967## 2968InstallMethod( InitCatnGroupRecords, "for a group", true, [ IsGroup ], 0, 2969function( G ) 2970 2971 if not HasCatnGroupNumbers( G ) then 2972 SetCatnGroupNumbers( G, rec() ); 2973 fi; 2974 if not HasCatnGroupNumbers( G ) then 2975 Error( "CatnGroupNumbers not set" ); 2976 fi; 2977 if not HasCatnGroupLists( G ) then 2978 SetCatnGroupLists( G, rec() ); 2979 CatnGroupLists( G ).omit := false; 2980 fi; 2981 if not HasCatnGroupLists( G ) then 2982 Error( "CatnGroupLists not set" ); 2983 fi; 2984end ); 2985