GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
############################################################################# #### ## #W options.gi ACE Package Greg Gamble ## ## This file installs functions and records for manipulating ACE options. ## #Y Copyright (C) 2000 Centre for Discrete Mathematics and Computing #Y Department of Information Technology & Electrical Eng. #Y University of Queensland, Australia. ## ############################################################################# #### ## #V KnownACEOptions . . . . . . record whose fields are the known ACE options ## . . . . . . . . . . . . . . . . . . each field is assigned a list of two ## . . . . . . . . . . . . . . . . . . components: [leastlength, listorfn] ## ## The known ACE options are the RecNames of KnownACEOptions. The value of ## of each RecName is a list [ leastlength, listorfn ], where leastlength is ## an integer specifying the least length of an abbreviation of the RecName ## that will match an ACE option, and listorfn is either a list of allowed ## values or a function that can be used to test that the value of an option ## is valid e.g. for the RecName "lookahead", we have knownOptions.lookahead ## equal to [ 4, [0..4] ] which indicates that "look", "looka", etc. are all ## valid abbreviations of the "lookahead" option, and the values that that ## option can take are in the (integer) range 0 to 4. ## ## If the allowed values listed for an option are 0 and 1, then false and ## true are also permitted (we translate false and true to 0 and 1, respect- ## ively when we call ACE). The empty string signifies that ACE expects no ## value for that option. ## ## Only single-word versions of options can be used by a user of ACE via the ## GAP interface e.g. "cc" is a synonym for "coset coincidence" as an ACE ## option, but the latter, being 2 words, is not available via the GAP ## interface. ## ## The commented out options are known ACE options that probably won't work ## via the GAP interface ... if the user uses these the interface program ## CALL_ACE will complain: `unknown (possibly new) or bad' but still pass ## these options to ACE ... at least the user will then know if ACE does not ## respond as expected that the options should not be used. We usually only ## warn that certain options might be bad, so that this interface has a good ## chance of still being functional if new options are added to the ACE bin- ## ary. ## ## Some options are `GAP-introduced' i.e. technically they are not ACE ## options ... there is a comment beside such options; and they are also ## listed in NonACEbinOptions below. ## InstallValue(KnownACEOptions, rec( # aceinfile, aceignore, aceignoreunknown, acenowarnings, silent (and # further down: aceoutfile) are GAP-introduced options ... they are # not ACE binary options. aceinfile := [5, IsString], aceignore := [5, x -> IsList(x) and ForAll(x, xi -> IsString(xi))], aceignoreunknown := [10, x -> IsList(x) and ForAll(x, xi -> IsString(xi))], acenowarnings := [6, [0,1]], aceecho := [7, [""]], aceincomment := [6, IsString], aceexampleoptions := [17, [0,1]], silent := [6, [0,1]], lenlex := [6, [0,1]], semilenlex := [10, [0,1]], incomplete := [10, [0,1]], sg := [2, IS_ACE_STRINGS], rl := [2, IS_ACE_STRINGS], aep := [3, [1..7]], ai := [2, IsString], ao := [2, IsString], # "aceoutfile" is a GAP-introduced aceoutfile := [4, IsString],# synonym for "ao" asis := [2, [0,1]], begin := [3, [""]], # "begin" and "start" are synomyms start := [5, [""]], # ... "end" synonym omitted (it is a GAP keyword) bye := [3, [""]], # "bye", "exit" and "qui" are synonyms exit := [4, [""]], qui := [1, [""]], # the "quit" form is not available since # it's a GAP keyword cc := [2, x -> IsInt(x) and x > 1], cfactor := [1, IsInt], # "cfactor" and "ct" are synonyms ct := [2, IsInt], check := [5, [""]], redo := [4, [""]], compaction := [3, [0..100]], continu := [4, [""]], # "continue" is a GAP 4.3+ keyword cycles := [2, [""]], dmode := [4, [0..4]], dsize := [4, x -> x = 0 or IsPosInt(x)], default := [3, [""]], ds := [2, IS_INC_POS_INT_LIST], dr := [2, IS_INC_POS_INT_LIST], dump := [1, x -> x in ["",0,1,2] or (IsList(x) and x[1] in [0..2] and (Length(x) = 1 or (Length(x) = 2 and x[2] in [0,1])))], easy := [4, [""]], echo := [4, [0,1,2]], # hijacked! ... we don't pass this to ACE enumeration := [4, IsString], felsch := [3, ["",0,1]], ffactor := [1, x -> x = 0 or IsPosInt(x)],# "ffactor" and "fill" fill := [3, x -> x = 0 or IsPosInt(x)], # are synonyms ... there is # no "fi" since it's a GAP # keyword ## Most interface functions require the next 3 ACE options to be ## passed as arguments rather than options group := [2, x -> IsInt(x) or IsString(x) or (IsList(x) and ForAll(x, xi -> IsString(xi) and (Length(xi) = 1) and IsLowerAlphaChar( xi[1] )))], # For group generators generators := [3, IS_ACE_STRINGS], # For subgroup generators relators := [3, IS_ACE_STRINGS], # For group relators hard := [2, [""]], help := [1, [""]], hlt := [3, [""]], hole := [2, [-1..100]], lookahead := [4, [0..4]], loop := [4, x -> x = 0 or IsPosInt(x)], max := [3, x -> x = 0 or (IsInt(x) and x >= 2)], mendelsohn := [4, [0,1]], messages := [4, IsInt], # "messages" and "monitor" are synonyms monitor := [3, IsInt], mode := [2, [""]], nc := [2, ["",0,1]], # "nc" and "normal" are synonyms normal := [6, ["",0,1]], no := [2, x -> IsInt(x) and x >= -1], options := [3, [""]], oo := [2, IsInt], # "oo" and "order" are synonyms order := [5, IsInt], #parameters := [3, [""]], # decommissioned ACE option path := [4, [0,1]], pmode := [4, [0..3]], psize := [4, x -> x = 0 or (IsInt(x) and IsEvenInt(x) and IsPrimePowerInt(x))], sr := [2, ["",0,1,2,3,4,5]], print := [2, x -> x = "" or IsInt(x) or (IsList(x) and Length(x) <= 3 and IsInt(x[1]) and ForAll(x{[2..Length(x)]}, IsPosInt)) ], purec := [5, [""]], # the ACE option is "pure c" purer := [5, [""]], # the ACE option is "pure r" rc := [2, x -> x = "" or IsInt(x) or (IsList(x) and Length(x) <= 2 and ForAll(x, IsInt))], recover := [4, [""]], # "recover" and "contiguous" contiguous := [6, [""]], # are synonyms ... "rec" is # not an allowed abbreviation # since it's a GAP keyword rep := [2, x -> x in [1..7] or (IsList(x) and Length(x) <= 2 and x[1] in [1..7] and ForAll(x{[2..Length(x)]}, IsInt))], #restart := [7, [""]], # decommissioned ACE option rfactor := [1, IsInt], # "rfactor" and "rt" are synonyms rt := [2, IsInt], row := [3, [0,1]], sc := [2, IsInt], # "sc" and "stabilising" are synonyms stabilising := [6, IsInt], sims := [4, [1,3,5,7,9]], standard := [2, [""]], statistics := [4, [""]], # "statistics" and "stats" are synonyms stats := [5, [""]], style := [5, [""]], subgroup := [4, IsString], system := [3, IsString], text := [4, IsString], time := [2, x -> IsInt(x) and x >= -1], tw := [2, x -> IsList(x) and Length(x) = 2 and IsInt(x[1]) and IsWord(x[2])], trace := [2, x -> IsList(x) and Length(x) = 2 and IsInt(x[1]) and IsWord(x[2])], workspace := [2, x -> IsInt(x) or (IsString(x) and x[Length(x)] in "0123456789kmgKMG")] )); ############################################################################# #### ## #V ACEOptionSynonyms . . . . . record whose fields are `preferred' known ACE ## . . . . . . . . . . . . . . options that have synonyms. The values are ## . . . . . . . . . . . . . . . . . . . . lists of synonymous alternatives. ## ## InstallValue(ACEOptionSynonyms, rec( ao := ["aceoutfile"], ct := ["cfactor"], fill := ["ffactor"], messages := ["monitor"], nc := ["normal"], order := ["oo"], recover := ["contiguous"], rt := ["rfactor"], sc := ["stabilising"], tw := ["trace"], stats := ["statistics"], start := ["begin"], bye := ["exit", "qui"], redo := ["check"] )); ############################################################################# #### ## #V NonACEbinOptions . . . . . . . list of known ACE options that are not ACE ## . . . . . . . . . . . . . . . . . . . . . . . . . . . . . binary options. ## InstallValue(NonACEbinOptions, [ "aceinfile", "aceoutfile", "aceignore", "aceignoreunknown", "acenowarnings", "aceecho", "aceincomment", "aceexampleoptions", "echo", "silent", "lenlex", "semilenlex", "incomplete" ] ); ############################################################################# #### ## #V ACE_INTERACT_FUNC_OPTIONS . . . . . list of non ACE options that are used ## . . . . . . . . . . . . . . . . . . . . by the interaction ACE functions ## InstallValue(ACE_INTERACT_FUNC_OPTIONS, [ # used by: ACEConjugatesForNormalClosure "add", # used by: ACEOrders "suborder", # used by: ACERandomlyApplyCosetCoincidence "attempts", "hibound", "lobound", "subindex" ] ); ############################################################################# #### ## #V ACEParameterOptions . . record whose fields are the known ACE parameter ## . . . . . . . . . . . . options. Each field is assigned the known ## . . . . . . . . . . . . default value, or is a record of default values. ## ## An ACE `parameter' option, is a known ACE option for which the ACE binary ## has a default value. These are the `Run Parameters' that ACE lists with ## the `sr: 1' command, except for `group', `relators' and `generators' ## (which the user provides a value for via arguments rather than options). ## ## For the case that the value of a field of the ACEParameterOptions record ## is itself a record, the fields of that record are `default' and ## strategies for which the value assigned by that strategy differs from the ## `default' strategy. A strategy here means a strategy option concatenated ## with any of its possible values (as strings). ## InstallValue(ACEParameterOptions, rec( asis := 0, # `ct' is synonymous with `cfactor' but here we list just once. ct := rec(default := 0, felsch0 := 1000, felsch1 := 1000, hard := 1000, purec := 1000, sims9 := 1000), compaction := rec(default := 10, easy := 100, purec := 100, purer := 100), dmode := rec(default := 4, easy := 0, hlt := 0, purer := 0, sims1 := 0, sims5 := 0), dsize := rec(default := 1000), enumeration := "G", # `fill' is synonymous with `ffactor' but here we list just once. fill := rec(default := 0, easy := 1, felsch0 := 1, hlt := 1, purec := 1, purer := 1, sims1 := 1, sims3 := 1, sims5 := 1, sims7 := 1, sims9 := 1), hole := -1, lookahead := rec(default := 0, hlt := 1), loop := 0, max := 0, mendelsohn := rec(default := 0, sims5 := 1, sims7 := 1), messages := 0, # Synonymous with `monitor' but here we list just once. no := rec(default := -1, easy := 0, felsch0 := 0, hlt := 0, purec := 0, purer := 0, sims1 := 0, sims3 := 0, sims5 := 0, sims7 := 0, sims9 := 0), path := rec(default := 0), pmode := rec(default := 3, easy := 0, felsch0 := 0, hlt := 0, purec := 0, purer := 0, sims1 := 0, sims3 := 0, sims5 := 0, sims7 := 0, sims9 := 0), psize := rec(default := 256), # `rt' is synonymous with `rfactor' but here we list just once. rt := rec(default := 0, easy := 1000, hard := 1, hlt := 1000, purer := 1000, sims1 := 1000, sims3 := -1000, sims5 := 1000, sims7 := -1000), row := rec(default := 1, felsch0 := 0, felsch1 := 0, purec := 0, purer := 0, sims9 := 0), subgroup := "H", time := -1, workspace := 1000000 )); ############################################################################# #### ## #V ACEStrategyOptions . list of known ACE options that are strategy options ## InstallValue(ACEStrategyOptions, [ "default", "easy", "felsch", "hard", "hlt", "purec", "purer", "sims" ] ); ############################################################################# #### ## #V ACE_OPT_TRANSLATIONS . . . . . record of ACE interface options for which ## . . . . . . . . . . . . . . . . . the ACE binary has a different name; ## . . . . . . . . . . . . . . . . . its fields are the ACE interface names, ## . . . . . . . . . . . . . . . . . its values are the ACE binary names. ## InstallValue(ACE_OPT_TRANSLATIONS, rec( purec := "pure c", # These first two haven't been called NonACEbinOptions purer := "pure r", aceoutfile := "ao", aceecho := "echo", aceincomment := "#" )); ############################################################################# #### ## #V ACE_OPT_ACTIONS . . . . . . . record of special actions of ACE options ## . . . . . . . . . . . . . . . its fields are the ACE option names with ## . . . . . . . . . . . . . . . special actions, its values are the actions ## InstallValue(ACE_OPT_ACTIONS, rec( purec := "passed to ACE via option: pure c", purer := "passed to ACE via option: pure r", aceoutfile := "passed to ACE via option: ao", aceecho := "passed to ACE via option: echo", aceincomment := "passed as an ACE comment, behind a '#'", aceexampleoptions := "inserted by ACEExample, not passed to ACE" )); ############################################################################# #### ## #V ACE_ERRORS . . . . . . . . . . . . record of ACE interface error messages ## ## InstallValue(ACE_ERRORS, rec( argnotopt := "should be passed as an argument, NOT an option" )); ############################################################################# #### ## #V ACE_OPT_SENTINELS . . . . . . . . . . . . . . record of option sentinels ## ## is a record whose fields are the preferred option name of those ACE ## options that normally produce output and whose values are either `fail' ## if there is no reliable way of detecting the last line of output or a ## function of an input line <line> that returns `true' if <line> is the ## last line of output expected for an option. ## InstallValue(ACE_OPT_SENTINELS, rec( start := line -> Length(line) > 1 and line[ Length(line) - 1 ] = ')', redo := line -> Length(line) > 1 and line[ Length(line) - 1 ] = ')', continu := line -> Length(line) > 1 and line[ Length(line) - 1 ] = ')', aep := line -> IsMatchingSublist(line, "* P"), rep := fail, cc := line -> IsMatchingSublist(line, "Coset"), mode := line -> IsMatchingSublist(line, "start ="), nc := fail, order := fail, options := line -> IsMatchingSublist(line, " host info"), dump := line -> IsMatchingSublist(line, " #----"), sr := line -> IsMatchingSublist(line, " #----"), stats := line -> IsMatchingSublist(line, " #----"), print := fail, rc := line -> Length(line) > 12 and line{[1..13]} in ["* No success;", "* An appropri", " finite ind", " * Unable t"], cycles := line -> Length(line) > 1 and line{[1..2]} in ["CO", "co"], recover := line -> Length(line) > 1 and line{[1..2]} in ["CO", "co"], standard := line -> Length(line) > 1 and line{[1..2]} in ["CO", "co"], sc := fail, style := line -> IsMatchingSublist(line, "style ="), test := fail, tw := line -> PositionSublist(line, "* word =") <> fail or IsMatchingSublist(line, "* Trace ") )); ############################################################################# #### ## #F IS_INC_POS_INT_LIST . . . . . . Internal function used in KnownACEOptions ## . . . . . . . . returns true if argument is a single positive integer or ## . . . . . . . . . . . is a strictly increasing list of positive integers ## InstallGlobalFunction(IS_INC_POS_INT_LIST, x -> IsPosInt(x) or (IsPosInt(x[1]) and IsSSortedList(x))); ############################################################################# #### ## #F IS_ACE_STRINGS . . . . . . . . Internal function used in KnownACEOptions ## . . . . . . . . . returns true if argument is a string or list of strings ## InstallGlobalFunction(IS_ACE_STRINGS, x -> IsString(x) or (IsList(x) and ForAll(x, xi -> IsString(xi)))); ############################################################################# #### ## #F IsKnownACEOption . . . . . . . . Returns true if optname is a mixed case ## . . . . . . . . . . . . . . . . . abbreviation of a field of ## . . . . . . . . . . . . . . . . . . KnownACEOptions, or false otherwise. ## InstallGlobalFunction(IsKnownACEOption, optname -> ACEOptionData(optname).known); ############################################################################# #### ## #F ACEPreferredOptionName . . . . Returns the lowercase unabbreviated first ## . . . . . . . . . . . . . . . . alternative of optname if it is a known ## . . . . . . . . . . . . . . . . ACE option, or optname in lowercase, ## . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . otherwise. ## InstallGlobalFunction(ACEPreferredOptionName, optname -> ACEOptionData(optname).synonyms[1]); ############################################################################# #### ## #F IsACEParameterOption . . Returns true if ACEPreferredOptionName(optname) ## . . . . . . . . . . . . . . . . . . . . is a field of ACEParameterOptions ## InstallGlobalFunction(IsACEParameterOption, optname -> ACEPreferredOptionName(optname) in RecNames(ACEParameterOptions)); ############################################################################# #### ## #F IsACEStrategyOption . . . Returns true if ACEPreferredOptionName(optname) ## . . . . . . . . . . . . . . . . . . . . . . . . is in ACEStrategyOptions ## InstallGlobalFunction(IsACEStrategyOption, optname -> ACEPreferredOptionName(optname) in ACEStrategyOptions); ############################################################################# #### ## #F ACE_OPTIONS . . . . . . . . . . . . . . . . . . . . . . Internal function ## . . . . . . . . . returns the options passed to an ACE interface function ## ## InstallGlobalFunction(ACE_OPTIONS, function() if IsEmpty(OptionsStack) then return rec(); else return OptionsStack[ Length(OptionsStack) ]; fi; end); ############################################################################# #### ## #F ACE_OPT_NAMES . . . . . . . . . . . . . . . . . . . . . Internal function ## . . . . . . . . returns option names passed to an ACE interface function ## . . . . . . . . . . . . . if acenowarnings is not an option it also warns ## . . . . . . . . . . . . . . . . . . . . . . . . about deprecated options ## InstallGlobalFunction(ACE_OPT_NAMES, function() local optnames; optnames := RecNames(ACE_OPTIONS()); if not VALUE_ACE_OPTION(optnames, false, "acenowarnings") then if "messfile" in optnames then Info(InfoACE + InfoWarning, 1, "ACE Warning: ", "Option `messfile' deprecated: use `ACEoutfile' instead"); elif "outfile" in optnames then Info(InfoACE + InfoWarning, 1, "ACE Warning: ", "Option `outfile' deprecated: use `ACEinfile' instead"); fi; fi; return optnames; end); ############################################################################# #### ## #F MATCHES_KNOWN_ACE_OPT_NAME . . . . . . . . . . . . . . Internal function ## . . . . returns true iff optname is a valid abbreviation of knownoptname ## . . . . . . . . . . . . . . . . . optname should be in lowercase already! ## InstallGlobalFunction(MATCHES_KNOWN_ACE_OPT_NAME, function(knownoptname, optname) return IsMatchingSublist(knownoptname, optname) and KnownACEOptions.(knownoptname)[1] <= Length(optname); end); ############################################################################# #### ## #F FULL_ACE_OPT_NAME . . . . . . . . . . . . . . . . . . Internal procedure ## . . . . . . sets opt.fullname to be the unabbreviated version of opt.name ## . . . . . . . . . . . if one exists among the fields of KnownACEOptions, ## . . . . . . . . . . . . . . in which case, opt.known is also set to true; ## . . . . . . . . . . . otherwise, opt.fullname is set to opt.name in ## . . . . . . . . . . . . . . lower case, and opt.known is set to false. ## InstallGlobalFunction(FULL_ACE_OPT_NAME, function(opt) local lcaseoptname, list; lcaseoptname := LowercaseString(opt.name); list := Filtered(RecNames(KnownACEOptions), s -> MATCHES_KNOWN_ACE_OPT_NAME(s, lcaseoptname)); opt.known := not( IsEmpty(list) ); if opt.known then opt.fullname := list[1]; # We assume any match is unique! else opt.fullname := lcaseoptname; fi; end); ############################################################################# #### ## #F ACE_OPTION_SYNONYMS . . . . . . . . . . . . . . . . . . Internal function ## . . . . . . . . . . . . . . . . . . returns a list of synonyms of optname ## ## InstallGlobalFunction(ACE_OPTION_SYNONYMS, function(optname) local list, recname; list := [ optname ]; for recname in RecNames(ACEOptionSynonyms) do if recname = optname or optname in ACEOptionSynonyms.(recname) then list := Concatenation( [ recname ], ACEOptionSynonyms.(recname) ); break; fi; od; return list; end); ############################################################################# #### ## #F ACE_IF_EXPR . . . . . . . . . . . . . . . . . . . . . . An expression if ## ## InstallGlobalFunction(ACE_IF_EXPR, function(bool, trueval, falseval, failval) if bool = true then return trueval; elif bool = false then return falseval; else return failval; fi; end); ############################################################################# #### ## #F ACE_VALUE_OPTION . . . . . . . . Essentially an extension of ValueOption ## . . . . . . . . . . . . . . . but also removes optname from OptionsStack ## ## ACE_VALUE_OPTION(optname, defaultval) returns ValueOption(optname) if ## optname is set and defaultval, otherwise. ## ## ACE_VALUE_OPTION(optname, val, trueval, elseval). If optname has value ## val then return trueval else return elseval. ## ## If ACE_VALUE_OPTION is called with a different no. of aguments to 1 or 2, ## all but the first argument is ignored, and ValueOption(arg[1]) is ## returned. Calling ACE_VALUE_OPTION with no arguments is an error. ## InstallGlobalFunction(ACE_VALUE_OPTION, function(arg) local optval; optval := ValueOption(arg[1]); if not IsEmpty(OptionsStack) then Unbind( OptionsStack[ Length(OptionsStack) ].(arg[1]) ); fi; if Length(arg) = 2 then return ACE_IF_EXPR(optval <> fail, optval, arg[2], arg[2]); elif Length(arg) = 4 then return ACE_IF_EXPR(optval = arg[2], arg[3], arg[4], arg[4]); elif not IsEmpty(arg) then # Ignore all but the first argument return optval; fi; end); ############################################################################# #### ## #F ACE_VALUE_OPTION_ERROR(<optrec>, <optname>, <defaultval>, <IsOK>, <errmsg>) ## ## returns: ## `false' if `ValueOption(<option>) = fail' ## (and sets `<optrec>.(<optname>) := <defaultval>') or ## if `<IsOK>( ValueOption(<option>) )' ## (and sets `<optrec>.(<optname>) := ValueOption(<option>)') ## `true' if `not <IsOK>( ValueOption(<option>) )' ## (and sets `<optrec>.errmsg := [<errmsg>]') ## InstallGlobalFunction(ACE_VALUE_OPTION_ERROR, function(optrec, optname, defaultval, IsOK, errmsg) local optval; optval := ValueOption(optname); if optval = fail then optrec.(optname) := defaultval; elif IsOK(optval) then optrec.(optname) := optval; else optrec.errmsg := [errmsg]; return true; fi; return false; end); ############################################################################# #### ## #F VALUE_ACE_OPTION . . . . . . . . . . . . . . . . . . . Internal function ## . . . . . . . checks among optnames for any settings of synonyms of optnm ## . . . . . . . (or if optnm is a list any synonyms of the members of ## . . . . . . . optnm). The latest such optname in optnames will prevail ## . . . . . . . and its value will be returned. Otherwise, if there isn't ## . . . . . . . . . . . . . . . . such an optname, defaultval is returned. ## InstallGlobalFunction(VALUE_ACE_OPTION, function(optnames, defaultval, optnm) local optname, optval, optnmlist; optval := defaultval; if IsString(optnm) then optnmlist := [ optnm ]; else optnmlist := optnm; # This situation is special ... useful for checking # whether a list of options have been set fi; optnmlist := Union( List(optnmlist, optname -> ACE_OPTION_SYNONYMS(optname)) ); for optname in Filtered(optnames, optname -> ForAny(optnmlist, s -> MATCHES_KNOWN_ACE_OPT_NAME( s, LowercaseString(optname) ) )) do optval := ValueOption(optname); od; return optval; end); ############################################################################# #### ## #F DATAREC_VALUE_ACE_OPTION . . . . . . . . . . . . . . . Internal function ## . . . . . . . checks among RecNames(datarec.options) for any settings of ## . . . . . . . synonyms of optnm The latest such optname prevails and its ## . . . . . . . value is returned. Otherwise, if there isn't such an ## . . . . . . . optname or datarec.options is unbound, defaultval is ## . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . returned. ## InstallGlobalFunction(DATAREC_VALUE_ACE_OPTION, function(datarec, defaultval, optnm) local optname, optval; optval := defaultval; if IsBound(datarec.options) then for optname in Filtered(RecNames(datarec.options), optname -> ForAny(ACE_OPTION_SYNONYMS(optnm), s -> MATCHES_KNOWN_ACE_OPT_NAME( s, LowercaseString(optname) ) )) do optval := datarec.options.(optname); od; fi; return optval; end); ############################################################################# #### ## #F ACE_COSET_TABLE_STANDARD . . . . . . Return either the user's choice for ## . . . . . . . . . . . . . . . . . . . the CosetTableStandard or, if the ## . . . . . . . . . . . . . . . . . . . user has made no choice, a string ## . . . . . . . . . . . . . . . . . . . representing the current GAP ## . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . standard. ## ## A check among options for any settings of `lenlex' or `semilenlex'. The ## latest such optname that is set to true is returned, or if there is no ## such setting a string representing the current GAP default is returned: ## for GAP 4.2 "GAPsemilenlex" was returned; since GAP 4.3, "GAP" ## concatenated with the value of `CosetTableStandard' (by default, ## "lenlex") is returned. ## InstallGlobalFunction(ACE_COSET_TABLE_STANDARD, function(options) local optname; for optname in Filtered(Reversed( RecNames(options) ), optname -> ForAny(["lenlex", "semilenlex"], s -> MATCHES_KNOWN_ACE_OPT_NAME( s, LowercaseString(optname) ) )) do if options.(optname) = true then return ACEPreferredOptionName(optname); fi; od; return Concatenation("GAP", CosetTableStandard); end); ############################################################################# #### ## #F ACE_VALUE_ECHO . . . . . . . . . . . . . . . . . . . . Internal function ## ## InstallGlobalFunction(ACE_VALUE_ECHO, function(optnames) local echoval; echoval := VALUE_ACE_OPTION(optnames, 0, "echo"); if echoval in KnownACEOptions.echo[2] then return echoval; else return ACE_IF_EXPR(echoval = true, 1, 0, 0); fi; end); ############################################################################# #### ## #F TO_ACE_GENS . . . . . . . . . . . . . . . . . . . . . . Internal function ## . . . . . . . . . . . . from the GAP free group generators fgens returns ## . . . . . . . . . . . . a record used to create the equivalent ACE group ## . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . generators ## ## Returns a record with fields: ## ## acegens ## the ACE equivalent of fgens; and ## ## toace ## the ACE directive string needed for the `group' option so that ACE ## uses acegens for its generators. ## InstallGlobalFunction(TO_ACE_GENS, function(fgens) local n, acegens; n := Length(fgens); # Define the generators ACE will use if n <= 26 then # if #generators <= 26 tell ACE to use alphabetic generators: a ... if ForAll(fgens, function(g) local gstring; gstring := String(g); return Length(gstring) = 1 and LowercaseString(gstring) = gstring; end) then # if all generators are represented by single lowercase letters # ... use the user's set of generators for ACE acegens := List(fgens, g -> String(g)); else acegens := List([1..n], i -> WordAlp(CHARS_LALPHA, i)); fi; return rec(acegens := acegens, toace := Flat(acegens)); else # if #generators > 26 tell ACE to use numerical generators: 1 ... return rec(acegens := List([1..n], i -> String(i)), toace := n); fi; end); ############################################################################# #### ## #F ACE_WORDS . . . . . . . . . . . . . . . . . . . . . . . Internal function ## . . . . . . . . . . returns the translation of words in generators fgens ## . . . . . . . . . . . to words in ACEgens (the generators ACE will use), ## . . . . . . . . . . . . . . . . . . . . . . . . . . . . . as one string. ## InstallGlobalFunction(ACE_WORDS, function(words, fgens, ACEgens) words := ACE_WORDS_ARG_CHK(fgens, words, ""); return JoinStringsWithSeparator( List(words, w -> String( MappedWord( w, fgens, GeneratorsOfGroup( FreeGroup(ACEgens) ) ) ) ) ); end); ############################################################################# #### ## #F ACE_RELS . . . . . . . . . . . . . . . . . . . . . . . Internal function ## . . . . . . . . . . . returns the translation of the relators rels in ## . . . . . . . . . . . generators fgens to words in ACEgens (the ## . . . . . . . . . . . generators ACE will use), as one string, but if ## . . . . . . . . . . . enforceAsis is true ensure the relator for the ## . . . . . . . . . . . first generator (which we'll represent as x) is ## . . . . . . . . . . . . . . . . . translated as "x*x" rather than "x^2". ## InstallGlobalFunction(ACE_RELS, function(rels, fgens, ACEgens, enforceAsis) if enforceAsis then return Concatenation( ACEgens[1], ACEgens[1], ", ", ACE_WORDS(Filtered(rels, rel -> rel <> fgens[1]^2), fgens, ACEgens) ); else return ACE_WORDS(rels, fgens, ACEgens); fi; end); ############################################################################# #### ## #F ToACEGroupGenerators . . . . . Given the GAP free group generators fgens ## . . . . . . . . . . . . . . . . returns the ACE directive string needed ## . . . . . . . . . . . . . . . . for the `group' option so that ACE uses ## . . . . . . . . . . . . . . . . an appropriate equivalent set of ## . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . generators. ## InstallGlobalFunction(ToACEGroupGenerators, function(fgens) fgens := ACE_FGENS_ARG_CHK(fgens); return TO_ACE_GENS(fgens).toace; end); ############################################################################# #### ## #F ToACEWords . . . . Returns the translation of words in generators fgens ## . . . . . . . . . . to equivalent ACE words, as one string, suitable for ## . . . . . . . . . . . . . . . . the `relators' and `generators' options. ## InstallGlobalFunction(ToACEWords, function(fgens, words) fgens := ACE_FGENS_ARG_CHK(fgens); return ACE_WORDS(words, fgens, TO_ACE_GENS(fgens).acegens); end); ############################################################################# #### ## #F ACE_FGENS_ARG_CHK( <fgens> ) ## ## Checks that <fgens> is a list of free group generators for the same free ## group, gives the user a chance to fix them if necessary, and then returns ## the (repaired) <fgens>. ## InstallGlobalFunction(ACE_FGENS_ARG_CHK, function(fgens) local errmsg, onbreakmsg, error, fam; onbreakmsg := ["Type: 'quit;' to quit to outer loop, or", "type: 'fgens := <val>; return;' to assign <val> to fgens to continue."]; error := true; repeat if not IsList(fgens) then errmsg := ["fgens must be a *list* of free group gen'rs"]; elif not ForAll(fgens, g -> IsAssocWordWithInverse(g) and (NumberSyllables(g) = 1) and (ExponentSyllable(g, 1) = 1)) then if ForAll(fgens, IsElementOfFpGroup) then errmsg := ["fgens must be a list of free group gen'rs,", "not fp group elements e.g. use 'FreeGeneratorsOfFpGroup'", "rather than 'GeneratorsOfGroup'"]; else errmsg := ["fgens must be a list of free group gen'rs"]; fi; else fam := FamilyObj(fgens[1]); if not ForAll(fgens{[2..Length(fgens)]}, g -> fam = FamilyObj(g)) then errmsg := ["fgens must all belong to the same free group"]; else error := false; fi; fi; if error then Error(ACE_ERROR(errmsg, onbreakmsg), "\n"); fi; until not error; return fgens; end); ############################################################################# #### ## #F ACE_WORDS_ARG_CHK( <fgens>, <words>, <whicharg> ) ## ## Checks that <words> is a valid list of words in the free group generators ## <fgens>. If not, an error message for the <whicharg> (which indicates ## what type of words they are, e.g. "relators", "subgp gen'rs" or "") ## argument is generated, telling the user how to fix the problem. Once ## everything is ok, <words> after being filtered of any identity elements ## is returned. ## InstallGlobalFunction(ACE_WORDS_ARG_CHK, function(fgens, words, whicharg) local fam, errmsg, onbreakmsg; onbreakmsg := ["Type: 'quit;' to quit to outer loop, or", "type: 'words := <val>; return;' to assign <val> to words to continue.", "Note: fgens is the list of free group generators."]; fam := FamilyObj(fgens[1]); errmsg := "words "; if whicharg <> "" then errmsg := Concatenation(errmsg, "(", whicharg, ") "); fi; while not IsList(words) or not ForAll(words, w -> FamilyObj(w) = fam) do if IsList(words) and ForAll(words, IsElementOfFreeGroup) then errmsg := [Concatenation( errmsg, "is a list of words in the *wrong* free grp gen'rs")]; elif IsList(words) and ForAll(words, IsElementOfFpGroup) then errmsg := [Concatenation( errmsg, "must be a list of words in the free group gen'rs,"), "not fp group elements. Perhaps, you should use 'UnderlyingElement'", "to convert each fp group element to a word in the free group gen'rs"]; else errmsg := [Concatenation( errmsg, "must be a list of words in the free group gen'rs")]; fi; Error(ACE_ERROR(errmsg, onbreakmsg), "\n"); od; return Filtered(words, word -> not IsOne(word)); end); ############################################################################# #### ## #F PROCESS_ACE_OPTIONS . . . . . . . . . . . . . . . . . Internal procedure ## . . . . . . . . . for the ACE function with name ACEfname process options ## . . . . . . . . . (on the top of OptionsStack) with names newoptnames, ## . . . . . . . . . other than those that are fields of disallowed or ## . . . . . . . . . listed in ignored, by sending them to ACE via the write ## . . . . . . . . . function ToACE, after appropriate translation where ## . . . . . . . . . necessary, mostly in the order specified by the user. ## . . . . . . . . . The list optnames contains the names of all currently ## . . . . . . . . . active options i.e. the fields of all options on top of ## . . . . . . . . . the OptionsStack. If echo is set then all options ## . . . . . . . . . processed are echoed along with an indication of how ## . . . . . . . . . they were handled by the interface. If the InfoLevel of ## . . . . . . . . . InfoACE or InfoWarning is at least 1 and the user has ## . . . . . . . . . not passed the acenowarnings option then a warning ## . . . . . . . . . message is issued for each optname that is a field of ## . . . . . . . . . disallowed or is in ignored or for some other reason is ## . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ignored. ## InstallGlobalFunction(PROCESS_ACE_OPTIONS, function(ACEfname, optnames, newoptnames, echo, datarec, disallowed, ignored) local ToACE, IsValidOptionValue, CheckValidOption, ProcessOption, AddIgnoreOptionsToIgnored, IsMyLine, nowarnings, ignoreunknown, paramoptnames, strategy, opt, optname, line, invokesEnumeration; ToACE := function(list) WRITE_LIST_TO_ACE_STREAM(datarec.stream, list); end; IsValidOptionValue := function(val) # Check that val is a valid value of opt.fullname. # This function will only be called when opt.known = true, # in which case, opt.fullname will be a field of KnownACEOptions if IsFunction(KnownACEOptions.(opt.fullname)[2]) then return KnownACEOptions.(opt.fullname)[2](val); elif IsBool(val) then return KnownACEOptions.(opt.fullname)[2] in ["", ["",0,1], [0,1]]; else return val in KnownACEOptions.(opt.fullname)[2]; fi; end; CheckValidOption := function(val) # If opt.fullname is a known allowed optname and val is a valid value, # warn the user of a possible error, if s/he wants to know and its # not an ignored option. if not(nowarnings or opt.ignore) then if opt.fullname in RecNames(disallowed) then Info(InfoACE + InfoWarning, 1, "ACE Warning: ", opt.name, ": ", disallowed.(opt.fullname)); elif opt.known then if not IsValidOptionValue(val) then Info(InfoACE + InfoWarning, 1, "ACE Warning: ", val, ": ", "possibly not an allowed value of ", opt.name); fi; else Info(InfoACE + InfoWarning, 1, "ACE Warning: ", opt.name, ": unknown (maybe new) or bad option"); fi; fi; end; ProcessOption := function(val) # Echo what we are about to do first, if the user has set the echo # option. if echo > 0 then if opt.ignore then Print(" ", opt.name, " := ", opt.value, " (ignored)\n"); elif opt.fullname in RecNames(ACE_OPT_ACTIONS) then Print(" ", opt.name); if val = "" then Print(" (no value, "); else Print(" := ", opt.value, " ("); fi; Print( ACE_OPT_ACTIONS.(opt.fullname), ")\n" ); elif opt.fullname in NonACEbinOptions then Print(" ", opt.name, " := ", opt.value, " (not passed to ACE)\n"); elif opt.list then Print(" ", opt.name, " := ", opt.value, " (brackets are not passed to ACE)\n"); elif val = "" then Print(" ", opt.name, " (no value)\n"); else Print(" ", opt.name, " := ", val, "\n"); fi; fi; # Warn user if opt.name is an unknown optname or has an unexpected value # if they want to know. CheckValidOption(val); # Now do it ... pass opt.ace (which is opt.name except when the ACE and # GAP optnames differ) to ACE with value val, except if opt.name is to # be ignored or is a NonACEbinOption without a translation. if not opt.donotpass and not opt.ignore then if opt.fullname in RecNames(ACE_OPT_TRANSLATIONS) then # The ACE optname differs from the GAP optname opt.ace := ACE_OPT_TRANSLATIONS.(opt.fullname); else # The ACE optname is the same as the GAP optname opt.ace := opt.name; fi; if opt.list then ToACE([ opt.ace,":", JoinStringsWithSeparator( List(val, String) ), ";" ]); elif val = "" then ToACE([ opt.ace, ";" ]); elif opt.fullname = "aceincomment" then ToACE([ opt.ace, val, ";" ]); else ToACE([ opt.ace, ":", val, ";" ]); fi; # Eventually we may include more general support for interpretation # of ACE output here ... for the moment we ensure the enumeration # result is set (for ACEStats) and the coset table is set (for # ACECosetTable[FromGensAndRels]) if there is an enumeration result if IsBound(datarec.procId) then if not IsBound( ACE_OPT_SENTINELS.(opt.synonyms[1]) ) then # Flush any available output ... it may contain errors line := ReadAllLine(datarec.stream); while line <> fail do Info(InfoACE + InfoWarning, 1, Chomp(line)); line := ReadAllLine(datarec.stream); od; elif opt.fullname = "print" and IsBound(datarec.stats) and val in [ "", datarec.stats.activecosets ] and (datarec.stats.index <> 0 or VALUE_ACE_OPTION(optnames, false, "incomplete") ) then datarec.cosettable := ACE_COSET_TABLE(datarec.stats.activecosets, datarec.acegens, datarec.stream, ACE_READ_NEXT_LINE); else if ACE_OPT_SENTINELS.(opt.synonyms[1]) = fail then ToACE([ "text:***" ]); IsMyLine := line -> IsMatchingSublist(line, "***"); else IsMyLine := ACE_OPT_SENTINELS.(opt.synonyms[1]); fi; invokesEnumeration := opt.synonyms[1] in ["start", "continu", "redo", "aep", "rep"]; repeat line := ACE_READ_NEXT_LINE(datarec.stream); if invokesEnumeration and not IsMatchingSublist(line, "** ERROR") and Length(line) > 1 and line[ Length(line) - 1 ] = ')' then datarec.enumResult := Chomp(line); datarec.stats := ACE_STATS(datarec.enumResult); fi; Info(InfoACE + InfoWarning, 1, Chomp(line)); until IsMyLine(line); fi; fi; fi; end; AddIgnoreOptionsToIgnored := function() local ignore, optname, opt; ignore := VALUE_ACE_OPTION(optnames, [], "aceignore"); for optname in ignore do opt := rec(name := optname); FULL_ACE_OPT_NAME(opt); # sets opt.known and opt.fullname Add(ignored, opt.fullname); od; end; if echo > 0 then Print(ACEfname, " called with the following options:\n"); if echo = 2 then paramoptnames := RecNames(ACEParameterOptions); strategy := "default"; fi; fi; nowarnings := VALUE_ACE_OPTION(optnames, false, "acenowarnings"); ignoreunknown := VALUE_ACE_OPTION(optnames, ACEIgnoreUnknownDefault, "aceignoreunknown"); AddIgnoreOptionsToIgnored(); for optname in newoptnames do opt := ACEOptionData(optname); # sets opt.name, opt.known, opt.fullname # and opt.synonyms opt.value := ValueOption(opt.name); if echo = 2 then paramoptnames := Difference(paramoptnames, opt.synonyms); if opt.fullname in ACEStrategyOptions then strategy := opt.fullname; if IsInt(opt.value) then strategy := Concatenation(strategy, String(opt.value)); elif opt.value and (opt.fullname = "felsch") then strategy := "felsch0"; # Hmm! I'd like to do this differently!! fi; fi; fi; # We don't pass the NonACEbinOptions options to ACE unless they # have a translation (i.e. are fields of ACE_OPT_TRANSLATIONS) opt.donotpass := (opt.fullname in NonACEbinOptions) and not (opt.fullname in RecNames(ACE_OPT_TRANSLATIONS)); opt.ignore := opt.fullname in RecNames(disallowed) or opt.fullname in ignored or (ignoreunknown and not opt.known); opt.list := false; if opt.value = true then # An option detected by GAP as boolean may in fact be a no-value # option of ACE ... unknown ACE options detected as being true are # assumed to be no-value options (since the user can still over-ride # this behaviour by entering values of 0 or 1 explicitly e.g. # ACEStats(... : `opt' := 1) ) if not opt.known or IsValidOptionValue("") then ProcessOption(""); else ProcessOption(1); fi; elif opt.value = false then ProcessOption(0); elif not IsString(opt.value) and IsList(opt.value) then opt.list := true; ProcessOption(opt.value); else ProcessOption(opt.value); fi; od; if echo = 2 then Print("Other options set via ACE defaults:\n"); for optname in paramoptnames do Print(" ", optname, " := "); if IsRecord(ACEParameterOptions.(optname)) then if IsBound(ACEParameterOptions.(optname).(strategy)) then Print(ACEParameterOptions.(optname).(strategy), "\n"); else Print(ACEParameterOptions.(optname).default, "\n"); fi; else Print(ACEParameterOptions.(optname), "\n"); fi; od; fi; end); ############################################################################# #### ## #F PROCESS_ACE_OPTION . . . . . . . . . . . . . . . . . Internal procedure ## . . . . . . . . . . . . . . . . . . . . . process a single ACE option ## . . . . . . . . . . . . . . . . . . . . . that hasn't been passed via ## . . . . . . . . . . . . . . . . . . . . . . . . . GAP's option mechanism ## ## Checks optval is a valid value of optname (which must be lowercase and ## unabbreviated) and pass it ACE by writing to stream. ## InstallGlobalFunction(PROCESS_ACE_OPTION, function(stream, optname, optval) local aceoptname, error; # Check that optval is a valid value of optname. if IsFunction(KnownACEOptions.(optname)[2]) then error := not KnownACEOptions.(optname)[2](optval); else error := not (optval in KnownACEOptions.(optname)[2]); fi; if error then Info(InfoACE + InfoWarning, 1, "ACE Warning: ", optval, ": ", "possibly not an allowed value of ", optname); fi; if optname in RecNames(ACE_OPT_TRANSLATIONS) then # The ACE optname differs from the GAP optname aceoptname := ACE_OPT_TRANSLATIONS.(optname); else # The ACE optname is the same as the GAP optname aceoptname := optname; fi; if optval = "" then WRITE_LIST_TO_ACE_STREAM(stream, [ aceoptname, ";" ]); elif not IsString(optval) and IsList(optval) then WRITE_LIST_TO_ACE_STREAM( stream, [ aceoptname,":", JoinStringsWithSeparator( List(optval, String) ), ";" ] ); else WRITE_LIST_TO_ACE_STREAM(stream, [ aceoptname, ":", optval, ";" ]); fi; return error; end); ############################################################################# #### ## #F ACEOptionData . . . returns a record of the known data of an option name ## ## For argument optname the fields of the returned record are: ## name . . . . optname (unchanged); ## known . . . . true iff optname is a valid mixed case abbreviation of a ## KnownACEOption field; ## fullname . . the lower case unabbreviated form of optname if the ## `known' field is set `true', or optname in lower case, ## otherwise; ## synonyms . . a list of KnownACEOptions fields that are option names ## synonymous with optname, if the `known' field is set ## set `true', or list with just fullname otherwise; ## abbrev . . . the shortest lowercase abbreviation of optname if the ## `known' field is set `true', or fullname otherwise. ## InstallGlobalFunction(ACEOptionData, function(optname) local opt; opt := rec(name := optname); FULL_ACE_OPT_NAME(opt); # Sets the `known' and `fullname' fields if opt.known then opt.synonyms := ACE_OPTION_SYNONYMS(opt.fullname); opt.abbrev := opt.fullname{[1 .. KnownACEOptions.(opt.fullname)[1]]}; else opt.synonyms := [ opt.fullname ]; opt.abbrev := opt.fullname; fi; return opt; end); ############################################################################# #### ## #F SANITISE_ACE_OPTIONS . . . . . . . . . . . . . . . . Internal procedure ## . . . . . . . . . . . . . . . . . . . . . . . . Called by SetACEOptions, ## . . . . . . . . . . . . . . . . . or by CALL_ACE when CALL_ACE is invoked ## . . . . . . . . . . . . . . . . . by ACEExample with user options ## ## Scrubs any option names in optsrec that match those in newoptsrec, ## to ensure that *all* new options are at the end of optsrec when it is ## updated with options from newoptsrec. ## InstallGlobalFunction(SANITISE_ACE_OPTIONS, function(optsrec, newoptsrec) local newoptnames, optname, opt; newoptnames := Concatenation( List(RecNames(newoptsrec), optname -> ACEOptionData(optname).synonyms) ); for optname in RecNames(optsrec) do opt := rec(name := optname); FULL_ACE_OPT_NAME(opt); # Sets opt.fullname if opt.fullname in newoptnames then Unbind(optsrec.(optname)); fi; od; end); ############################################################################# #### ## #F NEW_ACE_OPTIONS() ## ## Looks at OptionsStack and returns the new options. ## InstallGlobalFunction(NEW_ACE_OPTIONS, function() local newoptions, oldoptions, oldnames, optname; if IsEmpty(OptionsStack) then return rec(); elif Length(OptionsStack) = 1 then return OptionsStack[ Length(OptionsStack) ]; else newoptions := ShallowCopy( OptionsStack[ Length(OptionsStack) ] ); oldoptions := OptionsStack[ Length(OptionsStack) - 1 ]; oldnames := RecNames(oldoptions); for optname in RecNames(newoptions) do if optname in oldnames and oldoptions.(optname) = newoptions.(optname) then Unbind( newoptions.(optname) ); fi; od; return newoptions; fi; end); #E options.gi . . . . . . . . . . . . . . . . . . . . . . . . . . ends here