1############################################################################# 2## 3## This file is part of GAP, a system for computational discrete algebra. 4## This file's authors include Lukas Maas, Jack Schmidt. 5## 6## Copyright of GAP belongs to its developers, whose names are too numerous 7## to list here. Please refer to the COPYRIGHT file for details. 8## 9## SPDX-License-Identifier: GPL-2.0-or-later 10## 11## This file contains the implementation for Schur covers of symmetric and 12## alternating groups on Coxeter or standard generators. 13## 14 15############################################################################# 16## 17## Faithful, irreducible representations of minimal degree of the double 18## covers of symmetric groups can be constructed inductively using the 19## methods of https://arxiv.org/abs/0911.3794 20## 21## The inductive formulation uses a number of helper routines which are 22## wrapped inside a function call to keep from declaring a large number 23## of (private) global variables. 24## 25 26Perform( [1], function(x) 27 local S, S1, coeffS2, S2, coeffS3, S3, bmat, spinsteps, SpinDimSym, 28 BasicSpinRepSymPos, BasicSpinRepSymNeg, BasicSpinRepSym, 29 SanityCheckPos, SanityCheckNeg, BasicSpinRepSymTest; 30 31 32## let 2S+(n) = < t_1, ..., t_(n-1) > subject to the relations 33## (t_i)^2 = z for 1 <= i <= n-1, 34## z^2 = 1, 35## ( t_i*t_(i+1) )^3 = z for 1 <= i <= n-2, 36## t_i*t_j = z*t_j*t_i for 1 <= i, j <= n-1 with | i - j | > 1. 37## 38## The following functions allow the construction of basic spin 39## representations of 2S+(n) over fields of any characteristic. 40 41## SpinDimSym 42## IN integers n >= 4, p >= 0 43## OUT the degree of a basic spin repr. of 2S(n) over a field of 44## characteristic p 45SpinDimSym:= function( n, p ) 46 local r; 47 r:= n mod 2; 48 if r = 0 then 49 return 2^((n-2)/2); 50 elif p = 0 then 51 return 2^((n-1)/2); 52 elif r = 1 and n mod p = 0 then 53 return 2^((n-3)/2); 54 else 55 return 2^((n-1)/2); 56 fi; 57end; 58 59## SanityCheckPos 60## IN A record containing the matrices in T, the degree of the symmetric 61## group n, and the characteristic f the field p 62## OUT true if the matrices in T are the right size, over the right field, and 63## satisfy the presentation for 2S(n) given above. Also checks the 64## components Sym and Alt if present. 65SanityCheckPos := function( input ) 66 local i, j; 67 68 if input.n <> Length( input.T ) + 1 then 69 Print("#I SanityCheckPos: Wrong degree: ",input.n," vs. ",Length(input.T)+1,"\n"); 70 return false; 71 fi; 72 73 if input.p <> Characteristic( input.T[1] ) then 74 Print("#I SanityCheckPos: Wrong characteristic: ",input.p," vs. ",Characteristic(input.T[1]),"\n"); 75 return false; 76 fi; 77 78 if SpinDimSym( input.n, input.p ) <> Length( input.T[1] ) then 79 Print( "#I SanityCheckPos: Wrong degree: ",SpinDimSym( input.n, input.p )," vs. ",Length( input.T[1] ),"\n" ); 80 return false; 81 fi; 82 83 if not ForAll( input.T, mat -> Size(mat) = Size(mat[1]) and Size(mat)=Size(input.T[1])) then 84 Print("#I SanityCheckPos: Matrices not all same size\n"); 85 return false; 86 fi; 87 88 for i in [ 1 .. input.n-1 ] do 89 if not IsOne(-input.T[i]^2) then 90 Print( "#I SanityCheckPos: Wrong order for T[",i,"]\n"); 91 return false; 92 fi; 93 od; 94 for i in [ 1 .. input.n-2 ] do 95 if not IsOne( -( input.T[i]*input.T[i+1] )^3 ) then 96 Print( "#I SanityCheckPos: Braid relation failed at position ", i, "\n" ); 97 return false; 98 fi; 99 for j in [ i+2 .. input.n-1 ] do 100 if not IsOne( - ( input.T[i]*input.T[j] )^2 ) then 101 Print( "#I SanityCheckPos: Commutator relation failed for ( ", i, ", ", j ," )\n" ); 102 return false; 103 fi; 104 od; 105 od; 106 107 if IsBound( input.Sym ) then 108 if not input.Sym[1] = Product( Reversed( input.T ) ) then 109 Print( "SanityCheckPos: Wrong Sym[1]\n" ); 110 return false; 111 fi; 112 113 if not input.Sym[2] = input.T[1] then 114 Print( "SanityCheckPos: Wrong Sym[2]\n" ); 115 return false; 116 fi; 117 fi; 118 119 if IsBound( input.Alt ) then 120 if not input.Alt[1] = Product( Reversed( input.T{[1..2*Int((input.n-1)/2)]} ) ) then 121 Print( "SanityCheckPos: Wrong Alt[1]\n" ); 122 return false; 123 fi; 124 125 if not input.Alt[2] = input.T[input.n-1]*input.T[input.n-2] then 126 Print( "SanityCheckPos: Wrong Alt[2]\n" ); 127 return false; 128 fi; 129 fi; 130 131 return true; 132end; 133 134## SanityCheckNeg 135## IN A record containing the matrices in T, the degree of the symmetric 136## group n, and the characteristic f the field p 137## OUT true if the matrices in T are the right size, over the right field, and 138## satisfy the presentation for 2S-(n) given above. Also checks the 139## components Sym and Alt if present. 140SanityCheckNeg := function( S, p ) 141 local d, deg, z, t, i, j; 142 143 d:= Length( S ); 144 deg:= Length( S[1] ); 145 if SpinDimSym( d+1, p ) <> deg then 146 Print( "#I SanityCheckNeg: wrong degree!\n" ); 147 return false; 148 fi; 149 #Print( "#I SanityCheckNeg: degree: ", deg , "\n" ); 150 for i in [ 1 .. d ] do 151 if not IsOne( S[i]^2 ) then 152 Print( "#I SanityCheckNeg: order failed at position ", i, "\n" ); 153 return false; 154 fi; 155 od; 156 for i in [ 1 .. d-1 ] do 157 if not IsOne( ( S[i]*S[i+1] )^3 ) then 158 Print( "#I SanityCheckNeg: braid relation failed at position ", i, "\n" ); 159 return false; 160 fi; 161 for j in [ i+2 .. d ] do 162 if S[i]*S[j] <> -S[j]*S[i] then 163 Print( "#I SanityCheckNeg: commuting relation failed for ( ", i, ", ", j ," )\n" ); 164 return false; 165 fi; 166 od; 167 od; 168 #Print( "#I SanityCheckNeg: all relations satisfied\n" ); 169 return true; 170end; 171 172## bmat -- blck matrix maker 173## IN the blocks a,b,c,d of the matrix [[a,b],[c,d]] 174## OUT a normal matrix with the same entries as the corresponding block 175## matrix. 176bmat := function(a,b,c,d) 177 local mat; 178 mat := DirectSumMat( a, d ); 179 if b <> 0 then mat{[1..Length(a)]}{[1+Length(a[1])..Length(mat[1])]} := b; fi; 180 if c <> 0 then mat{[1+Length(a)..Length(mat)]}{[1..Length(a[1])]} := c; fi; 181 return mat; 182end; 183 184## construction S of Definition 4 / Lemma 5 185## IN an input record with n,p,T and optionally Sym and/or Alt, 186## where n,p satisfy the hypothesis of Def 4 / Lemma 5 187## OUT the same, but for 2S(n+1) 188S:= function( old ) 189 local new, I, z, i; 190 191 #Print("S from ",old.n," to ",new.n,"\n"); 192 new := rec( n := old.n+1, p:=old.p, T:=[] ); 193 194 for i in [ 1 .. new.n-3 ] do 195 new.T[i] := DirectSumMat( old.T[i], -old.T[i] ); 196 od; 197 I := old.T[1]^0; 198 z := 0*old.T[1]; 199 new.T[new.n-2] := bmat( old.T[new.n-2], -I, 0, -old.T[new.n-2] ); 200 new.T[new.n-1] := bmat( z, I, -I, z ); 201 202 if IsBound( old.Sym ) then 203 new.Sym := []; 204 if new.n < 5 205 then new.Sym[1] := Product(Reversed(new.T)); 206 else new.Sym[1] := bmat( 0*old.Sym[1], (-1)^new.n*old.Sym[1], -old.Sym[1], (-1)^new.n*old.T[new.n-2]*old.Sym[1] ); 207 fi; 208 new.Sym[2] := new.T[1]; 209 fi; 210 211 if IsBound( old.Alt ) then 212 new.Alt := []; 213 if IsOddInt(new.n) 214 then new.Alt[1] := new.Sym[1]; 215 else new.Alt[1] := -new.T[new.n-1]*new.Sym[1]; 216 fi; 217 new.Alt[2] := new.T[new.n-1]*new.T[new.n-2]; 218 fi; 219 220 Assert( 1, SanityCheckPos( new ) ); 221 return new; 222end; 223 224## construction S1 of Lemma 7 225## IN an input record with n,p,T and optionally Sym and/or Alt, 226## where n,p satisfy the hypothesis of Lemma 7 227## OUT the same, but for 2S(n+1) 228S1:= function( old ) 229 local new, J; 230 231 #Print("S1 from ",old.n," to ",new.n,"\n"); 232 new := rec( n := old.n + 1, p := old.p, T := ShallowCopy( old.T ) ); 233 234 J := Sum( [1..new.n-2], k -> k*old.T[k] ); 235 if new.p = 2 and 2 = new.n mod 4 then 236 new.T[new.n-1] := J + J^0; 237 else 238 new.T[new.n-1] := J; 239 fi; 240 241 if IsBound( old.Sym ) then 242 new.Sym := []; 243 new.Sym[1] := new.T[new.n-1]*old.Sym[1]; 244 new.Sym[2] := old.Sym[2]; 245 fi; 246 247 if IsBound( old.Alt ) then 248 new.Alt := []; 249 if IsOddInt(new.n) 250 then new.Alt[1] := new.Sym[1]; 251 else new.Alt[1] := old.Alt[1]; 252 fi; 253 new.Alt[2] := new.T[new.n-1]*new.T[new.n-2]; 254 fi; 255 256 Assert( 1, SanityCheckPos( new ) ); 257 return new; 258end; 259 260## return alpha ( = alpha^+ ) and beta as in Lemma 10 261## here n(n-1)(n-2) must not be divisible by p 262coeffS2:= function( n, p ) 263 local one, a, b, c, alpha; 264 if p = 0 then 265 c:= n-2; 266 alpha:= (n-1)^-1*( 1 + Sqrt( -n*c^-1 ) ); 267 else 268 one:= Z( p )^0; 269 c:= (n-2) mod p; 270 a:= -n*c^-1 mod p; 271 a:= LogFFE( a*one, Z(p^2) ) / 2; 272 b:= (n-1)^-1 mod p; 273 alpha:= b*(one+Z(p^2)^a); 274 fi; 275 return rec( alpha:= alpha, beta:= alpha*c ); 276end; 277 278## construction S2 of Lemma 10 279## IN an input record with n,p,T and optionally Sym and/or Alt, 280## where n,p satisfy the hypothesis of Lemma 10 281## OUT the same, but for 2S(n+2) 282S2:= function( old ) 283 local mid, new, coeffs, a, b, J, I; 284 285 #Print("S2 from ",old.n," to ",old.n+2," via S\n"); 286 287 mid := S( old ); 288 289 new := rec( n := mid.n + 1, p := mid.p, T := ShallowCopy( mid.T ) ); 290 291 coeffs:= coeffS2( new.n, new.p ); 292 a := coeffs.alpha; 293 b := coeffs.beta; 294 J := Sum( [ 1 .. new.n-3 ], k-> k*old.T[k] ); 295 I := old.T[1]^0; 296 new.T[new.n-1] := bmat( -a*J, (b-1)*I, b*I, a*J ); 297 298 if IsBound( old.Sym ) then 299 new.Sym := []; 300 new.Sym[1] := new.T[new.n-1]*mid.Sym[1]; 301 new.Sym[2] := mid.Sym[2]; 302 fi; 303 304 if IsBound( old.Alt ) then 305 new.Alt := []; 306 if IsOddInt( new.n ) 307 then new.Alt[1] := new.Sym[1]; 308 else new.Alt[1] := mid.Sym[1]; 309 fi; 310 new.Alt[2] := new.T[new.n-1]*new.T[new.n-2]; 311 fi; 312 313 Assert( 1, SanityCheckPos( new ) ); 314 return new; 315end; 316 317## coeffS3 - a needed coefficient 318## IN A prime p, or p = 0 319## OUT Sqrt(-1) in GF(p^2) or CF(4) 320coeffS3:= function( p ) 321 if 0 = p then return E(4); 322 elif 2 = p then return Z(2); 323 elif 1 = p mod 4 then return Z(p)^((p-1)/4); 324 else return Z(p^2)^((p^2-1)/4); 325 fi; 326end; 327 328## construction S3 of Lemma 11 329## IN an input record with n,p,T and optionally Sym and/or Alt, 330## where n,p satisfy the hypothesis of Lemma 11 331## OUT the same, but for 2S(n+4) 332S3:= function( old ) 333 local mid, new, a, J0, I, J; 334 #Print("S3 from ",old.n," to ",old.n+4," via S,S1,S\n"); 335 336 mid := S( S1( S( old ) ) ); # now at n-1 337 338 new := rec( n := mid.n + 1, p := mid.p, T := ShallowCopy( mid.T ) ); 339 340 a := coeffS3( old.p ); 341 J0:= Sum( [1..new.n-5], k-> k*old.T[k] ); 342 I := old.T[1]^0; 343 J := a*bmat(J0, 2*I, 2*I, -J0); 344 new.T[new.n-1] := bmat( J, -J^0, 0, -J ); 345 346 if IsBound( old.Sym ) then 347 new.Sym := []; 348 new.Sym[1] := new.T[new.n-1]*mid.Sym[1]; 349 new.Sym[2] := mid.Sym[2]; 350 fi; 351 352 if IsBound( old.Alt ) then 353 new.Alt := []; 354 if IsOddInt( new.n ) 355 then new.Alt[1] := new.Sym[1]; 356 else new.Alt[1] := mid.Alt[1]; 357 fi; 358 new.Alt[2] := new.T[new.n-1]*new.T[new.n-2]; 359 fi; 360 361 Assert( 1, SanityCheckPos( new ) ); 362 return new; 363end; 364 365## spinsteps 366## IN the degree n and characteristic p > 2 367## OUT a list which describes the steps of construction 368spinsteps:= function( n, p ) 369 local d, k, kmodp, parity; 370 d:= []; 371 k:= n; 372 while k > 4 do 373 kmodp:= k mod p; 374 parity:= k mod 2; 375 if kmodp > 2 then 376 if parity = 1 then 377 Add( d, 0 ); 378 k:= k-1; 379 else 380 Add( d, 2 ); 381 k:= k-2; 382 fi; 383 elif kmodp = 0 then 384 Add( d, 1 ); 385 k:= k-1; 386 elif kmodp = 1 then 387 Add( d, 0 ); 388 k:= k-1; 389 else 390 if parity = 1 then 391 Add( d, 0 ); 392 k:= k-1; 393 else 394 Add( d, 3 ); 395 k:= k-4; 396 fi; 397 fi; 398 od; 399 return Reversed( d ); 400end; 401 402## construction of a basic spin rep. of 2S+(n) in characteristic p 403BasicSpinRepSymPos := function( n, p ) 404 local z, M, k, i, kmodp, steps; 405 if not IsPosInt(n) or not IsInt(p) or n < 4 or not ( p = 0 or IsPrime( p ) ) then 406 return fail; 407 fi; 408 ## get the spin reps for 2S(4) 409 z := coeffS3(p); 410 if p = 0 then 411 M:= rec( 412 n := 2, 413 p := 0, 414 T := [ [ [ z ] ] ], 415 Sym := [~.T[1]], 416 Alt :=[] 417 ); 418 M:= S2( M ); 419 elif p = 2 then 420 M:= rec( 421 n := 2, 422 p := 2, 423 T := [ [ [ z ] ] ], 424 Sym := [~.T[1]], 425 Alt :=[] 426 ); 427 M:= S1( S( M ) ); 428 elif p = 3 then 429 M:= rec( 430 n := 3, 431 p := 3, 432 T := [ [ [ z ] ], [ [ z ] ] ], 433 Sym := [ [ [ z^2 ] ], ~.T[1] ], 434 Alt:=[ ~.Sym[1] ] 435 ); 436 M:= S( M ); 437 else # p>3 438 M:= rec( 439 n := 2, 440 p := p, 441 T := [ [ [ z ] ] ], 442 Sym := [ ~.T[1]], 443 Alt:=[] 444 ); 445 M:= S2( M ); 446 fi; 447 if n = 4 then return M; fi; 448 if ValueOption("Sym") <> true and ValueOption("Alt")<>true then Unbind(M.Sym); fi; 449 if ValueOption("Alt") <> true then Unbind(M.Alt); fi; 450 if p = 0 then 451 if n mod 2 = 0 then 452 k:= (n-4)/2; 453 for i in [ 1 .. k ] do 454 M:= S2( M ); 455 od; 456 else 457 k:= (n-5)/2; 458 for i in [ 1 .. k ] do 459 M:= S2( M ); 460 od; 461 # now M is a b.s.r. of 2S( n-1 ) 462 M:= S( M ); 463 fi; 464 elif p = 2 then 465 k:= 5; 466 while k <= n do 467 if k mod 2 = 1 then 468 M:= S( M ); 469 else 470 M:= S1( M ); 471 fi; 472 k:= k+1; 473 od; 474 else # p >= 3 475 steps:= spinsteps( n, p ); 476 for k in steps do 477 if k = 0 then 478 M := S( M ); 479 elif k = 1 then 480 M := S1( M ); 481 elif k = 2 then 482 M := S2( M ); 483 else 484 M := S3( M ); 485 fi; 486 od; 487 fi; 488 Assert( 1, SanityCheckPos( M ) ); 489 return M; 490end; 491 492BasicSpinRepSymNeg := function( n, p ) 493 local T, S; 494 T := BasicSpinRepSymPos( n, p ); 495 S := rec( n := T.n, p := T.p, T := coeffS3( p ) * T.T ); 496 if IsBound( T.Sym ) then S.Sym := [ coeffS3( p )^(n-1) * T.Sym[1], S.T[1] ]; fi; 497 if IsBound( T.Alt ) then S.Alt := [ (-1)^Int((n-1)/2)*T.Alt[1], -T.Alt[2] ]; fi; 498 Assert( 1, SanityCheckNeg( S.T, p ) ); 499 return S; 500end; 501 502BasicSpinRepSym := function( n, p, sign ) 503 if sign in [ 1, '+', "+", 4 ] then return BasicSpinRepSymPos(n,p); 504 elif sign in [ -1, '-', "-", 2 ] then return BasicSpinRepSymNeg(n,p); 505 else Error("<sign> should be +1 or -1"); 506 fi; 507end; 508 509########################################################################## 510## 511## Method Installations 512## 513 514InstallGlobalFunction( BasicSpinRepresentationOfSymmetricGroup, 515function(arg) 516 local n, p, s, mats; 517 if Length(arg) < 1 then Error("Usage: BasicSpinRepresentationOfSymmetricGroup( <n>, <p>, <sign> );"); fi; 518 n := arg[1]; 519 if Length(arg) < 2 then p := 3; else p := arg[2]; fi; 520 if Length(arg) < 3 then s := 1; else s := arg[3]; fi; 521 mats := BasicSpinRepSym(n,p,s).T; 522 if p = 2 then return List( mats, mat -> ImmutableMatrix( GF(p), mat ) ); 523 elif p > 0 then return List( mats, mat -> ImmutableMatrix( GF(p^2), mat ) ); fi; 524 return mats; 525end ); 526 527InstallMethod( SchurCoverOfSymmetricGroup, 528 "Use Lukas Maas's inductive construction of a basic spin rep", 529 [ IsPosInt, IsInt, IsInt ], 530function( n, p, s ) 531 local mats, grp; 532 533 if p = 2 then return fail; fi; # need a faithful rep 534 535 if n < 4 then TryNextMethod(); fi; 536 537 mats := BasicSpinRepSym(n,p,s:Sym); 538 539 mats.Z := -mats.T[1]^0; 540 541 grp := Group( mats.Sym ); 542 543 Assert( 3, Size( grp ) = 2*Factorial( n ) ); 544 SetSize( grp, 2*Factorial(n) ); 545 546 Assert( 3, Center( grp ) = Subgroup( grp, [ mats.Z ] ) ); 547 SetCenter( grp, SubgroupNC( grp, [ mats.Z ] ) ); 548 549 Assert( 3, IsAbelian( Center( grp ) ) ); 550 SetIsAbelian( Center( grp ), true ); 551 552 Assert( 3, Size( Center( grp ) ) = 2 ); 553 SetSize( Center( grp ), 2 ); 554 555 Assert( 3, AbelianInvariants( Center( grp ) ) = [ 2 ] ); 556 SetAbelianInvariants( Center( grp ), [ 2 ] ); 557 558 return grp; 559end ); 560 561InstallMethod( DoubleCoverOfAlternatingGroup, 562 "Use Lukas Maas's inductive construction of a basic spin rep", 563 [ IsPosInt, IsInt ], 564function( n, p ) 565 local mats, grp; 566 567 if p = 2 then return fail; fi; # need a faithful rep 568 569 mats := BasicSpinRepSym(n,p,1:Alt); 570 571 mats.Z := -mats.T[1]^0; 572 573 grp := Group( mats.Alt ); 574 575 Assert( 3, Size( grp ) = Factorial( n ) ); 576 SetSize( grp, Factorial(n) ); 577 578 Assert( 3, Center( grp ) = Subgroup( grp, [ mats.Z ] ) ); 579 SetCenter( grp, SubgroupNC( grp, [ mats.Z ] ) ); 580 581 Assert( 3, IsAbelian( Center( grp ) ) ); 582 SetIsAbelian( Center( grp ), true ); 583 584 Assert( 3, Size( Center( grp ) ) = 2 ); 585 SetSize( Center( grp ), 2 ); 586 587 Assert( 3, AbelianInvariants( Center( grp ) ) = [ 2 ] ); 588 SetAbelianInvariants( Center( grp ), [ 2 ] ); 589 590 if n >= 5 then 591 Assert( 3, IsPerfectGroup( grp ) ); 592 SetIsPerfectGroup( grp, true ); 593 fi; 594 595 return grp; 596end ); 597 598BasicSpinRepSymTest := function(n,p) 599 local mats, smtx, grp, sign; 600 for sign in [1,-1] do 601 mats := BasicSpinRepSym(n,p,sign).T; 602 if p > 0 then 603 smtx := GModuleByMats( mats, Field(Flat(mats)) ); 604 Assert( 0, SMTX.IsAbsolutelyIrreducible( smtx ) ); 605 fi; 606 grp := Group( mats.Sym ); 607 if n > 4 or p <> 2 then 608 Assert( 0, Size( grp ) = 2*Factorial(n)/GcdInt(p,2) ); 609 Assert( 0, Size( Center( grp ) ) = 2/GcdInt(p,2) ); 610 Assert( 0, Size( DerivedSubgroup( grp ) ) = Factorial(n)/GcdInt(p,2) ); 611 Assert( 0, IsSubgroup( DerivedSubgroup( grp ), Center( grp ) ) ); 612 Assert( 0, AbelianInvariants( grp ) = [ 2 ] ); 613 if n > 4 then Assert( 0, IsSimpleGroup( DerivedSubgroup( grp ) / Center( grp ) ) ); fi; 614 fi; 615 grp := Group( mats.Alt ); 616 if n > 4 or p <> 2 then 617 Assert( 0, Size( grp ) = Factorial(n)/GcdInt(p,2) ); 618 Assert( 0, Size( Center( grp ) ) = 2/GcdInt(p,2) ); 619 Assert( 0, Size( DerivedSubgroup( grp ) ) = Factorial(n)/GcdInt(p,2) ); 620 if n > 4 then Assert( 0, IsSimpleGroup( DerivedSubgroup( grp ) / Center( grp ) ) ); fi; 621 fi; 622 od; 623 return true; 624end; 625 626end ); 627 628 629############################################################################# 630## 631## Other method installations that do not require direct access to the 632## inductive procedure. 633## 634 635 636############################################################################# 637## 638## Convenience routines that supply default values. 639## 640 641InstallOtherMethod( SchurCoverOfSymmetricGroup, 642 "Sign=+1 by default", 643 [ IsPosInt, IsInt ], 644function( n, p ) 645 return SchurCoverOfSymmetricGroup( n, p, 1 ); 646end ); 647 648InstallOtherMethod( SchurCoverOfSymmetricGroup, 649 "P=3, Sign=+1 by default", 650 [ IsPosInt ], 651function( n ) 652 return SchurCoverOfSymmetricGroup( n, 3, 1 ); 653end ); 654 655InstallOtherMethod( DoubleCoverOfAlternatingGroup, 656 "P=3 by default", 657 [ IsPosInt ], 658function( n ) 659 return DoubleCoverOfAlternatingGroup( n, 3 ); 660end ); 661 662############################################################################# 663## 664## Quickly setup the standard epimorphisms 665## 666 667InstallMethod( EpimorphismSchurCover, 668 "Use library copy of double cover", 669 [ IsNaturalSymmetricGroup ], 670function( sym ) 671 local dom, deg, cox, chr, grp, hom, img; 672 dom := MovedPoints( sym ); 673 deg := Size( dom ); 674 if deg < 4 then return IdentityMapping( sym ); fi; 675 cox := List( [1..deg-1], i -> (dom[i],dom[i+1]) ); 676 Assert( 1, ForAll( cox, gen -> gen in sym ) ); 677 #chr := First( [3,5,7], p -> 0 = deg mod p ); 678 #if chr = fail then chr := 3; fi; 679 chr := 3; # appears to be the best choice regardless of deg 680 grp := SchurCoverOfSymmetricGroup( deg, chr, 1 ); 681 img := [ Product( Reversed( cox ) ), cox[1] ]; 682 if AssertionLevel() > 2 then 683 hom := GroupHomomorphismByImages( grp, sym, GeneratorsOfGroup( grp ), img ); 684 Assert( 3, KernelOfMultiplicativeGeneralMapping( hom ) = Center( grp ) ); 685 else 686 dom := RUN_IN_GGMBI; RUN_IN_GGMBI := true; 687 hom := GroupHomomorphismByImagesNC( grp, sym, GeneratorsOfGroup( grp ), img ); 688 RUN_IN_GGMBI := dom; 689 SetKernelOfMultiplicativeGeneralMapping( hom, Center( grp ) ); 690 fi; 691 return hom; 692end ); 693 694InstallMethod( EpimorphismSchurCover, 695 "Use library copy of double cover", 696 [ IsNaturalAlternatingGroup ], 697function( alt ) 698 local dom, deg, cox, chr, grp, hom, img; 699 dom := MovedPoints( alt ); 700 deg := Size( dom ); 701 if deg < 4 then return IdentityMapping( alt ); fi; 702 if deg in [6,7] then TryNextMethod(); fi; 703 cox := List( [1..deg-1], i -> (dom[i],dom[i+1]) ); 704 Assert( 1, ForAll( [1..deg-2], i -> cox[i]*cox[i+1] in alt ) ); 705 chr := 3; 706 grp := DoubleCoverOfAlternatingGroup( deg, chr ); 707 img := [ Product( Reversed( cox{[1..2*Int((deg-1)/2)]} ) ), cox[deg-1]*cox[deg-2] ]; 708 if AssertionLevel() > 2 then 709 hom := GroupHomomorphismByImages( grp, alt, GeneratorsOfGroup( grp ), img ); 710 Assert( 3, KernelOfMultiplicativeGeneralMapping( hom ) = Center( grp ) ); 711 else 712 dom := RUN_IN_GGMBI; RUN_IN_GGMBI := true; 713 hom := GroupHomomorphismByImagesNC( grp, alt, GeneratorsOfGroup( grp ), img ); 714 RUN_IN_GGMBI := dom; 715 SetKernelOfMultiplicativeGeneralMapping( hom, Center( grp ) ); 716 fi; 717 return hom; 718end ); 719 720########################################################################### 721## 722## Special cases just handled explicitly 723## 724 725InstallMethod( SchurCoverOfSymmetricGroup, 726 "Use explicit matrix reps for degrees 1,2,3", 727 [ IsPosInt, IsInt, IsInt ], 728 1, 729function( n, p, ignored ) 730 local R; 731 if p = 0 then R := Integers; else R:=GF(p); fi; 732 if n = 1 then return TrivialSubgroup( GL(1,R) ); 733 elif n = 2 and p<>2 then return Group( -One(GL(1,R)) ); 734 elif n = 3 and p<>3 then return Group( [ [[0,1],[-1,-1]], [[0,1],[1,0]] ]*One(R) ); 735 elif n = 2 and p = 2 then return Group( [[1,1],[0,1]]*One(R) ); # indecomposable, not irreducible 736 elif n = 3 and p = 3 then return Group( [ [[0,1],[-1,-1]], [[0,1],[1,0]] ]*One(R) ); # indecomposable, not irreducible 737 else TryNextMethod(); 738 fi; 739end ); 740 741InstallMethod( EpimorphismSchurCover, 742 "Use copy of AtlasRep's 6-fold cover", 743 [ IsNaturalAlternatingGroup ], 744 1, 745function( alt ) 746 local dom, deg, cox, img, z, gen, grp, cen, hom; 747 dom := MovedPoints( alt ); 748 deg := Size( dom ); 749 if deg = 6 then 750 z := Z(25); 751 gen := [ 752 [ [ z^ 0, z^16, z^22, z^ 8, z^ 8, z^13 ], 753 [ z^ 0, z^22, z^ 0, z^ 7, z^11, z^16 ], 754 [ z^11, z^ 7, z^ 0, z^ 6, z^10, z^ 7 ], 755 [ z^ 2, z^ 0, z^ 3, z* 0, z^18, z^21 ], 756 [ z^21, z^ 9, z^ 2, z^12, z^ 5, z^20 ], 757 [ z , z^ 5, z^ 2, z^ 4, z^16, z^ 6 ] ], 758 [ [ z^18, z^23, z^ 0, z^ 2, z^23, z^17 ], 759 [ z^ 2, z^10, z^17, z* 0, z^ 0, z^18 ], 760 [ z^17, z^ 4, z^12, z^23, z^22, z^ 4 ], 761 [ z , z^12, z , z^18, z^11, z^ 2 ], 762 [ z^21, z^ 4, z^15, z^ 8, z^19, z* 0 ], 763 [ z^ 8, z^ 6, z^14, z^18, z^18, z^ 9 ] ] ]; 764 grp := Group( gen ); 765 766 Assert( 2, Size( grp ) = 6*5*4*3*2/2 * 6 ); 767 SetSize( grp, 6*5*4*3*2/2 * 6 ); 768 769 cen := SubgroupNC( grp, [ DiagonalMat( [ z^4, z^4, z^4, z^4, z^4, z^4 ] ) ] ); 770 771 Assert( 1, Size( cen ) = 6 ); 772 SetSize( cen, 6 ); 773 774 Assert( 1, IsAbelian( cen ) ); 775 SetIsAbelian( cen, true ); 776 777 Assert( 1, AbelianInvariants( cen ) = [ 2, 3 ] ); 778 SetAbelianInvariants( cen, [ 2, 3 ] ); 779 780 Assert( 2, Center(grp) = cen ); 781 SetCenter( grp, cen ); 782 elif deg = 7 then 783 z := Z(25); 784 gen := [ 785 [ [ z* 0, z^14, z^10, z^19, z^11, z^ 6 ], 786 [ z^19, z^12, z^ 9, z , z^ 0, z ], 787 [ z^ 8, z^18, z^10, z^ 2, z^20, z^15 ], 788 [ z^ 2, z^ 0, z^23, z^ 0, z^12, z^ 5 ], 789 [ z^20, z^ 8, z^20, z^23, z^16, z^ 0 ], 790 [ z^10, z^ 2, z^13, z^ 5, z^20, z^11 ] ], 791 [ [ z^ 7, z^ 6, z^10, z^23, z^ 6, z^ 0 ], 792 [ z^14, z^19, z^ 9, z^22, z^ 2, z^ 0 ], 793 [ z^10, z^16, z^17, z^15, z^17, z^14 ], 794 [ z^ 0, z^17, z^10, z^13, z , z^ 6 ], 795 [ z^13, z^ 9, z^ 2, z^12, z^ 8, z^ 7 ], 796 [ z^ 8, z^ 8, z^16, z^23, z^ 4, z^19 ] ] ]; 797 798 grp := Group( gen ); 799 800 Assert( 2, Size( grp ) = 7*6*5*4*3*2/2 * 6 ); 801 SetSize( grp, 7*6*5*4*3*2/2 * 6 ); 802 803 cen := SubgroupNC( grp, [ DiagonalMat( [ z^4, z^4, z^4, z^4, z^4, z^4 ] ) ] ); 804 805 Assert( 1, Size( cen ) = 6 ); 806 SetSize( cen, 6 ); 807 808 Assert( 1, IsAbelian( cen ) ); 809 SetIsAbelian( cen, true ); 810 811 Assert( 1, AbelianInvariants( cen ) = [ 2, 3 ] ); 812 SetAbelianInvariants( cen, [ 2, 3 ] ); 813 814 Assert( 2, Center(grp) = cen ); 815 SetCenter( grp, cen ); 816 817 else TryNextMethod(); 818 fi; 819 cox := List( [1..deg-1], i -> (dom[i],dom[i+1]) ); 820 img := [ Product( Reversed( cox{[1..2*Int((deg-1)/2)]} ) ), cox[deg-1]*cox[deg-2] ]; 821 Assert( 1, ForAll( img, i -> i in alt ) ); 822 if AssertionLevel() > 1 then 823 hom := GroupHomomorphismByImages( grp, alt, gen, img ); 824 Assert( 2, KernelOfMultiplicativeGeneralMapping( hom ) = Center( grp ) ); 825 else 826 hom := GroupHomomorphismByImagesNC( grp, alt, gen, img ); 827 SetKernelOfMultiplicativeGeneralMapping( hom, Center( grp ) ); 828 fi; 829 return hom; 830end ); 831