3 Infrastructure Most of the details in this chapter are of a technical nature; the user need only skim over this chapter on a first reading. Mostly, it is enough to know that  you must do a LoadPackage("anupq"); before you can expect to use a command defined by the ANUPQ package (details are in Section 'Loading the ANUPQ Package');  partial results of ANUPQ commands and some other data are stored in the ANUPQData global variable (details are in Section 'The ANUPQData Record');  doing SetInfoLevel(InfoANUPQ, n); for n greater than the default value 1 will give progressively more information of what is going on behind the scenes (details are in Section 'Setting the Verbosity of ANUPQ via Info and InfoANUPQ');  in Section 'Utility Functions' we describe some utility functions and functions that run examples from the collection of examples of this package;  in Section 'Attributes and a Property for fp and pc p-groups' we describe the attributes and property NuclearRank, MultiplicatorRank and IsCapable; and  in Section 'Hints and Warnings regarding the use of Options' we describe some troubleshooting strategies. Also this section explains the utility of setting ANUPQWarnOfOtherOptions := true; (particularly for novice users) for detecting misspelt options and diagnosing other option usage problems. 3.1 Loading the ANUPQ Package To use the ANUPQ package, as with any GAP package, it must be requested explicitly. This is done by calling  Example  gap> LoadPackage( "anupq" ); --------------------------------------------------------------------------- Loading ANUPQ (ANU p-Quotient) 3.1 GAP code by Greg Gamble (address for correspondence)  Werner Nickel (http://www.mathematik.tu-darmstadt.de/~nickel/)  [uses ANU pq binary (C code program) version: 1.9] C code by Eamonn O'Brien (http://www.math.auckland.ac.nz/~obrien) Co-maintained by Max Horn    For help, type: ?ANUPQ --------------------------------------------------------------------------- true  Note that since the ANUPQ package uses the AutomorphimGroupPGroup function of the AutPGrp package and, in any case, often needs other AutPGrp functions when computing descendants, the user must ensure that the AutPGrp package is also installed, at least version 1.5. If the AutPGrp package is not installed, the ANUPQ package will fail to load. Also, if GAP cannot find a working pq binary, the call to LoadPackage will return fail. If you want to load the ANUPQ package by default, you can put the LoadPackage command into your gap.ini file (see Section Reference: The gap.ini and gaprc files in the GAP Reference Manual). By the way, the novice user of the ANUPQ package should probably also append the line  Example  ANUPQWarnOfOtherOptions := true;  to their gap.ini file, somewhere after the LoadPackage( "anupq" ); command (see ANUPQWarnOfOtherOptions (3.6-1)). 3.2 The ANUPQData Record This section contains fairly technical details which may be skipped on an initial reading. 3.2-1 ANUPQData ANUPQData global variable is a GAP record in which the essential data for an ANUPQ session within GAP is stored; its fields are: binary the path of the pq binary; tmpdir the path of the temporary directory used by the pq binary and GAP (i.e. the directory in which all the pq's temporary files are created) (also see ANUPQDirectoryTemporary (3.2-2) below); outfile the full path of the default pq output file; SPimages the full path of the file GAP_library to which the pq program writes its Standard Presentation images; version the version of the current pq binary; ni a data record used by non-interactive functions (see below and Chapter 'Non-interactive ANUPQ functions'); io list of data records for PqStart (see below and PqStart (5.1-1)) processes; topqlogfile name of file logged to by ToPQLog (see ToPQLog (3.4-7)); and logstream stream of file logged to by ToPQLog (see ToPQLog (3.4-7)). Each time an interactive ANUPQ process is initiated via PqStart (see PqStart (5.1-1)), an identifying number ioIndex is generated for the interactive process and a record ANUPQData.io[ioIndex] with some or all of the fields listed below is created. Whenever a non-interactive function is called (see Chapter 'Non-interactive ANUPQ functions'), the record ANUPQData.ni is updated with fields that, if bound, have exactly the same purpose as for a ANUPQData.io[ioIndex] record. stream the IOStream opened for interactive ANUPQ process ioIndex or non-interactive ANUPQ function; group the group given as first argument to PqStart, Pq, PqEpimorphism, PqDescendants or PqStandardPresentation (or any synonymous methods); haspcp is bound and set to true when a pc presentation is first set inside the pq program (e.g. by PqPcPresentation or PqRestorePcPresentation or a higher order function like Pq, PqEpimorphism, PqPCover, PqDescendants or PqStandardPresentation that does a PqPcPresentation operation, but not PqStart which only starts up an interactive ANUPQ process); gens a list of the generators of the group group as strings (the same as those passed to the pq program); rels a list of the relators of the group group as strings (the same as those passed to the pq program); name the name of the group whose pc presentation is defined by a call to the pq program (according to the pq program -- unless you have used the GroupName option (see e.g. Pq (4.1-1)) or applied the function SetName (see SetName (Reference: Name)) to the group, the generic name "[grp]" is set as a default); gpnum if not a null string, the number (i.e. the unique label assigned by the pq program) of the last descendant processed; class the largest lower exponent-p central class of a quotient group of the group (usually group) found by a call to the pq program; forder the factored order of the quotient group of largest lower exponent-p central class found for the group (usually group) by a call to the pq program (this factored order is given as a list [p,n], indicating an order of p^n); pcoverclass the lower exponent-p central class of the p-covering group of a p-quotient of the group (usually group) found by a call to the pq program; workspace the workspace set for the pq process (either given as a second argument to PqStart, or set by default to 10000000); menu the current menu of the pq process (the pq program is managed by various menus, the details of which the user shouldn't normally need to know about -- the menu field remembers which menu the pq process is currently in); outfname is the file to which pq output is directed, which is always ANUPQData.outfile, except when option SetupFile is used with a non-interactive function, in which case outfname is set to "PQ_OUTPUT"; pQuotient is set to the value returned by Pq (see Pq (4.1-1)) (the field pQepi is also set at the same time); pQepi is set to the value returned by PqEpimorphism (see PqEpimorphism (4.1-2)) (the field pQuotient is also set at the same time); pCover is set to the value returned by PqPCover (see PqPCover (4.1-3)); SP is set to the value returned by PqStandardPresentation or StandardPresentation (see PqStandardPresentation (5.3-4)) when called interactively, for process i (the field SPepi is also set at the same time); SPepi is set to the value returned by EpimorphismPqStandardPresentation or EpimorphismStandardPresentation (see EpimorphismPqStandardPresentation (5.3-5)) when called interactively, for process i (the field SP is also set at the same time); descendants is set to the value returned by PqDescendants (see PqDescendants (4.4-1)); treepos if set by a call to PqDescendantsTreeCoclassOne (see PqDescendantsTreeCoclassOne (A.4-1)), it contains a record with fields class, node and ndes being the information that determines the last descendant with a non-zero number of descendants processed; xgapsheet if set by a call to PqDescendantsTreeCoclassOne (see PqDescendantsTreeCoclassOne (A.4-1)) during an XGAP session, it contains the XGAP Sheet on which the descendants tree is displayed; and nextX if set by a call to PqDescendantsTreeCoclassOne (see PqDescendantsTreeCoclassOne (A.4-1)) during an XGAP session, it contains a list of integers, the ith entry of which is the x-coordinate of the next node (representing a descendant) for the ith class. 3.2-2 ANUPQDirectoryTemporary ANUPQDirectoryTemporary( dir )  function calls the UNIX command mkdir to create dir, which must be a string, and if successful a directory object for dir is both assigned to ANUPQData.tmpdir and returned. The field ANUPQData.outfile is also set to be a file in ANUPQData.tmpdir, and on exit from GAP dir is removed. Most users will never need this command; by default, GAP typically chooses a random subdirectory of /tmp for ANUPQData.tmpdir which may occasionally have limits on what may be written there. ANUPQDirectoryTemporary permits the user to choose a directory (object) where one is not so limited. 3.3 Setting the Verbosity of ANUPQ via Info and InfoANUPQ 3.3-1 InfoANUPQ InfoANUPQ info class The input to and the output from the pq program is, by default, not displayed. However the user may choose to see some, or all, of this input/output. This is done via the Info mechanism (see Section Reference: Info Functions in the GAP Reference Manual). For this purpose, there is the InfoClass InfoANUPQ. If the InfoLevel of InfoANUPQ is high enough each line of pq input/output is directed to a call to Info and will be displayed for the user to see. By default, the InfoLevel of InfoANUPQ is 1, and it is recommended that you leave it at this level, or higher. Messages that the user should presumably want to see and output from the pq program influenced by the value of the option OutputLevel (see the options listed in Section Pq (4.1-1)), other than timing and memory usage are directed to Info at InfoANUPQ level 1. To turn off all InfoANUPQ messaging, set the InfoANUPQ level to 0. There are five other user-intended InfoANUPQ levels: 2, 3, 4, 5 and 6.  Example  gap> SetInfoLevel(InfoANUPQ, 2);  enables the display of most timing and memory usage data from the pq program, and also the number of identity instances when the Identities option is used. (Some timing and memory usage data, particularly when profuse in quantity, is Info-ed at InfoANUPQ level 3 instead.) Note that the the GAP functions time and Runtime (see Runtime (Reference: Runtime) in the GAP Reference Manual) count the time spent by GAP and not the time spent by the (external) pq program.  Example  gap> SetInfoLevel(InfoANUPQ, 3);  enables the display of output of the nature of the first two InfoANUPQ that was not directly invoked by the user (e.g. some commands require GAP to discover something about the current state known to the pq program). The identity instances processed under the Identities option are also displayed at this level. In some cases, the pq program produces a lot of output despite the fact that the OutputLevel (see 6.2) is unset or is set to 0; such output is also Info-ed at InfoANUPQ level 3.  Example  gap> SetInfoLevel(InfoANUPQ, 4);  enables the display of all the commands directed to the pq program, behind a ToPQ>  prompt (so that you can distinguish it from the output from the pq program). See Section 'Hints and Warnings regarding the use of Options' for an example of how this can be a useful troubleshooting tool.  Example  gap> SetInfoLevel(InfoANUPQ, 5);  enables the display of the pq program's prompts for input. Finally,  Example  gap> SetInfoLevel(InfoANUPQ, 6);  enables the display of all other output from the pq program, namely the banner and menus. However, the timing data printed when the pq program exits can never be observed. 3.4 Utility Functions 3.4-1 PqLeftNormComm PqLeftNormComm( elts )  function returns for a list of elements of some group (e.g. elts may be a list of words in the generators of a free or fp group) the left normed commutator of elts, e.g. if w1, w2, w3 are such elements then PqLeftNormComm( [w1, w2, w3] ); is equivalent to Comm( Comm( w1, w2 ), w3 );. Note: elts must contain at least two elements. 3.4-2 PqGAPRelators PqGAPRelators( group, rels )  function returns a list of words that GAP understands, given a list rels of strings in the string representations of the generators of the fp group group prepared as a list of relators for the pq program. Note: The pq program does not use / to indicate multiplication by an inverse and uses square brackets to represent (left normed) commutators. Also, even though the pq program accepts relations, all elements of rels must be in relator form, i.e. a relation of form w1 = w2 must be written as w1*(w2)^-1. Here is an example:  Example  gap> F := FreeGroup("a", "b");  gap> PqGAPRelators(F, [ "a*b^2", "[a,b]^2*a", "([a,b,a,b,b]*a*b)^2*a" ]); [ a*b^2, a^-1*b^-1*a*b*a^-1*b^-1*a*b*a, b^-1*a^-1*b^-1*a^-1*b*a*b^-1*a*b*a^  -1*b*a^-1*b^-1*a*b*a*b^-1*a^-1*b^-1*a^-1*b*a*b^-1*a*b^-1*a^-1*b*a^-1*b^  -1*a*b*a*b*a^-1*b*a*b^-1*a*b*a^-1*b*a^-1*b^-1*a*b*a*b^-1*a^-1*b^-1*a^  -1*b*a*b^-1*a*b^-1*a^-1*b*a^-1*b^-1*a*b*a*b^2*a*b*a ]  3.4-3 PqParseWord PqParseWord( word, n )  function parses a word, a string representing a word in the pc generators x1,...,xn, through GAP. This function is provided as a rough-and-ready check of word for syntax errors. A syntax error will cause the entering of a break-loop, in which the error message may or may not be meaningful (depending on whether the syntax error gets caught at the GAP or kernel level). Note: The reason the generators must be x1,...,xn is that these are the pc generator names used by the pq program (as distinct from the generator names for the group provided by the user to a function like Pq that invokes the pq program). 3.4-4 PqExample PqExample( )  function PqExample( example[, PqStart][, Display] )  function PqExample( example[, PqStart][, filename] )  function With no arguments, or with single argument "index", or a string example that is not the name of a file in the examples directory, an index of available examples is displayed. With just the one argument example that is the name of a file in the examples directory, the example contained in that file is executed in its simplest form. Some examples accept options which you may use to modify some of the options used in the commands of the example. To find out which options an example accepts, use one of the mechanisms for displaying the example described below. Some examples have both non-interactive and interactive forms; those that are non-interactive only have a name ending in -ni; those that are interactive only have a name ending in -i; examples with names ending in .g also have only one form; all other examples have both non-interactive and interactive forms and for these giving PqStart as second argument invokes PqStart initially and makes the appropriate adjustments so that the example is executed or displayed using interactive functions. If PqExample is called with last (second or third) argument Display then the example is displayed without being executed. If the last argument is a non-empty string filename then the example is also displayed without being executed but is also written to a file with that name. Passing an empty string as last argument has the same effect as passing Display. Note: The variables used in PqExample are local to the running of PqExample, so there's no danger of having some of your variables over-written. However, they are not completely lost either. They are saved to a record ANUPQData.examples.vars, i.e. if F is a variable used in the example then you will be able to access it after PqExample has finished as ANUPQData.examples.vars.F. 3.4-5 AllPqExamples AllPqExamples( )  function returns a list of all currently available examples in default UNIX-listing (i.e. alphabetic) order. 3.4-6 GrepPqExamples GrepPqExamples( string )  function runs the UNIX command grep string over the ANUPQ examples and returns the list of examples for which there is a match. The actual matches are Info-ed at InfoANUPQ level 2. 3.4-7 ToPQLog ToPQLog( [filename] )  function With string argument filename, ToPQLog opens the file with name filename for logging; all commands written to the pq binary (that are Info-ed behind a ToPQ>  prompt at InfoANUPQ level 4) are then also written to that file (but without prompts). With no argument, ToPQLog stops logging to whatever file was being logged to. If a file was already being logged to, that file is closed and the file with name filename is opened for logging. 3.5 Attributes and a Property for fp and pc p-groups 3.5-1 NuclearRank NuclearRank( G )  attribute MultiplicatorRank( G )  attribute IsCapable( G )  property return the nuclear rank of G, p-multiplicator rank of G, and whether G is capable (i.e. true if it is, or false if it is not), respectively. These attributes and property are set automatically if G is one of the following:  an fp group returned by PqStandardPresentation or StandardPresentation (see PqStandardPresentation (4.2-1));  the image (fp group) of the epimorphism returned by an EpimorphismPqStandardPresentation or EpimorphismStandardPresentation call (see EpimorphismPqStandardPresentation (4.2-2)); or  one of the pc groups of the list of descendants returned by PqDescendants (see PqDescendants (4.4-1)). If G is an fp group or a pc p-group and not one of the above and the attribute or property has not otherwise been set for G, then PqStandardPresentation is called to set all three of NuclearRank, MultiplicatorRank and IsCapable, before returning the value of the attribute or property actually called. Such a group G must know in advance that it is a p-group; this is the case for the groups returned by the functions Pq and PqPCover, and the image group of the epimorphism returned by PqEpimorphism. Otherwise, if you know the group to be a p-group, then this can be set by typing  SetIsPGroup( G, true );  or by invoking IsPGroup( G ). Note that for an fp group G, the latter may result in a coset enumeration which might not terminate in a reasonable time. Note: For G such that HasNuclearRank(G) = true, IsCapable(G) is equivalent to (the truth or falsity of) NuclearRank( G ) = 0. 3.6 Hints and Warnings regarding the use of Options On a first reading we recommend you skip this section and come back to it if and when you run into trouble. Note: By options we refer to GAP options. The pq program also uses the term option; to distinguish the two usages of option, in this manual we use the term menu item to refer to what the pq program refers to as an option. Options are passed to the ANUPQ interface functions in either of the two usual mechanisms provided by GAP, namely:  options may be set globally using the function PushOptions (see Chapter Reference: Options Stack in the GAP Reference Manual); or  options may be appended to the argument list of any function call, separated by a colon from the argument list (see Chapter Reference: Function Calls in the GAP Reference Manual), in which case they are then passed on recursively to any subsequent inner function call, which may in turn have options of their own. Particularly, when one is using the interactive functions of Chapter 'Interactive ANUPQ functions', one should, in general, avoid using the global method of passing options. In fact, it is recommended that prior to calling PqStart the OptionsStack be empty. The essential problem with setting options globally using the function PushOptions is that options pushed onto OptionsStack, in this way, (generally) remain there until an explicit PopOptions() call is made. In contrast, options passed in the usual way behind a colon following a function's arguments (see Reference: Function Call With Options in the GAP Reference Manual) are local, and disappear from OptionsStack after the function has executed successfully. If the function does not execute successfully, i.e. it runs into error and the user quits the resulting break loop (see Section Reference: Break Loops in the Reference Manual) rather than attempting to repair the problem and typing return; then, unless the error at the kernel level, the OptionsStack is reset. If an error is detected inside the kernel (hopefully, this should occur only rarely, if at all) then the options of that function will not be cleared from OptionsStack; in such cases:  Example  gap> ResetOptionsStack(); #I Options stack is already empty  is usually necessary (see Chapter ResetOptionsStack (Reference: ResetOptionsStack) in the GAP Reference Manual), which recursively calls PopOptions() until OptionsStack is empty, or as in the above case warns you that the OptionsStack is already empty. Note that a function, that is passed options after the colon, will also see any global options or any options passed down recursively from functions calling that function, unless those options are over-ridden by options passed via the function. Also, note that duplication of option names for different programs may lead to misinterpretations, and mis-spelled options will not be seen. The non-interactive functions of Chapter 'Non-interactive ANUPQ functions' that have Pq somewhere in their name provide an alternative method of passing options as additional arguments. This has the advantages that options can be abbreviated and mis-spelled options will be trapped. 3.6-1 ANUPQWarnOfOtherOptions ANUPQWarnOfOtherOptions global variable is a global variable that is by default false. If it is set to true then any function provided by the ANUPQ function that recognises at least one option, will warn you of other options, i.e. options that the function does not recognise. These warnings are emitted at InfoWarning or InfoANUPQ level 1. This is useful for detecting mis-spelled options. Here is an example using the function Pq (first described in Chapter 'Non-interactive ANUPQ functions'):  Example  gap> SetInfoLevel(InfoANUPQ, 1); # Set InfoANUPQ to default level gap> ANUPQWarnOfOtherOptions := true;; gap> # The following makes entry into break loops very ``quiet'' ... gap> OnBreak := function() Where(0); end;; gap> F := FreeGroup( "a", "b" );  gap> Pq( F : Prime := 2, Classbound := 1 ); #I ANUPQ Warning: Options: [ "Classbound" ] ignored #I (invalid for generic function: `Pq'). user interrupt at moreOfline := ReadLine( iostream ); Entering break read-eval-print loop ... you can 'quit;' to quit to outer loop, or you can 'return;' to continue  Here we mistyped ClassBound as Classbound, and after seeing the Info-ed warning that Classbound was ignored, we typed a control-C (that's the user interrupt at message) which took us into a break loop. Since the Pq command was not able to finish, the options Prime and Classbound, in particular, will still be on the OptionsStack:  Example  brk> OptionsStack; [ rec( Prime := 2, Classbound := 1 ),   rec( Prime := 2, Classbound := 1, PqEpiOrPCover := "pQuotient" ) ]  The option PqEpiOrPCover is a behind-the-scenes option that need not concern the user. On quitting the break-loop the OptionsStack is reset and a warning telling you this is emitted:  Example  brk> quit; # to get back to the `gap>' prompt #I Options stack has been reset  Above, we altered OnBreak (see OnBreak (Reference: OnBreak) in the Reference manual) to reduce the back-tracing on entry into a break loop. We now restore OnBreak to its usual value.  Example  gap> OnBreak := Where;;  Notes In cases where functions recursively call others with options (e.g. when using PqExample with options), setting ANUPQWarnOfOtherOptions := true may give rise to spurious other option detections. It is recommended that the novice user set ANUPQWarnOfOtherOptions to true in their gap.ini file (see Section 'Loading the ANUPQ Package'). Other Troubleshooting Strategies There are some other strategies which may have helped us to see our error above. The function Pq recognises the option OutputLevel (see 6.2); if this option is set to at least 1, the pq program provides information on each class quotient as it is generated:  Example  gap> ANUPQWarnOfOtherOptions := false;; # Set back to normal gap> F := FreeGroup( "a", "b" );; gap> Pq( F : Prime := 2, Classbound := 1, OutputLevel := 1 );  #I Lower exponent-2 central series for [grp] #I Group: [grp] to lower exponent-2 central class 1 has order 2^2 #I Group: [grp] to lower exponent-2 central class 2 has order 2^5 #I Group: [grp] to lower exponent-2 central class 3 has order 2^10 #I Group: [grp] to lower exponent-2 central class 4 has order 2^18 #I Group: [grp] to lower exponent-2 central class 5 has order 2^32 #I Group: [grp] to lower exponent-2 central class 6 has order 2^55 #I Group: [grp] to lower exponent-2 central class 7 has order 2^96 #I Group: [grp] to lower exponent-2 central class 8 has order 2^167 #I Group: [grp] to lower exponent-2 central class 9 has order 2^294 #I Group: [grp] to lower exponent-2 central class 10 has order 2^520 #I Group: [grp] to lower exponent-2 central class 11 has order 2^932 #I Group: [grp] to lower exponent-2 central class 12 has order 2^1679 [... output truncated ...]  After seeing the information for the class 2 quotient we may have got the idea that the Classbound option was not recognised and may have realised that this was due to a mis-spelling. The above will ordinarily cause the available space to be exhausted, necessitating user-intervention by typing control-C and quit; (to escape the break loop); otherwise Pq terminates when the class reaches 63 (the default value of ClassBound). If you have some familiarity with keyword command input to the pq binary, then setting the level of InfoANUPQ to 4 would also have indicated a problem:  Example  gap> ResetOptionsStack(); # Necessary, if a break-loop was entered above gap> SetInfoLevel(InfoANUPQ, 4); gap> Pq( F : Prime := 2, Classbound := 1 ); #I ToPQ> 7 #to (Main) p-Quotient Menu #I ToPQ> 1 #define group #I ToPQ> name [grp] #I ToPQ> prime 2 #I ToPQ> class 63 #I ToPQ> exponent 0 #I ToPQ> output 0 #I ToPQ> generators { a,b } #I ToPQ> relators { }; [... output truncated ...]  Here the line #I ToPQ> class 63 indicates that a directive to set the classbound to 63 was sent to the pq program.