1############################################################################# 2## 3#W types.g GAP 4 package AtlasRep Thomas Breuer 4## 5#Y Copyright (C) 2001, Lehrstuhl D für Mathematik, RWTH Aachen, Germany 6## 7## This file contains implementations of the actual data types used in the 8## &ATLAS; of Group Representations. 9## 10 11 12############################################################################# 13## 14#V AtlasOfGroupRepresentationsInfo 15## 16BindGlobal( "AtlasOfGroupRepresentationsInfo", rec( 17 18 # user parameters 19 accessFunctions := AtlasOfGroupRepresentationsAccessFunctionsDefault, 20 21 # system parameters (filled automatically) 22 GAPnames := [], 23 24 ringinfo := [], 25 26 permrepinfo := rec(), 27 28 characterinfo := rec(), 29 30 notified := [], 31 32 filenames := [], 33 newfilenames := [], 34 35 TableOfContents := rec( core := rec(), 36 types := rec( rep := [], 37 prg := [], 38 cache := [] ), 39 merged := rec() ), 40 41 TOC_Cache := rec(), 42 ) ); 43 44 45############################################################################# 46## 47#D Permutation representations 48## 49## <#GAPDoc Label="type:perm:format"> 50## <Mark><M>groupname</M><C>G</C><M>i</M><C>-p</C><M>n</M><M>id</M><C>B</C><M>m</M><C>.m</C><M>nr</M></Mark> 51## <Item> 52## a file in &MeatAxe; text file format 53## containing the <M>nr</M>-th generator of a permutation representation 54## on <M>n</M> points. 55## An example is <C>M11G1-p11B0.m1</C>. 56## </Item> 57## <#/GAPDoc> 58## 59AGR.DeclareDataType( "rep", "perm", rec( 60 61 # `<groupname>G<i>-p<n><id>B<m>.m<nr>' 62 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 63 [ "p", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, 64 "B", IsDigitChar, ".m", IsDigitChar ] ], 65 [ ParseBackwards, ParseForwards ] ], 66 67 AddDescribingComponents := function( record, type ) 68 local repid, parsed, comp, info, pos; 69 70 repid:= record.identifier[2][1]; 71 if not IsString( repid ) then 72 repid:= repid[2]; 73 fi; 74 parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); 75 record.p:= Int( parsed[5] ); 76 record.id:= parsed[6]; 77 repid:= repid{ [ 1 .. Position( repid, '.' ) - 1 ] }; 78 if IsBound( AtlasOfGroupRepresentationsInfo.characterinfo.( 79 record.groupname ) ) then 80 info:= AtlasOfGroupRepresentationsInfo.characterinfo.( 81 record.groupname ); 82 if IsBound( info[1] ) then 83 info:= info[1]; 84 pos:= Position( info[2], repid ); 85 if pos <> fail then 86 record.constituents:= info[1][ pos ]; 87 if info[3][ pos ] <> fail then 88 record.charactername:= info[3][ pos ]; 89 fi; 90 fi; 91 92 fi; 93 fi; 94 if IsBound( AtlasOfGroupRepresentationsInfo.permrepinfo.( repid ) ) then 95 repid:= AtlasOfGroupRepresentationsInfo.permrepinfo.( repid ); 96 for comp in [ "isPrimitive", "orbits", "rankAction", "stabilizer", 97 "transitivity", "maxnr" ] do 98 if IsBound( repid.( comp ) ) and repid.( comp ) <> "???" then 99 record.( comp ):= repid.( comp ); 100 fi; 101 od; 102 fi; 103 end, 104 105 # `[ <i>, <n>, <id>, <m>, <filenames> ]' 106 AddFileInfo := function( list, entry, name ) 107 local known; 108 if 0 < entry[5] then 109 known:= First( list, x -> x{ [ 1 .. 4 ] } = entry{ [3, 5, 6, 8 ] } ); 110 if known = fail then 111 known:= entry{ [ 3, 5, 6, 8 ] }; 112 Add( known, [] ); 113 Add( list, known ); 114 fi; 115 known[5][ entry[10] ]:= name; 116 return true; 117 fi; 118 return false; 119 end, 120 121 DisplayOverviewInfo := [ "#", "r", function( conditions ) 122 # Put *all* types of representations together, in particular 123 # assume that the functions for the other "rep" kind types are trivial! 124 local info, no; 125 126 conditions:= ShallowCopy( conditions ); 127 conditions[1]:= conditions[1][1]; 128 info:= CallFuncList( AllAtlasGeneratingSetInfos, conditions ); 129 no:= Length( info ); 130 if no = 0 then 131 no:= ""; 132 fi; 133 return [ String( no ), 134 not ForAll( info, 135 x -> IsString( x.identifier[2] ) 136 or ForAll( x.identifier[2], IsString ) ) ]; 137 end ], 138 139 AccessGroupCondition := function( info, cond ) 140 return AGR.CheckOneCondition( IsPermGroup, x -> x = true, cond ) 141 and AGR.CheckOneCondition( IsPermGroup, cond ) 142 and AGR.CheckOneCondition( IsMatrixGroup, x -> x = false, cond ) 143 and AGR.CheckOneCondition( NrMovedPoints, 144 x -> ( IsFunction( x ) and x( info.p ) = true ) 145 or info.p = x, cond ) 146 and AGR.CheckOneCondition( IsTransitive, 147 x -> ( not IsBound( info.transitivity ) and x = fail ) or 148 ( IsBound( info.transitivity ) and 149 ( ( IsFunction( x ) and x( info.transitivity > 0 ) = true ) 150 or ( info.transitivity > 0 ) = x ) ), cond ) 151 and AGR.CheckOneCondition( Transitivity, 152 x -> ( not IsBound( info.transitivity ) and x = fail ) or 153 ( IsBound( info.transitivity ) and 154 ( ( IsFunction( x ) and x( info.transitivity ) = true ) 155 or info.transitivity = x ) ), cond ) 156 and AGR.CheckOneCondition( IsPrimitive, 157 x -> ( not IsBound( info.isPrimitive ) and x = fail ) or 158 ( IsBound( info.isPrimitive ) and 159 ( ( IsFunction( x ) and x( info.isPrimitive ) = true ) 160 or info.isPrimitive = x ) ), cond ) 161 and AGR.CheckOneCondition( RankAction, 162 x -> ( not IsBound( info.rankAction ) and x = fail ) or 163 ( IsBound( info.rankAction ) and 164 ( ( IsFunction( x ) and x( info.rankAction ) = true ) 165 or info.rankAction = x ) ), cond ) 166 and AGR.CheckOneCondition( Identifier, 167 x -> ( IsFunction( x ) and x( info.id ) = true ) 168 or info.id = x, cond ) 169 and IsEmpty( cond ); 170 end, 171 172 DisplayGroup := function( r ) 173 local disp, sep; 174 175 if AGR.ShowOnlyASCII() then 176 disp:= Concatenation( "G <= Sym(", String( r.p ), r.id, ")" ); 177 else 178 disp:= Concatenation( "G ≤ Sym(", String( r.p ), r.id, ")" ); 179 fi; 180 if IsBound( r.transitivity ) then 181 disp:= [ disp ]; 182 if r.transitivity = 0 then 183 # For intransitive repres., show the orbit lengths. 184 Add( disp, Concatenation( "orbit lengths ", 185 JoinStringsWithSeparator( List( r.orbits, String ), ", " ) ) ); 186 sep:= ", "; 187 elif r.transitivity = 1 then 188 # For transitivity 1, show the rank (if known). 189 if IsBound( r.rankAction ) and r.rankAction <> "???" then 190 Add( disp, Concatenation( "rank ", String( r.rankAction ) ) ); 191 sep:= ", "; 192 fi; 193 elif IsInt( r.transitivity ) then 194 # For transitivity at least 2, show the transitivity. 195 Add( disp, Concatenation( String( r.transitivity ), "-trans." ) ); 196 sep:= ", "; 197 else 198 # The transitivity is not known. 199 Add( disp, "" ); 200 sep:= ""; 201 fi; 202 if 0 < r.transitivity then 203 # For transitive representations, more info may be available. 204 if IsBound( r.isPrimitive ) and r.isPrimitive then 205 if IsBound( r.stabilizer ) and r.stabilizer <> "???" then 206 Add( disp, Concatenation( sep, "on cosets of " ) ); 207 Add( disp, r.stabilizer ); 208 if IsBound( r.maxnr ) and r.maxnr <> "???" then 209 Add( disp, Concatenation( " (", 210 Ordinal( r.maxnr ), " max.)" ) ); 211 else 212 Add( disp, "" ); 213 fi; 214 elif IsBound( r.maxnr ) and r.maxnr <> "???" then 215 Add( disp, Concatenation( sep, "on cosets of ", 216 Ordinal( r.maxnr ), " max." ) ); 217 else 218 Add( disp, Concatenation( sep, "primitive" ) ); 219 fi; 220 elif IsBound( r.stabilizer ) and r.stabilizer <> "???" then 221 Add( disp, Concatenation( sep, "on cosets of " ) ); 222 Add( disp, r.stabilizer ); 223 fi; 224 fi; 225 fi; 226 return disp; 227 end, 228 229 TestFileHeaders := function( tocid, groupname, entry, type ) 230 local name, cand, filename, len, file, line; 231 232 if tocid = "core" then 233 tocid:= "datagens"; 234 fi; 235 236 # Each generator is stored in a file of its own. 237 for name in entry[ Length( entry ) ] do 238 239 # Consider only local files, do not download them. 240 cand:= AtlasOfGroupRepresentationsLocalFilename( 241 [ [ tocid, name ] ], type ); 242 if not ( Length( cand ) = 1 and ForAll( cand[1][2], x -> x[2] ) ) then 243 return true; 244 fi; 245 filename:= cand[1][2][1][1]; 246 len:= Length( filename ); 247 if 3 < len and filename{ [ len-2 .. len ] } = ".gz" then 248 filename:= filename{ [ 1 .. len-3 ] }; 249 fi; 250 251 # Read the first line of the file. 252 file:= InputTextFile( filename ); 253 if file = fail then 254 return Concatenation( "cannot create input stream for file `", 255 filename,"'" ); 256 fi; 257 AGR.InfoRead( "#I reading `",filename,"' started\n" ); 258 line:= ReadLine( file ); 259 if line = fail then 260 CloseStream( file ); 261 return Concatenation( "no first line in file `",filename,"'" ); 262 fi; 263 while not '\n' in line do 264 Append( line, ReadLine( file ) ); 265 od; 266 CloseStream( file ); 267 AGR.InfoRead( "#I reading `",filename,"' done\n" ); 268 269 # The header must consist of four nonnegative integers. 270 line:= CMeatAxeFileHeaderInfo( line ); 271 if line = fail then 272 return Concatenation( "illegal header of file `", filename,"'" ); 273 fi; 274 275 # Start the specific tests for permutations. 276 # Check mode, number of permutations, and degree. 277 if line[1] <> 12 then 278 return Concatenation( "mode of file `", name, 279 "' differs from 12" ); 280 elif line[4] <> 1 then 281 return Concatenation( 282 "more than one permutation in file `", name, "'" ); 283 elif line[3] <> entry[2] then 284 return Concatenation( "perm. degree in file `", 285 name, "' is ", String( line[3] ) ); 286 fi; 287 288 od; 289 return true; 290 end, 291 292 TestFiles := AGR.TestFilesMTX, 293 294 # Permutation representations are sorted according to 295 # degree and identification string. 296 SortTOCEntries := entry -> entry{ [ 2, 3 ] }, 297 298 # Check whether the right number of files is available for each repres. 299 PostprocessFileInfo := function( toc, record ) 300 local list, i; 301 list:= record.perm; 302 for i in [ 1 .. Length( list ) ] do 303 if not IsDenseList( list[i][5] ) then 304#T better check whether the number of generators equals the number of 305#T standard generators 306 Info( InfoAtlasRep, 1, "not all generators for ", list[i][5] ); 307 Unbind( list[i] ); 308 fi; 309 od; 310 if not IsDenseList( list ) then 311 record.perm:= Compacted( list ); 312 fi; 313 end, 314 315 # We store the type, the full filename, and the list of CRC values. 316 TOCEntryString := function( typename, entry ) 317 local list, pos, name, crc, i, info; 318 319 list:= AtlasOfGroupRepresentationsInfo.filenames; 320 pos:= List( entry[5], nam -> PositionSorted( list, [ nam ] ) ); 321 if ForAll( pos, x -> x <= Length( list ) ) and 322 List( pos, x -> list[x][1] ) = entry[5] then 323 name:= list[ pos[1] ][2]; 324 crc:= []; 325 for i in [ 1 .. Length( pos ) ] do 326 if Length( list[ pos[i] ] ) < 4 then 327 # There is no crc value yet. 328 # If the file is available locally then compute the value, 329 # otherwise leave it out. 330 info:= AtlasOfGroupRepresentationsLocalFilename( 331 [ list[ pos[i] ]{ [ 3, 1 ] } ], typename ); 332 info:= First( info, l -> l[2][1][2] = true ); 333 if info <> fail then 334 crc[i]:= CrcFile( info[2][1][1] ); 335 else 336 crc[i]:= fail; 337 fi; 338 else 339 crc[i]:= list[ pos[i] ][4]; 340 fi; 341 od; 342 info:= Concatenation( "\"", typename, "\",\"", 343 name{ [ 1 .. PositionSublist( name, ".m" ) + 1 ] }, "\"" ); 344 if not fail in crc then 345 Append( info, Concatenation( ",", 346 ReplacedString( String( crc ), " ", "" ) ) ); 347 fi; 348 return info; 349 fi; 350 return fail; 351 end, 352 353 # The default access reads the text format files. 354 # Note that `ScanMeatAxeFile' returns a list of permutations. 355 ReadAndInterpretDefault := paths -> Concatenation( List( paths, 356 ScanMeatAxeFile ) ), 357 ) ); 358 359 360############################################################################# 361## 362#D Matrix representations over finite fields 363## 364## <#GAPDoc Label="type:matff:format"> 365## <Mark><M>groupname</M><C>G</C><M>i</M><C>-f</C><M>q</M><C>r</C><M>dim</M><M>id</M><C>B</C><M>m</M><C>.m</C><M>nr</M></Mark> 366## <Item> 367## a file in &MeatAxe; text file format 368## containing the <M>nr</M>-th generator of a matrix representation 369## over the field with <M>q</M> elements, of dimension <M>dim</M>. 370## An example is <C>S5G1-f2r4aB0.m1</C>. 371## </Item> 372## <#/GAPDoc> 373## 374AGR.DeclareDataType( "rep", "matff", rec( 375 376 # `<groupname>G<i>-f<q>r<dim><id>B<m>.m<nr>' 377 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 378 [ "f", IsDigitChar, "r", IsDigitChar, 379 AGR.IsLowerAlphaOrDigitChar, 380 "B", IsDigitChar, ".m", IsDigitChar ] ], 381 [ ParseBackwards, ParseForwards ] ], 382 383 AddDescribingComponents := function( record, type ) 384 local repid, parsed, info, char, pos; 385 386 repid:= record.identifier[2][1]; 387 if not IsString( repid ) then 388 repid:= repid[2]; 389 fi; 390 parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); 391 record.dim:= Int( parsed[7] ); 392 record.id:= parsed[8]; 393 record.ring:= GF( parsed[5] ); 394 if IsBound( AtlasOfGroupRepresentationsInfo.characterinfo.( 395 record.groupname ) ) then 396 info:= AtlasOfGroupRepresentationsInfo.characterinfo.( 397 record.groupname ); 398 char:= Characteristic( record.ring ); 399 if IsBound( info[ char ] ) then 400 info:= info[ char ]; 401 pos:= Position( info[2], repid{ [ 1 .. Position( repid, '.' ) - 1 ] } ); 402 if pos <> fail then 403 record.constituents:= info[1][ pos ]; 404 if IsInt( record.constituents ) then 405 record.constituents:= [ record.constituents ]; 406 fi; 407 if info[3][ pos ] <> fail then 408 record.charactername:= info[3][ pos ]; 409 fi; 410 fi; 411 fi; 412 fi; 413 end, 414 415 # `[ <i>, <q>, <dim>, <id>, <m>, <filenames> ]' 416 AddFileInfo := function( list, entry, name ) 417 local known; 418 if IsPrimePowerInt( entry[5] ) and 0 < entry[7] then 419 known:= First( list, x -> x{ [ 1 .. 5 ] } 420 = entry{ [ 3, 5, 7, 8, 10 ] } ); 421 if known = fail then 422 known:= entry{ [ 3, 5, 7, 8, 10 ] }; 423 Add( known, [] ); 424 Add( list, known ); 425 fi; 426 known[6][ entry[12] ]:= name; 427 return true; 428 fi; 429 return false; 430 end, 431 432 AccessGroupCondition := function( info, cond ) 433 return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) 434 and AGR.CheckOneCondition( IsMatrixGroup, cond ) 435 and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) 436 and AGR.CheckOneCondition( Characteristic, 437 function( p ) 438 local char; 439 char:= SmallestRootInt( Size( info.ring ) ); 440 return char = p or IsFunction( p ) and p( char ) = true; 441 end, 442 cond ) 443 and AGR.CheckOneCondition( Dimension, 444 x -> ( IsFunction( x ) and x( info.dim ) ) 445 or info.dim = x, cond ) 446 and AGR.CheckOneCondition( Ring, 447 R -> ( IsFunction( R ) and R( info.ring ) ) or 448 ( IsField( R ) and IsFinite( R ) 449 and Size( info.ring ) mod Characteristic( R ) = 0 450 and DegreeOverPrimeField( R ) 451 mod LogInt( Size( info.ring ), 452 Characteristic( R ) ) = 0 ), 453 cond ) 454 and AGR.CheckOneCondition( Identifier, 455 x -> ( IsFunction( x ) and x( info.id ) = true ) 456 or info.id = x, cond ) 457 and IsEmpty( cond ); 458 end, 459 460 DisplayGroup := function( r ) 461 local disp; 462 463 if AGR.ShowOnlyASCII() then 464 disp:= Concatenation( "G <= GL(", String( r.dim ), r.id, 465 ",", String( r.identifier[4] ), ")" ); 466 if IsBound( r.charactername ) then 467 disp:= [ disp, Concatenation( "character ", r.charactername ) ]; 468 fi; 469 else 470 disp:= Concatenation( "G ≤ GL(", String( r.dim ), r.id, 471 ",", String( r.identifier[4] ), ")" ); 472 if IsBound( r.charactername ) then 473 disp:= [ disp, Concatenation( "φ = ", r.charactername ) ]; 474 fi; 475 fi; 476 return disp; 477 end, 478 479 TestFileHeaders := function( tocid, groupname, entry, type ) 480 local name, cand, filename, len, file, line, errors; 481 482 if tocid = "core" then 483 tocid:= "datagens"; 484 fi; 485 486 # Each generator is stored in a file of its own. 487 for name in entry[ Length( entry ) ] do 488 489 # Consider only local files, do not download them. 490 cand:= AtlasOfGroupRepresentationsLocalFilename( 491 [ [ tocid, name ] ], type ); 492 if not ( Length( cand ) = 1 and ForAll( cand[1][2], x -> x[2] ) ) then 493 return true; 494 fi; 495 filename:= cand[1][2][1][1]; 496 len:= Length( filename ); 497 if 3 < len and filename{ [ len-2 .. len ] } = ".gz" then 498 filename:= filename{ [ 1 .. len-3 ] }; 499 fi; 500 501 # Read the first line of the file. 502 file:= InputTextFile( filename ); 503 if file = fail then 504 return Concatenation( "cannot create input stream for file `", 505 filename,"'" ); 506 fi; 507 AGR.InfoRead( "#I reading `",filename,"' started\n" ); 508 line:= ReadLine( file ); 509 if line = fail then 510 CloseStream( file ); 511 return Concatenation( "no first line in file `",filename,"'" ); 512 fi; 513 while not '\n' in line do 514 Append( line, ReadLine( file ) ); 515 od; 516 CloseStream( file ); 517 AGR.InfoRead( "#I reading `",filename,"' done\n" ); 518 519 # The header must consist of four nonnegative integers. 520 line:= CMeatAxeFileHeaderInfo( line ); 521 if line = fail then 522 return Concatenation( "illegal header of file `", filename,"'" ); 523 fi; 524 525 # Start the specific tests for matrices over finite fields. 526 # Check mode, field size, and dimension. 527 errors:= ""; 528 if 6 < line[1] then 529 Append( errors, Concatenation( "mode of file `", name, 530 "' is larger than 6" ) ); 531 elif line[2] <> entry[2] then 532 Append( errors, Concatenation( "file `", name, 533 "': field is of size ", String( line[2] ) ) ); 534 elif line[3] <> entry[3] then 535 Append( errors, Concatenation( "file `", name, 536 "': matrix dimension is ", String( line[3] ) ) ); 537 elif line[3] <> line[4] then 538 Append( errors, Concatenation( "file `", name, 539 "': matrix is not square" ) ); 540 fi; 541 if not IsEmpty( errors ) then 542 return errors; 543 fi; 544 545 od; 546 return true; 547 end, 548 549 TestFiles := AGR.TestFilesMTX, 550 551 # Matrix representations over finite fields are sorted according to 552 # field size, dimension, and identification string. 553 SortTOCEntries := entry -> entry{ [ 2 .. 4 ] }, 554 555 # Check whether the right number of files is available for each repres. 556 PostprocessFileInfo := function( toc, record ) 557 local list, i; 558 list:= record.matff; 559 for i in [ 1 .. Length( list ) ] do 560 if not IsDenseList( list[i][6] ) then 561#T better check whether the number of generators equals the number of 562#T standard generators 563 Info( InfoAtlasRep, 1, "not all generators for ", list[i][6] ); 564 Unbind( list[i] ); 565 fi; 566 od; 567 if not IsDenseList( list ) then 568 record.matff:= Compacted( list ); 569 fi; 570 end, 571 572 # We store the type, the full filename, and the list of CRC values. 573 TOCEntryString := function( typename, entry ) 574 local list, pos, name, crc, i, info; 575 576 list:= AtlasOfGroupRepresentationsInfo.filenames; 577 pos:= List( entry[6], nam -> PositionSorted( list, [ nam ] ) ); 578 if ForAll( pos, x -> x <= Length( list ) ) and 579 List( pos, x -> list[x][1] ) = entry[6] then 580 name:= list[ pos[1] ][2]; 581 crc:= []; 582 for i in [ 1 .. Length( pos ) ] do 583 if Length( list[ pos[i] ] ) < 4 then 584 # There is no crc value yet. 585 # If the file is available locally then compute the value, 586 # otherwise leave it out. 587 info:= AtlasOfGroupRepresentationsLocalFilename( 588 [ list[ pos[i] ]{ [ 3, 1 ] } ], typename ); 589 info:= First( info, l -> l[2][1][2] = true ); 590 if info <> fail then 591 crc[i]:= CrcFile( info[2][1][1] ); 592 else 593 crc[i]:= fail; 594 fi; 595 else 596 crc[i]:= list[ pos[i] ][4]; 597 fi; 598 od; 599 info:= Concatenation( "\"", typename, "\",\"", 600 name{ [ 1 .. PositionSublist( name, ".m" ) + 1 ] }, "\"" ); 601 if not fail in crc then 602 Append( info, Concatenation( ",", 603 ReplacedString( String( crc ), " ", "" ) ) ); 604 fi; 605 return info; 606 fi; 607 return fail; 608 end, 609 610 # The default access reads the text format files. 611 ReadAndInterpretDefault := paths -> List( paths, ScanMeatAxeFile ), 612 ) ); 613 614 615############################################################################# 616## 617#D Matrix representations over the integers 618## 619## <#GAPDoc Label="type:matint:format"> 620## <Mark><M>groupname</M><C>G</C><M>i</M><C>-Zr</C><M>dim</M><M>id</M><C>B</C><M>m</M>.g</Mark> 621## <Item> 622## a &GAP; readable file 623## containing all generators of a matrix representation 624## over the integers, of dimension <M>dim</M>. 625## An example is <C>A5G1-Zr4B0.g</C>. 626## </Item> 627## <#/GAPDoc> 628## 629AGR.DeclareDataType( "rep", "matint", rec( 630 631 # `<groupname>G<i>-Zr<dim><id>B<m>.g' 632 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 633 [ "Zr", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, 634 "B", IsDigitChar, ".g" ] ], 635 [ ParseBackwards, ParseForwards ] ], 636 637 AddDescribingComponents := function( record, type ) 638 local repid, parsed, info, pos; 639 640 repid:= record.identifier[2]; 641 if not IsString( repid ) then 642 # one private file 643 repid:= repid[1][2]; 644 fi; 645 parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); 646 record.dim:= Int( parsed[5] ); 647 record.id:= parsed[6]; 648 record.ring:= Integers; 649 if IsBound( AtlasOfGroupRepresentationsInfo.characterinfo.( 650 record.groupname ) ) then 651 info:= AtlasOfGroupRepresentationsInfo.characterinfo.( 652 record.groupname ); 653 if IsBound( info[1] ) then 654 info:= info[1]; 655 pos:= Position( info[2], repid{ [ 1 .. Position( repid, '.' ) - 1 ] } ); 656 if pos <> fail then 657 record.constituents:= info[1][ pos ]; 658 if IsInt( record.constituents ) then 659 record.constituents:= [ record.constituents ]; 660 fi; 661 if info[3][ pos ] <> fail then 662 record.charactername:= info[3][ pos ]; 663 fi; 664 fi; 665 fi; 666 fi; 667 end, 668 669 # `[ <i>, <dim>, <id>, <m>, <filename> ]' 670 AddFileInfo := function( list, entry, name ) 671 if 0 < entry[5] then 672 Add( list, Concatenation( entry{ [ 3, 5, 6, 8 ] }, [ name ] ) ); 673 return true; 674 fi; 675 return false; 676 end, 677 678 AccessGroupCondition := function( info, cond ) 679 return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) 680 and AGR.CheckOneCondition( IsMatrixGroup, cond ) 681 and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) 682 and AGR.CheckOneCondition( Characteristic, 683 p -> p = 0 or ( IsFunction( p ) and p( 0 ) = true ), 684 cond ) 685 and AGR.CheckOneCondition( Dimension, 686 x -> ( IsFunction( x ) and x( info.dim ) ) 687 or info.dim = x, cond ) 688 and AGR.CheckOneCondition( Ring, 689 R -> ( IsFunction( R ) and R( Integers ) ) or 690 ( IsRing( R ) and IsCyclotomicCollection( R ) ), cond ) 691 and AGR.CheckOneCondition( Identifier, 692 x -> ( IsFunction( x ) and x( info.id ) = true ) 693 or info.id = x, cond ) 694 and IsEmpty( cond ); 695 end, 696 697 TestFileHeaders := function( tocid, groupname, entry, type ) 698 return AGR.TestFileHeadersDefault( tocid, groupname, entry, type, 699 entry[2], 700 function( entry, mats, filename ) 701 if not ForAll( mats, mat -> ForAll( mat, 702 row -> ForAll( row, IsInt ) ) ) then 703 return Concatenation( "matrices in `", filename, 704 "' are not over the integers" ); 705 fi; 706 return true; 707 end ); 708 end, 709 710 DisplayGroup := function( r ) 711 local disp; 712 713 if AGR.ShowOnlyASCII() then 714 disp:= Concatenation( "G <= GL(", String( r.dim ), r.id, ",Z)" ); 715 if IsBound( r.charactername ) then 716 disp:= [ disp, Concatenation( "character ", r.charactername ) ]; 717 fi; 718 else 719 disp:= Concatenation( "G ≤ GL(", String( r.dim ), r.id, ",ℤ)" ); 720 if IsBound( r.charactername ) then 721 disp:= [ disp, Concatenation( "χ = ", r.charactername ) ]; 722 fi; 723 fi; 724 return disp; 725 end, 726 727 # Matrix representations over the integers are sorted according to 728 # dimension and identification string. 729 SortTOCEntries := entry -> entry{ [ 2, 3 ] }, 730 731 # There is only one file. 732 ReadAndInterpretDefault := paths -> AtlasDataGAPFormatFile( 733 paths[1] ).generators, 734 ) ); 735 736 737############################################################################# 738## 739#D Matrix representations over algebraic number fields 740## 741## <#GAPDoc Label="type:matalg:format"> 742## <Mark><M>groupname</M><C>G</C><M>i</M><C>-Ar</C><M>dim</M><M>id</M><C>B</C><M>m</M><C>.g</C></Mark> 743## <Item> 744## a &GAP; readable file 745## containing all generators of a matrix representation of dimension 746## <M>dim</M> over an algebraic number field not specified further. 747## An example is <C>A5G1-Ar3aB0.g</C>. 748## </Item> 749## <#/GAPDoc> 750## 751AGR.DeclareDataType( "rep", "matalg", rec( 752 753 # `<groupname>G<i>-Ar<dim><id>B<m>.g' 754 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 755 [ "Ar", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, 756 "B", IsDigitChar, ".g" ] ], 757 [ ParseBackwards, ParseForwards ] ], 758 759 AddDescribingComponents := function( record, type ) 760 local repid, parsed, info, pos; 761 762 repid:= record.identifier[2]; 763 if not IsString( repid ) then 764 # one private file 765 repid:= repid[1][2]; 766 fi; 767 parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); 768 record.dim:= Int( parsed[5] ); 769 record.id:= parsed[6]; 770 info:= repid{ [ 1 .. Position( repid, '.' )-1 ] }; 771 info:= First( AtlasOfGroupRepresentationsInfo.ringinfo, 772 x -> x[1] = info ); 773 if info <> fail then 774 record.ring:= info[3]; 775 fi; 776 if IsBound( AtlasOfGroupRepresentationsInfo.characterinfo.( 777 record.groupname ) ) then 778 info:= AtlasOfGroupRepresentationsInfo.characterinfo.( 779 record.groupname ); 780 if IsBound( info[1] ) then 781 info:= info[1]; 782 pos:= Position( info[2], repid{ [ 1 .. Position( repid, '.' ) - 1 ] } ); 783 if pos <> fail then 784 record.constituents:= info[1][ pos ]; 785 if IsInt( record.constituents ) then 786 record.constituents:= [ record.constituents ]; 787 fi; 788 if info[3][ pos ] <> fail then 789 record.charactername:= info[3][ pos ]; 790 fi; 791 fi; 792 fi; 793 fi; 794 end, 795 796 # `[ <i>, <dim>, <id>, <m>, <filename> ]' 797 AddFileInfo := function( list, entry, name ) 798 if 0 < entry[5] then 799 Add( list, Concatenation( entry{ [ 3, 5, 6, 8 ] }, [ name ] ) ); 800 return true; 801 fi; 802 return false; 803 end, 804 805 AccessGroupCondition := function( info, cond ) 806 return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) 807 and AGR.CheckOneCondition( IsMatrixGroup, cond ) 808 and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) 809 and AGR.CheckOneCondition( Characteristic, 810 p -> p = 0 or ( IsFunction( p ) and p( 0 ) = true ), 811 cond ) 812 and AGR.CheckOneCondition( Dimension, 813 x -> ( IsFunction( x ) and x( info.dim ) = true ) 814 or info.dim = x, cond ) 815 and AGR.CheckOneCondition( Ring, 816 x -> IsIdenticalObj( x, Cyclotomics ) or 817 ( not IsBound( info.ring ) and x = fail ) or 818 ( IsBound( info.ring ) and 819 ( ( IsFunction( x ) and x( info.ring ) = true ) 820 or ( IsRing( x ) and IsCyclotomicCollection( x ) 821#T problem with GAP: 822#T 'IsSubset( Integers, CF(5) )' runs into an error 823 and ( not IsIdenticalObj( x, Integers ) and 824 IsSubset( x, info.ring ) ) ) ) ), cond ) 825 and AGR.CheckOneCondition( Identifier, 826 x -> ( IsFunction( x ) and x( info.id ) = true ) 827 or info.id = x, cond ) 828 and IsEmpty( cond ); 829 end, 830 831 TestFileHeaders := function( tocid, groupname, entry, type ) 832 return AGR.TestFileHeadersDefault( tocid, groupname, entry, type, 833 entry[2], 834 function( entry, mats, filename ) 835 local info; 836 837 if not IsCyclotomicCollCollColl( mats ) then 838 return Concatenation( "matrices in `",filename, 839 "' are not over cyclotomics" ); 840 elif ForAll( Flat( mats ), IsInt ) then 841 return Concatenation( "matrices in `",filename, 842 "' are over the integers" ); 843 fi; 844 filename:= filename{ [ 1 .. Position( filename, '.' )-1 ] }; 845 info:= First( AtlasOfGroupRepresentationsInfo.ringinfo, 846 triple -> triple[1] = filename ); 847 if info = fail then 848 return Concatenation( "field info for `",filename, 849 "' missing" ); 850 elif Field( Rationals, Flat( mats ) ) <> info[3] then 851 return Concatenation( "field info for `",filename, 852 "' should be ", 853 String( Field( Rationals, Flat( mats ) ) ) ); 854 fi; 855 return true; 856 end ); 857 end, 858 859 DisplayGroup := function( r ) 860 local fld, disp; 861 862 fld:= r.identifier[2]; 863 if not IsString( fld ) then 864 fld:= fld[1][2]; 865 fi; 866 fld:= fld{ [ 1 .. Length( fld )-2 ] }; 867 fld:= First( AtlasOfGroupRepresentationsInfo.ringinfo, 868 p -> p[1] = fld ); 869 if AGR.ShowOnlyASCII() then 870 if fld <> fail then 871 fld:= fld[2]; 872 else 873 fld:= "C"; 874 fi; 875 disp:= Concatenation( "G <= GL(", String( r.dim ), r.id, ",", 876 fld, ")" ); 877 if IsBound( r.charactername ) then 878 disp:= [ disp, Concatenation( "character ", r.charactername ) ]; 879 fi; 880 else 881 if fld <> fail then 882 fld:= fld[2]; 883 else 884 fld:= "ℂ"; 885 fi; 886 disp:= Concatenation( "G ≤ GL(", String( r.dim ), r.id, ",", 887 fld, ")" ); 888 if IsBound( r.charactername ) then 889 disp:= [ disp, Concatenation( "χ = ", r.charactername ) ]; 890 fi; 891 fi; 892 return disp; 893 end, 894 895 # Matrix representations over algebraic extension fields are sorted 896 # according to dimension and identification string. 897 SortTOCEntries := entry -> entry{ [ 2, 3 ] }, 898 899 # There is only one file. 900 ReadAndInterpretDefault := paths -> AtlasDataGAPFormatFile( 901 paths[1] ).generators, 902 ) ); 903 904 905############################################################################# 906## 907#D Matrix representations over residue class rings 908## 909## <#GAPDoc Label="type:matmodn:format"> 910## <Mark><M>groupname</M><C>G</C><M>i</M><C>-Z</C><M>n</M><C>r</C><M>dim</M><M>id</M><C>B</C><M>m</M><C>.g</C></Mark> 911## <Item> 912## a &GAP; readable file 913## containing all generators of a matrix representation of dimension 914## <M>dim</M> over the ring of integers mod <M>n</M>. 915## An example is <C>2A8G1-Z4r4aB0.g</C>. 916## </Item> 917## <#/GAPDoc> 918## 919AGR.DeclareDataType( "rep", "matmodn", rec( 920 921 # `<groupname>G<i>-Z<n>r<dim><id>B<m>.g' 922 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 923 [ "Z", IsDigitChar, "r", IsDigitChar, 924 AGR.IsLowerAlphaOrDigitChar, 925 "B", IsDigitChar, ".g" ] ], 926 [ ParseBackwards, ParseForwards ] ], 927 928 AddDescribingComponents := function( record, type ) 929 local repid, parsed; 930 931 repid:= record.identifier[2]; 932 if not IsString( repid ) then 933 # one private file 934 repid:= repid[1][2]; 935 fi; 936 parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); 937 record.dim:= Int( parsed[7] ); 938 record.id:= parsed[8]; 939 record.ring:= ZmodnZ( parsed[5] ); 940 end, 941 942 # `[ <i>, <n>, <dim>, <id>, <m>, <filename> ]' 943 AddFileInfo := function( list, entry, name ) 944 if 0 < entry[5] and 0 < entry[7] then 945 Add( list, Concatenation( entry{ [ 3, 5, 7, 8, 10 ] }, [ name ] ) ); 946 return true; 947 fi; 948 return false; 949 end, 950 951 AccessGroupCondition := function( info, cond ) 952 return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) 953 and AGR.CheckOneCondition( IsMatrixGroup, cond ) 954 and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) 955 and AGR.CheckOneCondition( Characteristic, 956 p -> p = fail or ( IsFunction( p ) and p( fail ) = true ), 957 cond ) 958 and AGR.CheckOneCondition( Dimension, 959 x -> ( IsFunction( x ) and x( info.dim ) ) 960 or info.dim = x, cond ) 961 and AGR.CheckOneCondition( Ring, 962 R -> ( IsFunction( R ) and R( info.ring ) ) or 963 ( IsRing( R ) 964 and IsZmodnZObjNonprimeCollection( R ) 965 and ModulusOfZmodnZObj( One( R ) ) = Size( info.ring ) ), 966 cond ) 967 and AGR.CheckOneCondition( Identifier, 968 x -> ( IsFunction( x ) and x( info.id ) = true ) 969 or info.id = x, cond ) 970 and IsEmpty( cond ); 971 end, 972 973 DisplayGroup := function( r ) 974 if AGR.ShowOnlyASCII() then 975 return Concatenation( "G <= GL(",String( r.dim ), r.id, 976 ",Z/", String( r.identifier[4] ),"Z)" ); 977 else 978 return Concatenation( "G ≤ GL(",String( r.dim ), r.id, 979 ",ℤ/", String( r.identifier[4] ),"ℤ)" ); 980 fi; 981 end, 982 983 TestFileHeaders := function( tocid, groupname, entry, type ) 984 return AGR.TestFileHeadersDefault( tocid, groupname, entry, type, 985 entry[3], 986 function( entry, mats, filename ) 987 if not IsZmodnZObjNonprimeCollCollColl( mats ) then 988 return Concatenation( "matrices in `", filename, 989 "' are not over a residue class ring" ); 990 elif ModulusOfZmodnZObj( mats[1][1][1] ) <> entry[2] then 991 return Concatenation( "matrices in `", filename, 992 "' are not over Z/", entry[2], "Z" ); 993 fi; 994 return true; 995 end ); 996 end, 997 998 # Matrix representations over residue class rings are sorted according 999 # to modulus, dimension, and identification string. 1000 SortTOCEntries := entry -> entry{ [ 2 .. 4 ] }, 1001 1002 # There is only one file. 1003 ReadAndInterpretDefault := paths -> AtlasDataGAPFormatFile( 1004 paths[1] ).generators, 1005 ) ); 1006 1007 1008############################################################################# 1009## 1010#D Quaternionic matrix representations 1011## 1012## <#GAPDoc Label="type:quat:format"> 1013## <Mark><M>groupname</M><C>G</C><M>i</M><C>-Hr</C><M>dim</M><M>id</M><C>B</C><M>m</M><C>.g</C></Mark> 1014## <Item> 1015## a &GAP; readable file 1016## containing all generators of a matrix representation 1017## over a quaternion algebra over an algebraic number field, 1018## of dimension <M>dim</M>. 1019## An example is <C>2A6G1-Hr2aB0.g</C>. 1020## </Item> 1021## <#/GAPDoc> 1022## 1023AGR.DeclareDataType( "rep", "quat", rec( 1024 1025 # `<groupname>G<i>-Hr<dim><id>B<m>.g' 1026 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 1027 [ "Hr", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, 1028 "B", IsDigitChar, ".g" ] ], 1029 [ ParseBackwards, ParseForwards ] ], 1030 1031 AddDescribingComponents := function( record, type ) 1032 local repid, parsed, info; 1033 1034 repid:= record.identifier[2]; 1035 if not IsString( repid ) then 1036 # one private file 1037 repid:= repid[1][2]; 1038 fi; 1039 parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); 1040 record.dim:= Int( parsed[5] ); 1041 record.id:= parsed[6]; 1042 info:= repid{ [ 1 .. Position( repid, '.' )-1 ] }; 1043 info:= First( AtlasOfGroupRepresentationsInfo.ringinfo, 1044 x -> x[1] = info ); 1045 if info <> fail then 1046 record.ring:= info[3]; 1047 fi; 1048 end, 1049 1050 # `[ <i>, <dim>, <id>, <m>, <filename> ]' 1051 AddFileInfo := function( list, entry, name ) 1052 if 0 < entry[5] then 1053 Add( list, Concatenation( entry{ [ 3, 5, 6, 8 ] }, [ name ] ) ); 1054 return true; 1055 fi; 1056 return false; 1057 end, 1058 1059 AccessGroupCondition := function( info, cond ) 1060 return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) 1061 and AGR.CheckOneCondition( IsMatrixGroup, cond ) 1062 and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) 1063 and AGR.CheckOneCondition( Characteristic, 1064 p -> p = 0 or ( IsFunction( p ) and p( 0 ) = true ), 1065 cond ) 1066 and AGR.CheckOneCondition( Dimension, 1067 x -> ( IsFunction( x ) and x( info.dim ) = true ) 1068 or info.dim = x, cond ) 1069 and AGR.CheckOneCondition( Ring, 1070 x -> ( not IsBound( info.ring ) and x = fail ) or 1071 ( IsBound( info.ring ) and 1072 ( ( IsFunction( x ) and x( info.ring ) = true ) 1073 or ( IsRing( x ) and IsQuaternionCollection( x ) 1074 and IsSubset( x, info.ring ) ) ) ), cond ) 1075 and AGR.CheckOneCondition( Identifier, 1076 x -> ( IsFunction( x ) and x( info.id ) = true ) 1077 or info.id = x, cond ) 1078 and IsEmpty( cond ); 1079 end, 1080 1081 TestFileHeaders := function( tocid, groupname, entry, type ) 1082 return AGR.TestFileHeadersDefault( tocid, groupname, entry, type, 1083 entry[2], 1084 function( entry, mats, filename ) 1085 local info; 1086 1087 if not ForAll( mats, IsQuaternionCollColl ) then 1088 return Concatenation( "matrices in `",filename, 1089 "' are not over the quaternions" ); 1090 fi; 1091 filename:= filename{ [ 1 .. Position( filename, '.' )-1 ] }; 1092 info:= First( AtlasOfGroupRepresentationsInfo.ringinfo, 1093 triple -> triple[1] = filename ); 1094 if info = fail then 1095 return Concatenation( "field info for `",filename, 1096 "' missing" ); 1097 elif Field( Flat( List( Flat( mats ), ExtRepOfObj ) ) ) 1098 <> EvalString( Concatenation( "Field", 1099 info[2]{ [ Position( info[2], '(' ) .. 1100 Length( info[2] ) ] } ) ) then 1101 return Concatenation( "field info for `", filename, 1102 "' should involve ", 1103 Field( Flat( List( Flat( mats ), 1104 ExtRepOfObj ) ) ) ); 1105 fi; 1106 return true; 1107 end ); 1108 end, 1109 1110 DisplayGroup := function( r ) 1111 local fld; 1112 1113 fld:= r.identifier[2]; 1114 if not IsString( fld ) then 1115 fld:= fld[1][2]; 1116 fi; 1117 fld:= fld{ [ 1 .. Length( fld )-2 ] }; 1118 fld:= First( AtlasOfGroupRepresentationsInfo.ringinfo, 1119 p -> p[1] = fld ); 1120 if AGR.ShowOnlyASCII() then 1121 if fld = fail then 1122 fld:= "QuaternionAlgebra(C)"; 1123 else 1124 fld:= fld[2]; 1125 fi; 1126 return Concatenation( "G <= GL(", String( r.dim ), r.id, ",", fld, 1127 ")" ); 1128 else 1129 if fld = fail then 1130 fld:= "QuaternionAlgebra(ℂ)"; 1131 else 1132 fld:= fld[2]; 1133 fi; 1134 return Concatenation( "G ≤ GL(", String( r.dim ), r.id, ",", fld, 1135 ")" ); 1136 fi; 1137 end, 1138 1139 # Matrix representations over the quaternions are sorted according to 1140 # dimension and identification string. 1141 SortTOCEntries := entry -> entry{ [ 2, 3 ] }, 1142 1143 # There is only one file. 1144 ReadAndInterpretDefault := paths -> AtlasDataGAPFormatFile( 1145 paths[1] ).generators, 1146 ) ); 1147 1148 1149############################################################################# 1150## 1151#D Straight line programs for generators of maximal subgroups 1152## 1153## <#GAPDoc Label="type:maxes:format"> 1154## <Mark><M>groupname</M><C>G</C><M>i</M><C>-max</C><M>k</M><C>W</C><M>n</M></Mark> 1155## <Item> 1156## In this case, the file contains a straight line program that takes 1157## generators of <M>G</M> w. r. t. the <M>i</M>-th set 1158## of standard generators, 1159## and returns a list of generators 1160## (in general <E>not</E> standard generators) 1161## for a subgroup <M>U</M> in the <M>k</M>-th class of maximal subgroups 1162## of <M>G</M>. 1163## An example is <C>J1G1-max7W1</C>. 1164## </Item> 1165## <#/GAPDoc> 1166## 1167AGR.DeclareDataType( "prg", "maxes", rec( 1168 1169 # `<groupname>G<i>-max<k>W<n>' 1170 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 1171 [ "max", IsDigitChar, "W", IsDigitChar ] ], 1172 [ ParseBackwards, ParseForwards ] ], 1173 1174 # `[ <i>, <k>, <filename> ]' 1175 AddFileInfo := function( list, entry, name ) 1176 if 0 < entry[5] then 1177 Add( list, Concatenation( entry{ [ 3, 5 ] }, [ name ] ) ); 1178 return true; 1179 fi; 1180 return false; 1181 end, 1182 1183 DisplayOverviewInfo := [ "maxes", "r", function( conditions ) 1184 local groupname, tocs, std, info, factgroupinfo, maxext, value, 1185 private, toc, record, new, finfo, factgroupname; 1186 1187 groupname:= conditions[1][2]; 1188 tocs:= AGR.TablesOfContents( conditions ); 1189 if Length( conditions ) = 1 or 1190 not ( IsInt( conditions[2] ) or IsList( conditions[2] ) ) then 1191 std:= true; 1192 else 1193 std:= conditions[2]; 1194 if IsInt( std ) then 1195 std:= [ std ]; 1196 fi; 1197 fi; 1198 1199 info:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1200 x -> x[2] = groupname ); 1201 if info = fail or not IsBound( info[3].maxext ) 1202 or not IsBound( info[3].factorCompatibility ) then 1203 factgroupinfo:= []; 1204 maxext:= []; 1205 else 1206 factgroupinfo:= Filtered( info[3].factorCompatibility, 1207 x -> ( std = true or x[1] in std ) 1208 and x[4] = true ); 1209 maxext:= Filtered( info[3].maxext, 1210 x -> std = true or x[1] in std ); 1211 fi; 1212 1213 value:= []; 1214 private:= false; 1215 for toc in tocs do 1216 # If a straight line program for the restriction is available 1217 # then take it. 1218 if IsBound( toc.( groupname ) ) then 1219 record:= toc.( groupname ); 1220 if IsBound( record.maxes ) then 1221 new:= List( Filtered( record.maxes, 1222 x -> std = true or x[1] in std ), 1223 x -> x[2] ); 1224 if toc.TocID <> "core" and not IsEmpty( new ) then 1225 private:= true; 1226 fi; 1227 UniteSet( value, new ); 1228 fi; 1229 fi; 1230 1231 # If a straight line program is available for the restriction 1232 # to the maximal subgroup of a factor group, 1233 # and if this program can be used also here 1234 # then take it. 1235 for finfo in factgroupinfo do 1236 factgroupname:= finfo[2]; 1237 info:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1238 x -> x[1] = factgroupname ); 1239 factgroupname:= info[2]; 1240 if IsBound( toc.( factgroupname ) ) then 1241 record:= toc.( factgroupname ); 1242 if IsBound( record.maxes ) then 1243 new:= List( Filtered( maxext, 1244 l -> ForAny( record.maxes, 1245 fl -> fl[3] = l[3][1] ) ), 1246 x -> x[2] ); 1247 if toc.TocID <> "core" and not IsEmpty( new ) then 1248 private:= true; 1249 fi; 1250 UniteSet( value, new ); 1251 fi; 1252 fi; 1253 od; 1254 od; 1255 if IsEmpty( value ) then 1256 value:= ""; 1257 else 1258 value:= String( Length( value ) ); 1259 fi; 1260 return [ value, private ]; 1261 end ], 1262 1263 DisplayPRG := function( tocs, names, std, stdavail ) 1264 local data, sortkeys, alltocs, info, 1265 factgroupinfo, maxext, prvwidth, toc, record, i, private, mxstd, 1266 pos, finfo, factgroupname, facti, ker, kerid, pi, result, nrmaxes, 1267 title, entry, line, width, prvphantom, maxnr, j, line2; 1268 1269 data:= []; 1270 sortkeys:= []; 1271 1272 alltocs := AGR.TablesOfContents( "all" ); 1273 info:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1274 x -> x[2] = names[2] ); 1275 if info = fail or not IsBound( info[3].maxext ) 1276 or not IsBound( info[3].factorCompatibility ) then 1277 factgroupinfo:= []; 1278 maxext:= []; 1279 else 1280 factgroupinfo:= Filtered( info[3].factorCompatibility, 1281 x -> ( std = true or x[1] in std ) 1282 and x[4] = true ); 1283 maxext:= Filtered( info[3].maxext, 1284 x -> std = true or x[1] in std ); 1285 fi; 1286 1287 prvwidth:= 0; 1288 for toc in tocs do 1289 # If a straight line program for the restriction is available 1290 # then take it. 1291 if IsBound( toc.( names[2] ) ) then 1292 record:= toc.( names[2] ); 1293 if IsBound( record.maxes ) then 1294 for i in record.maxes do 1295 if std = true or i[1] in std then 1296 if toc.TocID <> "core" then 1297 private:= UserPreference( "AtlasRep", 1298 "AtlasRepMarkNonCoreData" ); 1299 prvwidth:= Length( private ); 1300 else 1301 private := ""; 1302 fi; 1303 1304 entry:= [ , 1305 private, 1306 String( i[1] ), 1307 AGR.VersionOfSLP( i[3] ), 1308 [ names[1], i[3], i[1] ] ]; 1309 if toc.TocID <> "core" then 1310 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 1311 fi; 1312 1313 # If *standard* generators of the max. subgroup are available 1314 # (perhaps in another table of contents) then mention this, 1315 # in a line of its own; 1316 # note that Browse will allow one to click on the line. 1317 mxstd:= AGR.StandardizeMaximalSubgroup( names[2], i[3], true, 1318 true ); 1319 Add( data, entry ); 1320 Add( sortkeys, [ i[2], i[1], Int( entry[4] ) ] ); 1321 if mxstd <> fail then 1322 entry:= ShallowCopy( entry ); 1323 entry[5]:= ShallowCopy( entry[5] ); 1324 if IsString( entry[5][2] ) then 1325 entry[5][2]:= [ entry[5][2], mxstd[1] ]; 1326 else 1327 Add( entry[5][2], mxstd[1] ); 1328 fi; 1329 entry[6]:= Concatenation( "std. ", String( mxstd[2] ) ); 1330 Add( data, entry ); 1331 Add( sortkeys, [ i[2], i[1], Int( entry[4] ), mxstd[2] ] ); 1332 fi; 1333 fi; 1334 od; 1335 fi; 1336 fi; 1337 1338 # If a straight line program is available for the restriction 1339 # to the maximal subgroup of a factor group, 1340 # and if this program can be used also here 1341 # then take it. 1342 for finfo in factgroupinfo do 1343 factgroupname:= finfo[2]; 1344 info:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1345 x -> x[1] = factgroupname ); 1346 factgroupname:= info[2]; 1347 if IsBound( toc.( factgroupname ) ) then 1348 record:= toc.( factgroupname ); 1349 if IsBound( record.maxes ) then 1350 for i in maxext do 1351 facti:= First( record.maxes, fl -> fl[3] = i[3][1] ); 1352 if facti <> fail and ( std = true or i[1] in std ) then 1353 if toc.TocID <> "core" then 1354 private:= UserPreference( "AtlasRep", 1355 "AtlasRepMarkNonCoreData" ); 1356 prvwidth:= Length( private ); 1357 else 1358 private := ""; 1359 fi; 1360 1361 entry:= [ , 1362 private, 1363 String( i[1] ), 1364 AGR.VersionOfSLP( facti[3] ), 1365 [ names[1], i[3], i[1] ] ]; 1366 if Length( i[3] ) = 1 then 1367 entry[5][2]:= i[3][1]; 1368 # No additional kernel generators are needed. 1369 if toc.TocID <> "core" then 1370 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 1371 fi; 1372 else 1373 # We have to specify a program for computing the kernel. 1374 ker:= AtlasProgramInfo( names[1], std, "kernel", finfo[2] ); 1375 if ker <> fail then 1376 kerid:= ker.identifier[2]; 1377 if IsString( kerid ) then 1378 entry[5][2]:= [ entry[5][2][1], kerid ]; 1379 else 1380 entry[5][2]:= [ entry[5][2][1], kerid[1] ]; 1381 fi; 1382 if toc.TocID <> "core" then 1383 entry[5][2][1]:= [ toc.TocID, entry[5][2][1] ]; 1384 fi; 1385 fi; 1386 fi; 1387 Add( data, entry ); 1388 Add( sortkeys, [ i[2], i[1], Int( entry[4] ) ] ); 1389 fi; 1390 od; 1391 fi; 1392 fi; 1393 od; 1394 od; 1395 1396 title:= "maxes"; 1397 if not IsEmpty( data ) then 1398 entry:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1399 x -> x[2] = names[2] ); 1400 if IsBound( entry[3].nrMaxes ) then 1401 title:= "maxes ("; 1402 nrmaxes:= Length( Set( List( sortkeys, x -> x[1] ) ) ); 1403 if nrmaxes = entry[3].nrMaxes then 1404 Append( title, "all " ); 1405 else 1406 Append( title, String( nrmaxes ) ); 1407 Append( title, " out of " ); 1408 fi; 1409 Append( title, String( entry[3].nrMaxes ) ); 1410 Append( title, ")" ); 1411 fi; 1412 1413 SortParallel( sortkeys, data ); 1414 1415 width:= Length( String( sortkeys[ Length( sortkeys ) ][1] ) ); 1416 prvphantom:= RepeatedString( " ", prvwidth ); 1417 1418 for i in [ 1 .. Length( data ) ] do 1419 # Compute the value for the first column (including privacy flag). 1420 maxnr:= sortkeys[i][1]; 1421 line:= String( maxnr, width ); 1422 Append( line, data[i][2] ); 1423 if IsBound( entry[3].structureMaxes ) and 1424 IsBound( entry[3].structureMaxes[ maxnr ] ) then 1425 Append( line, ": " ); 1426 if data[i][2] = "" then 1427 Append( line, prvphantom ); 1428 fi; 1429 Append( line, entry[3].structureMaxes[ maxnr ] ); 1430 fi; 1431 data[i][1]:= line; 1432 data[i][2]:= ""; 1433 od; 1434 fi; 1435 1436 return AGR.CommonDisplayPRG( title, stdavail, data, false ); 1437 end, 1438 1439 # Create the program info from the identifier. 1440 AtlasProgramInfo := function( type, identifier, groupname ) 1441 local filename, i, result, gapname; 1442 1443 # We need only the information about the restriction part, 1444 # not a standardization or kernel generators. 1445 filename:= identifier[2]; 1446 if not IsString( filename ) then 1447 if IsString( filename[1] ) then 1448 filename:= filename[1]; 1449 else 1450 filename:= filename[1][2]; 1451 fi; 1452 fi; 1453 1454 i:= AGR.ParseFilenameFormat( filename, type[2].FilenameFormat ); 1455 if i = fail then 1456 return fail; 1457 fi; 1458 i:= i[5]; 1459 1460 result:= rec( standardization := identifier[3], 1461 identifier := identifier ); 1462 1463 # Set the size if available. 1464 gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1465 pair -> pair[2] = groupname ); 1466 if IsBound( gapname[3].sizesMaxes ) 1467 and IsBound( gapname[3].sizesMaxes[i] ) then 1468 result.size:= gapname[3].sizesMaxes[i]; 1469 fi; 1470 if IsBound( gapname[3].structureMaxes ) and 1471 IsBound( gapname[3].structureMaxes[i] ) then 1472 result.subgroupname:= gapname[3].structureMaxes[i]; 1473 fi; 1474 1475 return result; 1476 end, 1477 1478 # Create the program from the identifier. 1479 AtlasProgram := function( type, identifier, groupname ) 1480 local i, std, result, entry, prog, names, pos, maxstd, info, datadirs, 1481 name, kerprg, gapname; 1482 1483 i:= identifier[2]; 1484 if not IsString( i ) then 1485 i:= i[1]; 1486 if not IsString( i ) then 1487 i:= i[2]; 1488 fi; 1489 fi; 1490 i:= AGR.ParseFilenameFormat( i, type[2].FilenameFormat ); 1491 if i = fail then 1492 return fail; 1493 fi; 1494 i:= i[5]; 1495 std:= identifier[3]; 1496 1497 # The second entry is one of 1498 # - the filename of the program, 1499 # - this filename plus a filename for standardization 1500 # (so we need the *composition* of two programs). 1501 # - this filename plus a filename for kernel generators 1502 # (so we need the *union* of two sets of generators), 1503 if IsString( identifier[2] ) or Length( identifier[2] ) = 1 then 1504 # There is just one program. 1505 result:= AtlasProgramDefault( type, identifier, groupname ); 1506 elif Length( identifier[2] ) = 2 then 1507 # The second entry describes two files. 1508 entry:= identifier[2][1]; 1509 if IsString( entry ) then 1510 prog:= AGR.FileContents( [ [ "dataword", entry ] ], type ); 1511 names:= [ entry ]; 1512 else 1513 prog:= AGR.FileContents( [ entry ], type ); 1514 names:= [ entry[2] ]; 1515 fi; 1516 if prog = fail then 1517 return fail; 1518 fi; 1519 1520 entry:= identifier[2][2]; 1521 if IsString( entry ) then 1522 Add( names, entry ); 1523 else 1524 Add( names, entry[2] ); 1525 entry:= [ entry ]; 1526 fi; 1527 1528 # Decide in which situation we are. 1529 pos:= Position( names[2], '-' ); 1530 if pos <> fail and names[2]{ [ 1 .. pos - 1 ] } 1531 = ReplacedString( names[1], "-", "" ) then 1532 # One program for the restriction, one for the standardization. 1533 type:= First( AGR.DataTypes( "prg" ), x -> x[1] = "maxstd" ); 1534 maxstd:= AtlasProgramDefault( type, [ groupname, entry, std ], 1535 groupname ); 1536 if maxstd = fail then 1537 return fail; 1538 fi; 1539 prog:= CompositionOfStraightLinePrograms( maxstd.program, 1540 prog.program ); 1541 else 1542 # One program for a factor group and some kernel generators 1543 # must be integrated. 1544 type:= First( AGR.DataTypes( "prg" ), x -> x[1] = "kernel" ); 1545 kerprg:= AtlasProgramDefault( type, [ groupname, entry, std ], 1546 groupname ); 1547 if kerprg = fail then 1548 return fail; 1549 fi; 1550 prog:= [ prog.program, kerprg.program ]; 1551 prog:= IntegratedStraightLineProgramExt( prog ); 1552 fi; 1553 result:= rec( program := prog, 1554 standardization := std, 1555 identifier := identifier ); 1556 else 1557 return fail; 1558 fi; 1559 1560 # Set subgroup size and subgroup name if available. 1561 gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1562 pair -> pair[2] = groupname ); 1563 if IsBound( gapname[3].sizesMaxes ) and 1564 IsBound( gapname[3].sizesMaxes[i] ) then 1565 result.size:= gapname[3].sizesMaxes[i]; 1566 fi; 1567 if IsBound( gapname[3].structureMaxes ) and 1568 IsBound( gapname[3].structureMaxes[i] ) then 1569 result.subgroupname:= gapname[3].structureMaxes[i]; 1570 fi; 1571 1572 return result; 1573 end, 1574 1575 # entry: `[ <std>, <maxnr>, <file> ]', 1576 # conditions: `[ "maxes", <maxnr> ]' or `[ "maxes", <maxnr>, <std2> ]' 1577 # or together with `[ "version", <vers> ]' 1578 AccessPRG := function( toc, groupname, std, conditions ) 1579 local std2, version, record, entry, mxstd, info, factgroupinfo, maxext, 1580 finfo, factgroupname, i, istd, ker; 1581 1582 std2:= true; 1583 version:= true; 1584 if not ( Length( conditions ) in [ 2 .. 5 ] and conditions[1] = "maxes" 1585 and IsPosInt( conditions[2] ) ) then 1586 return fail; 1587 elif Length( conditions ) = 3 then 1588 std2:= conditions[3]; 1589 if not IsPosInt( std2 ) then 1590 return fail; 1591 fi; 1592 elif Length( conditions ) = 4 then 1593 if conditions[3] <> "version" then 1594 return fail; 1595 fi; 1596 version:= String( conditions[4] ); 1597 elif Length( conditions ) = 5 then 1598 std2:= conditions[3]; 1599 if not ( IsPosInt( std2 ) and conditions[4] = "version" ) then 1600 return fail; 1601 fi; 1602 version:= String( conditions[5] ); 1603 fi; 1604 1605 if IsBound( toc.( groupname ) ) then 1606 record:= toc.( groupname ); 1607 1608 # If a straight line program for the restriction is available 1609 # then take it. 1610 if IsBound( record.maxes ) then 1611 for entry in record.maxes do 1612 if ( std = true or entry[1] in std ) 1613 and entry[2] = conditions[2] then 1614 if version = true or AGR.VersionOfSLP( entry[3] ) = version then 1615 # Note that the version number refers to the straight line 1616 # program for computing the restriction, not to the program 1617 # for standardizing the result of the restriction. 1618 # (This feature is needed by 'BrowseAtlasInfo'.) 1619 if std2 = true then 1620 # We need not standardize the subgroup generators. 1621 entry:= entry{ [ 3, 1 ] }; 1622 if toc.TocID <> "core" then 1623 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 1624 fi; 1625 return entry; 1626 else 1627 # We have to find a slp for computing *standard* generators 1628 # of the max. subgp., perhaps in another table of contents. 1629 mxstd:= AGR.StandardizeMaximalSubgroup( groupname, 1630 entry[3], std2, true ); 1631 if mxstd <> fail then 1632 entry:= [ [ entry[3], mxstd[1] ], entry[1] ]; 1633 if toc.TocID <> "core" then 1634 entry[1][1]:= [ toc.TocID, entry[1][1] ]; 1635 fi; 1636 return entry; 1637 fi; 1638 fi; 1639 fi; 1640 fi; 1641 od; 1642 fi; 1643 fi; 1644 1645 # If a straight line program is available for the restriction 1646 # to the maximal subgroup of a factor group, 1647 # and if this program can be used also here 1648 # then take it. 1649 # In this case, we cannot return *standard* generators. 1650 # We do not want to support version numbers, 1651 # they would depend on two programs. 1652 if Length( conditions ) <> 2 then 1653 return fail; 1654 fi; 1655 1656 info:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1657 x -> x[2] = groupname ); 1658 if info = fail or not IsBound( info[3].maxext ) 1659 or not IsBound( info[3].factorCompatibility ) then 1660 return fail; 1661 fi; 1662 factgroupinfo:= Filtered( info[3].factorCompatibility, 1663 x -> ( std = true or x[1] in std ) 1664 and x[4] = true ); 1665 maxext:= Filtered( info[3].maxext, 1666 x -> ( std = true or x[1] in std ) 1667 and x[2] = conditions[2] ); 1668 for finfo in factgroupinfo do 1669 factgroupname:= finfo[2]; 1670 info:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1671 x -> x[1] = factgroupname ); 1672 factgroupname:= info[2]; 1673 if IsBound( toc.( factgroupname ) ) then 1674 record:= toc.( factgroupname ); 1675 if IsBound( record.maxes ) then 1676 for i in maxext do 1677 if ForAny( record.maxes, fl -> fl[3] = i[3][1] ) then 1678 entry:= i{ [ 3, 1 ] }; 1679 if Length( entry[1] ) = 1 then 1680 # No additional kernel generators are needed. 1681 entry[1]:= entry[1][1]; 1682 if toc.TocID <> "core" then 1683 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 1684 fi; 1685 return entry; 1686 else 1687 # We have to specify a program for computing the kernel. 1688 if std = true then 1689 ker:= AtlasProgramInfo( AGR.GAPNameAtlasName( groupname ), 1690 "kernel", finfo[2] ); 1691 else 1692 for istd in std do 1693 ker:= AtlasProgramInfo( AGR.GAPNameAtlasName( groupname ), 1694 istd, "kernel", finfo[2] ); 1695 if ker <> fail then 1696 break; 1697 fi; 1698 od; 1699 fi; 1700 if ker <> fail then 1701 entry[1]:= ShallowCopy( entry[1] ); 1702 if IsString( ker.identifier[2] ) then 1703 entry[1][2]:= ker.identifier[2]; 1704 else 1705 entry[1][2]:= ker.identifier[2][1]; 1706 fi; 1707 if toc.TocID <> "core" then 1708 entry[1][1]:= [ toc.TocID, entry[1][1] ]; 1709 fi; 1710 return entry; 1711 fi; 1712 fi; 1713 fi; 1714 od; 1715 fi; 1716 fi; 1717 od; 1718 return fail; 1719 end, 1720 1721 # Maxes are sorted according to their natural position. 1722 SortTOCEntries := entry -> entry[2], 1723 1724 # In addition to the tests in `AGR.TestWordsSLPDefault', 1725 # compute the images in a representation if available, 1726 # and compare the group order with that stored in the 1727 # GAP Character Table Library (if available). 1728 TestWords:= function( tocid, name, file, type, verbose ) 1729 local prog, prg, gens, pos, pos2, maxnr, gapname, storedsize, tbl, 1730 subname, subtbl, std, grp, size; 1731 1732 # Read the program. 1733 if tocid = "core" then 1734 tocid:= "dataword"; 1735 fi; 1736 prog:= AGR.FileContents( [ [ tocid, file ] ], type ); 1737 if prog = fail then 1738 Print( "#E file `", file, "' is corrupted\n" ); 1739 return false; 1740 fi; 1741 1742 # Check consistency. 1743 if prog = fail or not IsInternallyConsistent( prog.program ) then 1744 Print( "#E program `", file, "' not internally consistent\n" ); 1745 return false; 1746 fi; 1747 prg:= prog.program; 1748 1749 # Create a list of trivial generators. 1750 gens:= ListWithIdenticalEntries( 1751 NrInputsOfStraightLineProgram( prg ), () ); 1752 1753 # Run the program. 1754 gens:= ResultOfStraightLineProgram( prg, gens ); 1755 1756 # Compute the position in the `Maxes' list. 1757 pos:= PositionSublist( file, "-max" ); 1758 pos2:= pos + 4; 1759 while file[ pos2 ] <> 'W' do 1760 pos2:= pos2 + 1; 1761 od; 1762 maxnr:= Int( file{ [ pos+4 .. pos2-1 ] } ); 1763 1764 # Fetch a perhaps stored value. 1765 gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 1766 pair -> name = pair[2] ); 1767 if gapname = fail then 1768 Print( "#E problem: no GAP name for `", name, "'\n" ); 1769 return false; 1770 fi; 1771 storedsize:= fail; 1772 if IsBound( gapname[3].sizesMaxes ) and 1773 IsBound( gapname[3].sizesMaxes[ maxnr ] ) then 1774 storedsize:= gapname[3].sizesMaxes[ maxnr ]; 1775 fi; 1776 1777 # Identify the group in the GAP Character Table Library. 1778 tbl:= CharacterTable( gapname[1] ); 1779 if tbl = fail and storedsize = fail then 1780 if verbose then 1781 Print( "#I no character table for `", gapname[1], 1782 "', no check for `", file, "'\n" ); 1783 fi; 1784 return true; 1785 fi; 1786 1787 # Identify the subgroup in the GAP Character Table Library. 1788 if tbl <> fail then 1789 if HasMaxes( tbl ) then 1790 if Length( Maxes( tbl ) ) < maxnr then 1791 Print( "#E program `", file, 1792 "' contradicts `Maxes( ", tbl, " )'\n" ); 1793 return false; 1794 fi; 1795 subname:= Maxes( tbl )[ maxnr ]; 1796 else 1797 subname:= Concatenation( Identifier( tbl ), "M", String( maxnr ) ); 1798 fi; 1799 subtbl:= CharacterTable( subname ); 1800 if IsCharacterTable( subtbl ) then 1801 if storedsize <> fail and storedsize <> Size( subtbl ) then 1802 Print( "#E program `", file, 1803 "' contradicts stored subgroup order'\n" ); 1804 return false; 1805 elif storedsize = fail then 1806 storedsize:= Size( subtbl ); 1807 fi; 1808 elif storedsize = fail then 1809 if verbose then 1810 Print( "#I no character table for `", subname, 1811 "', no check for `", file, "'\n" ); 1812 fi; 1813 return true; 1814 fi; 1815 fi; 1816 if storedsize = fail then 1817 return true; 1818 fi; 1819 1820 # Compute the standardization. 1821 pos2:= pos - 1; 1822 while file[ pos2 ] <> 'G' do 1823 pos2:= pos2-1; 1824 od; 1825 std:= Int( file{ [ pos2+1 .. pos-1 ] } ); 1826 1827 # Get a representation if available, and map the generators. 1828 gapname:= gapname[1]; 1829 gens:= OneAtlasGeneratingSetInfo( gapname, std, 1830 NrMovedPoints, [ 2 .. AGR.Test.MaxTestDegree ], 1831 "contents", [ tocid, "local" ] ); 1832 if gens = fail then 1833 if verbose then 1834 Print( "#I no perm. repres. for `", gapname, 1835 "', no check for `", file, "'\n" ); 1836 fi; 1837 else 1838 gens:= AtlasGenerators( gens ); 1839 grp:= Group( gens.generators ); 1840 if tbl <> fail then 1841 if IsBound( gens.size ) and gens.size <> Size( tbl ) then 1842 Print( "#E wrong size for group`", gapname, "'\n" ); 1843 return false; 1844 fi; 1845 SetSize( grp, Size( tbl ) ); 1846 fi; 1847 gens:= ResultOfStraightLineProgram( prg, gens.generators ); 1848 size:= Size( SubgroupNC( grp, gens ) ); 1849 if size <> storedsize then 1850 Print( "#E program `", file, "' for group of order ", size, 1851 " not ", storedsize, "\n" ); 1852 if subtbl <> fail then 1853 Print( "#E (contradicts character table of `", 1854 Identifier( subtbl ), "')\n" ); 1855 fi; 1856 return false; 1857 fi; 1858 fi; 1859 1860 # No more tests are available. 1861 return true; 1862 end, 1863 1864 # There is only one file. 1865 ReadAndInterpretDefault := paths -> ScanStraightLineProgram( paths[1] ), 1866 ) ); 1867 1868 1869############################################################################# 1870## 1871#D Straight line programs for class representatives 1872## 1873## <#GAPDoc Label="type:classes:format"> 1874## <Mark><M>groupname</M><C>G</C><M>i</M><C>-cclsW</C><M>n</M></Mark> 1875## <Item> 1876## In this case, the file contains a straight line program that returns 1877## a list of conjugacy class representatives of <M>G</M>. 1878## An example is <C>RuG1-cclsW1</C>. 1879## </Item> 1880## <#/GAPDoc> 1881## 1882AGR.DeclareDataType( "prg", "classes", rec( 1883 1884 # `<groupname>G<i>-cclsW<n>' 1885 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 1886 [ "cclsW", IsDigitChar ] ], 1887 [ ParseBackwards, ParseForwards ] ], 1888 1889 # `[ <i>, <filename> ]' 1890 AddFileInfo := function( list, entry, name ) 1891 Add( list, Concatenation( entry{ [ 3 ] }, [ name ] ) ); 1892 return true; 1893 end, 1894 1895 DisplayOverviewInfo := [ "cl", "c", function( conditions ) 1896 local groupname, tocs, std, value, private, toc, record, i, pos, rel; 1897 1898 groupname:= conditions[1][2]; 1899 tocs:= AGR.TablesOfContents( conditions ); 1900 if Length( conditions ) = 1 or 1901 not ( IsInt( conditions[2] ) or IsList( conditions[2] ) ) then 1902 std:= true; 1903 else 1904 std:= conditions[2]; 1905 if IsInt( std ) then 1906 std:= [ std ]; 1907 fi; 1908 fi; 1909 1910 value:= false; 1911 private:= false; 1912 for toc in tocs do 1913 if IsBound( toc.( groupname ) ) then 1914 record:= toc.( groupname ); 1915 if IsBound( record.classes ) and 1916 ( ( std = true and not IsEmpty( record.classes ) ) or 1917 ForAny( record.classes, l -> l[1] in std ) ) then 1918 value:= true; 1919 elif IsBound( record.cyc2ccl ) and IsBound( record.cyclic ) then 1920 for i in record.cyc2ccl do 1921 # Check that for scripts of the form 1922 # `<groupname>G<i>cycW<n>-cclsW<m>', 1923 # a script of the form `<groupname>G<i>-cycW<n>' is available. 1924 pos:= PositionSublist( i[2], "cycW" ); 1925 rel:= Concatenation( i[2]{ [ 1 .. pos-1 ] }, "-", 1926 i[2]{ [ pos .. Position( i[2], '-' ) - 1 ] } ); 1927 if ( std = true or i[1] in std ) and 1928 ForAny( record.cyclic, 1929 x -> x[2] = rel and ( std = true or x[1] in std ) ) then 1930 value:= true; 1931 break; 1932 fi; 1933 od; 1934 fi; 1935 if value then 1936 if toc.TocID <> "core" then 1937 private:= true; 1938 fi; 1939 break; 1940 fi; 1941 fi; 1942 od; 1943 if value then 1944 value:= "+"; 1945 else 1946 value:= ""; 1947 fi; 1948 return [ value, private ]; 1949 end ], 1950 1951 DisplayPRG := function( tocs, names, std, stdavail ) 1952 local data, c2c, cyc, toc, record, private, i, filec2c, filecyc, pos, 1953 rel, match, entry; 1954 1955 data:= []; 1956 1957 # The information can be stored either directly or via two scripts 1958 # in `cyclic' and `cyc2ccl'. 1959 c2c:= []; 1960 cyc:= []; 1961 1962 for toc in tocs do 1963 if IsBound( toc.( names[2] ) ) then 1964 record:= toc.( names[2] ); 1965 if toc.TocID <> "core" then 1966 private:= UserPreference( "AtlasRep", 1967 "AtlasRepMarkNonCoreData" ); 1968 else 1969 private:= ""; 1970 fi; 1971 if IsBound( record.classes ) then 1972 for i in record.classes do 1973 if std = true or i[1] in std then 1974 entry:= [ "", 1975 private, 1976 String( i[1] ), 1977 AGR.VersionOfSLP( i[2] ), 1978 [ names[1], i[2], i[1] ] ]; 1979 if toc.TocID <> "core" then 1980 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 1981 fi; 1982 Add( data, entry ); 1983 fi; 1984 od; 1985 fi; 1986 1987 if IsBound( record.cyc2ccl ) then 1988 for i in record.cyc2ccl do 1989 if std = true or i[1] in std then 1990 entry:= [ i, private ]; 1991 if toc.TocID <> "core" then 1992 entry[3]:= toc.TocID; 1993 fi; 1994 Add( c2c, entry ); 1995 fi; 1996 od; 1997 fi; 1998 1999 if IsBound( record.cyclic ) then 2000 for i in record.cyclic do 2001 if std = true or i[1] in std then 2002 entry:= [ i, private ]; 2003 if toc.TocID <> "core" then 2004 entry[3]:= toc.TocID; 2005 fi; 2006 Add( cyc, entry ); 2007 fi; 2008 od; 2009 fi; 2010 fi; 2011 od; 2012 2013 for i in c2c do 2014 2015 # Check if for scripts of the form `<groupname>G<i>cycW<n>-cclsW<m>', 2016 # a script of the form `<groupname>G<i>-cycW<n>' is available. 2017 filec2c:= i[1][2]; 2018 pos:= PositionSublist( filec2c, "cycW" ); 2019 rel:= Concatenation( filec2c{ [ 1 .. pos-1 ] }, "-", 2020 filec2c{ [ pos .. Position( filec2c, '-' ) - 1 ] } ); 2021 match:= First( cyc, x -> x[1][2] = rel ); 2022 if match <> fail then 2023 private:= ""; 2024 if i[2] <> "" then 2025 private:= i[2]; 2026 elif match[2] <> "" then 2027 private:= match[2]; 2028 fi; 2029 if Length( i ) = 3 then 2030 filec2c:= [ i[3], filec2c ]; 2031 fi; 2032 filecyc:= match[1][2]; 2033 if Length( match ) = 3 then 2034 filecyc:= [ match[3], filecyc ]; 2035 fi; 2036 entry:= [ "(composed)", 2037 private, 2038 String( match[1][1] ), 2039 JoinStringsWithSeparator( AGR.VersionOfSLP( filec2c ), 2040 ", " ), 2041 [ names[1], [ filec2c, filecyc ], match[1][1] ] ]; 2042 Add( data, entry ); 2043 fi; 2044 od; 2045 2046 if ForAny( data, x -> x[1] = "(composed)" ) then 2047 for i in data do 2048 if i[1] = "" then 2049 i[1]:= "(direct)"; 2050 fi; 2051 od; 2052 fi; 2053 2054 return AGR.CommonDisplayPRG( "class repres.", stdavail, data, true ); 2055 end, 2056 2057 # entry: `[ <std>, <file> ]', 2058 # conditions: `[ "classes" ]' 2059 # or together with `[ "version", <vers> ]' 2060 AccessPRG := function( toc, groupname, std, conditions ) 2061 local version, record, entry, toc2, record2, pos, rel, entry2, file2; 2062 2063 if not IsBound( toc.( groupname ) ) then 2064 return fail; 2065 elif Length( conditions ) = 1 and conditions[1] = "classes" then 2066 version:= true; 2067 elif Length( conditions ) = 3 and conditions[1] = "classes" 2068 and conditions[2] = "version" then 2069 version:= String( conditions[3] ); 2070 else 2071 return fail; 2072 fi; 2073 2074 # Check whether there is a program for computing class repres. 2075 record:= toc.( groupname ); 2076 if IsBound( record.classes ) then 2077 for entry in record.classes do 2078 if ( std = true or entry[1] in std ) and 2079 ( version = true or AGR.VersionOfSLP( entry[2] ) = version ) then 2080 entry:= entry{ [ 2, 1 ] }; 2081 if toc.TocID <> "core" then 2082 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 2083 fi; 2084 return entry; 2085 fi; 2086 od; 2087 fi; 2088 2089 # Try to compose the program for computing classes 2090 # from a program for computing repres. of cyclic subgroups 2091 # (in the given table of contents) 2092 # and a program for computing class representatives from the outputs of 2093 # this program (in *any* table of contents). 2094 for toc2 in AGR.TablesOfContents( "all" ) do 2095 if IsBound( toc2.( groupname ) ) then 2096 record2:= toc2.( groupname ); 2097 2098 if IsBound( record.cyclic ) and IsBound( record2.cyc2ccl ) 2099 and version = true then 2100 for entry2 in record2.cyc2ccl do 2101 if std = true or entry2[1] in std then 2102 2103 # Check if for `<groupname>G<i>cycW<n>-cclsW<m>' scripts, 2104 # a script of the form `<groupname>G<i>-cycW<n>' exists. 2105 file2:= entry2[2]; 2106 pos:= PositionSublist( file2, "cycW" ); 2107 rel:= Concatenation( file2{ [ 1 .. pos-1 ] }, "-", 2108 file2{ [ pos .. Position( file2, '-' ) - 1 ] } ); 2109 for entry in record.cyclic do 2110 if entry[2] = rel and ( std = true or entry[1] in std ) then 2111 if toc.TocID <> "core" then 2112 rel:= [ toc.TocID, rel ]; 2113 fi; 2114 if toc.TocID <> "core" then 2115 file2:= [ toc2.TocID, file2 ]; 2116 fi; 2117 return [ [ file2, rel ], entry2[1] ]; 2118 fi; 2119 od; 2120 fi; 2121 od; 2122 fi; 2123 fi; 2124 od; 2125 2126 return fail; 2127 end, 2128 2129 # Create the program info from the identifier. 2130 AtlasProgramInfo := function( type, identifier, groupname ) 2131 local filename; 2132 2133 # If only one file is involved then use the default function. 2134 filename:= identifier[2]; 2135 if IsString( filename ) or Length( filename ) = 1 then 2136 return AtlasProgramInfoDefault( type, identifier, groupname ); 2137 fi; 2138 2139 # Two files are involved. 2140 filename:= identifier[2][1]; 2141 if not IsString( filename ) then 2142 filename:= filename[2]; 2143 fi; 2144 type:= First( AGR.DataTypes( "prg" ), x -> x[1] = "cyc2ccl" ); 2145 if AGR.ParseFilenameFormat( filename, type[2].FilenameFormat ) 2146 = fail then 2147 return fail; 2148 fi; 2149 2150 filename:= identifier[2][2]; 2151 if not IsString( filename ) then 2152 filename:= filename[2]; 2153 fi; 2154 type:= First( AGR.DataTypes( "prg" ), x -> x[1] = "cyclic" ); 2155 if AGR.ParseFilenameFormat( filename, type[2].FilenameFormat ) 2156 = fail then 2157 return fail; 2158 fi; 2159 2160 return rec( standardization := identifier[3], 2161 identifier := identifier ); 2162 end, 2163 2164 # Create the program from the identifier. 2165 AtlasProgram := function( type, identifier, groupname ) 2166 local type1, entry1, filename, type2, entry2, prog1, prog2, prog, 2167 result; 2168 2169 if IsString( identifier[2] ) or Length( identifier[2] ) = 1 then 2170 # The second entry describes one file. 2171 return AtlasProgramDefault( type, identifier, groupname ); 2172 elif Length( identifier[2] ) = 2 then 2173 # The second entry describes two files to be composed. 2174 type1:= First( AGR.DataTypes( "prg" ), x -> x[1] = "cyclic" ); 2175 entry1:= identifier[2][2]; 2176 if IsString( entry1 ) then 2177 filename:= entry1; 2178 entry1:= [ "dataword", entry1 ]; 2179 else 2180 filename:= entry1[2]; 2181 fi; 2182 if AGR.ParseFilenameFormat( filename, type1[2].FilenameFormat ) 2183 = fail then 2184 return fail; 2185 fi; 2186 2187 type2:= First( AGR.DataTypes( "prg" ), x -> x[1] = "cyc2ccl" ); 2188 entry2:= identifier[2][1]; 2189 if IsString( entry2 ) then 2190 filename:= entry2; 2191 entry2:= [ "dataword", entry2 ]; 2192 else 2193 filename:= entry2[2]; 2194 fi; 2195 if AGR.ParseFilenameFormat( filename, type2[2].FilenameFormat ) 2196 = fail then 2197 return fail; 2198 fi; 2199 2200 prog1:= AGR.FileContents( [ entry1 ], type1 ); 2201 if prog1 = fail then 2202 return fail; 2203 fi; 2204 prog2:= AGR.FileContents( [ entry2 ], type2 ); 2205 if prog2 = fail then 2206 return fail; 2207 fi; 2208 2209 prog:= CompositionOfStraightLinePrograms( prog2.program, 2210 prog1.program ); 2211 if prog = fail then 2212 return fail; 2213 fi; 2214 2215 result:= rec( program := prog, 2216 standardization := identifier[3], 2217 identifier := identifier ); 2218 2219 if IsBound( prog2.outputs ) then 2220 # Take the outputs of the last program in the composition. 2221 result.outputs:= prog2.outputs; 2222 fi; 2223 2224 return result; 2225 fi; 2226 2227 return fail; 2228 end, 2229 2230 TestWords := function( tocid, name, file, type, verbose ) 2231 return AGR.TestWordsSLPDefault( tocid, name, file, type, true, verbose ); 2232 end, 2233 2234 # There is only one file. 2235 ReadAndInterpretDefault := paths -> ScanStraightLineProgram( paths[1] ), 2236 ) ); 2237 2238 2239############################################################################# 2240## 2241#D Straight line programs for representatives of cyclic subgroups 2242## 2243## <#GAPDoc Label="type:cyclic:format"> 2244## <Mark><M>groupname</M><C>G</C><M>i</M><C>-cycW</C><M>n</M></Mark> 2245## <Item> 2246## In this case, the file contains a straight line program that returns 2247## a list of representatives of generators 2248## of maximally cyclic subgroups of <M>G</M>. 2249## An example is <C>Co1G1-cycW1</C>. 2250## </Item> 2251## <#/GAPDoc> 2252## 2253AGR.DeclareDataType( "prg", "cyclic", rec( 2254 # `<groupname>G<i>-cycW<n>' 2255 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 2256 [ "cycW", IsDigitChar ] ], 2257 [ ParseBackwards, ParseForwards ] ], 2258 2259 # `[ <i>, <filename> ]' 2260 AddFileInfo := function( list, entry, name ) 2261 Add( list, Concatenation( entry{ [ 3 ] }, [ name ] ) ); 2262 return true; 2263 end, 2264 2265 DisplayOverviewInfo := AGR.DisplayOverviewInfoDefault( "cyc", "c", "cyclic" ), 2266 2267 DisplayPRG := function( tocs, names, std, stdavail ) 2268 local data, toc, record, private, i, entry; 2269 2270 data:= []; 2271 2272 for toc in tocs do 2273 if IsBound( toc.( names[2] ) ) then 2274 record:= toc.( names[2] ); 2275 if IsBound( record.cyclic ) then 2276 if toc.TocID <> "core" then 2277 private:= UserPreference( "AtlasRep", 2278 "AtlasRepMarkNonCoreData" ); 2279 else 2280 private := ""; 2281 fi; 2282 for i in record.cyclic do 2283 if std = true or i[1] in std then 2284 entry:= [ "", 2285 private, 2286 String( i[1] ), 2287 AGR.VersionOfSLP( i[2] ), 2288 [ names[1], i[2], i[1] ] ]; 2289 if toc.TocID <> "core" then 2290 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 2291 fi; 2292 Add( data, entry ); 2293 fi; 2294 od; 2295 fi; 2296 fi; 2297 od; 2298 2299 return AGR.CommonDisplayPRG( "repr. cyc. subg.", stdavail, data, true ); 2300 end, 2301 2302 # entry: `[ <std>, <file> ]', 2303 # conditions: `[ "cyclic" ]' 2304 # or together with `[ "version", <vers> ]' 2305 AccessPRG := function( toc, groupname, std, conditions ) 2306 local version, record, entry; 2307 2308 if not IsBound( toc.( groupname ) ) then 2309 return fail; 2310 elif Length( conditions ) = 1 and conditions[1] = "cyclic" then 2311 version:= true; 2312 elif Length( conditions ) = 3 and conditions[1] = "cyclic" 2313 and conditions[2] = "version" then 2314 version:= String( conditions[3] ); 2315 else 2316 return fail; 2317 fi; 2318 2319 record:= toc.( groupname ); 2320 if IsBound( record.cyclic ) then 2321 for entry in record.cyclic do 2322 if ( std = true or entry[1] in std ) and 2323 ( version = true or AGR.VersionOfSLP( entry[2] ) = version ) then 2324 entry:= entry{ [ 2, 1 ] }; 2325 if toc.TocID <> "core" then 2326 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 2327 fi; 2328 return entry; 2329 fi; 2330 od; 2331 fi; 2332 return fail; 2333 end, 2334 2335 TestWords := function( tocid, name, file, type, verbose ) 2336 return AGR.TestWordsSLPDefault( tocid, name, file, type, true, verbose ); 2337 end, 2338 2339 # There is only one file. 2340 ReadAndInterpretDefault := paths -> ScanStraightLineProgram( paths[1] ), 2341 ) ); 2342 2343 2344############################################################################# 2345## 2346#D Straight line programs for computing class representatives from 2347#D representatives of cyclic subgroups 2348## 2349## <#GAPDoc Label="type:cyc2ccls:format"> 2350## <Mark><M>groupname</M><C>G</C><M>i</M><C>cycW</C><M>n</M><C>-cclsW</C><M>m</M></Mark> 2351## <Item> 2352## In this case, the file contains a straight line program that takes 2353## the return value of the program in the file 2354## <M>groupname</M><C>G</C><M>i</M><C>-cycW</C><M>n</M> 2355## (see above), 2356## and returns a list of conjugacy class representatives of <M>G</M>. 2357## An example is <C>M11G1cycW1-cclsW1</C>. 2358## </Item> 2359## <#/GAPDoc> 2360## 2361AGR.DeclareDataType( "prg", "cyc2ccl", rec( 2362 2363 # `<groupname>G<i>cycW<n>-cclsW<m>' 2364 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar, "cycW", IsDigitChar ], 2365 [ "cclsW", IsDigitChar ] ], 2366 [ ParseBackwards, ParseForwards ] ], 2367 2368 # `[ <i>, <filename> ]' 2369 AddFileInfo := function( list, entry, name ) 2370 Add( list, Concatenation( entry{ [ 3 ] }, [ name ] ) ); 2371 return true; 2372 end, 2373 2374 # entry: `[ <std>, <file> ]', 2375 # conditions: `[ "cyc2ccl" ]' or 2376 # `[ "cyc2ccl", <vers> ]' or 2377 # `[ "cyc2ccl", "version", <version> ]' or 2378 # `[ "cyc2ccl", <vers>, "version", <version> ]' 2379 # where <vers> is the version number of the 'cyc' script 2380 # and <version> is the version number of the program itself 2381 AccessPRG := function( toc, groupname, std, conditions ) 2382 local version, record, versions, entry; 2383 2384 if not IsBound( toc.( groupname ) ) then 2385 return fail; 2386 elif Length( conditions ) = 1 and conditions[1] = "cyc2ccl" then 2387 version:= true; 2388 elif Length( conditions ) = 2 and conditions[1] = "cyc2ccl" then 2389 version:= [ conditions[2], true ]; 2390 elif Length( conditions ) = 3 and conditions[1] = "cyc2ccl" 2391 and conditions[2] = "version" then 2392 version:= [ true, conditions[3] ]; 2393 elif Length( conditions ) = 4 and conditions[1] = "cyc2ccl" 2394 and conditions[3] = "version" then 2395 version:= [ conditions[2], conditions[4] ]; 2396 else 2397 return fail; 2398 fi; 2399 2400 record:= toc.( groupname ); 2401 if IsBound( record.cyc2ccl ) then 2402 for entry in record.cyc2ccl do 2403 if version <> true then 2404 # Note that 'AGR.VersionOfSLP' returns two strings in this case. 2405 versions:= AGR.VersionOfSLP( entry[2] ); 2406 fi; 2407 if ( std = true or entry[1] in std ) and 2408 ( version = true or 2409 ( ( version[1] = true or 2410 String( version[1] ) = versions[1] ) and 2411 ( version[2] = true or 2412 String( version[2] ) = versions[2] ) ) ) then 2413 entry:= entry{ [ 2, 1 ] }; 2414 if toc.TocID <> "core" then 2415 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 2416 fi; 2417 return entry; 2418 fi; 2419 od; 2420 fi; 2421 return fail; 2422 end, 2423 2424 TestWords := function( tocid, name, file, type, verbose ) 2425 return AGR.TestWordsSLPDefault( tocid, name, file, type, true, verbose ); 2426 end, 2427 2428 # There is only one file. 2429 ReadAndInterpretDefault := paths -> ScanStraightLineProgram( paths[1] ), 2430 ) ); 2431 2432 2433############################################################################# 2434## 2435#D Straight line programs for computing kernel generators 2436## 2437## <#GAPDoc Label="type:kernel:format"> 2438## <Mark><M>groupname</M><C>G</C><M>i</M><C>-ker</C><M>factgroupname</M><C>W</C><M>n</M></Mark> 2439## <Item> 2440## In this case, the file contains a straight line program that takes 2441## generators of <M>G</M> w. r. t. the <M>i</M>-th set of 2442## standard generators, 2443## and returns generators of the kernel of an epimorphism 2444## that maps <M>G</M> to a group with <Package>ATLAS</Package>-file name 2445## <M>factgroupname</M>. 2446## An example is <C>2A5G1-kerA5W1</C>. 2447## </Item> 2448## <#/GAPDoc> 2449## 2450AGR.DeclareDataType( "prg", "kernel", rec( 2451 2452 # `<groupname>G<i>-ker<factgroupname>W<n>' 2453 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 2454 [ "ker", IsChar, "W", IsDigitChar ] ], 2455 [ ParseBackwards, ParseBackwardsWithPrefix ] ], 2456 2457 # `[ <i>, <factgroupname>, <filename> ]' 2458 AddFileInfo := function( list, entry, name ) 2459 Add( list, [ entry[3], entry[5], name ] ); 2460 return true; 2461 end, 2462 2463 # no DisplayOverviewInfo function 2464 DisplayPRG := function( tocs, names, std, stdavail ) 2465 local data, gapname, toc, record, private, i, entry; 2466 2467 data:= []; 2468 if AGR.ShowOnlyASCII() then 2469 gapname:= Concatenation( names[1], " -> " ); 2470 else 2471 gapname:= Concatenation( names[1], " → " ); 2472 fi; 2473 2474 for toc in tocs do 2475 if IsBound( toc.( names[2] ) ) then 2476 record:= toc.( names[2] ); 2477 if IsBound( record.kernel ) then 2478 if toc.TocID <> "core" then 2479 private:= UserPreference( "AtlasRep", 2480 "AtlasRepMarkNonCoreData" ); 2481 else 2482 private := ""; 2483 fi; 2484 for i in record.kernel do 2485 if std = true or i[1] in std then 2486 entry:= [ Concatenation( gapname, 2487 AGR.GAPNameAtlasName( i[2] ) ), 2488 private, 2489 String( i[1] ), 2490 AGR.VersionOfSLP( i[3] ), 2491 [ names[1], i[3], i[1] ] ]; 2492 if toc.TocID <> "core" then 2493 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 2494 fi; 2495 Add( data, entry ); 2496 fi; 2497 od; 2498 fi; 2499 fi; 2500 od; 2501 2502 return AGR.CommonDisplayPRG( "kernels", stdavail, data, false ); 2503 end, 2504 2505 # entry: `[ <std>, <descr>, <file> ]', 2506 # conditions: `[ "kernel", <factgroupname> ]' 2507 # or together with `[ "version", <vers> ]' 2508 AccessPRG := function( toc, groupname, std, conditions ) 2509 local version, record, info, entry; 2510 2511 if not IsBound( toc.( groupname ) ) then 2512 return fail; 2513 elif Length( conditions ) = 2 and conditions[1] = "kernel" then 2514 version:= true; 2515 elif Length( conditions ) = 4 and conditions[1] = "kernel" 2516 and conditions[3] = "version" then 2517 version:= String( conditions[4] ); 2518 else 2519 return fail; 2520 fi; 2521 2522 record:= toc.( groupname ); 2523 if IsBound( record.kernel ) then 2524 info:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 2525 x -> x[1] = conditions[2] ); 2526 if info = fail then 2527 return fail; 2528 fi; 2529 info:= info[2]; 2530 2531 for entry in record.kernel do 2532 if ( std = true or entry[1] in std ) and 2533 ( version = true or AGR.VersionOfSLP( entry[3] ) = version ) and 2534 info = entry[2] then 2535 entry:= entry{ [ 3, 1, 2 ] }; 2536 if toc.TocID <> "core" then 2537 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 2538 fi; 2539 return entry; 2540 fi; 2541 od; 2542 fi; 2543 return fail; 2544 end, 2545 2546 TestWords := function( tocid, name, file, type, verbose ) 2547 return AGR.TestWordsSLPDefault( tocid, name, file, type, false, verbose ); 2548 end, 2549 2550 # There is only one file. 2551 ReadAndInterpretDefault := paths -> ScanStraightLineProgram( paths[1] ), 2552 ) ); 2553 2554 2555############################################################################# 2556## 2557#D Straight line programs for standardizing generators of maximal subgroups 2558## 2559## <#GAPDoc Label="type:maxstd:format"> 2560## <Mark><M>groupname</M><C>G</C><M>i</M><C>max</C><M>k</M><C>W</C><M>n</M><C>-</C><M>subgroupname</M><C>G</C><M>j</M><C>W</C><M>m</M></Mark> 2561## <Item> 2562## In this case, the file contains a straight line program that takes 2563## the return value of the program in the file 2564## <M>groupname</M><C>G</C><M>i</M><C>-max</C><M>k</M><C>W</C><M>n</M> 2565## (see above), 2566## which are generators for a group <M>U</M>, say; 2567## <M>subgroupname</M> is a name for <M>U</M>, 2568## and the return value is a list of standard generators for <M>U</M>, 2569## w. r. t. the <M>j</M>-th set of standard generators. 2570## (Of course this implies that the groups in the <M>k</M>-th class of 2571## maximal subgroups of <M>G</M> are isomorphic to the group with name 2572## <M>subgroupname</M>.) 2573## An example is <C>J1G1max1W1-L211G1W1</C>; 2574## the first class of maximal subgroups of the Janko group <M>J_1</M> 2575## consists of groups isomorphic to the linear group <M>L_2(11)</M>, 2576## for which standard generators are defined. 2577## </Item> 2578## <#/GAPDoc> 2579## 2580AGR.DeclareDataType( "prg", "maxstd", rec( 2581 # `<groupname>G<i>max<k>W<n>-<subgroupname>G<j>W<m>' 2582 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar, "max", IsDigitChar, 2583 "W", IsDigitChar ], 2584 [ IsChar, "G", IsDigitChar, "W", IsDigitChar ] ], 2585 [ ParseBackwards, ParseBackwards ] ], 2586 2587 # `[ <i>, <k>, <n>, <subgroupname>, <j>, <filename> ]' 2588 AddFileInfo := function( list, entry, name ) 2589 Add( list, Concatenation( entry{ [ 3, 5, 7, 8, 10 ] }, [ name ] ) ); 2590 return true; 2591 end, 2592 2593 # no DisplayOverviewInfo function 2594 DisplayPRG := function( tocs, names, std, stdavail ) 2595 local data, toc, record, private, i, entry; 2596 2597 data:= []; 2598 2599 for toc in tocs do 2600 if IsBound( toc.( names[2] ) ) then 2601 record:= toc.( names[2] ); 2602 if IsBound( record.maxstd ) then 2603 if toc.TocID <> "core" then 2604 private:= UserPreference( "AtlasRep", 2605 "AtlasRepMarkNonCoreData" ); 2606 else 2607 private := ""; 2608 fi; 2609 for i in record.maxstd do 2610 if std = true or i[1] in std then 2611 entry:= [ Concatenation( "from ", Ordinal( i[2] ), 2612 " max., version ", String( i[3] ), 2613 " to ", 2614 AGR.GAPNameAtlasName( i[4] ), 2615 ", std. ", String( i[5] ) ), 2616 private, 2617 String( i[1] ), 2618 AGR.VersionOfSLP( i[6] ), 2619 [ names[1], i[6], i[1] ] ]; 2620 if toc.TocID <> "core" then 2621 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 2622 fi; 2623 Add( data, entry ); 2624 fi; 2625 od; 2626 fi; 2627 fi; 2628 od; 2629 2630 return AGR.CommonDisplayPRG( "standardizations of maxes", 2631 stdavail, data, false ); 2632 end, 2633 2634 # Check whether ATLAS names are defined. 2635 PostprocessFileInfo := function( toc, record ) 2636 local list, i; 2637 list:= record.maxstd; 2638 for i in [ 1 .. Length( list ) ] do 2639 if ForAll( AtlasOfGroupRepresentationsInfo.GAPnames, 2640 pair -> pair[2] <> list[i][4] ) then 2641 Info( InfoAtlasRep, 3, 2642 "t.o.c. construction: ignoring name `", list[i][6], "'" ); 2643 Unbind( list[i] ); 2644 fi; 2645 od; 2646 if not IsDenseList( list ) then 2647 record.maxstd:= Compacted( list ); 2648 fi; 2649 end, 2650 2651 # entry: `[ <std>, <maxnr>, <vers>, <subgroupname>, <substd>, <file> ]', 2652 # conditions: `[ "maxstd", <maxnr>, <vers>, <substd> ]' 2653 # or together with `[ "version", <vers> ]' 2654 AccessPRG := function( toc, groupname, std, conditions ) 2655 local record, version, entry; 2656 2657 if not IsBound( toc.( groupname ) ) then 2658 return fail; 2659 fi; 2660 record:= toc.( groupname ); 2661 2662 if Length( conditions ) in [ 4, 6 ] and conditions[1] = "maxstd" 2663 and IsBound( record.maxstd ) then 2664 version:= true; 2665 if Length( conditions ) = 6 then 2666 if conditions[5] <> "version" then 2667 return fail; 2668 fi; 2669 version:= String( conditions[6] ); 2670 fi; 2671 for entry in record.maxstd do 2672 if ( std = true or entry[1] in std ) 2673 and conditions[2] = entry[2] 2674 and conditions[3] = entry[3] 2675 and conditions[4] = entry[5] 2676 and ( version = true or 2677 version = Int( AGR.VersionOfSLP( entry[6] ) ) ) then 2678 entry:= entry{ [ 6, 1, 2, 3, 5 ] }; 2679 if toc.TocID <> "core" then 2680 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 2681 fi; 2682 return entry; 2683 fi; 2684 od; 2685 fi; 2686 return fail; 2687 end, 2688 2689 TestWords := function( tocid, name, file, type, verbose ) 2690 return AGR.TestWordsSLPDefault( tocid, name, file, type, false, verbose ); 2691 end, 2692 2693 # There is only one file. 2694 ReadAndInterpretDefault := paths -> ScanStraightLineProgram( paths[1] ), 2695 ) ); 2696 2697 2698############################################################################# 2699## 2700#D Straight line programs for computing images of standard generators 2701#D under outer automorphisms 2702## 2703## <#GAPDoc Label="type:out:format"> 2704## <Mark><M>groupname</M><C>G</C><M>i</M><C>-a</C><M>outname</M><C>W</C><M>n</M></Mark> 2705## <Item> 2706## In this case, the file contains a straight line program that takes 2707## generators of <M>G</M> w. r. t. the <M>i</M>-th set 2708## of standard generators, 2709## and returns the list of their images 2710## under the outer automorphism <M>\alpha</M> of <M>G</M> 2711## given by the name <M>outname</M>; 2712## if this name is empty then <M>\alpha</M> is the unique nontrivial 2713## outer automorphism of <M>G</M>; 2714## if it is a positive integer <M>k</M> then <M>\alpha</M> is a 2715## generator of the unique cyclic order <M>k</M> subgroup of the outer 2716## automorphism group of <M>G</M>; 2717## if it is of the form <C>2_1</C> or <C>2a</C>, 2718## <C>4_2</C> or <C>4b</C>, <C>3_3</C> or <C>3c</C> 2719## <M>\ldots</M> then <M>\alpha</M> 2720## generates the cyclic group of automorphisms induced on <M>G</M> by 2721## <M>G.2_1</M>, <M>G.4_2</M>, <M>G.3_3</M> <M>\ldots</M>; 2722## finally, if it is of the form <M>k</M><C>p</C><M>d</M>, 2723## with <M>k</M> one of the above forms and <M>d</M> an integer then 2724## <M>d</M> denotes the number of dashes 2725## appended to the automorphism described by <M>k</M>; 2726## if <M>d = 1</M> then <M>d</M> can be omitted. 2727## Examples are <C>A5G1-aW1</C>, <C>L34G1-a2_1W1</C>, 2728## <C>U43G1-a2_3pW1</C>, and <C>O8p3G1-a2_2p5W1</C>; 2729## these file names describe the outer order <M>2</M> automorphism of 2730## <M>A_5</M> (induced by the action of <M>S_5</M>) 2731## and the order <M>2</M> automorphisms of 2732## <M>L_3(4)</M>, <M>U_4(3)</M>, and <M>O_8^+(3)</M> 2733## induced by the actions of 2734## <M>L_3(4).2_1</M>, <M>U_4(3).2_2^{\prime}</M>, 2735## and <M>O_8^+(3).2_2^{{\prime\prime\prime\prime\prime}}</M>, 2736## respectively. 2737## </Item> 2738## <#/GAPDoc> 2739## 2740AGR.DeclareDataType( "prg", "out", rec( 2741 # `<groupname>G<i>-a<outname>W<n>' 2742 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 2743 [ "a", IsChar, "W", IsDigitChar ] ], 2744 [ ParseBackwards, ParseBackwardsWithPrefix ] ], 2745 2746 # `[ <i>, <nam>, <filename> ]' 2747 AddFileInfo := function( list, entry, name ) 2748 local std, descr, pos, dashes, order, index; 2749 std:= entry[3]; 2750 descr:= entry[5]; 2751 pos:= Position( descr, 'p' ); 2752 if pos = fail then 2753 dashes:= ""; 2754 pos:= Length( descr ) + 1; 2755 elif pos = Length( descr ) then 2756 dashes:= "'"; 2757 else 2758 dashes:= Int( descr{ [ pos+1 .. Length( descr ) ] } ); 2759 if dashes = fail then 2760 return false; 2761 fi; 2762 dashes:= ListWithIdenticalEntries( dashes, '\'' ); 2763 fi; 2764 descr:= descr{ [ 1 .. pos-1 ] }; 2765 pos:= Position( descr, '_' ); 2766 if pos = fail then 2767 order:= descr; 2768 index:= ""; 2769 else 2770 order:= descr{ [ 1 .. pos-1 ] }; 2771 index:= descr{ [ pos+1 .. Length( descr ) ] }; 2772 fi; 2773 if Int( order ) = fail or Int( index ) = fail then 2774 return false; 2775 elif order = "" then 2776 order:= "2"; 2777 fi; 2778 if index <> "" then 2779 order:= Concatenation( order, "_", index ); 2780 fi; 2781 order:= Concatenation( order, dashes ); 2782 Add( list, [ std, order, name ] ); 2783 return true; 2784 end, 2785 2786 DisplayOverviewInfo := [ "out", "r", function( conditions ) 2787 local groupname, tocs, std, value, private, toc, record, new; 2788 2789 groupname:= conditions[1][2]; 2790 tocs:= AGR.TablesOfContents( conditions ); 2791 if Length( conditions ) = 1 or 2792 not ( IsInt( conditions[2] ) or IsList( conditions[2] ) ) then 2793 std:= true; 2794 else 2795 std:= conditions[2]; 2796 if IsInt( std ) then 2797 std:= [ std ]; 2798 fi; 2799 fi; 2800 2801 value:= [];; 2802 private:= false; 2803 for toc in tocs do 2804 if IsBound( toc.( groupname ) ) then 2805 record:= toc.( groupname ); 2806 if IsBound( record.out ) then 2807 new:= Set( List( Filtered( record.out, 2808 x -> std = true or x[1] in std ), 2809 x -> x[2] ) ); 2810 if toc.TocID <> "core" and not IsEmpty( new ) then 2811 private:= true; 2812 fi; 2813 UniteSet( value, new ); 2814 fi; 2815 fi; 2816 od; 2817 value:= JoinStringsWithSeparator( value, "," ); 2818 return [ value, private ]; 2819 end ], 2820 2821 DisplayPRG := function( tocs, names, std, stdavail ) 2822 local data, toc, record, private, i, entry; 2823 2824 data:= []; 2825 2826 for toc in tocs do 2827 if IsBound( toc.( names[2] ) ) then 2828 record:= toc.( names[2] ); 2829 if IsBound( record.out ) then 2830 if toc.TocID <> "core" then 2831 private:= UserPreference( "AtlasRep", 2832 "AtlasRepMarkNonCoreData" ); 2833 else 2834 private:= ""; 2835 fi; 2836 for i in record.out do 2837 if std = true or i[1] in std then 2838 entry:= [ i[2], 2839 private, 2840 String( i[1] ), 2841 AGR.VersionOfSLP( i[3] ), 2842 [ names[1], i[3], i[1] ] ]; 2843 if toc.TocID <> "core" then 2844 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 2845 fi; 2846 Add( data, entry ); 2847 fi; 2848 od; 2849 fi; 2850 fi; 2851 od; 2852 2853 return AGR.CommonDisplayPRG( "automorphisms", stdavail, data, false ); 2854 end, 2855 2856 # entry: `[ <std>, <autname>, <file> ]', 2857 # conditions: `[ "automorphism", <autname> ]' 2858 # or together with `[ "version", <vers> ]' 2859 AccessPRG := function( toc, groupname, std, conditions ) 2860 local version, record, entry; 2861 2862 if not IsBound( toc.( groupname ) ) then 2863 return fail; 2864 elif Length( conditions ) = 2 and conditions[1] = "automorphism" then 2865 version:= true; 2866 elif Length( conditions ) = 4 and conditions[1] = "automorphism" 2867 and conditions[3] = "version" then 2868 version:= String( conditions[4] ); 2869 else 2870 return fail; 2871 fi; 2872 2873 record:= toc.( groupname ); 2874 if IsBound( record.out ) then 2875 for entry in record.out do 2876 if ( std = true or entry[1] in std ) and 2877 ( version = true or AGR.VersionOfSLP( entry[3] ) = version ) and 2878 entry[2] = conditions[2] then 2879 entry:= entry{ [ 3, 1 ] }; 2880 if toc.TocID <> "core" then 2881 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 2882 fi; 2883 return entry; 2884 fi; 2885 od; 2886 fi; 2887 return fail; 2888 end, 2889 2890 # Create the program info from the identifier. 2891 AtlasProgramInfo := function( type, identifier, groupname ) 2892 local filename, parsed; 2893 2894 filename:= identifier[2]; 2895 if not IsString( filename ) then 2896 filename:= filename[1][2]; 2897 fi; 2898 2899 if IsString( filename ) then 2900 parsed:= AGR.ParseFilenameFormat( filename, type[2].FilenameFormat ); 2901 if parsed <> fail then 2902 return rec( standardization := identifier[3], 2903 identifier := identifier, 2904 autname := parsed[5] ); 2905 fi; 2906 fi; 2907 2908 return fail; 2909 end, 2910 2911 # It would be good to check whether the order of the automorphism 2912 # fits to the name of the script, but the scripts do not describe 2913 # automorphisms of minimal possible order. 2914 # (So the power given by the name of the script is an inner 2915 # automorphism; how could we check this with reasonable effort?) 2916 # Thus we check just whether the name fits to the structure of the 2917 # outer automorphism group and to the order of the automorphism. 2918 # (We copy the relevant part of the code of `AGR.TestWordsSLPDefault' 2919 # into this function.) 2920 TestWords := function( tocid, name, file, type, verbose ) 2921 local filename, prog, prg, gens, gapname, pos, claimedorder, tbl, 2922 outinfo, bound, imgs, order; 2923 2924 # Read the program. 2925 if tocid = "core" then 2926 tocid:= "dataword"; 2927 fi; 2928 prog:= AGR.FileContents( [ [ tocid, file ] ], type ); 2929 if prog = fail then 2930 Print( "#E file `", file, "' is corrupted\n" ); 2931 return false; 2932 fi; 2933 2934 # Check consistency. 2935 if prog = fail or not IsInternallyConsistent( prog.program ) then 2936 Print( "#E program `", file, "' not internally consistent\n" ); 2937 return false; 2938 fi; 2939 prg:= prog.program; 2940 2941 # Create the list of (trivial) generators. 2942 gens:= ListWithIdenticalEntries( NrInputsOfStraightLineProgram( prg ), 2943 () ); 2944 2945 # Run the program. 2946 gens:= ResultOfStraightLineProgram( prg, gens ); 2947 2948 # Get the GAP name of `name'. 2949 gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 2950 pair -> name = pair[2] ); 2951 if gapname = fail then 2952 Print( "#E problem: no GAP name for `", name, "'\n" ); 2953 return false; 2954 fi; 2955 gapname:= gapname[1]; 2956 2957 # Get the order of the automorphism from the filename. 2958 pos:= PositionSublist( file, "-a" ); 2959 claimedorder:= file{ [ pos+2 .. Length( file ) ] }; 2960 pos:= Position( claimedorder, 'W' ); 2961 claimedorder:= claimedorder{ [ 1 .. pos-1 ] }; 2962 pos:= Position( claimedorder, 'p' ); 2963 if pos <> fail then 2964 if not ForAll( claimedorder{ [ pos+1 .. Length( claimedorder ) ] }, 2965 IsDigitChar ) then 2966 Print( "#E wrong number of dashes in `", file, "'\n" ); 2967 return false; 2968 elif claimedorder{ [ pos+1 .. Length( claimedorder ) ] } = "0" then 2969 Print( "#E wrong name `", file, "'\n" ); 2970 return false; 2971 fi; 2972 claimedorder:= claimedorder{ [ 1 .. pos-1 ] }; 2973 fi; 2974 pos:= Position( claimedorder, '_' ); 2975 if pos <> fail then 2976 claimedorder:= claimedorder{ [ 1 .. pos-1 ] }; 2977 fi; 2978 if not ForAll( claimedorder, IsDigitChar ) then 2979 Print( "#E wrong name `", file, "'\n" ); 2980 return false; 2981 fi; 2982 claimedorder:= Int( claimedorder ); 2983 2984 # Get the structure of the automorphism group. 2985 # If this group is cyclic then we compare orders. 2986 tbl:= CharacterTable( gapname ); 2987 if tbl <> fail and IsBound( AGR.HasExtensionInfoCharacterTable ) 2988 and AGR.HasExtensionInfoCharacterTable( tbl ) then 2989 outinfo:= AGR.ExtensionInfoCharacterTable( tbl )[2]; 2990 if outinfo = "" then 2991 Print( "#E automorphism `", file, 2992 "' for group without outer automorphisms\n" ); 2993 return false; 2994 elif outinfo <> "2" and claimedorder = 0 then 2995 Print( "#E automorphism `", file, 2996 "' but the outer automorphism is not unique\n" ); 2997 return false; 2998 elif Int( outinfo ) <> fail and claimedorder <> 0 2999 and Int( outinfo ) mod claimedorder <> 0 then 3000 Print( "#E automorphism `", file, 3001 "' for outer automorphism group ", outinfo, "\n" ); 3002 return false; 3003 fi; 3004 fi; 3005 3006 if claimedorder = 0 then 3007 claimedorder:= 2; 3008 fi; 3009 3010 # Get generators of the group in question. 3011 gens:= OneAtlasGeneratingSetInfo( gapname, 3012 "contents", [ tocid, "local" ] ); 3013 if gens <> fail and tbl <> fail then 3014 gens:= AtlasGenerators( gens ); 3015 if gens <> fail then 3016 gens:= gens.generators; 3017 bound:= Exponent( tbl ) * claimedorder; 3018 3019 # Compute the order of the automorphism. 3020 imgs:= ResultOfStraightLineProgram( prg, gens ); 3021 order:= 1; 3022 while order < bound and imgs <> gens do 3023 imgs:= ResultOfStraightLineProgram( prg, imgs ); 3024 order:= order + 1; 3025 od; 3026 3027 if imgs <> gens then 3028 Print( "#E order ", order, " of automorphism `", file, 3029 "' is larger than ", bound, "\n" ); 3030 return false; 3031 elif order mod claimedorder <> 0 then 3032 Print( "#E order ", order, " of automorphism `", file, 3033 "' not divisible by ", claimedorder, "\n" ); 3034 return false; 3035 fi; 3036 fi; 3037 fi; 3038 3039 return true; 3040 end, 3041 3042 # There is only one file. 3043 ReadAndInterpretDefault := paths -> ScanStraightLineProgram( paths[1] ), 3044 ) ); 3045 3046 3047############################################################################# 3048## 3049#D Straight line programs for switching between different standardizations 3050## 3051## <#GAPDoc Label="type:switch:format"> 3052## <Mark><M>groupname</M><C>G</C><M>i</M><C>-G</C><M>j</M><C>W</C><M>n</M></Mark> 3053## <Item> 3054## In this case, the file contains a straight line program that takes 3055## generators of <M>G</M> w. r. t. the <M>i</M>-th set 3056## of standard generators, and returns standard generators of <M>G</M> 3057## w. r. t. the <M>j</M>-th set of standard generators. 3058## An example is <C>L35G1-G2W1</C>. 3059## </Item> 3060## <#/GAPDoc> 3061## 3062AGR.DeclareDataType( "prg", "switch", rec( 3063 # `<groupname>G<i>-G<j>W<n>' 3064 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 3065 [ "G", IsDigitChar, "W", IsDigitChar ] ], 3066 [ ParseBackwards, ParseForwards ] ], 3067 3068 # `[ <i>, <j>, <filename> ]' 3069 AddFileInfo := function( list, entry, name ) 3070 Add( list, [ entry[3], entry[5], name ] ); 3071 return true; 3072 end, 3073 3074 DisplayPRG := function( tocs, names, std, stdavail ) 3075 local data, toc, record, private, i, entry; 3076 3077 data:= []; 3078 3079 for toc in tocs do 3080 if IsBound( toc.( names[2] ) ) then 3081 record:= toc.( names[2] ); 3082 if IsBound( record.switch ) then 3083 if toc.TocID <> "core" then 3084 private:= UserPreference( "AtlasRep", 3085 "AtlasRepMarkNonCoreData" ); 3086 else 3087 private:= ""; 3088 fi; 3089 for i in record.switch do 3090 if std = true or i[1] in std then 3091 entry:= [ Concatenation( String( i[1] ), " -> ", 3092 String( i[2] ) ), 3093 private, 3094 String( i[1] ), 3095 AGR.VersionOfSLP( i[3] ), 3096 [ names[1], i[3], i[1] ] ]; 3097 if toc.TocID <> "core" then 3098 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 3099 fi; 3100 Add( data, entry ); 3101 fi; 3102 od; 3103 fi; 3104 fi; 3105 od; 3106 3107 return AGR.CommonDisplayPRG( "restandardizations", stdavail, data, false ); 3108 end, 3109 3110 # entry: `[ <std>, <descr>, <file> ]', 3111 # conditions: `[ "restandardize", <std2> ]' 3112 # or together with `[ "version", <vers> ]' 3113 AccessPRG := function( toc, groupname, std, conditions ) 3114 local version, record, entry; 3115 3116 if not IsBound( toc.( groupname ) ) then 3117 return fail; 3118 elif Length( conditions ) = 2 and conditions[1] = "restandardize" then 3119 version:= true; 3120 elif Length( conditions ) = 4 and conditions[1] = "restandardize" 3121 and conditions[3] = "version" then 3122 version:= String( conditions[4] ); 3123 else 3124 return fail; 3125 fi; 3126 record:= toc.( groupname ); 3127 3128 if IsBound( record.switch ) then 3129 for entry in record.switch do 3130 if ( std = true or entry[1] in std ) and 3131 ( version = true or AGR.VersionOfSLP( entry[3] ) = version ) and 3132 conditions[2] = entry[2] then 3133 entry:= entry{ [ 3, 1, 2 ] }; 3134 if toc.TocID <> "core" then 3135 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 3136 fi; 3137 return entry; 3138 fi; 3139 od; 3140 fi; 3141 return fail; 3142 end, 3143 3144 TestWords := function( tocid, name, file, type, verbose ) 3145 return AGR.TestWordsSLPDefault( tocid, name, file, type, false, verbose ); 3146 end, 3147 3148 # There is only one file. 3149 ReadAndInterpretDefault := paths -> ScanStraightLineProgram( paths[1] ), 3150 ) ); 3151 3152 3153############################################################################# 3154## 3155#D Black box programs for finding standard generators 3156## 3157## <#GAPDoc Label="type:find:format"> 3158## <Mark><M>groupname</M><C>G</C><M>i</M><C>-find</C><M>n</M></Mark> 3159## <Item> 3160## <Index Subkey="for finding standard generators">black box program 3161## </Index> 3162## In this case, the file contains a black box program that takes 3163## a group, and returns (if it is successful) a set of standard generators 3164## for <M>G</M>, w. r. t. the <M>i</M>-th standardization. 3165## </Item> 3166## <#/GAPDoc> 3167## 3168AGR.DeclareDataType( "prg", "find", rec( 3169 # `<groupname>G<i>-find<j>' 3170 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 3171 [ "find", IsDigitChar ] ], 3172 [ ParseBackwards, ParseBackwardsWithPrefix ] ], 3173 3174 # `[ <i>, <j>, <filename> ]' 3175 AddFileInfo := function( list, entry, name ) 3176 Add( list, [ entry[3], entry[5], name ] ); 3177 return true; 3178 end, 3179 3180 DisplayOverviewInfo := AGR.DisplayOverviewInfoDefault( "fnd", "c", "find" ), 3181 3182 DisplayPRG := function( tocs, names, std, stdavail ) 3183 local data, toc, record, private, i, entry; 3184 3185 data:= []; 3186 3187 for toc in tocs do 3188 if IsBound( toc.( names[2] ) ) then 3189 record:= toc.( names[2] ); 3190 if IsBound( record.find ) then 3191 if toc.TocID <> "core" then 3192 private:= UserPreference( "AtlasRep", 3193 "AtlasRepMarkNonCoreData" ); 3194 else 3195 private:= ""; 3196 fi; 3197 for i in record.find do 3198 if std = true or i[1] in std then 3199 entry:= [ "", 3200 private, 3201 String( i[1] ), 3202 String( i[2] ), 3203 [ names[1], i[3], i[1] ] ]; 3204 if toc.TocID <> "core" then 3205 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 3206 fi; 3207 Add( data, entry ); 3208 fi; 3209 od; 3210 fi; 3211 fi; 3212 od; 3213 3214 return AGR.CommonDisplayPRG( "std. gen. finder", stdavail, data, true ); 3215 end, 3216 3217 # entry: `[ <std>, <version>, <file> ]', 3218 # conditions: `[ "find" ]' 3219 # or together with `[ "version", <vers> ]' 3220 AccessPRG := function( toc, groupname, std, conditions ) 3221 local version, record, entry; 3222 3223 if not IsBound( toc.( groupname ) ) then 3224 return fail; 3225 elif Length( conditions ) = 1 and conditions[1] = "find" then 3226 version:= true; 3227 elif Length( conditions ) = 3 and conditions[1] = "find" 3228 and conditions[2] = "version" then 3229 version:= String( conditions[3] ); 3230 else 3231 return fail; 3232 fi; 3233 3234 record:= toc.( groupname ); 3235 if IsBound( record.find ) then 3236 for entry in record.find do 3237 if ( std = true or entry[1] in std ) and 3238 ( version = true or AGR.VersionOfSLP( entry[3] ) = version ) then 3239 # the part of the identifier 3240 entry:= entry{ [ 3, 1, 2 ] }; 3241 if toc.TocID <> "core" then 3242 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 3243 fi; 3244 return entry; 3245 fi; 3246 od; 3247 fi; 3248 return fail; 3249 end, 3250 3251 # There is only one file. 3252 ReadAndInterpretDefault := paths -> ScanBBoxProgram( AGR.StringFile( 3253 paths[1] ) ), 3254 3255 # If there is a representation for this group (independent of the 3256 # standardization) then we apply the script, and check whether at least 3257 # the whole group is generated by the result; if also a `check' script 3258 # is available for this standardization then we run it on the result. 3259 TestWords := function( tocid, name, file, type, verbose ) 3260 local prog, prg, gapname, gens, G, res, pos, pos2, std, check; 3261 3262 # Read the program. 3263 if tocid = "core" then 3264 tocid:= "dataword"; 3265 fi; 3266 prog:= AGR.FileContents( [ [ tocid, file ] ], type ); 3267 if prog = fail then 3268 Print( "#E file `", file, "' is corrupted\n" ); 3269 return false; 3270 fi; 3271 prg:= prog.program; 3272 3273 # Get the GAP name of `name'. 3274 gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 3275 pair -> name = pair[2] ); 3276 if gapname = fail then 3277 Print( "#E problem: no GAP name for `", name, "'\n" ); 3278 return false; 3279 fi; 3280 3281 # Get generators of the group in question. 3282 gens:= OneAtlasGeneratingSetInfo( gapname[1], "contents", "local" ); 3283 if gens <> fail then 3284 gens:= AtlasGenerators( gens ); 3285 if gens <> fail then 3286 gens:= gens.generators; 3287 G:= Group( gens ); 3288 if IsBound( gapname[3].size ) then 3289 SetSize( G, gapname[3].size ); 3290 fi; 3291 res:= ResultOfBBoxProgram( prg, G ); 3292 if IsList( res ) and not IsString( res ) then 3293 # Compute the standardization. 3294 pos:= Position( file, '-' ); 3295 pos2:= pos - 1; 3296 while file[ pos2 ] <> 'G' do 3297 pos2:= pos2-1; 3298 od; 3299 std:= Int( file{ [ pos2+1 .. pos-1 ] } ); 3300 check:= AtlasProgram( gapname[1], std, "check" ); 3301 if check <> fail then 3302 if not ResultOfStraightLineDecision( check.program, res ) then 3303 Print( "#E return values of `", file, 3304 "' do not fit to the check file\n" ); 3305 return false; 3306 fi; 3307 fi; 3308 # Check the group order only for permutation groups. 3309 if IsPermGroup( G ) then 3310 if not IsSubset( G, res ) then 3311 Print( "#E return values of `", file, 3312 "' do not lie in the group\n" ); 3313 return false; 3314 elif Size( SubgroupNC( G, res ) ) <> Size( G ) then 3315 Print( "#E return values of `", file, 3316 "' do not generate the group\n" ); 3317 return false; 3318 fi; 3319 fi; 3320 fi; 3321 fi; 3322 fi; 3323 3324 return true; 3325 end, 3326 3327 ) ); 3328 3329 3330############################################################################# 3331## 3332#D Straight line programs for checking standard generators 3333## 3334## <#GAPDoc Label="type:check:format"> 3335## <Mark><M>groupname</M><C>G</C><M>i</M><C>-check</C><M>n</M></Mark> 3336## <Item> 3337## <Index>semi-presentation</Index> 3338## In this case, the file contains a straight line decision that takes 3339## generators of <M>G</M>, and returns <K>true</K> if these generators are 3340## standard generators w. r. t. the <M>i</M>-th 3341## standardization, and <K>false</K> otherwise. 3342## </Item> 3343## <#/GAPDoc> 3344## 3345AGR.DeclareDataType( "prg", "check", rec( 3346 # `<groupname>G<i>-check<j>' 3347 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 3348 [ "check", IsDigitChar ] ], 3349 [ ParseBackwards, ParseBackwardsWithPrefix ] ], 3350 3351 # `[ <i>, <j>, <filename> ]' 3352 AddFileInfo := function( list, entry, name ) 3353 Add( list, [ entry[3], entry[5], name ] ); 3354 return true; 3355 end, 3356 3357 DisplayOverviewInfo := [ "chk", "c", function( conditions ) 3358 local groupname, tocs, std, value, private, toc, record; 3359 3360 groupname:= conditions[1][2]; 3361 tocs:= AGR.TablesOfContents( conditions ); 3362 if Length( conditions ) = 1 or 3363 not ( IsInt( conditions[2] ) or IsList( conditions[2] ) ) then 3364 std:= true; 3365 else 3366 std:= conditions[2]; 3367 if IsInt( std ) then 3368 std:= [ std ]; 3369 fi; 3370 fi; 3371 3372 value:= ""; 3373 private:= false; 3374 for toc in tocs do 3375 if IsBound( toc.( groupname ) ) then 3376 record:= toc.( groupname ); 3377 if ( IsBound( record.check ) and 3378 ForAny( record.check, x -> std = true or x[1] in std ) ) or 3379 ( IsBound( record.pres ) and 3380 ForAny( record.pres, x -> std = true or x[1] in std ) ) then 3381 value:= "+"; 3382 if toc.TocID <> "core" then 3383 private:= true; 3384 fi; 3385 break; 3386 fi; 3387 fi; 3388 od; 3389 return [ value, private ]; 3390 end ], 3391 3392 DisplayPRG := function( tocs, names, std, stdavail ) 3393 local data, toc, record, private, comp, i, entry; 3394 3395 data:= []; 3396 3397 for toc in tocs do 3398 if IsBound( toc.( names[2] ) ) then 3399 record:= toc.( names[2] ); 3400 if toc.TocID <> "core" then 3401 private:= UserPreference( "AtlasRep", 3402 "AtlasRepMarkNonCoreData" ); 3403 else 3404 private:= ""; 3405 fi; 3406 for comp in [ "check", "pres" ] do 3407 if IsBound( record.( comp ) ) then 3408 for i in record.( comp ) do 3409 if std = true or i[1] in std then 3410 entry:= [ Concatenation( "(", comp, ")" ), 3411 private, 3412 String( i[1] ), 3413 String( i[2] ), 3414 [ names[1], i[3], i[1] ] ]; 3415 if toc.TocID <> "core" then 3416 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 3417 fi; 3418 Add( data, entry ); 3419 fi; 3420 od; 3421 fi; 3422 od; 3423 fi; 3424 od; 3425 3426 return AGR.CommonDisplayPRG( "std. gen. checker", stdavail, data, true ); 3427 end, 3428 3429 # entry: `[ <std>, <version>, <file> ]', 3430 # conditions: `[ "check" ]' 3431 # or together with `[ "version", <vers> ]' 3432 AccessPRG := function( toc, groupname, std, conditions ) 3433 local version, record, entry, comp; 3434 3435 if not IsBound( toc.( groupname ) ) then 3436 return fail; 3437 elif Length( conditions ) = 1 and conditions[1] = "check" then 3438 version:= true; 3439 elif Length( conditions ) = 3 and conditions[1] = "check" 3440 and conditions[2] = "version" then 3441 version:= String( conditions[3] ); 3442 else 3443 return fail; 3444 fi; 3445 record:= toc.( groupname ); 3446 3447 for comp in [ "check", "pres" ] do 3448 if IsBound( record.( comp ) ) then 3449 for entry in record.( comp ) do 3450 if ( std = true or entry[1] in std ) and 3451 ( version = true or AGR.VersionOfSLP( entry[3] ) = version ) then 3452 # the part of the identifier 3453 entry:= entry{ [ 3, 1, 2 ] }; 3454 if toc.TocID <> "core" then 3455 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 3456 fi; 3457 return entry; 3458 fi; 3459 od; 3460 fi; 3461 od; 3462 return fail; 3463 end, 3464 3465 TestWords := function( tocid, name, file, type, verbose ) 3466 return AGR.TestWordsSLDDefault( tocid, name, file, type, 3467 [ IsChar, "G", IsDigitChar, "-check", IsDigitChar ], 3468 verbose ); end, 3469 3470 # There is only one file. 3471 ReadAndInterpretDefault := paths -> ScanStraightLineDecision( 3472 AGR.StringFile( paths[1] ) ), 3473 ) ); 3474 3475 3476############################################################################# 3477## 3478#D Straight line decisions representing presentations 3479## 3480## <#GAPDoc Label="type:pres:format"> 3481## <Mark><M>groupname</M><C>G</C><M>i</M><C>-P</C><M>n</M></Mark> 3482## <Item> 3483## <Index>presentation</Index> 3484## In this case, the file contains a straight line decision that takes 3485## some group elements, and returns <K>true</K> if these elements are 3486## standard generators for <M>G</M>, 3487## w. r. t. the <M>i</M>-th standardization, 3488## and <K>false</K> otherwise. 3489## </Item> 3490## <#/GAPDoc> 3491## 3492AGR.DeclareDataType( "prg", "pres", rec( 3493 # `<groupname>G<i>-P<j>' 3494 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 3495 [ "P", IsDigitChar ] ], 3496 [ ParseBackwards, ParseBackwardsWithPrefix ] ], 3497 3498 # `[ <i>, <j>, <filename> ]' 3499 AddFileInfo := function( list, entry, name ) 3500 Add( list, [ entry[3], entry[5], name ] ); 3501 return true; 3502 end, 3503 3504 DisplayOverviewInfo := AGR.DisplayOverviewInfoDefault( "prs", "c", "pres" ), 3505 3506 DisplayPRG := function( tocs, names, std, stdavail ) 3507 local data, toc, record, private, i, entry; 3508 3509 data:= []; 3510 3511 for toc in tocs do 3512 if IsBound( toc.( names[2] ) ) then 3513 record:= toc.( names[2] ); 3514 if IsBound( record.pres ) then 3515 if toc.TocID <> "core" then 3516 private:= UserPreference( "AtlasRep", 3517 "AtlasRepMarkNonCoreData" ); 3518 else 3519 private:= ""; 3520 fi; 3521 for i in record.pres do 3522 if std = true or i[1] in std then 3523 entry:= [ "", 3524 private, 3525 String( i[1] ), 3526 String( i[2] ), 3527 [ names[1], i[3], i[1] ] ]; 3528 if toc.TocID <> "core" then 3529 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 3530 fi; 3531 Add( data, entry ); 3532 fi; 3533 od; 3534 fi; 3535 fi; 3536 od; 3537 3538 return AGR.CommonDisplayPRG( "presentation", stdavail, data, true ); 3539 end, 3540 3541 # entry: `[ <std>, <version>, <file> ]', 3542 # conditions: `[ "presentation" ]' 3543 # or together with `[ "version", <vers> ]' 3544 AccessPRG := function( toc, groupname, std, conditions ) 3545 local version, record, entry; 3546 3547 if not IsBound( toc.( groupname ) ) then 3548 return fail; 3549 elif Length( conditions ) = 1 and conditions[1] = "presentation" then 3550 version:= true; 3551 elif Length( conditions ) = 3 and conditions[1] = "presentation" 3552 and conditions[2] = "version" then 3553 version:= String( conditions[3] ); 3554 else 3555 return fail; 3556 fi; 3557 record:= toc.( groupname ); 3558 3559 if IsBound( record.pres ) then 3560 for entry in record.pres do 3561 if ( std = true or entry[1] in std ) and 3562 ( version = true or AGR.VersionOfSLP( entry[3] ) = version ) then 3563 # the part of the identifier 3564 entry:= entry{ [ 3, 1, 2 ] }; 3565 if toc.TocID <> "core" then 3566 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 3567 fi; 3568 return entry; 3569 fi; 3570 od; 3571 fi; 3572 return fail; 3573 end, 3574 3575 TestWords := function( tocid, name, file, type, verbose ) 3576 return AGR.TestWordsSLDDefault( tocid, name, file, type, 3577 [ IsChar, "G", IsDigitChar, "-P", IsDigitChar ], 3578 verbose ); end, 3579 3580 # There is only one file. 3581 ReadAndInterpretDefault := paths -> ScanStraightLineDecision( 3582 AGR.StringFile( paths[1] ) ), 3583 ) ); 3584 3585 3586############################################################################# 3587## 3588#D Other straight line programs 3589## 3590## <#GAPDoc Label="type:otherscripts:format"> 3591## <Mark><M>groupname</M><C>G</C><M>i</M><C>-X</C><M>descr</M><C>W</C><M>n</M></Mark> 3592## <Item> 3593## In this case, the file contains a straight line program that takes 3594## generators of <M>G</M> w. r. t. the <M>i</M>-th set 3595## of standard generators, 3596## and whose return value corresponds to <M>descr</M>. 3597## This format is used only in private extensions 3598## (see Chapter <Ref Chap="chap:Private Extensions"/>), 3599## such a script can be accessed with <M>descr</M> as the third argument 3600## of <Ref Func="AtlasProgram"/>. 3601## </Item> 3602## <#/GAPDoc> 3603## 3604AGR.DeclareDataType( "prg", "otherscripts", rec( 3605 3606 # `<groupname>G<i>-X<descr>W<n>' 3607 FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], 3608 [ "X", IsChar, "W", IsDigitChar ] ], 3609 [ ParseBackwards, ParseBackwardsWithPrefix ] ], 3610 3611 # `[ <i>, <descr>, <filename> ]' 3612 AddFileInfo := function( list, entry, name ) 3613 Add( list, Concatenation( entry{ [ 3, 5 ] }, [ name ] ) ); 3614 return true; 3615 end, 3616 3617 DisplayPRG := function( tocs, names, std, stdavail ) 3618 local data, toc, record, private, i, entry; 3619 3620 data:= []; 3621 3622 for toc in tocs do 3623 if IsBound( toc.( names[2] ) ) then 3624 record:= toc.( names[2] ); 3625 if IsBound( record.otherscripts ) then 3626 if toc.TocID <> "core" then 3627 private:= UserPreference( "AtlasRep", 3628 "AtlasRepMarkNonCoreData" ); 3629 else 3630 private:= ""; 3631 fi; 3632 for i in record.otherscripts do 3633 if std = true or i[1] in std then 3634 entry:= [ Concatenation( "\"", i[2], "\"" ), 3635 private, 3636 String( i[1] ), 3637 AGR.VersionOfSLP( i[3] ), 3638 [ names[1], i[3], i[1] ] ]; 3639 if toc.TocID <> "core" then 3640 entry[5][2]:= [ [ toc.TocID, entry[5][2] ] ]; 3641 fi; 3642 Add( data, entry ); 3643 fi; 3644 od; 3645 fi; 3646 fi; 3647 od; 3648 3649 return AGR.CommonDisplayPRG( "other scripts", stdavail, data, false ); 3650 end, 3651 3652 # entry: `[ <std>, <descr>, <file> ]', 3653 # conditions: `[ "other", <descr> ]' 3654 # or together with `[ "version", <vers> ]' 3655 AccessPRG := function( toc, groupname, std, conditions ) 3656 local version, record, entry; 3657 3658 if not IsBound( toc.( groupname ) ) then 3659 return fail; 3660 elif Length( conditions ) = 2 and conditions[1] = "other" then 3661 version:= true; 3662 elif Length( conditions ) = 4 and conditions[1] = "other" 3663 and conditions[3] = "version" then 3664 version:= String( conditions[4] ); 3665 else 3666 return fail; 3667 fi; 3668 3669 record:= toc.( groupname ); 3670 if IsBound( record.otherscripts ) then 3671 for entry in record.otherscripts do 3672 if ( std = true or entry[1] in std ) and 3673 ( version = true or AGR.VersionOfSLP( entry[3] ) = version ) and 3674 entry[2] = conditions[2] then 3675 entry:= entry{ [ 3, 1 ] }; 3676 if toc.TocID <> "core" then 3677 entry[1]:= [ [ toc.TocID, entry[1] ] ]; 3678 fi; 3679 return entry; 3680 fi; 3681 od; 3682 fi; 3683 return fail; 3684 end, 3685 3686 TestWords := function( tocid, name, file, type, verbose ) 3687 return AGR.TestWordsSLPDefault( tocid, name, file, type, false, verbose ); 3688 end, 3689 3690 # There is only one file. 3691 ReadAndInterpretDefault := paths -> ScanStraightLineProgram( paths[1] ), 3692 ) ); 3693 3694 3695############################################################################# 3696## 3697## Read the known tables of contents, 3698## as given by the user preference "AtlasRepTOCData". 3699## 3700## Note that the current file gets notified via 3701## 'DeclareAutoreadableVariables', 3702## because we want to delay the evaluation of the data. 3703## 3704## We cannot read the tables of contents in 'read.g' because this would 3705## trigger that 'gap/types.g' and then 'atlasprm.json' etc. are read. 3706## This would not work because some functions are not yet available in this 3707## situation. 3708## 3709## (A notification of the "internal" extension in test mode is contained 3710## in the test file 'tst/atlasrep.tst'.) 3711## 3712AGR.EvaluateTOC:= function() 3713 local entry, pos, id, filename; 3714 3715 for entry in UserPreference( "AtlasRep", "AtlasRepTOCData" ) do 3716 pos:= Position( entry, '|' ); 3717 if pos <> fail then 3718 id:= entry{ [ 1 .. pos-1 ] }; 3719 filename:= entry{ [ pos+1 .. Length( entry ) ] }; 3720 AtlasOfGroupRepresentationsNotifyData( filename, id ); 3721 fi; 3722 od; 3723end; 3724 3725AGR.EvaluateTOC(); 3726 3727 3728############################################################################# 3729## 3730## For backwards compatibility, we set the components of the global record 3731## 'AtlasOfGroupRepresentationsInfo' that were used up to version 1.5.1 3732## of the package, for specifying user preferences. 3733## Note that the values of the "real" user preferences 3734## are relevant for setting the record components, 3735## modifying the record components does *not* affect these user preferences. 3736## 3737## (We cannot move the code to 'obsolete.gi' because then 'types.g' would 3738## be read too early.) 3739## 3740if UserPreference( "gap", "ReadObsolete" ) <> false then 3741 AtlasOfGroupRepresentationsInfo.SetComponentsOfUserParameters:= function() 3742 local url, pos, wget; 3743 3744 AtlasOfGroupRepresentationsInfo.remote:= UserPreference( "AtlasRep", 3745 "AtlasRepAccessRemoteFiles" ); 3746 3747 url:= First( AtlasOfGroupRepresentationsInfo.notified, 3748 r -> r.ID = "core" ).DataURL; 3749 if 7 < Length( url ) and 3750 LowercaseString( url{ [ 1 .. 7 ] } ) = "http://" then 3751 url:= url{ [ 8 .. Length( url ) ] }; 3752 fi; 3753 pos:= Position( url, '/' ); 3754 AtlasOfGroupRepresentationsInfo.servers:= [ 3755 [ url{ [ 1 .. pos - 1 ] }, url{ [ pos+1 .. Length( url ) ] } ] ]; 3756 3757 wget:= UserPreference( "AtlasRep", "FileTransferTool" ); 3758 if wget = "wget" then 3759 AtlasOfGroupRepresentationsInfo.wget:= true; 3760 elif wget = "io" then 3761 AtlasOfGroupRepresentationsInfo.wget:= false; 3762 else 3763 AtlasOfGroupRepresentationsInfo.wget:= "prefer IO to wget"; 3764 fi; 3765 3766 AtlasOfGroupRepresentationsInfo.compress:= UserPreference( "AtlasRep", 3767 "CompressDownloadedMeatAxeFiles" ); 3768 3769 AtlasOfGroupRepresentationsInfo.displayFunction:= EvalString( 3770 UserPreference( "AtlasRep", "DisplayFunction" ) ); 3771 3772 AtlasOfGroupRepresentationsInfo.markprivate:= UserPreference( "AtlasRep", 3773 "AtlasRepMarkNonCoreData" ); 3774 3775 end; 3776 3777 AtlasOfGroupRepresentationsInfo.SetComponentsOfUserParameters(); 3778fi; 3779 3780 3781############################################################################# 3782## 3783#E 3784 3785