|
|
|
|
Quelle anupqi.gi
Sprache: unbekannt
|
|
#############################################################################
####
##
#W anupqi.gi ANUPQ package Greg Gamble
##
## This file installs interactive functions that execute individual pq menu
## options.
##
#Y Copyright (C) 2001 Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
##
#############################################################################
##
#F PQ_UNBIND( <datarec>, <fields> ) . . . . . unbind fields of a data record
##
## unbinds the fields in the list <fields> of that data record <datarec>.
##
InstallGlobalFunction( PQ_UNBIND, function( datarec, fields )
local field;
for field in fields do
Unbind( datarec.(field) );
od;
end );
#############################################################################
##
#F PQ_AUT_GROUP( <G> ) . . . . . . . . . . . . . . . . . automorphism group
##
## returns the automorphism group of a $p$-group as a record, avoiding
## computation if possible (currently it *isn't* possible), or else uses
## {\AutPGrp}'s `AutomorphismGroupPGroup'.
##
InstallGlobalFunction( PQ_AUT_GROUP, function( G )
local autgrp;
if not IsPGroup(G) then
Error("group <G> must be a p-group\n");
fi;
if false and HasANUPQAutomorphisms(G) then
# Can't use this because we currently don't know how to interpret
# the automorphism information returned by the standalone properly.
autgrp := PqSupplementInnerAutomorphisms(G);
elif false and HasAutomorphismGroup(G) then
# Can't use existing automorphism information because it does not
# contain the information required by the standalone.
autgrp := AutomorphismGroup( G );
elif LoadPackage("autpgrp") = true or IsAbelian(G) then
autgrp := AutomorphismGroupPGroup(G);
else
return Error( "since package `AutPGrp' is not installed\n",
"<G> must have class 1 or <G>'s aut. group must be known.\n",
"Please install the `AutPGrp' package\n" );
fi;
return autgrp;
end );
#############################################################################
##
#F PQ_AUT_INPUT( <datarec>, <G> : <options> ) . . . . . . automorphism input
##
## inputs automorphism data for `<datarec>.group' given by <options> to the
## `pq' binary derived from the pc group <G> (used in option 1 of the
## $p$-Group Generation menu and option 2 of the Standard Presentation menu).
##
InstallGlobalFunction( PQ_AUT_INPUT, function( datarec, G )
local autrec, nrautos, rank, gens, i, aut, j, g, exponents;
autrec := PQ_AUT_GROUP( G );
nrautos := Length( autrec.glAutos ) + Length( autrec.agAutos );
## the automorphisms have to be in a special form which PQ_AUT_GROUP()
## *must* deliver.
rank := RankPGroup( G );
gens := PcgsPCentralSeriesPGroup( G );
ToPQ(datarec, [ nrautos ], [ " #number of automorphisms" ]);
## First write out the automorphisms generating a soluble normal subgroup
## of the automorphism group of the p-group. These automorphisms may
## not have a faithful representation on the Frattini quotient of the
## p-group and are treated accordingly by the standalone.
##
## They are written out in bottom up fashion as this is the order in
## which the orbit algorithm for a group given by an ag-system needs
## them.
for i in Reversed([1..Length(autrec.agAutos)]) do
aut := autrec.agAutos[i];
for j in [1..rank] do
g := gens[j];
exponents := Flat( List( ExponentsOfPcElement(gens, Image( aut, g )),
e -> [ String(e), " "] ) );
ToPQ(datarec, [ exponents ],
[ " #gen'r exp'ts of im(ag aut ", i, ", gen ", j, ")" ]);
od;
od;
## Now output the automorphisms from the insoluble quotient of the
## automorphism group of the p-group. These have a faithful
## representation on the Frattini quotient of the p-group and are
## treated accordingly by the standalone.
for i in Reversed( [1..Length(autrec.glAutos)] ) do
aut := autrec.glAutos[i];
for j in [1..rank] do
g := gens[j];
exponents := Flat( List( ExponentsOfPcElement(gens, Image( aut, g )),
e -> [ String(e), " "] ) );
ToPQ(datarec, [ exponents ],
[ " #gen'r exp'ts of im(gl aut ", i, ", gen ", j, ")" ]);
od;
od;
if PQ_MENU(datarec) = "pG" then
## ?? Why only the pG menu ??
## Finally, tell the standalone the number of soluble automorphisms
## and the relative order of each automorphism.
ToPQ(datarec, [ Length(autrec.agOrder) ],
[ " #number of soluble automorphisms" ]);
for i in Reversed( [1..Length( autrec.agOrder )] ) do
ToPQ( datarec, [ autrec.agOrder[i] ],
[ " #rel order of ", i, "th ag automorphism" ] );
od;
fi;
end );
#############################################################################
##
#F PQ_MANUAL_AUT_INPUT(<datarec>,<mlist>) . automorphism input w/o an Aut gp
##
## inputs automorphism data for `<datarec>.group' given by <mlist> to the
## `pq' binary.
##
InstallGlobalFunction( PQ_MANUAL_AUT_INPUT, function( datarec, mlist )
local line, nauts, nsolauts, rank, nexpts, i, j, aut, exponents;
nauts := Length(mlist);
rank := Length(mlist[1]);
ToPQ(datarec, [ nauts ], [ " #no. of auts" ]);
if datarec.line = "Input the number of exponents: " then
nexpts := Length(mlist[1][1]);
ToPQ(datarec, [ nexpts ], [ " #no. of exponents" ]);
fi;
for i in [1..nauts] do
aut := mlist[i];
for j in [1..rank] do
exponents := Flat( List( aut[j], e -> [ String(e), " "] ) );
ToPQ(datarec, [ exponents ],
[ " #gen'r exp'ts of im(aut ", i, ", gen ", j, ")" ]);
od;
od;
if PQ_MENU(datarec) = "pG" then
## ?? Why only the pG menu ??
## Finally, tell the standalone the number of soluble automorphisms
## and the relative order of each automorphism.
ToPQ(datarec, [ datarec.NumberOfSolubleAutomorphisms ],
[ " #number of soluble automorphisms" ]);
if datarec.NumberOfSolubleAutomorphisms > 0 then
for i in datarec.RelativeOrders do
ToPQ( datarec, [ datarec.RelativeOrders[i] ],
[ " #rel order of ", i, "th ag automorphism" ] );
od;
fi;
fi;
end );
#############################################################################
##
#F PQ_AUT_ARG_CHK(<minnargs>, <args>) . checks args for a func defining auts
##
## checks that the arguments make sense for a function that defines
## automorphisms, and if one of the arguments is a list checks as much as is
## possible that it is a list of matrices that will be valid input as
## automorphisms for the `pq' binary. If the arguments look ok a list
## containing the `ANUPQData.io' index of the data record and, if relevant,
## a list of matrices is returned.
##
InstallGlobalFunction( PQ_AUT_ARG_CHK, function( minnargs, args )
local ioIndex, datarec, mlist, rank, nexpts;
if Length(args) < minnargs then
Error("expected at least 1 argument\n"); #minnargs is 0 or 1
elif 2 < Length(args) then
Error("expected at most 2 arguments\n");
fi;
if not IsEmpty(args) and IsList(args[ Length(args) ]) then
mlist := args[ Length(args) ];
args := args{[1 .. Length(args) - 1]};
fi;
ioIndex := CallFuncList(PqProcessIndex, args);
if not IsBound(mlist) then
return [ioIndex];
elif not( IsList(mlist) and ForAll(mlist, IsMatrix) and
ForAll(Flat(mlist), i -> IsInt(i) and i >= 0) ) then
Error("<mlist> must be a list of matrices with ",
"non-negative integer coefficients\n");
fi;
datarec := ANUPQData.io[ ioIndex ];
if IsBound( datarec.pQuotient ) then
rank := RankPGroup( datarec.pQuotient );
else
rank := Length(mlist[1]); # Should we allow this?
fi;
if not ForAll(mlist, mat -> Length(mat) = rank) then
Error("no. of rows in each matrix of <mlist> must be the rank of ",
"p-quotient (", rank, ")\n");
fi;
nexpts := Length(mlist[1][1]);
if not ForAll(mlist, mat -> Length(mat[1]) = nexpts) then
Error("each matrix of <mlist> must have the same no. of columns\n");
fi;
return [ioIndex, mlist];
end );
#############################################################################
##
#F PQ_PC_PRESENTATION( <datarec>, <menu> ) . . . . . . p-Q/SP menu option 1
##
## inputs data given by <options> to the `pq' binary for group
## `<datarec>.group' to compute a pc presentation (do option 1 of the
## relevant menu) according to the <menu> menu, where <menu> is either
## `"pQ"' (main $p$-Quotient menu) or `"SP' (Standard Presentation menu).
##
InstallGlobalFunction( PQ_PC_PRESENTATION, function( datarec, menu )
local gens, rels, p, fpgrp, identities, pcgs, len, strp, i, j, Rel, line;
p := VALUE_PQ_OPTION("Prime", fail, datarec); # "Prime" is a `global' option
PQ_MENU(datarec, menu);
identities := menu = "pQ" and
VALUE_PQ_OPTION("Identities", [], datarec) <> [];
# Option 1 of p-Quotient/Standard Presentation Menu: defining the group
ToPQk(datarec, [1], [" #define group"]);
if VALUE_PQ_OPTION("GroupName", "[grp]", datarec) = "[grp]" and
IsBound(datarec.group) and IsBound(datarec.group!.Name) then
datarec.GroupName := datarec.group!.Name;
fi;
ToPQk(datarec, ["name ", datarec.GroupName], []);
ToPQk(datarec, ["prime ", p], []);
if identities then
datarec.prevngens := 0;
ToPQk(datarec, ["class ", 1], []);
else
ToPQk(datarec, ["class ", VALUE_PQ_OPTION("ClassBound", 63, datarec)], []);
fi;
ToPQk(datarec, ["exponent ", VALUE_PQ_OPTION("Exponent", 0, datarec)], []);
# "Exponent" is a `global' option
if VALUE_PQ_OPTION( "Metabelian", false, datarec ) = true then
ToPQk(datarec, [ "metabelian" ], []);
fi;
ToPQk(datarec, ["output ", VALUE_PQ_OPTION("OutputLevel", 0, datarec)], []);
if IsFpGroup(datarec.group) then
gens := FreeGeneratorsOfFpGroup(datarec.group);
rels := VALUE_PQ_OPTION("Relators", datarec);
if rels = fail then
rels := RelatorsOfFpGroup(datarec.group);
elif ForAll( rels, rel -> PqParseWord(datarec.group, rel) ) then
Info(InfoANUPQ, 2, "Relators parsed ok.");
fi;
elif not( IsPGroup(datarec.group) ) then
fpgrp := FpGroupPcGroup( datarec.group );
gens := FreeGeneratorsOfFpGroup(fpgrp);
rels := RelatorsOfFpGroup(fpgrp);
else
pcgs := PcgsPCentralSeriesPGroup(datarec.group);
datarec.pcgs := pcgs;
len := Length(pcgs);
gens := List( [1..len], i -> Concatenation( "g", String(i) ) );
strp := String(p);
Rel := function(elt, eltstr)
local rel, expts, factors;
rel := eltstr;
expts := ExponentsOfPcElement( pcgs, elt );
if ForAny( expts, x -> x<>0 ) then
factors
:= Filtered(
List( [1..len],
function(i)
if expts[i] = 0 then
return "";
fi;
return Concatenation(gens[i], "^", String(expts[i]));
end ),
factor -> factor <> "");
Append(rel, "=");
Append(rel, JoinStringsWithSeparator(factors, "*"));
fi;
return rel;
end;
rels := List( [1..len],
i -> Rel( pcgs[i]^p, Concatenation(gens[i], "^", strp) ) );
for i in [1..len] do
for j in [1..i-1] do
Add(rels, Rel( Comm( pcgs[i], pcgs[j] ),
Concatenation("[", gens[i], ",", gens[j], "]") ));
od;
od;
fi;
if Length(gens) > 511 then
# The pq program defines MAXGENS to be 511 in `../include/runtime.h'
# ... on the other hand, the number of pc gen'rs can be up to 65535
Error("number of defining generators, ", Length(gens), ", too large.\n",
"The pq program defines MAXGENS (the maximum number of defining\n",
"generators) to be 511.\n");
fi;
datarec.gens := gens;
datarec.rels := rels;
ToPQk(datarec, "gens", []);
datarec.match := true;
ToPQ(datarec, "rels", []);
## pq is intolerant of long lines and integers that are split over lines
#rels := Concatenation(
# "relators { ", JoinStringsWithSeparator( rels, ", " ), " };");
#while Length(rels) >= 69 do
# i := 68;
# while not (rels[i] in "*^, ") do i := i - 1; od;
# ToPQk(datarec, [ rels{[1 .. i]} ], []);
# rels := Concatenation( " ", rels{[i + 1 .. Length(rels)]} );
#od;
#ToPQ(datarec, [ rels ], []);
datarec.haspcp := true;
# The `pq' only sets OutputLevel locally within the menu item
# ... for the GAP interface this would be too confusing; so we
# set it `globally'
PQ_SET_OUTPUT_LEVEL(datarec, datarec.OutputLevel);
PQ_SET_GRP_DATA(datarec);
if identities and datarec.ngens[1] <> 0 then
PQ_EVALUATE_IDENTITIES(datarec);
VALUE_PQ_OPTION("ClassBound", 63, datarec);
while datarec.class < datarec.ClassBound and
datarec.prevngens <> datarec.ngens[ datarec.class ] do
PQ_NEXT_CLASS(datarec);
od;
fi;
end );
#############################################################################
##
#F PqPcPresentation( <i> : <options> ) . . user version of p-Q menu option 1
#F PqPcPresentation( : <options> )
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to compute the pc presentation of the quotient (determined by
## <options>) of the group of the process, which for process <i> is stored
## as `ANUPQData.io[<i>].group'.
##
## The possible <options> are the same as for the interactive `Pq'
## (see~"Pq!interactive") function, namely: `Prime', `ClassBound',
## `Exponent', `Relators', `GroupName', `Metabelian' and `OutputLevel' (see
## Chapter~"ANUPQ options" for a detailed description for these options).
## The option `Prime' is required unless already provided to `PqStart'.
## Also, option `ClassBound' *must* be supplied.
##
## *Notes*
##
## The pc presentation is held by the `pq' binary. There is no output of a
## {\GAP} pc group; see~`PqCurrentGroup' ("PqCurrentGroup") if you need the
## corresponding {\GAP} pc group.
##
## For those familiar with the `pq' binary, `PqPcPresentation' performs menu
## item 1 of the main $p$-Quotient menu.
##
InstallGlobalFunction( PqPcPresentation, function( arg )
local datarec;
PQ_OTHER_OPTS_CHK("PqPcPresentation", true);
datarec := CallFuncList(ANUPQDataRecord, arg);
PQ_PC_PRESENTATION( datarec, "pQ" );
end );
#############################################################################
##
#F PQ_SAVE_PC_PRESENTATION( <datarec>, <filename> ) . . . p-Q menu option 2
##
## directs the `pq' binary to save the pc presentation previously computed
## for `<datarec>.group' to <filename> using option 2 of the main
## $p$-Quotient menu.
##
InstallGlobalFunction( PQ_SAVE_PC_PRESENTATION, function( datarec, filename )
PQ_MENU(datarec, "pQ");
ToPQ(datarec, [ 2 ], [ " #save pc presentation to file" ]);
datarec.filter := ["Presentation"];
ToPQ(datarec, [ filename ], [ " #filename" ]);
Unbind(datarec.filter);
end );
#############################################################################
##
#F PQ_PATH_CURRENT_DIRECTORY() . . . . . . . . . . essentially the UNIX pwd
##
## returns a string that is the path of the current directory.
##
InstallGlobalFunction( PQ_PATH_CURRENT_DIRECTORY, function()
local path, stream;
path := "";
stream := OutputTextString(path, true);
if 0 = Process( DirectoryCurrent(),
Filename(DirectoriesSystemPrograms(), "pwd"),
InputTextNone(),
stream,
[] ) then
CloseStream(stream);
return Chomp(path);
fi;
Error("could not determine the path of the current directory!?!\n");
end );
#############################################################################
##
#F PQ_CHK_PATH(<filename>, <rw>, <datarec>) . . . . . . . check/add to path
##
## checks <filename> is a non-empty string, if it doesn't begin with a `/'
## prepends a path for the current directory, and checks the result is the
## name of a readable (resp. writable) if <rw> is `"r"' (resp. if <rw> is
## `"w"') and if there is no error returns the result.
##
InstallGlobalFunction( PQ_CHK_PATH, function( filename, rw, datarec )
if not IsString(filename) or filename = "" then
Error( "argument <filename> must be a non-empty string\n" );
fi;
if filename[1] <> '/' then
# we need to do this as pq executes in ANUPQData.tmpdir
filename := Concatenation(PQ_PATH_CURRENT_DIRECTORY(), "/", filename);
fi;
if rw = "r" then
if IsReadableFile(filename) <> true then
Error( "file with name <filename> is not readable\n" );
fi;
else # rw = "w"
if not IsBound(datarec.setupfile) then
PrintTo(filename, ""); # This is what will generate the error
# but it also ensures it's empty
fi;
if IsWritableFile(filename) <> true then
Error( "file with name <filename> cannot be written to\n" );
fi;
fi;
return filename;
end );
#############################################################################
##
#F PqSavePcPresentation( <i>, <filename> ) . . user ver. of p-Q menu opt. 2
#F PqSavePcPresentation( <filename> )
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## program to save the pc presentation previously computed for the quotient
## of the group of that process to the file with name <filename>. If the
## first character of the string <filename> is not `/', <filename> is
## assumed to be the path of a writable file relative to the directory in
## which {\GAP} was started. A saved file may be restored by
## `PqRestorePcPresentation' (see~"PqRestorePcPresentation").
##
## *Note:* For those familiar with the `pq' binary, `PqSavePcPresentation'
## performs menu item 2 of the main $p$-Quotient menu.
##
InstallGlobalFunction( PqSavePcPresentation, function( arg )
local datarec, filename;
if 0 = Length(arg) or Length(arg) > 2 then
Error( "expected 1 or 2 arguments\n" );
fi;
datarec := CallFuncList(ANUPQDataRecord, arg{[1..Length(arg) - 1]});
filename := PQ_CHK_PATH( arg[Length(arg)], "w", datarec );
PQ_SAVE_PC_PRESENTATION( datarec, filename );
end );
#############################################################################
##
#F PQ_RESTORE_PC_PRESENTATION( <datarec>, <filename> ) . . p-Q menu option 3
##
## directs the `pq' binary to restore the pc presentation previously saved
## to <filename> using option 3 of the main $p$-Quotient menu.
##
InstallGlobalFunction( PQ_RESTORE_PC_PRESENTATION, function( datarec, filename )
PQ_MENU(datarec, "pQ");
ToPQ(datarec, [ 3 ], [ " #restore pc presentation from file" ]);
datarec.match := true;
ToPQ(datarec, [ filename ], [ " #filename" ]);
datarec.haspcp := true;
PQ_SET_GRP_DATA(datarec);
end );
#############################################################################
##
#F PqRestorePcPresentation( <i>, <filename> ) . user ver. of p-Q menu opt. 3
#F PqRestorePcPresentation( <filename> )
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## program to restore the pc presentation previously saved to <filename>, by
## `PqSavePcPresentation' (see~"PqSavePcPresentation"). If the first
## character of the string <filename> is not `/', <filename> is assumed to
## be the path of a readable file relative to the directory in which {\GAP}
## was started.
##
## *Note:*
## For those familiar with the `pq' binary, `PqRestorePcPresentation'
## performs menu item 3 of the main $p$-Quotient menu.
##
InstallGlobalFunction( PqRestorePcPresentation, function( arg )
local datarec, filename;
if 0 = Length(arg) or Length(arg) > 2 then
Error( "expected 1 or 2 arguments\n" );
fi;
datarec := CallFuncList(ANUPQDataRecord, arg{[1..Length(arg) - 1]});
filename := PQ_CHK_PATH( arg[Length(arg)], "r", datarec );
PQ_RESTORE_PC_PRESENTATION( datarec, filename );
end );
#############################################################################
##
#F PQ_DISPLAY_PRESENTATION( <datarec> ) . . . . . . . . . any menu option 4
##
## directs the `pq' binary to display the pc presentation of the group to
## the current class, using option 4 of the current menu.
##
InstallGlobalFunction( PQ_DISPLAY_PRESENTATION, function( datarec )
if datarec.menu[ Length(datarec.menu) ] <> 'G' and
VALUE_PQ_OPTION("OutputLevel", datarec) <> fail then
PQ_SET_OUTPUT_LEVEL( datarec, datarec.OutputLevel );
fi;
ToPQ(datarec, [ 4 ], [ " #display presentation" ]);
end );
#############################################################################
##
#F PQ_GRP_EXISTS_CHK( <datarec> ) . . check the `pq' binary knows about a gp
##
## checks that `<datarec>.ngens' is set and non-empty (which can only happen
## if the `pq' binary has been fed a group) and generates an error if not.
##
InstallGlobalFunction( PQ_GRP_EXISTS_CHK, function( datarec )
if not IsBound(datarec.ngens) or IsEmpty(datarec.ngens) then
Error( "huh! No current group defined for this process!?\n" );
fi;
end );
#############################################################################
##
#F PQ_SET_GRP_DATA( <datarec> ) . save group data of current class of group
##
## If `<datarec>.matchedline' is not set the `pq' binary is called to
## display the presentation; usually `<datarec>.matchedline' is set when
## filtering `pq' output for lines starting with `"Group"' (the value set
## for `<datarec>.match'), but no such lines occur when computing a pc
## presentation with the `OutputLevel' option set to 0, or when restoring a
## pc presentation, or when computing tails etc. From this line the fields
## `name', `class' and `forder' of the record <datarec> are set to the name,
## class and factored order of that group, respectively. Also,
## `<datarec>.ngens' is updated, and if it is afterwards incomplete and the
## call to `PQ_SET_GRP_DATA' was not initiated by `PQ_DATA' then `PQ_DATA'
## is called to ensure `<datarec>.ngens' is complete.
##
InstallGlobalFunction( PQ_SET_GRP_DATA, function( datarec )
local line, classpos;
if IsBound(datarec.setupfile) then
# A fudge ... some things we can only know by actually running it!
Info(InfoANUPQ + InfoWarning,1,
"Guess made of `class' and `ngens' fields");
Info(InfoANUPQ + InfoWarning,1,
"... please check commands ok by running without `SetupFile' option");
Info(InfoANUPQ + InfoWarning,1,
"and comparing with `ToPQ> ' commands observed at InfoANUPQ level 4");
datarec.class := datarec.ClassBound;
datarec.ngens := [ 1 ];
return;
fi;
# Either datarec.matchedline is of one of the following forms:
# Group completed. Lower exponent-<p> central class = <c>, Order = <p>^<n>
# Group: [grp] to lower exponent-<p> central class <c> has order <p>^<n>
if not IsBound(datarec.matchedline) then
PushOptions(rec(nonuser := true));
ToPQ(datarec, [ 4 ], [ " #display presentation" ]);
PopOptions();
fi;
line := SplitString(datarec.matchedline, "", ":,. ^\n");
if line[2] = "completed" then
classpos := Position(line, "class") + 2;
#if not IsBound(datarec.name) then #do we need to bother?
# datarec.name := "[grp]";
#fi;
else
# Only the ``incomplete'' form of datarec.matchedline gives the name
datarec.name := line[2];
datarec.gpnum := JoinStringsWithSeparator(
line{[3 .. Position(line, "to") - 1]}, " " );
classpos := Position(line, "class") + 1;
fi;
datarec.class := Int( line[classpos] );
datarec.forder := List( line{[classpos + 3, classpos + 4]}, Int);
PQ_UNBIND(datarec, ["match", "matchedline"]);
# First see if we can update datarec.ngens cheaply
if not IsBound(datarec.ngens) then
datarec.ngens := [];
fi;
if datarec.class > 0 then
datarec.ngens[ datarec.class ] := datarec.forder[2];
#The `pq' binary reduces the class by 1
#if the no. of gen'rs doesn't increase
Unbind( datarec.ngens[ datarec.class + 1 ] );
fi;
if not IsBound(datarec.inPQ_DATA) and not IsDenseList(datarec.ngens) then
# It wasn't possible to update datarec.ngens cheaply
PQ_DATA( datarec );
fi;
end );
#############################################################################
##
#F PQ_DATA( <datarec> ) . . . . gets class/gen'r data from (A)p-Q menu opt 4
##
## ensures that the menu is a $p$-Quotient menu and that the output level is
## 3 and using option 4 of the now current menu extracts the number of
## generators of each class currently known to the `pq' binary. (The order
## of each $p$-class quotient is taken as $p^n$ where $n$ is the number of
## generators for the class; this may be an over-estimate if tails have been
## added and the necessary consistency checks, relation collections,
## exponent law checks and redundant generator eliminations have not been
## done for a class.) All output that would have appeared at `InfoANUPQ'
## levels 1 or 2 if user-initiated is `Info'-ed at `InfoANUPQ' level 3. The
## menu and output level are reset to their original values (if changed) on
## leaving.
##
InstallGlobalFunction( PQ_DATA, function( datarec )
local menu, lev, ngen, i, line, class;
if not( IsBound(datarec.haspcp) and datarec.haspcp ) then
Error( "a pc presentation for the group of the process ",
"has not yet been defined\n" );
fi;
PushOptions(rec(nonuser := true));
datarec.inPQ_DATA := true;
if datarec.menu[ Length(datarec.menu) ] <> 'Q' then
menu := datarec.menu;
PQ_MENU(datarec, "pQ");
fi;
if not IsBound(datarec.OutputLevel) then
lev := 0;
PQ_SET_OUTPUT_LEVEL( datarec, 3 );
elif datarec.OutputLevel < 3 then
lev := datarec.OutputLevel;
PQ_SET_OUTPUT_LEVEL( datarec, 3 );
fi;
datarec.matchlist := ["Group", "Class", " is defined on "];
datarec.matchedlines := [];
ToPQ(datarec, [ 4 ], [ " #display presentation" ]);
datarec.matchedline := datarec.matchedlines[1];
PQ_SET_GRP_DATA(datarec);
for i in [2 .. Length(datarec.matchedlines)] do
line := SplitString(datarec.matchedlines[i], "", " \n");
if line[1] = "Class" then
class := Int( line[2] );
if class > 1 then
datarec.ngens[class - 1] := Int(ngen);
if class = datarec.class then
break;
fi;
fi;
else
ngen := line[1];
fi;
od;
if IsBound(menu) then
PQ_MENU(datarec, menu);
fi;
if IsBound(lev) then
PQ_SET_OUTPUT_LEVEL( datarec, lev );
fi;
PQ_UNBIND( datarec, ["matchlist", "matchedlines", "inPQ_DATA"] );
PopOptions();
end );
#############################################################################
##
#F PQ_DATA_CHK( <args> ) . . . call PQ_DATA if class/gen'r data out-of-date
##
## determines the data record <datarec>, calls `PQ_DATA' if necessary and
## returns <datarec>.
##
InstallGlobalFunction( PQ_DATA_CHK, function( args )
local datarec;
datarec := CallFuncList(ANUPQDataRecord, args);
if not IsBound(datarec.ngens) or IsEmpty(datarec.ngens) or
not IsDenseList(datarec.ngens) then
PQ_DATA( datarec );
fi;
return datarec;
end );
#############################################################################
##
#F PqFactoredOrder( <i> ) . the `pq' binary's current group's factored order
#F PqFactoredOrder()
##
## for the <i>th or default interactive {\ANUPQ} process, return an estimate
## of the factored order of the lower exponent $p$-class quotient of the
## group currently determined by the process as a list `[<p>, <n> ]'.
##
## *Note:* The order of each $p$-class quotient is taken as $p^n$ where $n$
## is the number of generators for the class; this may be an over-estimate
## if tails have been added and the necessary consistency checks, relation
## collections, exponent law checks and redundant generator eliminations
## have not yet been done for a class.
##
InstallGlobalFunction( PqFactoredOrder, function( arg )
return PQ_DATA_CHK(arg).forder;
end );
#############################################################################
##
#F PqOrder( <i> ) . . . . the order of the current group of the `pq' binary
#F PqOrder()
##
## for the <i>th or default interactive {\ANUPQ} process, return an estimate
## of the order of the lower exponent $p$-class quotient of the group
## currently determined by the process.
##
## *Note:* The order of each $p$-class quotient is taken as $p^n$ where $n$
## is the number of generators for the class; this may be an over-estimate
## if tails have been added and the necessary consistency checks, relation
## collections, exponent law checks and redundant generator eliminations
## have not been done for a class.
##
InstallGlobalFunction( PqOrder, function( arg )
local forder;
forder := CallFuncList( PqFactoredOrder, arg );
return forder[1]^forder[2];
end );
#############################################################################
##
#F PqPClass( <i> ) . . . the p class of the current group of the `pq' binary
#F PqPClass()
##
## for the <i>th or default interactive {\ANUPQ} process, return the lower
## exponent $p$-class of the quotient group currently determined by the
## process.
##
InstallGlobalFunction( PqPClass, function( arg )
return PQ_DATA_CHK(arg).class;
end );
#############################################################################
##
#F PqNrPcGenerators( <i> ) . number of pc gen'rs of `pq' binary's current gp
#F PqNrPcGenerators()
##
## for the <i>th or default interactive {\ANUPQ} process, return the number
## of pc generators of the lower exponent $p$-class quotient of the group
## currently determined by the process.
##
InstallGlobalFunction( PqNrPcGenerators, function( arg )
return PQ_DATA_CHK(arg).forder[2];
end );
#############################################################################
##
#F PqWeight( <i>, <j> ) . . . . . . . . . . . . . . . weight of a generator
#F PqWeight( <j> )
##
## for the <i>th or default interactive {\ANUPQ} process, return the weight
## of the <j>th pc generator of the lower exponent $p$-class quotient of the
## group currently determined by the process, or `fail' if there is no such
## numbered pc generator.
##
InstallGlobalFunction( PqWeight, function( arg )
local ngens, i, j;
if not Length(arg) in [1, 2] then
Error( "expected 1 or 2 arguments\n" );
fi;
j := arg[ Length(arg) ];
if not IsPosInt(j) then
Error( "argument <j> should be a positive integer\n" );
fi;
Unbind( arg[ Length(arg) ] );
ngens := PQ_DATA_CHK(arg).ngens;
return First([1 .. Length(ngens)], i -> ngens[i] >= j);
end );
#############################################################################
##
#F PqCurrentGroup( <i> ) . extracts current p-quotient or p-cover as a pc gp
#F PqCurrentGroup()
##
## for the <i>th or default interactive {\ANUPQ} process, return the lower
## exponent $p$-class quotient of the group or $p$-covering group currently
## determined by the process as a {\GAP} pc group.
##
InstallGlobalFunction( PqCurrentGroup, function( arg )
local datarec, out;
datarec := PQ_DATA_CHK(arg);
datarec.outfname := ANUPQData.outfile;
PushOptions( rec(nonuser := true) );
PQ_WRITE_PC_PRESENTATION(datarec, datarec.outfname);
PopOptions();
if IsBound(datarec.pcoverclass) and datarec.pcoverclass = datarec.class then
out := "pCover";
else
out := "pQuotient";
fi;
PQ_GROUP_FROM_PCP( datarec, out );
return datarec.(out);
end );
#############################################################################
##
#F PqDisplayPcPresentation( <i> ) . . . . user version of any menu option 4
#F PqDisplayPcPresentation()
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to display the pc presentation of the lower exponent $p$-class
## quotient of the group currently determined by the process.
##
## Except if the last command communicating with the `pq' binary was a
## $p$-group generation command (for which there is only a verbose output
## level), to set the amount of information this command displays you may
## wish to call `PqSetOutputLevel' first (see~"PqSetOutputLevel"), or
## equivalently pass the option `OutputLevel' (see~"option OutputLevel").
##
## *Note:*
## For those familiar with the `pq' binary, `PqDisplayPcPresentation'
## performs menu item 4 of the current menu of the `pq' binary.
##
InstallGlobalFunction( PqDisplayPcPresentation, function( arg )
local datarec;
datarec := CallFuncList(ANUPQDataRecord, arg);
PQ_GRP_EXISTS_CHK( datarec );
PQ_DISPLAY_PRESENTATION( datarec );
end );
#############################################################################
##
#F PQ_SET_OUTPUT_LEVEL(<datarec>, <lev>) . . . . p-Q/SP/A p-Q menu option 5
##
## inputs data to the `pq' binary to set the print level to <lev> in the
## current menu or the ``basic'' $p$-Quotient menu if the current menu is a
## $p$-Group generation menu.
##
InstallGlobalFunction( PQ_SET_OUTPUT_LEVEL, function( datarec, lev )
if datarec.menu[ Length(datarec.menu) ] = 'G' then
PQ_MENU(datarec, "pQ");
fi;
ToPQ(datarec, [ 5 ], [ " #set output level" ]);
ToPQ(datarec, [ lev ], [ " #output level" ]);
datarec.OutputLevel := lev;
end );
#############################################################################
##
#F PqSetOutputLevel( <i>, <lev> ) . user version of p-Q/SP/A p-Q menu opt 5
#F PqSetOutputLevel( <lev> )
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to set the output level of the `pq' binary to <lev>.
##
## *Note:* For those familiar with the `pq' binary, `PqSetOutputLevel'
## performs menu item 5 of the main (or advanced) $p$-Quotient menu, or the
## Standard Presentation menu.
##
InstallGlobalFunction( PqSetOutputLevel, function( arg )
local datarec, lev;
if not(Length(arg) in [1, 2]) then
Error( "1 or 2 arguments expected\n");
fi;
lev := arg[Length(arg)];
if not(lev in [0..3]) then
Error( "argument <lev> should be an integer in [0 .. 3]\n" );
fi;
datarec := CallFuncList(ANUPQDataRecord, arg{[1..Length(arg) - 1]});
PQ_SET_OUTPUT_LEVEL( datarec, lev);
end );
#############################################################################
##
#F PQ_NEXT_CLASS( <datarec> ) . . . . . . . . . . . . . . p-Q menu option 6
##
## directs the `pq' binary to calculate the next class of `<datarec>.group',
## using option 6 of the main $p$-Quotient menu.
##
#T Another possibility for checking for whether a queue factor is needed
#T is to test for `<datarec>.hasAuts'.
##
InstallGlobalFunction( PQ_NEXT_CLASS, function( datarec )
local line;
PQ_MENU(datarec, "pQ");
PQ_UNBIND(datarec, ["pQuotient", "pQepi", "pCover"]);
if VALUE_PQ_OPTION("Identities", [], datarec) <> [] then
if datarec.class >= 1 then
datarec.prevngens := datarec.ngens[ datarec.class ];
fi;
PQ_P_COVER(datarec);
PQ_FINISH_NEXT_CLASS(datarec);
else
datarec.match := true;
ToPQ(datarec, [ 6 ], [ " #calculate next class" ]);
if IsMatchingSublist(datarec.line, "Input queue factor:") then
ToPQ(datarec, [ VALUE_PQ_OPTION("QueueFactor", 15) ],
[ " #queue factor"]);
fi;
PQ_SET_GRP_DATA(datarec);
fi;
end );
#############################################################################
##
#F PqNextClass( <i> [: <option>]) . . . . user version of p-Q menu option 6
#F PqNextClass( [: <option>])
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq' to
## calculate the next class of `ANUPQData.io[<i>].group'.
##
## \atindex{option QueueFactor}{@option \noexpand`QueueFactor'}
## `PqNextClass' accepts the option `QueueFactor' (see also~"option
## QueueFactor") which should be a positive integer if automorphisms have
## been previously supplied. If the `pq' binary requires a queue factor and
## none is supplied via the option `QueueFactor' a default of 15 is taken.
##
## *Notes*
##
## The single command: `PqNextClass(<i>);' is equivalent to executing
##
## \){\kernttindent}PqSetupTablesForNextClass(<i>);
## \){\kernttindent}PqTails(<i>, 0);
## \){\kernttindent}PqDoConsistencyChecks(<i>, 0, 0);
## \){\kernttindent}PqCollectDefiningRelations(<i>);
## \){\kernttindent}PqDoExponentChecks(<i>);
## \){\kernttindent}PqEliminateRedundantGenerators(<i>);
##
## For those familiar with the `pq' binary, `PqNextClass' performs menu item
## 6 of the main $p$-Quotient menu.
##
InstallGlobalFunction( PqNextClass, function( arg )
local datarec;
PQ_OTHER_OPTS_CHK("PqNextClass", true);
datarec := CallFuncList(ANUPQDataRecord, arg);
PQ_GRP_EXISTS_CHK( datarec );
PQ_NEXT_CLASS( datarec );
end );
#############################################################################
##
#F PQ_P_COVER( <datarec> ) . . . . . . . . . . . . . . . . p-Q menu option 7
##
## directs the `pq' binary to compute the $p$-covering group of
## `<datarec>.group', using option 7 of the main $p$-Quotient menu.
##
InstallGlobalFunction( PQ_P_COVER, function( datarec )
local savefile;
PQ_MENU(datarec, "pQ");
Unbind( datarec.pCover );
datarec.match := true;
ToPQ(datarec, [ 7 ], [ " #compute p-cover" ]);
PQ_SET_GRP_DATA(datarec);
datarec.pcoverclass := datarec.class;
Unbind(datarec.capable);
end );
#############################################################################
##
#F PqComputePCover( <i> ) . . . . . . . . user version of p-Q menu option 7
#F PqComputePCover()
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq' to
## compute the $p$-covering group of `ANUPQData.io[<i>].group'.
##
## *Notes*
##
## The single command: `PqComputePCover(<i>);' is equivalent to executing
##
## \){\kernttindent}PqSetupTablesForNextClass(<i>);
## \){\kernttindent}PqTails(<i>, 0);
## \){\kernttindent}PqDoConsistencyChecks(<i>, 0, 0);
## \){\kernttindent}PqEliminateRedundantGenerators(<i>);
##
## For those familiar with the `pq' binary, `PqComputePCover' performs menu
## item 7 of the main $p$-Quotient menu.
##
InstallGlobalFunction( PqComputePCover, function( arg )
local datarec;
datarec := CallFuncList(ANUPQDataRecord, arg);
PQ_GRP_EXISTS_CHK( datarec );
PQ_P_COVER( datarec );
end );
#############################################################################
##
#F PQ_EVALUATE_IDENTITIES(<datarec>) . evaluate Identities option identities
##
InstallGlobalFunction( PQ_EVALUATE_IDENTITIES, function( datarec )
local identity, procId;
procId := datarec.procId;
for identity in VALUE_PQ_OPTION("Identities", [], datarec) do
PQ_EVALUATE_IDENTITY(procId, identity);
od;
PQ_ELIMINATE_REDUNDANT_GENERATORS( datarec );
Info(InfoANUPQ, 1, "Class ", datarec.class, " with ",
PqNrPcGenerators(procId), " generators." );
end );
#############################################################################
##
#F PqEvaluateIdentities( <i> ) . . . . evaluate Identities option identities
#F PqEvaluateIdentities()
##
## for the <i>th or default interactive {\ANUPQ} process, invoke the
## evaluation of identities defined by the `Identities' option, and
## eliminate any redundant pc generators formed. Since a previous value of
## `Identities' is saved in the data record of the process, it is
## unnecessary to pass the `Identities' if set previously.
##
## *Note:* This function is mainly implemented at the {\GAP} level. It does
## not correspond to a menu item of the `pq' program.
##
InstallGlobalFunction( PqEvaluateIdentities, function( arg )
PQ_OTHER_OPTS_CHK("PqEvaluateIdentities", true);
PQ_EVALUATE_IDENTITIES( CallFuncList(ANUPQDataRecord, arg) );
end );
#############################################################################
##
#F PQ_FINISH_NEXT_CLASS( <datarec> ) . . . take the p-cover to a next class
##
## does the usual operations required after calculating the <p>-cover that
## brings the pcp back to a next class, except that it also slips in the
## evaluation of the identities of the `Identities' option.
##
InstallGlobalFunction( PQ_FINISH_NEXT_CLASS, function( datarec )
PushOptions( rec(nonuser := true) );
PQ_COLLECT_DEFINING_RELATIONS( datarec );
PQ_DO_EXPONENT_CHECKS( datarec, [1, datarec.class] );
PQ_EVALUATE_IDENTITIES( datarec );
PopOptions();
end );
#############################################################################
##
#F PQ_COLLECT( <datarec>, <word> ) . . . . . . . . . . . A p-Q menu option 1
##
## instructs the `pq' binary to do a collection on <word> a string
## representing a word in the current pc generators, e.g. `"x3*x2*x1"',
## using option 1 of the interactive $p$-Quotient menu.
##
InstallGlobalFunction( PQ_COLLECT, function( datarec, word )
PQ_MENU(datarec, "ApQ"); #we need options from the Advanced p-Q Menu
ToPQ(datarec, [ 1 ], [ " #do individual collection" ]);
datarec.match := "The result of collection is";
ToPQ(datarec, [ word, ";"], [ " #word to be collected" ]);
return PQ_WORD(datarec);
end );
#############################################################################
##
#F PQ_CHECK_WORD( <datarec>, <wordOrList>, <ngens> ) . . check word or list
##
## checks that <wordOrList> is a valid word in the current pc generators
## (<ngens> is the number of current pc generators) or a valid list of
## generator number-exponent pairs that will generate such a word, and
## either emits an error or returns the valid word.
##
InstallGlobalFunction( PQ_CHECK_WORD, function( datarec, wordOrList, ngens )
local parts, gens;
if not IsList(wordOrList) or
not IsString(wordOrList) and
not ForAll(wordOrList, pair -> IsList(pair) and 2 = Length(pair) and
ForAll(pair, IsInt) ) then
Error( "argument <wordOrList> should be a string e.g. \"x3*x2^2*x1\",\n",
"or a list of gen'r no.-exponent pairs from which such a word ",
"may be generated\n" );
fi;
if IsString(wordOrList) then
#check word makes sense
PqParseWord(ngens, wordOrList);
elif IsList(wordOrList) then
if not ForAll(wordOrList,
pair -> IsPosInt(pair[1]) and pair[1] <= ngens) then
Error( "generator numbers in argument <wordOrList> must be in the ",
"range: ", "[1 .. ", ngens, "]\n" );
fi;
wordOrList := JoinStringsWithSeparator(
List( wordOrList,
pair -> Concatenation( "x", String(pair[1]),
"^", String(pair[2]) ) ),
"*" );
fi;
if IsEmpty(wordOrList) then
wordOrList := "x1^0";
fi;
return wordOrList;
end );
#############################################################################
##
#F PQ_WORD( <datarec> ) . . . . parse pq output for a word in pc generators
##
## parses `<datarec>.matchedline' for a word in the current pc generators
## and returns it as a list of gen'r no.-exponent pairs; `<datarec>.match'
## must have previously been set.
##
InstallGlobalFunction( PQ_WORD, function( datarec )
local word;
word := SplitString( datarec.matchedline{[Length(datarec.match) + 1 ..
Length(datarec.matchedline)]},
"", " \n" );
if word = [ "IDENTITY" ] then
word := [];
else
word := List( word,
function(syl)
syl := List( SplitString(syl, "", ".^"), Int );
if 1 = Length(syl) then
Add(syl, 1);
fi;
return syl;
end );
fi;
PQ_UNBIND(datarec, ["match", "matchedline"]);
return word;
end );
#############################################################################
##
#F PQ_CHK_COLLECT_COMMAND_ARGS( <args> ) . . check args for a collect cmd ok
##
## returns a list of valid arguments for a low-level collect command or
## generates an error.
##
InstallGlobalFunction( PQ_CHK_COLLECT_COMMAND_ARGS, function( args )
local datarec, wordOrList, ngens;
if IsEmpty(args) or 2 < Length(args) then
Error( "1 or 2 arguments expected\n");
fi;
wordOrList := args[Length(args)];
datarec := CallFuncList(ANUPQDataRecord, args{[1..Length(args) - 1]});
ngens := datarec.ngens[ Length(datarec.ngens) ];
wordOrList := PQ_CHECK_WORD(datarec, wordOrList, ngens);
return [datarec, wordOrList];
end );
#############################################################################
##
#F PqCollect( <i>, <word> ) . . . . . . user version of A p-Q menu option 1
#F PqCollect( <word> )
##
## for the <i>th or default interactive {\ANUPQ} process, instruct the `pq'
## program to do a collection on <word>, a word in the current pc generators
## (the form of <word> required is described below). `PqCollect' returns the
## resulting word of the collection as a list of generator number, exponent
## pairs (the same form as the second allowed input form of <word>; see
## below).
##
## The argument <word> may be input in either of the following ways:
##
## \beginlist%ordered
##
## \item{1.}
## <word> may be a string, where the <i>th pc generator is represented by
## `x<i>', e.g.~`"x3*x2^2*x1"'. This way is quite versatile as parentheses
## and left-normed commutators -- using square brackets, in the same way as
## `PqGAPRelators' (see~"PqGAPRelators") -- are permitted; <word> is checked
## for correct syntax via `PqParseWord' (see~"PqParseWord").
##
## \item{2.}
## Otherwise, <word> must be a list of generator number, exponent pairs of
## integers, i.e.~ each pair represents a ``syllable'' so that `[ [3, 1],
## [2, 2], [1, 1] ]' represents the same word as that of the example given
## for the first allowed form of <word>.
##
## \endlist
##
## *Note:* For those familiar with the `pq' program, `PqCollect' performs
## menu item 1 of the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqCollect, function( arg )
return CallFuncList( PQ_COLLECT, PQ_CHK_COLLECT_COMMAND_ARGS(arg) );
end );
#############################################################################
##
#F PQ_SOLVE_EQUATION( <datarec>, <a>, <b> ) . . . . . . A p-Q menu option 2
##
## inputs data to the `pq' binary for option 2 of the Advanced $p$-Quotient
## menu, to solve $<a> * <x> = <b>$ for <x>.
##
InstallGlobalFunction( PQ_SOLVE_EQUATION, function( datarec, a, b )
PQ_MENU(datarec, "ApQ"); #we need options from the Advanced p-Q Menu
ToPQ(datarec, [ 2 ], [ " #solve equation" ]);
ToPQ(datarec, [ a, ";" ], [ " #word a" ]);
ToPQ(datarec, [ b, ";" ], [ " #word b" ]);
end );
#############################################################################
##
#F PqSolveEquation( <i>, <a>, <b> ) . . user version of A p-Q menu option 2
#F PqSolveEquation( <a>, <b> )
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to solve $<a> * <x> = <b>$ for <x>.
##
## *Note:*
## For those familiar with the `pq' binary, `PqSolveEquation' performs
## menu item 2 of the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqSolveEquation, function( arg )
local len, datarec;
len := Length(arg);
if not(len in [2,3]) then
Error("expected 2 or 3 arguments\n");
fi;
#@need to add argument checking for a and b@
datarec := CallFuncList(ANUPQDataRecord, arg{[1 .. len - 2]});
PQ_SOLVE_EQUATION( datarec, arg[len - 1], arg[len] );
end );
#############################################################################
##
#F PQ_COMMUTATOR( <datarec>, <words>, <pow>, <item> ) . A p-Q menu opts 3/24
##
## inputs data to the `pq' binary for option 3 or 24 of the Advanced
## $p$-Quotient menu, to compute the left normed commutator of the list
## <words> of words in the generators raised to the integer power <pow>,
## where <item> is `"3 #commutator"' for option 3 or `"24 #commutator of
## defining genrs"' for option 24.
##
InstallGlobalFunction( PQ_COMMUTATOR, function( datarec, words, pow, item )
local i;
PQ_MENU(datarec, "ApQ"); #we need options from the Advanced p-Q Menu
ToPQ(datarec, item[1], item[2]);
ToPQ(datarec, [ Length(words) ], [ " #no. of components" ]);
for i in [1..Length(words)] do
ToPQ(datarec, [ words[i], ";" ], [ " #word ", i ]);
od;
datarec.match := "The commutator is";
ToPQ(datarec, [ pow ], [ " #power" ]);
return PQ_WORD(datarec);
end );
#############################################################################
##
#F PQ_COMMUTATOR_CHK_ARGS( <args> ) . . . . check args for commutator cmd ok
##
## returns a list of valid arguments for a low-level commutator command or
## generates an error.
##
InstallGlobalFunction( PQ_COMMUTATOR_CHK_ARGS, function( args )
local len, words, pow, item, datarec, ngens;
len := Length(args);
if not(len in [3, 4]) then
Error("expected 3 or 4 arguments\n");
fi;
words := args[len - 2];
pow := args[len - 1];
item := args[len];
if not IsPosInt(pow) then
Error( "argument <pow> must be a positive integer\n" );
fi;
datarec := CallFuncList(ANUPQDataRecord, args{[1 .. len - 3]});
if item[1][1] = 3 then
ngens := datarec.ngens[ Length(datarec.ngens) ];
else
ngens := datarec.ngens[ 1 ];
fi;
words := List( words, w -> PQ_CHECK_WORD(datarec, w, ngens) );
return [datarec, words, pow, item];
end );
#############################################################################
##
#F PqCommutator( <i>, <words>, <pow> ) . user version of A p-Q menu option 3
#F PqCommutator( <words>, <pow> )
##
## for the <i>th or default interactive {\ANUPQ} process, compute a
## user-defined commutator in the pc generators of the class 1 quotient,
## i.e.~the pc generators that correspond to the original fp or pc group of
## the process, and return the result as a list of generator number,
## exponent pairs. The form required for each word of <words> is the same as
## that required for the <word> argument of `PqCollect' (see~"PqCollect").
## The form of the output word is also the same as for `PqCollect'
## (see~"PqCollect").
##
## *Notes*
##
## It is illegal for any word of <words> to contain pc generators of weight
## larger than 1. Except for this distinction,
## `PqCommutatorDefiningGenerators' works just like `PqCommutator'
## (see~"PqCommutator").
##
## For those familiar with the `pq' program, `PqCommutatorDefiningGenerators'
## performs menu item 24 of the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqCommutator, function( arg )
return CallFuncList( PQ_COMMUTATOR,
PQ_COMMUTATOR_CHK_ARGS(
Concatenation( arg, [[[3], [" #commutator"]]] ) ) );
end );
#############################################################################
##
#F PQ_SETUP_TABLES_FOR_NEXT_CLASS( <datarec> ) . . . . . A p-Q menu option 6
##
## inputs data to the `pq' binary for option 6 of the Advanced $p$-Quotient
## menu to set up tables for next class.
##
InstallGlobalFunction( PQ_SETUP_TABLES_FOR_NEXT_CLASS, function( datarec )
PQ_MENU(datarec, "ApQ"); #we need options from the Advanced p-Q Menu
ToPQ(datarec, [ 6 ], [ " #set up tables for next class" ]);
datarec.match := true;
PQ_SET_GRP_DATA(datarec); #Just to be sure it's up-to-date
datarec.setupclass := datarec.class;
end );
#############################################################################
##
#F PqSetupTablesForNextClass( <i> ) . . user version of A p-Q menu option 6
#F PqSetupTablesForNextClass()
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to set up tables for the next class. As as side-effect,
## after `PqSetupTablesForNextClass(<i>)' the value returned by
## `PqPClass(<i>)' will be one more than it was previously.
##
## *Note:*
## For those familiar with the `pq' binary, `PqSetupTablesForNextClass'
## performs menu item 6 of the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqSetupTablesForNextClass, function( arg )
local datarec;
datarec := CallFuncList(ANUPQDataRecord, arg);
PQ_SETUP_TABLES_FOR_NEXT_CLASS( datarec );
end );
#############################################################################
##
#F PQ_INSERT_TAILS( <datarec>, <weight>, <which> ) . . A p-Q menu option 7
##
## inputs data to the `pq' binary for option 7 of the Advanced $p$-Quotient
## menu, to add and/or compute tails.
##
InstallGlobalFunction( PQ_INSERT_TAILS, function( datarec, weight, which )
local intwhich;
PQ_MENU(datarec, "ApQ"); #we need options from the Advanced p-Q Menu
intwhich := Position( [ "compute and add", "add", "compute" ], which ) - 1;
ToPQ(datarec, [ 7 ], [ " #", which, " tails" ]);
ToPQ(datarec, [ weight ], [ " #weight of tails" ]);
ToPQ(datarec, [ intwhich ], [ " #", which ]);
if intwhich <= 1 then
datarec.match := true;
PQ_SET_GRP_DATA(datarec);
fi;
end );
#############################################################################
##
#F PQ_CHK_TAILS_ARGS( <args> ) . . . . . check args for insert tails cmd ok
##
InstallGlobalFunction( PQ_CHK_TAILS_ARGS, function( args )
local weight, datarec;
if IsEmpty(args) or 2 < Length(args) then
Error( "1 or 2 arguments expected\n");
fi;
weight := args[Length(args)];
datarec := CallFuncList(ANUPQDataRecord, args{[1 .. Length(args) - 1]});
if not IsBound(datarec.setupclass) or datarec.class <> datarec.setupclass then
Error( "tables to start next class have not been set up.\n",
"Please call `PqSetupTablesForNextClass' first\n" );
fi;
if not(weight = 0 or weight in [2 .. datarec.class]) then
Error( "argument <weight> should be an integer in [0] U [2 .. <class>],\n",
"where <class> is the current class (", datarec.class, ")\n" );
fi;
return datarec;
end );
#############################################################################
##
#F PqAddTails( <i>, <weight> ) . . . . adds tails using A p-Q menu option 7
#F PqAddTails( <weight> )
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to add tails of weight <weight> if <weight> is in the integer
## range `[2 .. PqPClass(<i>)]' (assuming <i> is the number of the process)
## or for all weights if `<weight> = 0'. See `PqTails' ("PqTails") for more
## details.
##
## *Note:*
## For those familiar with the `pq' binary, `PqAddTails' uses menu item 7 of
## the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqAddTails, function( arg )
PQ_INSERT_TAILS( PQ_CHK_TAILS_ARGS(arg), arg[Length(arg)], "add" );
end );
#############################################################################
##
#F PqComputeTails( <i>, <weight> ) . . computes tails using A p-Q menu opt 7
#F PqComputeTails( <weight> )
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to compute tails of weight <weight> if <weight> is in the integer
## range `[2 .. PqPClass(<i>)]' (assuming <i> is the number of the process)
## or for all weights if `<weight> = 0'. See `PqTails' ("PqTails") for more
## details.
##
## *Note:*
## For those familiar with the `pq' binary, `PqComputeTails' uses menu item
## 7 of the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqComputeTails, function( arg )
PQ_INSERT_TAILS( PQ_CHK_TAILS_ARGS(arg), arg[Length(arg)], "compute" );
end );
#############################################################################
##
#F PqTails( <i>, <weight> ) . computes and adds tails using A p-Q menu opt 7
#F PqTails( <weight> )
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to compute and add tails of weight <weight> if <weight> is in the
## integer range `[2 .. PqPClass(<i>)]' (assuming <i> is the number of the
## process) or for all weights if `<weight> = 0'.
##
## If <weight> is non-zero, then tails that introduce new generators for
## only weight <weight> are computed and added, and in this case and if
## `<weight> \< PqPClass(<i>)', it is assumed that the tails that introduce
## new generators for each weight from `PqPClass(<i>)' downto weight
## `<weight> + 1' have already been added. You may wish to call
## `PqSetMetabelian' (see~"PqSetMetabelian") prior to calling `PqTails'.
##
## *Notes*
##
## For its use in the context of finding the next class see "PqNextClass";
## in particular, a call to `PqSetupTablesForNextClass'
## (see~"PqSetupTablesForNextClass") needs to have been made prior to
## calling `PqTails'.
##
## The single command: `PqTails(<i>, <weight>);' is equivalent to
##
## \){\kernttindent}PqComputeTails(<i>, <weight>);
## \){\kernttindent}PqAddTails(<i>, <weight>);
##
## For those familiar with the `pq' binary, `PqTails' uses menu item 7 of
## the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqTails, function( arg )
PQ_INSERT_TAILS(PQ_CHK_TAILS_ARGS(arg), arg[Length(arg)], "compute and add");
end );
#############################################################################
##
#F PQ_DO_CONSISTENCY_CHECKS(<datarec>, <weight>, <type>) . A p-Q menu opt 8
##
## inputs data to the `pq' binary for option 8 of the Advanced $p$-Quotient
## menu, to do consistency checks.
##
InstallGlobalFunction( PQ_DO_CONSISTENCY_CHECKS,
function( datarec, weight, type )
PQ_MENU(datarec, "ApQ"); #we need options from the Advanced p-Q Menu
ToPQ(datarec, [ 8 ], [ " #check consistency" ]);
ToPQ(datarec, [ weight ], [ " #weight to be checked" ]);
ToPQ(datarec, [ type ], [ " #type" ]);
end );
#############################################################################
##
#F PqDoConsistencyChecks(<i>,<weight>,<type>) . user ver of A p-Q menu opt 8
#F PqDoConsistencyChecks( <weight>, <type> )
##
## for the <i>th or default interactive {\ANUPQ} process, do consistency
## checks for weight <weight> if <weight> is in the integer range `[3 ..
## PqPClass(<i>)]' (assuming <i> is the number of the process) or for all
## weights if `<weight> = 0', and for type <type> if <type> is in the range
## `[1, 2, 3]' (see below) or for all types if `<type> = 0'. (For its use in
## the context of finding the next class see "PqNextClass".)
##
## The *type* of a consistency check is defined as follows.
## `PqDoConsistencyChecks(<i>, <weight>, <type>)' for <weight> in `[3 ..
## PqPClass(<i>)]' and the given value of <type> invokes the following
## `PqJacobi' checks (see~"PqDoConsistencyCheck"):
##
## \beginitems
##
## `<type> = 1':&
## `PqJacobi(<i>, <a>, <a>, <a>)' checks for pc generators of index <a>
## satisfying `2 * PqWeight(<i>, <a>) + 1 = <weight>'.
##
## `<type> = 2':&
## `PqJacobi(<i>, <b>, <b>, <a>)' checks for pc generators of indices <b>,
## <a> satisfying `<b> > <a>' and `PqWeight(<i>, <b>) + PqWeight(<i>, <a>) +
## 1 = <weight>'.
##
## `<type> = 3':&
## `PqJacobi(<i>, <c>, <b>, <a>)' checks for pc generators of indices <c>,
## <b>, <a> satisfying `<c> > <b> > <a>' and the sum of the weights of these
## generators equals <weight>.
##
## \enditems
##
## *Notes*
##
## `PqWeight(<i>, <j>)' returns the weight of the <j>th pc generator, for
## process <i> (see~"PqWeight").
##
## It is assumed that tails for the given weight (or weights) have already
## been added (see~"PqTails").
##
## For those familiar with the `pq' binary, `PqDoConsistencyChecks' performs
## menu item 8 of the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqDoConsistencyChecks, function( arg )
local len, datarec, weight, type;
len := Length(arg);
if not(len in [2, 3]) then
Error("expected 2 or 3 arguments\n");
fi;
weight := arg[len - 1];
type := arg[len];
arg := arg{[1 .. len - 2]};
datarec := CallFuncList(ANUPQDataRecord, arg);
if not IsBound(datarec.setupclass) or datarec.class <> datarec.setupclass then
Error( "tables to start next class have not been set up.\n",
"Please call `PqSetupTablesForNextClass' first\n" );
fi;
if not(weight = 0 or weight in [3 .. datarec.class]) then
Error( "argument <weight> should be an integer in [0] U [3 .. <class>],\n",
"where <class> is the current class (", datarec.class, ")\n" );
fi;
if not(type in [0..3]) then
Error( "argument <type> should be in [0,1,2,3]\n" );
fi;
PQ_DO_CONSISTENCY_CHECKS( datarec, weight, type );
end );
#############################################################################
##
#F PQ_COLLECT_DEFINING_RELATIONS( <datarec> ) . . . . . A p-Q menu option 9
##
## inputs data to the `pq' binary for option 9 of the Advanced $p$-Quotient
## menu, to collect defining relations.
##
InstallGlobalFunction( PQ_COLLECT_DEFINING_RELATIONS, function( datarec )
PQ_MENU(datarec, "ApQ"); #we need options from the Advanced p-Q Menu
ToPQ(datarec, [ 9 ], [ " #collect defining relations" ]);
end );
#############################################################################
##
#F PqCollectDefiningRelations( <i> ) . . user version of A p-Q menu option 9
#F PqCollectDefiningRelations()
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to collect the images of the defining relations of the original fp
## group of the process, with respect to the current pc presentation, in the
## context of finding the next class (see~"PqNextClass"). If the tails
## operation is not complete then the relations may be evaluated
## incorrectly.
##
## *Note:*
## For those familiar with the `pq' binary, `PqCollectDefiningRelations'
## performs menu item 9 of the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqCollectDefiningRelations, function( arg )
local datarec;
datarec := CallFuncList(ANUPQDataRecord, arg);
PQ_COLLECT_DEFINING_RELATIONS( datarec );
end );
#############################################################################
##
#F PQ_DO_EXPONENT_CHECKS( <datarec>, <bnds> ) . . . . . A p-Q menu option 10
##
## inputs data to the `pq' binary to do exponent checks for weights between
## <bnds> inclusive, using option 10 of the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PQ_DO_EXPONENT_CHECKS, function( datarec, bnds )
#@does default only at the moment@
PQ_MENU(datarec, "ApQ"); #we need options from the Advanced p-Q Menu
datarec.match := "Group is complete";
ToPQ(datarec, [ 10 ], [ " #do exponent checks" ]);
if IsBound(datarec.matchedline) and
IsMatchingSublist(datarec.matchedline, "Group is complete") then
PQ_UNBIND(datarec, ["match", "matchedline"]);
datarec.complete := true;
return;
elif IsMatchingSublist(datarec.line, "Input exponent law") then
ToPQ(datarec, [ VALUE_PQ_OPTION("Exponent", 0, datarec) ],
[ " #exponent" ]);
fi;
ToPQ(datarec, [ bnds[1] ], [ " #start weight" ]);
ToPQ(datarec, [ bnds[2] ], [ " #end weight" ]);
ToPQ(datarec, [ 1 ], [ " #do default check" ]);
Unbind(datarec.match);
end );
#############################################################################
##
#F PqDoExponentChecks(<i>[: Bounds := <list>]) . user ver A p-Q menu opt. 10
#F PqDoExponentChecks([: Bounds := <list>])
##
## for the <i>th or default interactive {\ANUPQ} process, direct the `pq'
## binary to do exponent checks for weights (inclusively) between the bounds
## of `Bounds' or for all weights if `Bounds' is not given. The value <list>
## of `Bounds' (assuming the interactive process is numbered <i>) should be
## a list of two integers <low>, <high> satisfying $1 \le <low> \le
## <high> \le `PqPClass(<i>)'$ (see~"PqPClass").
##
## *Note:*
## For those familiar with the `pq' binary, `PqDoExponentChecks' performs
## menu item 10 of the Advanced $p$-Quotient menu.
##
InstallGlobalFunction( PqDoExponentChecks, function( arg )
local datarec;
PQ_OTHER_OPTS_CHK("PqDoExponentChecks", true);
datarec := PQ_DATA_CHK(arg);
PQ_DO_EXPONENT_CHECKS( datarec, PQ_BOUNDS(datarec, datarec.class) );
end );
#############################################################################
##
#F PQ_ELIMINATE_REDUNDANT_GENERATORS( <datarec> ) . . . A p-Q menu option 11
##
## inputs data to the `pq' binary for option 11 of the Advanced $p$-Quotient
## menu, to eliminate redundant generators.
##
InstallGlobalFunction( PQ_ELIMINATE_REDUNDANT_GENERATORS, function( datarec )
PQ_MENU(datarec, "ApQ"); #we need options from the Advanced p-Q Menu
ToPQ(datarec, [ 11 ], [ " #eliminate redundant generators" ]);
datarec.match := true;
PQ_SET_GRP_DATA(datarec);
end );
--> --------------------
--> maximum size reached
--> --------------------
[ Dauer der Verarbeitung: 0.35 Sekunden
(vorverarbeitet)
]
|
2026-04-02
|
|
|
|
|