1############################################################################# 2## 3#W types.gi 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 functions for administrating 8## the data types used in the ATLAS of Group Representations. 9## 10 11 12############################################################################# 13## 14#F TOCEntryStringDefault( <typename>, <entry> ) 15## 16BindGlobal( "TOCEntryStringDefault", function( typename, entry ) 17 local list, name, pos, info, crc; 18 19 list:= AtlasOfGroupRepresentationsInfo.filenames; 20 name:= entry[ Length( entry ) ]; 21 pos:= PositionSorted( list, [ name ] ); 22 if pos <= Length( list ) and list[ pos ][1] = name then 23 entry:= list[ pos ]; 24 if Length( entry ) < 4 then 25 # There is no crc value yet. 26 # If the file is available locally then compute the value, 27 # otherwise leave it out. 28 info:= AtlasOfGroupRepresentationsLocalFilename( [ [ entry[3], entry[1] ] ], typename ); 29 info:= First( info, l -> l[2][1][2] = true ); 30 if info <> fail then 31 crc:= CrcFile( info[2][1][1] ); 32 else 33 crc:= fail; 34 fi; 35 else 36 crc:= entry[4]; 37 fi; 38 info:= Concatenation( "\"", typename, "\",\"", entry[2], "\"" ); 39 if crc <> fail then 40 Append( info, Concatenation( ",[", String( crc ), "]" ) ); 41 fi; 42 return info; 43 else 44 return fail; 45 fi; 46end ); 47 48 49############################################################################# 50## 51#F AGR.DisplayOverviewInfoDefault( <dispname>, <align>, <compname> ) 52## 53AGR.DisplayOverviewInfoDefault:= function( dispname, align, compname ) 54 return [ dispname, align, function( conditions ) 55 local groupname, tocs, std, value, private, toc, record, new; 56 57 groupname:= conditions[1][2]; 58 tocs:= AGR.TablesOfContents( conditions ); 59 if Length( conditions ) = 1 or 60 not ( IsInt( conditions[2] ) or IsList( conditions[2] ) ) then 61 std:= true; 62 else 63 std:= conditions[2]; 64 if IsInt( std ) then 65 std:= [ std ]; 66 fi; 67 fi; 68 69 value:= false; 70 private:= false; 71 for toc in tocs do 72 if IsBound( toc.( groupname ) ) then 73 record:= toc.( groupname ); 74 if IsBound( record.( compname ) ) then 75 new:= ForAny( record.( compname ), 76 x -> std = true or x[1] in std ); 77 if toc.TocID <> "core" and new then 78 private:= true; 79 fi; 80 value:= value or new; 81 fi; 82 fi; 83 od; 84 if value then 85 value:= "+"; 86 else 87 value:= ""; 88 fi; 89 return [ value, private ]; 90 end ]; 91 end; 92 93 94############################################################################# 95## 96#F AGR.TestWordsSLPDefault( <tocid>, <name>, <file>, <type>, <outputs>, 97#F <verbose> ) 98## 99## For the straight line program that is returned by 100## <Ref Func="AGR.FileContents"/> when this is called 101## with the first four arguments, 102## it is checked that it is internally consistent and that it can be 103## evaluated at the right number of arguments. 104## If the argument <A>outputs</A> is <K>true</K> then it is additionally 105## checked that the result record has a component <C>outputs</C>, 106## a list whose length equals the number of outputs of the program. 107## (The argument <A>verbose</A> is currently not used, 108## in other <C>TestWords</C> functions the value <K>true</K> triggers that 109## more statements may be printed than just error messages. 110## 111AGR.TestWordsSLPDefault:= function( tocid, name, file, type, outputs, verbose ) 112 local filename, prog, prg, gens; 113 114 # Read the program. 115 if tocid = "core" then 116 tocid:= "dataword"; 117 fi; 118 prog:= AGR.FileContents( [ [ tocid, file ] ], type ); 119 if prog = fail then 120 Print( "#E file `", file, "' is corrupted\n" ); 121 return false; 122 fi; 123 124 # Check consistency. 125 if prog = fail or not IsInternallyConsistent( prog.program ) then 126 Print( "#E program `", file, "' not internally consistent\n" ); 127 return false; 128 fi; 129 prg:= prog.program; 130 131 # Create the list of (trivial) generators. 132 gens:= ListWithIdenticalEntries( NrInputsOfStraightLineProgram( prg ), 133 () ); 134 135 # Run the program. 136 gens:= ResultOfStraightLineProgram( prg, gens ); 137 138 # If the script computes class representatives then 139 # check whether there is an `outputs' component of the right length. 140 if outputs = true then 141 if not IsBound( prog.outputs ) then 142 Print( "#E program `", file, "' without component `outputs'\n" ); 143 return false; 144 elif Length( prog.outputs ) <> Length( gens ) then 145 Print( "#E program `", file, "' with wrong number of `outputs'\n" ); 146 return false; 147 fi; 148 fi; 149 150 return true; 151 end; 152 153 154############################################################################# 155## 156#F AGR.TestWordsSLDDefault( <tocid>, <name>, <file>, <type>, <format>, 157#F <verbose> ) 158## 159## For the straight line decision that is returned by 160## <Ref Func="AGR.FileContents"/> when this is called 161## with the same arguments, 162## it is checked that it is internally consistent and that it can be 163## evaluated in all relevant representations. 164## 165AGR.TestWordsSLDDefault:= function( tocid, name, file, type, format, verbose ) 166 local filename, prog, result, gapname, orderfunc, std, entry, gens; 167 168 # Read the program. 169 if tocid = "core" then 170 tocid:= "dataword"; 171 fi; 172 prog:= AGR.FileContents( [ [ tocid, file ] ], type ); 173 if prog = fail then 174 Print( "#E file `", file, "' is corrupted\n" ); 175 return false; 176 fi; 177 178 # Check consistency. 179 if not IsInternallyConsistent( prog.program ) then 180 Print( "#E program `", file, "' not internally consistent\n" ); 181 return false; 182 fi; 183 prog:= prog.program; 184 185 # Evaluate the program in *all* relevant representations. 186 result:= true; 187 gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 188 pair -> name = pair[2] ); 189 if gapname = fail then 190 Print( "#E problem: no GAP name for `", name, "'\n" ); 191 return false; 192 fi; 193 gapname:= gapname[1]; 194 195 orderfunc:= function( g ) 196 if IsMatrix( g ) then 197 # We know that the group elements that occur have small order. 198 return OrderMatTrial( g, 10000 ); 199 else 200 return Order( g ); 201 fi; 202 end; 203 204 std:= ParseBackwards( file, format ); 205 std:= std[3]; 206 for entry in AllAtlasGeneratingSetInfos( gapname, std, 207 "contents", "local" ) do 208 gens:= AtlasGenerators( entry.identifier ); 209 if gens <> fail then 210 if not ResultOfStraightLineDecision( prog, gens.generators, 211 orderfunc ) then 212 Print( "#E program `", file, "' does not fit to\n#E `", 213 entry.identifier, "'\n" ); 214 result:= false; 215 fi; 216 fi; 217 od; 218 219 return result; 220 end; 221 222 223############################################################################# 224## 225#F AGR.TestFileHeadersDefault( <tocid>, <groupname>, <entry>, <type>, <dim>, 226#F <special> ) 227## 228## This function can be used only if the last entry in the list <entry> is 229## the name of *one* file that contains a list of matrices. 230## 231AGR.TestFileHeadersDefault:= function( tocid, groupname, entry, type, dim, special ) 232 local filename, cand, name, mats; 233 234 if tocid = "core" then 235 tocid:= "datagens"; 236 fi; 237 238 # Try to read the file. 239 dim:= [ dim, dim ]; 240 filename:= entry[ Length( entry ) ]; 241 cand:= AtlasOfGroupRepresentationsLocalFilename( 242 [ [ tocid, filename ] ], type ); 243 if not ( Length( cand ) = 1 and ForAll( cand[1][2], x -> x[2] ) ) then 244 return true; 245 fi; 246 mats:= AGR.FileContents( [ [ tocid, filename ] ], type ); 247 248 # Check that the file contains a list of matrices of the right dimension. 249 if mats = fail then 250 Print( "#E filename `", filename, "' not found\n" ); 251 return false; 252 elif not ( IsList( mats ) and ForAll( mats, IsMatrix ) ) then 253 Print( "#E file `", filename, 254 "' does not contain a list of matrices\n" ); 255 return false; 256 elif ForAny( mats, mat -> DimensionsMat( mat ) <> dim ) then 257 Print( "#E matrices in `",filename,"' have wrong dimensions\n" ); 258 return false; 259 fi; 260 261 # Check the entries. 262 special:= special( entry, mats, filename ); 263 if IsString( special ) then 264 Print( "#E ", special, "\n" ); 265 return false; 266 fi; 267 268 return true; 269 end; 270 271 272############################################################################# 273## 274#F AGR.TestFilesMTX( <tocid>, <groupname>, <entry>, <type> ) 275## 276AGR.TestFilesMTX:= function( tocid, groupname, entry, type ) 277 local result, filename; 278 279 if tocid = "core" then 280 tocid:= "datagens"; 281 fi; 282 283 # Read the file(s). 284 result:= true; 285 for filename in entry[ Length( entry ) ] do 286 if AGR.FileContents( [ [ tocid, filename ] ], type ) = fail then 287 Print( "#E file `", filename, "' corrupted\n" ); 288 result:= false; 289 fi; 290 od; 291 292 return result; 293 end; 294 295 296############################################################################# 297## 298#F AtlasProgramInfoDefault( <type>, <identifier>, <groupname> ) 299## 300## This function can be used only in the case that the second entry in 301## <identifier> is either one filename or a list of length one, 302## such that the unique entry is a list of a t.o.c. identifier and 303## a filename. 304## 305BindGlobal( "AtlasProgramInfoDefault", 306 function( type, identifier, groupname ) 307 local filename; 308 309 filename:= identifier[2]; 310 if not IsString( filename ) then 311 filename:= filename[1][2]; 312 fi; 313 314 if IsString( filename ) and 315 AGR.ParseFilenameFormat( filename, type[2].FilenameFormat ) 316 <> fail then 317 return rec( standardization := identifier[3], 318 identifier := identifier ); 319 fi; 320 321 return fail; 322end ); 323 324 325############################################################################# 326## 327#F AtlasProgramDefault( <type>, <identifier>, <groupname> ) 328## 329## This function can be used only in the case that the second entry in 330## <identifier> is either one filename or a list of length one, 331## such that the unique entry is a list of a t.o.c. identifier and 332## a filename. 333## 334BindGlobal( "AtlasProgramDefault", function( type, identifier, groupname ) 335 local filename, tocid, prog, result; 336 337 filename:= identifier[2]; 338 if IsString( filename ) then 339 tocid:= "dataword"; 340 else 341 tocid:= filename[1][1]; 342 filename:= filename[1][2]; 343 fi; 344 345 if IsString( filename ) and 346 AGR.ParseFilenameFormat( filename, type[2].FilenameFormat ) 347 <> fail then 348 prog:= AGR.FileContents( [ [ tocid, filename ] ], type ); 349 if prog <> fail then 350 result:= rec( program := prog.program, 351 standardization := identifier[3], 352 identifier := identifier ); 353 if IsBound( prog.outputs ) then 354 result.outputs:= prog.outputs; 355 fi; 356 return result; 357 fi; 358 fi; 359 360 return fail; 361end ); 362 363 364############################################################################# 365## 366#F AGR.CheckOneCondition( <func>[, <detect>], <condlist> ) 367## 368## This function always returns `true'; it changes <condlist> in place. 369## 370AGR.CheckOneCondition:= function( arg ) 371 local func, detect, condlist, pos, val; 372 373 func:= arg[1]; 374 if Length( arg ) = 2 then 375 condlist:= arg[2]; 376 else 377 detect:= arg[2]; 378 condlist:= arg[3]; 379 fi; 380 pos:= Position( condlist, func ); 381 while pos <> fail do 382 if Length( arg ) = 2 then 383 # Support `IsPermGroup' etc. *without* subsequent `true'. 384 Unbind( condlist[ pos ] ); 385 else 386 if pos = Length( condlist ) then 387 # Keep `condlist' unchanged. 388 # If there is a call without <detect> then it will remove the entry. 389 return true; 390 fi; 391 val:= condlist[ pos+1 ]; 392 if ( IsString( val ) and detect( val ) ) 393 or ( not IsList( val ) and detect( val ) ) 394 or ( IsList( val ) and ForAny( val, detect ) ) then 395 Unbind( condlist[ pos ] ); 396 Unbind( condlist[ pos+1 ] ); 397 fi; 398 fi; 399 pos:= Position( condlist, func, pos ); 400 od; 401 return true; 402 end; 403 404 405############################################################################# 406## 407#F AGR.DeclareDataType( <kind>, <name>, <record> ) 408## 409## Check that the necessary components are bound, 410## and add default values if necessary. 411## 412AGR.DeclareDataType:= function( kind, name, record ) 413 local types, nam; 414 415 # Check that the type does not yet exist. 416 types:= AtlasOfGroupRepresentationsInfo.TableOfContents.types; 417 if ForAny( types.( kind ), x -> x[1] = name ) then 418 Error( "data type <name> exists already" ); 419 fi; 420 record:= ShallowCopy( record ); 421 422 # Check mandatory components. 423 for nam in [ "FilenameFormat", "AddFileInfo", 424 "ReadAndInterpretDefault" ] do 425 if not IsBound( record.( nam ) ) then 426 Error( "the component `", nam, "' must be bound in <record>" ); 427 fi; 428 od; 429 430 # Add default components. 431 if not IsBound( record.DisplayOverviewInfo ) then 432 record.DisplayOverviewInfo:= fail; 433 fi; 434 if not IsBound( record.TOCEntryString ) then 435 record.TOCEntryString := TOCEntryStringDefault; 436 fi; 437 if not IsBound( record.PostprocessFileInfo ) then 438 record.PostprocessFileInfo := Ignore; 439 fi; 440 if kind = "rep" then 441 for nam in [ "DisplayGroup", "AddDescribingComponents" ] do 442 if not IsBound( record.( nam ) ) then 443 Error( "the component `", nam, "' must be bound in <record>" ); 444 fi; 445 od; 446 if not IsBound( record.AccessGroupCondition ) then 447 record.AccessGroupCondition := ReturnFalse; 448 fi; 449 if not IsBound( record.TestFileHeaders ) then 450 record.TestFileHeaders := ReturnTrue; 451 fi; 452 if not IsBound( record.TestFiles ) then 453 record.TestFiles := ReturnTrue; 454 fi; 455 elif kind = "prg" then 456 if not IsBound( record.DisplayPRG ) then 457 record.DisplayPRG := function( tocs, names, std, stdavail ) 458 return []; end; 459 fi; 460 if not IsBound( record.AccessPRG ) then 461 record.AccessPRG := function( toc, groupname, std, conditions ) 462 return fail; 463 end; 464 fi; 465 if not IsBound( record.AtlasProgram ) then 466 record.AtlasProgram := AtlasProgramDefault; 467 fi; 468 if not IsBound( record.AtlasProgramInfo ) then 469 record.AtlasProgramInfo := AtlasProgramInfoDefault; 470 fi; 471 else 472 Error( "<kind> must be one of \"rep\", \"prg\"" ); 473 fi; 474 475 # Add the pair. 476 Add( types.( kind ), [ name, record, kind ] ); 477 478 # Clear the cache. 479 types.cache:= []; 480 end; 481 482 483############################################################################# 484## 485#F AGR.DataTypes( <kind1>[, <kind2>] ) 486## 487## returns the list of pairs <C>[ <A>name</A>, <A>record</A> ]</C> 488## as declared for the kinds in question. 489## 490AGR.DataTypes:= function( arg ) 491 local types, result, kind; 492 493 types:= AtlasOfGroupRepresentationsInfo.TableOfContents.types; 494 result:= First( types.cache, x -> x[1] = arg ); 495 496 if result = fail then 497 result:= []; 498 for kind in arg do 499 if IsBound( types.( kind ) ) then 500 Append( result, types.( kind ) ); 501 fi; 502 od; 503 result:= [ arg, result ]; 504 Add( types.cache, result ); 505 fi; 506 507 return result[2]; 508 end; 509 510 511############################################################################# 512## 513#F AGR.VersionOfSLP( <filename> ) 514## 515## Note that 'cyc2ccl' scripts involve *two* version numbers, 516## the one of the corresponding 'cyc' script and the one of their own. 517## We return the *list* of these version numbers in this case. 518## 519AGR.VersionOfSLP:= function( filename ) 520 local len, pos, pos2; 521 522 if not IsString( filename ) then 523 # a list of one or more file descriptions, take the first of them 524 filename:= filename[1]; 525 if not IsString( filename ) then 526 # a file from a private extension 527 filename:= filename[2]; 528 fi; 529 fi; 530 531 len:= Length( filename ); 532 pos:= len; 533 while IsDigitChar( filename[ pos ] ) do 534 pos:= pos - 1; 535 od; 536 if 6 < pos and filename{ [ pos-5 .. pos ] } = "-cclsW" then 537 # Check whether we are in the case of a 'cyc2ccls' script. 538 pos2:= pos-6; 539 while IsDigitChar( filename[ pos2 ] ) do 540 pos2:= pos2 - 1; 541 od; 542 if 4 < pos2 and filename{ [ pos2-3 .. pos2 ] } = "cycW" then 543 return [ filename{ [ pos2+1 .. pos-6 ] }, 544 filename{ [ pos+1 .. len ] } ]; 545 fi; 546 fi; 547 548 return filename{ [ pos+1 .. len ] }; 549 end; 550 551 552############################################################################# 553## 554#F AGR.StandardizeMaximalSubgroup( <groupname>, <maxslpname>, <std>, <vers> ) 555## 556## returns <K>fail</K> or the list 557## <C>[ <A>filename</A>, <A>std</A> ]</C> 558## where a straight line program for standardizing the generators of the 559## maximal subgroup given by <maxslpname> can be found in the file 560## <A>filename</A> (which is either a string or a list containng the 561## name of the table of contents and the actual filename. 562## The standardization number of the result is <A>std</A>. 563## One can prescribe this standardization via a list or integer <std>, 564## otherwise one can enter <K>true</K> as <std>. 565## If <A>vers</A> is <K>true</K> then any version of the program is taken, 566## otherwise only a version in the list <A>vers</A>. 567## 568AGR.StandardizeMaximalSubgroup:= function( groupname, maxslpname, std, vers ) 569 local prefix, toc, r, l, filename; 570 571 if IsInt( std ) then 572 std:= [ std ]; 573 fi; 574 if IsInt( vers ) then 575 vers:= [ vers ]; 576 fi; 577 prefix:= ReplacedString( maxslpname, "-", "" ); 578 for toc in AGR.TablesOfContents( "all" ) do 579 if IsBound( toc.( groupname ) ) then 580 r:= toc.( groupname ); 581 if IsBound( r.maxstd ) then 582 for l in r.maxstd do 583 filename:= l[6]; 584 if l[6]{ [ 1 .. Position( filename, '-' ) - 1 ] } = prefix and 585 ( std = true or l[5] in std ) and 586 ( vers = true or AGR.VersionOfSLP( filename ) in vers ) then 587 if toc.TocID <> "core" then 588 return [ [ toc.TocID, filename], l[5] ]; 589 else 590 return [ filename, l[5] ]; 591 fi; 592 fi; 593 od; 594 fi; 595 fi; 596 od; 597 598 return fail; 599 end; 600 601 602############################################################################# 603## 604#F AGR.CommonDisplayPRG( <title>, <stdavail>, <data>, <onelineonly> ) 605## 606## This is a utility for the 'DisplayPRG' functions of "prg" types. 607## 608## <data> is a matrix whose columns correspond to 609## 1. the values to be shown in the first column 610## 2. the privacy flags 611## 3. the standardizations, 612## 4. the versions, 613## 5. the identifiers, 614## 6. (optional) additional information for the second column 615## 616AGR.CommonDisplayPRG:= function( title, stdavail, data, onelineonly ) 617 local res, entry, line, private; 618 619 res:= []; 620 621 if Length( data ) = 0 then 622 return res; 623 elif Length( data ) = 1 and onelineonly then 624 # Show just one line. 625 # (If there is only one line then showing version info makes no sense.) 626 entry:= data[1]; 627 if 1 < Length( stdavail ) then 628 Add( res, Concatenation( "(for std. generators ", entry[3], ")" ) ); 629 fi; 630 if IsBound( entry[6] ) then 631 Add( res, Concatenation( "(", entry[6], ")" ) ); 632 fi; 633 return [ Concatenation( title, entry[2] ), 634 JoinStringsWithSeparator( res, " " ), 635 entry[5] ]; 636 else 637 # Show a header line plus one line for each program. 638 for entry in data do 639 line:= []; 640 # Show the standardization only if several are available. 641 if 1 < Length( stdavail ) then 642 Add( line, Concatenation( "(for std. gen. ", entry[3], ")" ) ); 643 fi; 644 # Show the version only if several are available. 645 if 0 < Number( data, x -> x[1] = entry[1] and x[4] <> entry[4] ) then 646 Add( line, Concatenation( "(version ", entry[4], ")" ) ); 647 fi; 648 # Show additional information whenever available. 649 if IsBound( entry[6] ) then 650 Add( line, Concatenation( "(", entry[6], ")" ) ); 651 fi; 652 Add( res, [ Concatenation( entry[1], entry[2] ), 653 JoinStringsWithSeparator( line, " " ), 654 entry[5] ] ); 655 od; 656 657 private:= First( data, x -> x[2] <> "" ); 658 if private = fail then 659 private:= ""; 660 else 661 private:= private[2]; 662 fi; 663 return Concatenation( [ Concatenation( title, private ) ], res ); 664 fi; 665 end; 666 667 668############################################################################# 669## 670#F AtlasProgramInfoForFilename( <filename> ) 671## 672## returns the `AtlasProgramInfo' record for the straight line program with 673## filename <filename>, which must be a string. 674## 675## A copy of this function is in 'ctblocks/gap/access.g'! 676## 677BindGlobal( "AtlasProgramInfoForFilename", function( filename ) 678 local type, parsed, gapname, toc, data, l, id; 679 680 for type in AGR.DataTypes( "prg" ) do 681 parsed:= AGR.ParseFilenameFormat( filename, type[2].FilenameFormat ); 682 if parsed <> fail then 683 # We need always GAP name, filename, and standardization. 684 # In case of a private extension, 685 # the second entry is a pair of the form [ <tocid>, <gapname> ]. 686 gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, 687 pair -> pair[2] = parsed[1] )[1]; 688 689 for toc in AGR.TablesOfContents( "all" ) do 690 if IsBound( toc.( parsed[1] ) ) then 691 data:= toc.( parsed[1] ); 692 if IsBound( data.( type[1] ) ) then 693 for l in data.( type[1] ) do 694 if l[ Length( l ) ] = filename then 695 id:= [ gapname, filename, parsed[3] ]; 696 if toc.TocID <> "core" then 697 id[2]:= [ [ toc.TocID, filename ] ]; 698 fi; 699 # ... 700 if type[1] in [ "check", "find", "kernel", "pres", "switch" ] then 701 id[4]:= parsed[5]; 702 elif type[1] = "out" then 703 id[3]:= parsed[5]; 704#T is this really intended? -> better add the standardization of G!!! 705 elif not type[1] in [ "maxes", "classes", "cyclic", 706 "cyc2ccl", "maxstd", "switch", 707 "otherscripts" ] then 708 Error( "unknown type <type>" ); 709 fi; 710 return AtlasProgramInfo( id ); 711 fi; 712 od; 713 fi; 714 fi; 715 od; 716 fi; 717 od; 718 719 return fail; 720 end ); 721 722 723############################################################################# 724## 725#E 726 727