1############################################################################## 2## 3#W gpdaut.gi GAP4 package `groupoids' Chris Wensley 4#W & Emma Moore 5#Y Copyright (C) 2000-2019, Emma Moore and Chris Wensley, 6#Y School of Computer Science, Bangor University, U.K. 7## 8 9############################################################################# 10## 11#M GroupoidAutomorphismByObjectPermNC 12#M GroupoidAutomorphismByObjectPerm 13## 14InstallMethod( GroupoidAutomorphismByObjectPermNC , 15 "for a single piece groupoid and a permutation of objects", true, 16 [ IsGroupoid and IsDirectProductWithCompleteDigraphDomain, 17 IsHomogeneousList ], 0, 18function( gpd, oims ) 19 20 local obs, gens, ngens, images, i, a, pt, ph, mor, L; 21 22 obs := gpd!.objects; 23 gens := GeneratorsOfGroupoid( gpd ); 24 ngens := Length( gens ); 25 images := [1..ngens]; 26 for i in [1..ngens] do 27 a := gens[i]; 28 pt := Position( obs, a![2] ); 29 ph := Position( obs, a![3] ); 30 images[i] := Arrow( gpd, a![1], oims[pt], oims[ph] ); 31 od; 32 if ( fail in images ) then 33 Error( "the set of images contains 'fail'" ); 34 fi; 35 mor := GroupoidHomomorphismFromSinglePiece( gpd, gpd, gens, images ); 36 SetIsInjectiveOnObjects( mor, true ); 37 SetIsSurjectiveOnObjects( mor, true ); 38 L := [1..Length(obs)]; 39 SortParallel( ShallowCopy( oims ), L ); 40 SetOrder( mor, Order( PermList( L ) ) ); 41 SetIsGroupoidAutomorphismByObjectPerm( mor, true ); 42 return mor; 43end ); 44 45InstallMethod( GroupoidAutomorphismByObjectPermNC , 46 "for a single piece groupoid with rays rep", true, 47 [ IsGroupoid and IsSinglePieceRaysRep, IsHomogeneousList ], 0, 48function( gpd, oims ) 49 50 local iso, inv, sgpd, aut; 51 52 iso := IsomorphismStandardGroupoid( gpd, ObjectList( gpd ) ); 53 inv := InverseGeneralMapping( iso ); 54 sgpd := Image( iso ); 55 aut := GroupoidAutomorphismByObjectPermNC( sgpd, oims ); 56 return iso * aut * inv; 57end ); 58 59InstallMethod( GroupoidAutomorphismByObjectPermNC, 60 "for a hom discrete groupoid and a permutation of objects", true, 61 [ IsHomogeneousDiscreteGroupoid, IsHomogeneousList ], 0, 62function( gpd, oims ) 63 64 local gpd1, gp, id, homs, mor, L; 65 66 gpd1 := Pieces( gpd )[1]; 67 gp := gpd1!.magma; 68 id := IdentityMapping( gp ); 69 homs := List( oims, o -> id ); 70 mor := GroupoidHomomorphismFromHomogeneousDiscreteNC 71 ( gpd, gpd, homs, oims ); 72 SetIsInjectiveOnObjects( mor, true ); 73 SetIsSurjectiveOnObjects( mor, true ); 74 L := [1..Length(oims)]; 75 SortParallel( ShallowCopy( oims ), L ); 76 SetOrder( mor, Order( PermList( L ) ) ); 77 SetIsGroupoidAutomorphismByObjectPerm( mor, true ); 78 return mor; 79end ); 80 81InstallMethod( GroupoidAutomorphismByObjectPerm, 82 "for a groupoid and a permutation of objects", true, 83 [ IsGroupoid, IsHomogeneousList ], 0, 84function( gpd, oims ) 85 86 local obs, pos; 87 88 obs := ObjectList( gpd ); 89 pos := PermList( List( oims, o -> Position( obs, o ) ) ); 90 if ( pos = fail ) then 91 Error( "object images not a permutation of the objects" ); 92 fi; 93 return GroupoidAutomorphismByObjectPermNC( gpd, oims ); 94end ); 95 96############################################################################# 97## 98#M GroupoidAutomorphismByGroupAutoNC 99#M GroupoidAutomorphismByGroupAuto 100## 101InstallMethod( GroupoidAutomorphismByGroupAutoNC , 102 "for a groupoid and an automorphism of the root group", true, 103 [ IsGroupoid and IsSinglePiece, IsGroupHomomorphism and IsBijective ], 0, 104function( gpd, hom ) 105 106 local gens, images, i, a, mor; 107 108 gens := GeneratorsOfGroupoid( gpd ); 109 images := ShallowCopy( gens ); 110 for i in [1..Length(gens) - Length(ObjectList(gpd)) + 1] do 111 a := gens[i]; 112 images[i] := Arrow( gpd, ImageElm(hom,a![1]), a![2], a![3] ); 113 od; 114 mor := GroupoidHomomorphismFromSinglePiece( gpd, gpd, gens, images ); 115 SetIsInjectiveOnObjects( mor, true ); 116 SetIsSurjectiveOnObjects( mor, true ); 117 SetOrder( mor, Order( hom ) ); 118 SetIsGroupoidAutomorphismByGroupAuto( mor, true ); 119 return mor; 120end ); 121 122InstallMethod( GroupoidAutomorphismByGroupAuto, 123 "for a groupoid and an automorphism of the root group", true, 124 [ IsGroupoid and IsSinglePiece, IsGroupHomomorphism ], 0, 125function( gpd, hom ) 126 127 local rgp; 128 129 rgp := gpd!.magma; 130 if not ( (Source(hom) = rgp) and (Range(hom) = rgp) ) then 131 Error( "hom not an endomorphism of the root group" ); 132 fi; 133 if not IsBijective( hom ) then 134 Error( "hom is not an automorphism" ); 135 fi; 136 return GroupoidAutomorphismByGroupAutoNC( gpd, hom ); 137end ); 138 139############################################################################# 140## 141#M GroupoidAutomorphismByGroupAutosNC 142#M GroupoidAutomorphismByGroupAutos 143## 144InstallMethod( GroupoidAutomorphismByGroupAutosNC , 145 "for homogeneous discrete groupoid and automorphism list", true, 146 [ IsHomogeneousDiscreteGroupoid, IsHomogeneousList ], 0, 147function( gpd, homs ) 148 149 local obs, orders, m; 150 151 obs := ObjectList( gpd ); 152 m := GroupoidHomomorphismFromHomogeneousDiscreteNC( gpd, gpd, homs, obs ); 153 SetIsEndoGeneralMapping( m, true ); 154 SetIsInjectiveOnObjects( m, true ); 155 SetIsSurjectiveOnObjects( m, true ); 156 orders := List( homs, h -> Order( h ) ); 157 SetOrder( m, Lcm( orders ) ); 158 return m; 159end ); 160 161InstallMethod( GroupoidAutomorphismByGroupAutos, 162 "for homogeneous discrete groupoid and automorphism list", true, 163 [ IsHomogeneousDiscreteGroupoid, IsHomogeneousList ], 0, 164function( gpd, homs ) 165 166 local pieces, len, i, p, g, h; 167 168 pieces := Pieces( gpd ); 169 len := Length( pieces ); 170 if not ( len = Length( homs ) ) then 171 Error( "length of <homs> not equal to number of objects on <gpd>," ); 172 fi; 173 for i in [1..len] do 174 p := pieces[i]; 175 g := p!.magma; 176 h := homs[i]; 177 if not ( (Source(h) = g) and (Range(h) = g) ) then 178 Error( "<h> not an endomorphism of group <g> at object <i>," ); 179 fi; 180 if not IsBijective( h ) then 181 Error( "<h> not an automorphism of group <g> at object <i>," ); 182 fi; 183 od; 184 return GroupoidAutomorphismByGroupAutosNC( gpd, homs ); 185end ); 186 187############################################################################# 188## 189#M GroupoidAutomorphismByRayShiftsNC 190#M GroupoidAutomorphismByRayShifts 191## 192InstallMethod( GroupoidAutomorphismByRayShiftsNC , 193 "for a groupoid and a list of elements of the root group", true, 194 [ IsGroupoid and IsSinglePiece, IsHomogeneousList ], 0, 195function( gpd, shifts ) 196 197 local gens, ngens, nobs, images, i, k, a, mor; 198 199 gens := GeneratorsOfGroupoid( gpd ); 200 ngens := Length( gens ); 201 nobs := Length( gpd!.objects ); 202 images := ShallowCopy( gens ); 203 k := ngens - nobs; 204 for i in [2..nobs] do 205 a := gens[i+k]; 206 images[i+k] := Arrow( gpd, a![1]*shifts[i], a![2], a![3] ); 207 od; 208 mor := GroupoidHomomorphismFromSinglePiece( gpd, gpd, gens, images ); 209 SetOrder( mor, Lcm( List( shifts, i -> Order(i) ) ) ); 210 SetIsInjectiveOnObjects( mor, true ); 211 SetIsSurjectiveOnObjects( mor, true ); 212 SetIsGroupoidAutomorphismByRayShifts( mor, true ); 213 return mor; 214end ); 215 216InstallMethod( GroupoidAutomorphismByRayShifts, 217 "for a groupoid and a list of elements of the root group", true, 218 [ IsGroupoid and IsSinglePiece, IsHomogeneousList ], 0, 219function( gpd, shifts ) 220 221 local rgp, rays, nobs, conj; 222 223 rgp := gpd!.magma; 224 rays := gpd!.rays; 225 nobs := Length( gpd!.objects ); 226 if not ForAll( shifts, s -> s in rgp ) then 227 Error( "ray shifts not all in the root group" ); 228 fi; 229 if not ( shifts[1] = One( rgp ) ) then 230 Error( "the first ray shift is not the identity" ); 231 fi; 232 return GroupoidAutomorphismByRayShiftsNC( gpd, shifts ); 233end ); 234 235############################################################################# 236## 237#M GroupoidInnerAutomorphism 238## 239InstallMethod( GroupoidInnerAutomorphism, 240 "for a groupoid and an element", true, 241 [ IsGroupoid, IsGroupoidElement ], 0, 242function( gpd, e ) 243 Error( "not yet implemented for unions of groupoids" ); 244end ); 245 246InstallMethod( GroupoidInnerAutomorphism, 247 "for a groupoid and an element", true, 248 [ IsGroupoid and IsSinglePieceDomain, IsGroupoidElement ], 0, 249function( gpd, e ) 250 251 local gens, images; 252 253 Info( InfoGroupoids, 3, "GroupoidInnerAutomorphism from single piece" ); 254 gens := GeneratorsOfGroupoid( gpd ); 255 images := List( gens, g -> g^e ); 256 return GroupoidHomomorphism( gpd, gpd, gens, images ); 257end ); 258 259InstallMethod( GroupoidInnerAutomorphism, 260 "for a groupoid and an element", true, 261 [ IsGroupoid and IsDiscreteDomainWithObjects, IsGroupoidElement ], 0, 262function( gpd, e ) 263 264 local obs, nobs, pos, id, auts; 265 266 Info( InfoGroupoids, 3, "GroupoidInnerAutomorphism from discrete domain" ); 267 obs := gpd!.objects; 268 nobs := Length( obs ); 269 pos := Position( obs, e![2] ); 270 id := IdentityMapping( gpd!.magma ); 271 auts := List( [1..nobs], i -> id ); 272 auts[pos] := InnerAutomorphism( gpd!.magma, e![1] ); 273 return GroupoidAutomorphismByGroupAutosNC( gpd, auts ); 274end ); 275 276InstallOtherMethod( GroupoidInnerAutomorphism, 277 "for a groupoid, a subgroupoid, and an element", true, 278 [ IsGroupoid and IsSinglePieceDomain, IsGroupoid, IsGroupoidElement ], 0, 279function( gpd, sub, e ) 280 281 local gens, images, inn, res; 282 283 Info( InfoGroupoids, 3, "GroupoidInnerAutomorphism for a subgroupoid" ); 284 if not IsSubgroupoid( gpd, sub ) then 285 Error( "sub is not a subgroupoid of gpd" ); 286 fi; 287 gens := GeneratorsOfGroupoid( gpd ); 288 images := List( gens, g -> g^e ); 289 inn := GroupoidHomomorphism( gpd, gpd, gens, images ); 290 res := RestrictedMappingGroupoids( inn, sub ); 291 return res; 292end ); 293 294############################################################################# 295## 296#M Size( <agpd> ) . . . . . . . . . . . . . . . . . for a connected groupoid 297## 298InstallMethod( Size, "for a groupoid automorphism group", true, 299 [ IsAutomorphismGroupOfGroupoid ], 0, 300function( agpd ) 301 302 local gpd, gp, n, aut; 303 304 gpd := AutomorphismDomain( agpd ); 305 gp := gpd!.magma; 306 if IsSinglePieceDomain( gpd ) then 307 n := Length( ObjectList( gpd ) ); 308 aut := AutomorphismGroup( gpd!.magma ); 309 return Factorial( n ) * Size( aut ) * Size( gp )^(n-1); 310 elif IsDiscreteDomainWithObjects( gpd ) 311 and IsHomogeneousDomainWithObjects( gpd ) then 312 n := Length( ObjectList( gpd ) ); 313 aut := AutomorphismGroup( gpd!.magma ); 314 return Factorial( n ) * Size( aut )^n; 315 fi; 316 return fail; 317end ); 318 319############################################################################## 320## 321#M NiceObjectAutoGroupGroupoid( <gpd>, <aut> ) . . create a nice monomorphism 322## 323InstallMethod( NiceObjectAutoGroupGroupoid, "for a single piece groupoid", true, 324 [ IsGroupoid and IsSinglePieceDomain, IsAutomorphismGroupOfGroupoid ], 0, 325function( gpd, aut ) 326 327 local genaut, rgp, genrgp, nrgp, agp, genagp, nagp, iso1, im1, iso2, 328 pagp, iso, obs, n, L, symm, gensymm, nsymm, ngp, genngp, nngp, 329 ninfo, nemb, gens1, i, pi, imi, j, gens2, k, krgp, ikrgp, 330 pasy, esymm, epagp, genpasy, gens12, actgp, ok, action, sdp, 331 sinfo, siso, ssdp, epasy, engp, gennorm, norm, a, c, c1, c2, c12, 332 agens1, agens2, agens3, agens, nat, autgen, eno, gim1, gim2, gim3, 333 niceob, nicemap; 334 335 genaut := GeneratorsOfGroup( aut ); 336 ## first: automorphisms of the root group 337 rgp := gpd!.magma; 338 genrgp := GeneratorsOfGroup( rgp ); 339 nrgp := Length( genrgp ); 340 agp := AutomorphismGroup( rgp ); 341 genagp := SmallGeneratingSet( agp ); 342 nagp := Length( genagp ); 343 iso1 := IsomorphismPermGroup( agp ); 344 im1 := Image( iso1 ); 345 iso2 := SmallerDegreePermutationRepresentation( im1 ); 346 pagp := Image( iso2 ); 347 iso := iso1*iso2; 348 agens1 := List( genagp, a -> ImageElm( iso, a ) ); 349 ## second: permutations of the objects 350 obs := gpd!.objects; 351 n := Length( obs ); 352 if ( n = 1 ) then 353 return pagp; 354 elif ( n = 2 ) then 355 gensymm := [ (1,2) ]; 356 else 357 L := [2..n]; 358 Append( L, [1] ); 359 gensymm := [ PermList(L), (1,2) ]; #? replace (1,2) with (n-1,n) ?? 360 fi; 361 symm := Group( gensymm ); 362 nsymm := Length( gensymm ); 363 ## third: ray products 364 ngp := DirectProduct( ListWithIdenticalEntries( n, rgp ) ); 365 genngp := GeneratorsOfGroup( ngp ); 366 nngp := Length( genngp ); 367 ninfo := DirectProductInfo( ngp ); 368 ## force construction of the n embeddings 369 for i in [1..n] do 370 k := Embedding( ngp, i ); 371 od; 372 nemb := ninfo!.embeddings; 373 # action of agp on ngp 374 gens1 := [1..nagp]; 375 for i in [1..nagp] do 376 k := genagp[i]; 377 krgp := List( genrgp, r -> ImageElm( k, r ) ); 378 ikrgp := [ ]; 379 for j in [1..n] do 380 Append( ikrgp, List( krgp, x -> ImageElm( nemb[j], x ) ) ); 381 od; 382 gens1[i] := GroupHomomorphismByImages( ngp, ngp, genngp, ikrgp ); 383 od; 384 ## action of symm on ngp = rgp^n 385 gens2 := [1..nsymm]; 386 for i in [1..nsymm] do 387 pi := gensymm[i]^-1; 388 gens2[i] := GroupHomomorphismByImages( ngp, ngp, genngp, 389 List( [1..nngp], j -> genngp[ RemInt( j-1, nrgp ) + 1 390 + nrgp * (( QuoInt( j-1, nrgp ) + 1 )^pi - 1 ) ] ) ); 391 od; 392 pasy := DirectProduct( pagp, symm ); 393 epagp := Embedding( pasy, 1 ); 394 agens1 := List( agens1, g -> ImageElm( epagp, g ) ); 395 esymm := Embedding( pasy, 2 ); 396 agens2 := List( gensymm, g -> ImageElm( esymm, g ) ); 397 ## genpasy := GeneratorsOfGroup( pasy ); 398 genpasy := Concatenation( agens1, agens2 ); 399 # construct the semidirect product 400 gens12 := Concatenation( gens1, gens2 ); 401 actgp := Group( gens12 ); 402 ok := IsGroupOfAutomorphisms( actgp ); 403 action := GroupHomomorphismByImages( pasy, actgp, genpasy, gens12 ); 404 sdp := SemidirectProduct( pasy, action, ngp ); 405 Info( InfoGroupoids, 2, "sdp has ", 406 Length(GeneratorsOfGroup(sdp)), " gens." ); 407 sinfo := SemidirectProductInfo( sdp ); 408 siso := SmallerDegreePermutationRepresentation( sdp ); 409 ssdp := Image( siso ); 410 epasy := Embedding( sdp, 1 ) * siso; 411 agens1 := List( agens1, g -> ImageElm( epasy, g ) ); 412 agens2 := List( agens2, g -> ImageElm( epasy, g ) ); 413 engp := Embedding( sdp, 2 ) * siso; 414 # why [3..nngp]? no doubt because Sn has two generators? 415 agens3 := List( genngp{[3..nngp]}, g -> ImageElm( engp, g ) ); 416 # construct the normal subgroup 417 gennorm := [1..nrgp ]; 418 for i in [1..nrgp] do 419 c := genrgp[i]; 420 a := GroupHomomorphismByImages( rgp, rgp, genrgp, List(genrgp,x->x^c) ); 421 c1 := ImageElm( epasy, ImageElm( epagp, ImageElm( iso, a ) ) ); 422 c := c^-1; 423 c2 := ImageElm( engp, 424 Product( List( [1..n], j->ImageElm( nemb[j], c ) ) ) ); 425 gennorm[i] := c1 * c2; 426 od; 427 norm := Subgroup( ssdp, gennorm ); 428 ok := IsNormal( ssdp, norm ); 429 if not ok then 430 Error( "norm should be a normal subgroup of ssdp" ); 431 fi; 432 nat := NaturalHomomorphismByNormalSubgroup( ssdp, norm ); 433 niceob := Image( nat ); 434 eno := ListWithIdenticalEntries( n+2, 0 ); 435 eno[1] := iso * epagp * epasy * nat; ## agp->pagp->pasy->ssdp->niceob 436 eno[2] := esymm * epasy * nat; ## symm->pasy->ssdp->niceob 437 for i in [1..n] do 438 gim1 := List( genrgp, g -> ImageElm( nemb[i], g ) ); 439 gim2 := List( gim1, g -> ImageElm( engp, g ) ); 440 gim3 := List( gim2, g -> ImageElm( nat, g ) ); 441 eno[i+2] := GroupHomomorphismByImages( rgp, niceob, genrgp, gim3 ); 442 od; 443 autgen := Concatenation( agens1, agens2, agens3 ); 444 agens := List( autgen, g -> ImageElm( nat, g ) ); 445 return [ niceob, eno ]; 446end ); 447 448InstallMethod( NiceObjectAutoGroupGroupoid, "for a hom discrete groupoid", true, 449 [ IsHomogeneousDiscreteGroupoid, IsAutomorphismGroupOfGroupoid ], 0, 450function( gpd, aut ) 451 452 local pieces, obs, m, p1, g1, geng1, ng1, ag1, genag1, nag, 453 iso1, ag2, genag2, mag2, genmag2, nmag2, minfo, i, k, memb, 454 K, L, symm, gensymm, imact, pi, actgp, ok, action, sdp, sinfo, 455 siso, ssdp, esymm, egensymm, emag2, egenmag2, agens, 456 im1, im2, im3, eno; 457 458 pieces := Pieces( gpd ); 459 obs := ObjectList( gpd ); 460 m := Length( obs ); 461 ## first: automorphisms of the object groups 462 p1 := pieces[1]; 463 g1 := p1!.magma; 464 geng1 := GeneratorsOfGroup( g1 ); 465 ng1 := Length( geng1 ); 466 ag1 := AutomorphismGroup( g1 ); 467 genag1 := SmallGeneratingSet( ag1 ); 468 nag := Length( genag1 ); 469 iso1 := IsomorphismPermGroup( ag1 ); 470 genag2 := List( genag1, g -> ImageElm( iso1, g ) ); 471 ag2 := Group( genag2 ); 472 mag2 := DirectProduct( ListWithIdenticalEntries( m, ag2 ) ); 473 genmag2 := GeneratorsOfGroup( mag2 ); 474 nmag2 := Length( genmag2 ); 475 minfo := DirectProductInfo( mag2 ); 476 ## force construction of the m embeddings 477 for i in [1..m] do 478 k := Embedding( mag2, i ); 479 od; 480 memb := minfo!.embeddings; 481 ## second: permutations of the objects 482 if ( m = 1 ) then 483 Error( "only one object, so no permutations" ); 484 elif ( m = 2 ) then 485 K := [1]; 486 gensymm := [ (1,2) ]; 487 else 488 K := [1,2]; 489 L := [2..m]; 490 Append( L, [1] ); 491 gensymm := [ PermList(L), (1,2) ]; #? replace (1,2) with (m-1,m) ?? 492 fi; 493 symm := Group( gensymm ); 494 ## action of symm on mag2 = ag2^m 495 imact := ShallowCopy( K ); 496 for i in K do 497 pi := gensymm[i]^-1; 498 imact[i] := GroupHomomorphismByImages( mag2, mag2, genmag2, 499 List( [1..nmag2], j -> genmag2[ RemInt( j-1, nag ) + 1 500 + nag * (( QuoInt( j-1, nag ) + 1 )^pi - 1 ) ] ) ); 501 od; 502 # construct the semidirect product: symm acting on mag2 503 actgp := Group( imact ); 504 ok := IsGroupOfAutomorphisms( actgp ); 505 action := GroupHomomorphismByImages( symm, actgp, gensymm, imact ); 506 sdp := SemidirectProduct( symm, action, mag2 ); 507 Info( InfoGroupoids, 2, "sdp has ", 508 Length(GeneratorsOfGroup(sdp)), " gens." ); 509 sinfo := SemidirectProductInfo( sdp ); 510 ## (13/04/16) comment this out for the moment and replace with identity 511 ## siso := SmallerDegreePermutationRepresentation( sdp ); 512 siso := IdentityMapping( sdp ); 513 ssdp := Image( siso ); 514 esymm := Embedding( sdp, 1 ) * siso; 515 egensymm := List( gensymm, g -> ImageElm( esymm, g ) ); 516 emag2 := Embedding( sdp, 2 ) * siso; 517 egenmag2 := List( genmag2{[1..nag]}, g -> ImageElm( emag2, g ) ); 518 eno := ListWithIdenticalEntries( m+1, 0 ); 519 eno[1] := esymm; 520 for i in [1..m] do 521 im1 := List( genag1, g -> ImageElm( iso1, g ) ); 522 im2 := List( im1, g -> ImageElm( memb[i], g ) ); 523 im3 := List( im2, g -> ImageElm( emag2, g ) ); 524 eno[i+1] := GroupHomomorphismByImages( ag1, ssdp, genag1, im3 ); 525 od; 526 agens := Concatenation( egensymm, egenmag2 ); 527 return [ ssdp, agens, eno ]; 528end ); 529 530############################################################################# 531## 532#M AutomorphismGroupOfGroupoid( <gpd> ) 533## 534InstallMethod( AutomorphismGroupOfGroupoid, "for one-object groupoid", true, 535 [ IsGroupoid and IsSinglePieceDomain and IsDiscreteDomainWithObjects ], 0, 536function( gpd ) 537 538 local autgen, rgp, agp, genagp, a, a0, ok, id, aut; 539 540 Info( InfoGroupoids, 2, 541 "AutomorphismGroupOfGroupoid for one-object groupoids" ); 542 autgen := [ ]; 543 rgp := gpd!.magma; 544 agp := AutomorphismGroup( rgp ); 545 genagp := SmallGeneratingSet( agp ); 546 for a in genagp do 547 a0 := GroupoidAutomorphismByGroupAutoNC( gpd, a ); 548 ok := IsAutomorphismWithObjects( a0 ); 549 Add( autgen, a0 ); 550 od; 551 id := IdentityMapping( gpd ); 552 aut := GroupWithGenerators( autgen, id ); 553 SetIsAutomorphismGroup( aut, true ); 554 SetIsFinite( aut, true ); 555 SetIsAutomorphismGroupOfGroupoid( aut, true ); 556 SetAutomorphismGroup( gpd, aut ); 557 SetAutomorphismDomain( aut, gpd ); 558 Info( InfoGroupoids, 2, "nice object not yet coded in this case" ); 559 return aut; 560end ); 561 562InstallMethod( AutomorphismGroupOfGroupoid, "for a single piece groupoid", 563 true, [ IsGroupoid and IsSinglePieceDomain ], 0, 564function( gpd ) 565 566 local autgen, nautgen, rgp, genrgp, agp, genagp, a, obs, n, imobs, 567 L, ok, id, ids, cids, i, c, aut, niceob, nicemap, rgh, ioo, ior; 568 569 Info( InfoGroupoids, 2, 570 "AutomorphismGroupOfGroupoid for single piece groupoids" ); 571 ## first: automorphisms of the root group 572 autgen := [ ]; 573 rgp := gpd!.magma; 574 genrgp := GeneratorsOfGroup( rgp ); 575 agp := AutomorphismGroup( rgp ); 576 genagp := SmallGeneratingSet( agp ); 577 for a in genagp do 578 Add( autgen, GroupoidAutomorphismByGroupAutoNC( gpd, a ) ); 579 od; 580 ## second: permutations of the objects 581 obs := gpd!.objects; 582 n := Length( obs ); 583 if ( n = 2 ) then 584 imobs := [ obs[2], obs[1] ]; 585 Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) ); 586 else 587 L := [2..n]; 588 Append( L, [1] ); 589 imobs := List( L, i -> obs[i] ); 590 Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) ); 591 imobs := ShallowCopy( obs ); 592 imobs[1] := obs[2]; 593 imobs[2] := obs[1]; 594 Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) ); 595 fi; 596 ## third: add in the ray prods 597 ids := List( obs, o -> One( rgp ) ); 598 for i in [2..n] do 599 for c in genrgp do 600 cids := ShallowCopy( ids ); 601 cids[i] := c; 602 Add( autgen, GroupoidAutomorphismByRayShifts( gpd, cids ) ); 603 od; 604 od; 605 nautgen := Length( autgen ); 606 ## generating set for the automorphism group now complete 607 for a in autgen do 608 ok := IsAutomorphismWithObjects( a ); 609 od; 610 id := IdentityMapping( gpd ); 611 ## imobs := L[0]; 612 aut := GroupWithGenerators( autgen, id ); 613 SetIsAutomorphismGroup( aut, true ); 614 SetIsFinite( aut, true ); 615 SetIsAutomorphismGroupOfGroupoid( aut, true ); 616 niceob := NiceObjectAutoGroupGroupoid( gpd, aut ); 617 SetNiceObject( aut, niceob[1] ); 618 SetEmbeddingsInNiceObject( aut, niceob[2] ); 619 #? SetInnerAutomorphismsAutomorphismGroup( aut, ?? ); 620 SetAutomorphismGroup( gpd, aut ); 621 SetAutomorphismDomain( aut, gpd ); 622 623 ## now construct nicemap using GroupHomomorphismByFunction 624 nicemap := GroupHomomorphismByFunction( aut, niceob[1], 625 function( alpha ) 626 local G, autG, q, eno, obG, nobG, oha, j, ioa, Lpos, Lmap; 627 G := Source( alpha ); 628 autG := AutomorphismGroup( G ); 629 q := One( NiceObject( autG ) ); 630 eno := EmbeddingsInNiceObject( autG ); 631 obG := ObjectList( G ); 632 nobG := Length( obG ); 633 rgh := RootGroupHomomorphism( alpha ); 634 q := ImageElm( eno[1], rgh ); 635 ior := ImageElementsOfRays( alpha ); 636 for j in [1..nobG] do 637 q := q * ImageElm( eno[j+2], ior[j] ); 638 od; 639 ioo := ImagesOfObjects( alpha ); 640 Lpos := List( ioo, j -> Position( obG, j ) ); 641 Lmap := MappingPermListList( [1..nobG], Lpos ); 642 q := q * ImageElm( eno[2], Lmap ); 643 return q; 644 end); 645 646 SetNiceMonomorphism( aut, nicemap ); 647 ## SetIsHandledByNiceMonomorphism( aut, true ); 648 SetIsCommutative( aut, IsCommutative( niceob[1] ) ); 649 if HasName( gpd ) then 650 SetName( aut, Concatenation( "Aut(", Name( gpd ), ")" ) ); 651 fi; 652 return aut; 653end ); 654 655InstallMethod( AutomorphismGroupOfGroupoid, "for a hom. discrete groupoid", 656 true, [ IsHomogeneousDiscreteGroupoid ], 0, 657function( gpd ) 658 659 local pieces, autgen, nautgen, p1, g1, ag1, id1, genag1, a, b, auts, 660 obs, n, imobs, L, ok, id, ids, aut, niceob, nicemap; 661 662 Info( InfoGroupoids, 2, 663 "AutomorphismGroupOfGroupoid for homogeneous discrete groupoids" ); 664 pieces := Pieces( gpd ); 665 obs := ObjectList( gpd ); 666 n := Length( obs ); 667 ## first: automorphisms of the first object group 668 autgen := [ ]; 669 p1 := pieces[1]; 670 g1 := p1!.magma; 671 ag1 := AutomorphismGroup( g1 ); 672 id1 := IdentityMapping( g1 ); 673 auts := ListWithIdenticalEntries( n, id1 ); 674 genag1 := SmallGeneratingSet( ag1 ); 675 for a in genag1 do 676 auts[1] := a; 677 b := GroupoidAutomorphismByGroupAutos( gpd, auts ); 678 SetIsGroupWithObjectsHomomorphism( b, true ); 679 Add( autgen, b ); 680 od; 681 ## second: permutations of the objects 682 if ( n = 2 ) then 683 imobs := [ obs[2], obs[1] ]; 684 Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) ); 685 else 686 L := [2..n]; 687 Append( L, [1] ); 688 imobs := List( L, i -> obs[i] ); 689 Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) ); 690 imobs := ShallowCopy( obs ); 691 imobs[1] := obs[2]; 692 imobs[2] := obs[1]; 693 Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) ); 694 fi; 695 ## generating set for the automorphism group now complete 696 nautgen := Length( autgen ); 697 for a in autgen do 698 ok := IsAutomorphismWithObjects( a ); 699 od; 700 id := IdentityMapping( gpd ); 701 ## imobs := L[0]; 702 aut := GroupWithGenerators( autgen, id ); 703 SetIsAutomorphismGroup( aut, true ); 704 SetIsFinite( aut, true ); 705 SetIsAutomorphismGroupOfGroupoid( aut, true ); 706 niceob := NiceObjectAutoGroupGroupoid( gpd, aut ); 707 SetNiceObject( aut, niceob[1] ); 708 SetEmbeddingsInNiceObject( aut, niceob[3] ); 709 SetAutomorphismGroup( gpd, aut ); 710 SetAutomorphismDomain( aut, gpd ); 711 712 ## now construct nicemap using GroupHomomorphismByFunction 713 nicemap := GroupHomomorphismByFunction( aut, niceob[1], 714 function( alpha ) 715 local G, autG, q, eno, obG, nobG, oha, j, ioa, Lpos, Lmap; 716 G := Source( alpha ); 717 autG := AutomorphismGroup( G ); 718 q := One( NiceObject( autG ) ); 719 eno := EmbeddingsInNiceObject( autG ); 720 obG := ObjectList( G ); 721 nobG := Length( obG ); 722 oha := ObjectHomomorphisms( alpha ); 723 for j in [1..nobG] do 724 q := q * ImageElm( eno[j+1], oha[j] ); 725 od; 726 ioa := ImagesOfObjects( alpha ); 727 Lpos := List( ioa, j -> Position( obG, j ) ); 728 Lmap := MappingPermListList( Lpos, [1..nobG] ); 729 q := q * ImageElm( eno[1], Lmap ); 730 return q; 731 end); 732 733 SetNiceMonomorphism( aut, nicemap ); 734 ## SetIsHandledByNiceMonomorphism( aut, true ); 735 #? SetInnerAutomorphismsAutomorphismGroup( aut, ?? ); 736 SetIsCommutative( aut, IsCommutative( niceob[1] ) ); 737 if HasName( gpd ) then 738 SetName( aut, Concatenation( "Aut(", Name( gpd ), ")" ) ); 739 fi; 740 return aut; 741end ); 742 743InstallMethod( AutomorphismGroupOfGroupoid, "for an arbitrary groupoid", 744 true, [ IsGroupoid ], 0, 745function( gpd ) 746 Info( InfoGroupoids, 1, 747 "use AutomorphismGroupoidOfGroupoid for a union of pieces" ); 748 return fail; 749end ); 750 751## ======================================================================== 752## Homogeneous groupoid automorphisms 753## ======================================================================== ## 754 755InstallMethod( \in, 756 "method for an automorphism of a single object groupoid", true, 757 [ IsGroupWithObjectsHomomorphism, IsGroupoidHomomorphismCollection ], 758 0, 759function( arr, aut0 ) 760 761 local o; 762 763 o := ObjectList( aut0 )[1]; 764 if not ( ( o = arr![2] ) and ( o = arr![3] ) ) then 765 return false; 766 fi; 767 return ( arr![1] in aut0!.magma ); 768end ); 769 770InstallMethod( \in, 771 "method for an automorphism of a single piece groupoid", true, 772 [ IsGroupWithObjectsHomomorphism, IsAutomorphismGroupOfGroupoid ], 773 0, 774function( a, aut ) 775 776 local gpd, gp, data; 777 778 gpd := AutomorphismDomain( aut ); 779 gp := gpd!.magma; 780 data := MappingToSinglePieceData( a )[1]; 781 if not ( data[1] in AutomorphismGroup( gp ) ) then 782 return false; 783 fi; 784 if not ForAll( data[2], o -> o in ObjectList( gpd ) ) then 785 return false; 786 fi; 787 if not ForAll( data[3], e -> e in gp ) then 788 return false; 789 fi; 790 return true; 791end ); 792 793InstallMethod( \in, 794 "for groupoid hom and automorphism group : discrete", true, 795 [ IsGroupoidHomomorphismFromHomogeneousDiscrete and IsGroupoidHomomorphism, 796 IsAutomorphismGroupOfGroupoid ], 0, 797function( a, aut ) 798 799 local gens, g1, gpd, obs, imobs, G, AG; 800 801 gens := GeneratorsOfGroup( aut ); 802 gpd := AutomorphismDomain( aut ); 803 if not ( ( Source(a) = gpd ) and ( Range(a) = gpd ) ) then 804 Info( InfoGroupoids, 2, "require Source(a) = Range(a) = gpd" ); 805 return false; 806 fi; 807 obs := ObjectList( gpd ); 808 imobs := ShallowCopy( ImagesOfObjects( a ) ); 809 Sort( imobs ); 810 if not ( obs = imobs ) then 811 Info( InfoGroupoids, 2, "incorrect images of objects" ); 812 return false; 813 fi; 814 G := Source(a)!.magma; 815 AG := AutomorphismGroup( G ); 816 if not ForAll( ObjectHomomorphisms(a), h -> h in AG ) then 817 Info( InfoGroupoids, 2, "object homomorphisms incorrect" ); 818 return false; 819 fi; 820 #? is there anything else to test? 821 return true; 822end ); 823 824############################################################################## 825## methods added 11/09/18 for automorphisms of homogeneous groupoids 826 827InstallMethod( GroupoidAutomorphismByPiecesPermNC, 828 "for a homogeneous groupoid and a permutation of the pieces", true, 829 [ IsGroupoid and IsHomogeneousDomainWithObjects, IsPerm ], 0, 830function( gpd, p ) 831 832 local pieces, n, isos, mor; 833 834 pieces := Pieces( gpd ); 835 n := Length( pieces ); 836 isos := List( [1..n], 837 i -> IsomorphismNewObjects( pieces[i], pieces[i^p]!.objects ) ); 838 mor := HomomorphismByUnion( gpd, gpd, isos ); 839 SetOrder( mor, Order( p ) ); 840 SetIsGroupoidAutomorphismByPiecesPerm( mor, true ); 841 return mor; 842end ); 843 844InstallMethod( GroupoidAutomorphismByPiecesPerm, 845 "for a homogeneous groupoid and a permutation of pieces", true, 846 [ IsGroupoid and IsHomogeneousDomainWithObjects, IsPerm ], 0, 847function( gpd, p ) 848 849 local pieces, n, obs, pos; 850 851 pieces := Pieces( gpd ); 852 n := Length( pieces ); 853 if ( LargestMovedPoint( p ) > n ) then 854 Error( "degree of permutation too large" ); 855 fi; 856 return GroupoidAutomorphismByPiecesPermNC( gpd, p ); 857end ); 858 859############################################################################# 860## 861#M IsomorphismClassPositionsOfGroupoid 862## 863InstallMethod( IsomorphismClassPositionsOfGroupoid, "for a gpd with pieces", 864 true, [ IsGroupoid ], 0, 865function( gpd ) 866 867 local P, lenP, found, i, classes, L, j, iso; 868 869 P := Pieces( gpd ); 870 lenP := Length( P ); 871 found := ListWithIdenticalEntries( lenP, false ); 872 i := 0; 873 classes := [ ]; 874 while ( i < lenP ) do 875 i := i+1; 876 while ( ( i <= lenP ) and found[i] ) do 877 i := i + 1; 878 od; 879 if ( i <= lenP ) then 880 L := [ i ]; 881 found[i] := true; 882 for j in [i+1..lenP] do 883 if not found[j] then 884 iso := IsomorphismGroupoids( P[i], P[j] ); 885 if not ( iso = fail ) then 886 Add( L, j ); 887 found[j] := true; 888 fi; 889 fi; 890 od; 891 Add( classes, L ); 892 fi; 893 od; 894 return classes; 895end ); 896 897############################################################################# 898## 899#M AutomorphismGroupoidOfGroupoid 900## 901InstallMethod( AutomorphismGroupoidOfGroupoid, "for a single piece groupoid", 902 true, [ IsGroupoid and IsSinglePieceDomain ], 0, 903function( gpd ) 904 905 local obs, A; 906 907 A := AutomorphismGroupOfGroupoid( gpd ); 908 obs := ObjectList( gpd ); 909 return DomainWithSingleObject( A, obs ); 910end ); 911 912InstallMethod( AutomorphismGroupoidOfGroupoid, "for a homogeneous groupoid", 913 true, [ IsGroupoid and IsHomogeneousDomainWithObjects ], 0, 914function( gpd ) 915 916 local pieces, obs, n, p1, ap1, rays, aut, niceob, nicemap; 917 918 Info( InfoGroupoids, 2, 919 "AutomorphismGroupoidOfGroupoid for homogeneous groupoids" ); 920 pieces := Pieces( gpd ); 921 obs := List( pieces, p -> p!.objects ); 922 n := Length( pieces ); 923 p1 := pieces[1]; 924 ap1 := AutomorphismGroupOfGroupoid( p1 ); 925 rays := Concatenation( [ One( ap1 ) ], 926 List( [1..n-1], i -> IsomorphismNewObjects( p1, obs[i+1] ) ) ); 927 aut := SinglePieceGroupoidWithRays( ap1, obs, rays ); 928 if HasName( gpd ) then 929 SetName( aut, Concatenation( "Aut(", Name( gpd ), ")" ) ); 930 fi; 931 SetAutomorphismDomain( aut, gpd ); 932 return aut; 933end ); 934 935InstallMethod( AutomorphismGroupoidOfGroupoid, "for a groupoid", true, 936 [ IsGroupoid ], 0, 937function( gpd ) 938 939 local pieces, cpos, numc, obs, comp, i, lenc, pos, pi, auti, geni, 940 lenpi, idp, isos, obsi, j, pj, isoj, invj, genj, autj, isosj; 941 942 pieces := Pieces( gpd ); 943 cpos := IsomorphismClassPositionsOfGroupoid( gpd ); 944 numc := Length( cpos ); 945 obs := List( pieces, p -> p!.objects ); 946 obs := List( cpos, K -> obs{K} ); 947 obs := List( obs, K -> Set( Flat( K ) ) ); 948 comp := ListWithIdenticalEntries( numc, 0 ); 949 for i in [1..numc] do 950 pos := cpos[i]; 951 lenc := Length( pos ); 952 pi := pieces[ pos[1] ]; 953 auti := AutomorphismGroupOfGroupoid( pi ); 954 if HasName( pi ) then 955 SetName( auti, Concatenation( "Aut(", Name(pi), ")" ) ); 956 fi; 957 geni := GeneratorsOfGroup( auti ); 958 lenpi := Length( pi!.objects ); 959 if ( lenc = 1 ) then 960 comp[i] := DomainWithSingleObject( auti, pi!.objects ); 961 else 962 obsi := List( pos, k -> pieces[k]!.objects ); 963 isos := ListWithIdenticalEntries( lenpi, 0 ); 964 isos[1] := IdentityMapping( auti ); 965 for j in [2..lenc] do 966 pj := pieces[ pos[j] ]; 967 isoj := IsomorphismGroupoids( pi, pj ); 968 invj := InverseGeneralMapping( isoj ); 969 genj := List( geni, g -> invj * g * isoj ); 970 autj := Group( genj ); 971 SetAutomorphismGroupOfGroupoid( pj, autj ); 972 if HasName( pj ) then 973 SetName( autj, Concatenation( "Aut(", Name(pj), ")" ) ); 974 fi; 975 isosj := GroupHomomorphismByImagesNC(auti,autj,geni,genj); 976 SetIsInjective( isosj, true ); 977 SetIsSurjective( isosj, true ); 978 isos[j] := isosj; 979 od; 980 comp[i] := GroupoidByIsomorphisms( auti, obsi, isos ); 981 fi; 982 od; 983 return UnionOfPieces( comp ); 984end ); 985 986