Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve nice gens functionality and docs #278

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
6 changes: 6 additions & 0 deletions PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CachedSLPToNiceGenerators
Completely independent implementation. Computes an SLP and maybe also the
nicegens, then stores it. Then, whenever someone needs another
SLPToNiceGenerators, this can be taken and evaluated.
Wherever this is called, assert that this and `CalcNiceGens` return the same
group elements, maybe even SLPs with equal `LinesOfSLP`.
3 changes: 1 addition & 2 deletions doc/recognition.xml
Original file line number Diff line number Diff line change
Expand Up @@ -264,15 +264,14 @@ returns <K>true</K>.
</ManSection>


The following two attributes are concerned with the relation between
The following four attributes are concerned with the relation between
the original generators and the nice generators for a node.
They are used to transport this information from a successful find
homomorphism method up to the recursive recognition function:

<#Include Label="calcnicegens">
<#Include Label="CalcNiceGensGeneric">
<#Include Label="CalcNiceGensHomNode">
<#Include Label="CalcNiceGens">
<#Include Label="slptonice">

The following three attributes are concerned with the administration of the
Expand Down
80 changes: 39 additions & 41 deletions gap/base/recognition.gd
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,24 @@ DeclareAttribute( "Homom", IsRecogNode, "mutable" );
## <#GAPDoc Label="NiceGens">
## <ManSection>
## <Attr Name="NiceGens" Arg="ri"/>
## <Attr Name="NiceGens" Arg="ri, origgens"/>
## <Description>
## The value of this attribute must be set for all nodes and contains
## the nice generators. The <Ref Func="SLPforElement"/> function of the
## The value of this attribute contains the nice generators and must be set
## for all nodes. The <Ref Func="SLPforElement"/> function of the
## node will write its straight line program in terms of these nice
## generators. For leaf nodes, the find homomorphism method is responsible
## to set the value of <Ref Attr="NiceGens"/>. By default, the original
## generators of the group at this node are taken. For a homomorphism
## (or isomorphism), the <Ref Attr="NiceGens"/> will be the concatenation
## of preimages of the <Ref Attr="NiceGens"/> of the image group
## generators.
## <P/>
## For a leaf node, <Ref Attr="NiceGens"/> can be any list of generators.
## <P/>
## For a splitting node, <Ref Attr="NiceGens"/> is the concatenation
## of preimages of the <Ref Attr="NiceGens"/> of the factor group
## (see <Ref Attr="pregensfac"/>) and
## the <Ref Attr="NiceGens"/> of the kernel. A find homomorphism method
## does not have to set <Ref Attr="NiceGens"/> if it finds a homomorphism.
## Note however, that such a find homomorphism method has to ensure somehow,
## that preimages of the <Ref Attr="NiceGens"/> of the image group
## can be acquired. See <Ref Attr="calcnicegens"/>, <Ref Func="CalcNiceGens"/>
## and <Ref Attr="slptonice"/>
## for instructions.
## the <Ref Attr="NiceGens"/> of the kernel.
## <P/>
## To compute the nice generators, a method with two-arguments is installed
## for <Ref Attr="NiceGens"/> which takes the value of the attribute
## <Ref Attr="calcnicegens"/> and calls it with the arguments <A>ri</A> and
## <A>origgens</A>. For more information see <Ref Attr="calcnicegens"/>.
## </Description>
## </ManSection>
## <#/GAPDoc>
Expand Down Expand Up @@ -202,21 +203,30 @@ DeclareAttribute( "validatehomominput", IsRecogNode);
## <ManSection>
## <Attr Name="calcnicegens" Arg="ri"/>
## <Description>
## To make the recursion work, we have to acquire preimages of the
## nice generators in image groups under the homomorphism found.
## But we want to keep the information, how the nice generators
## were found, locally at the node where they were found. This
## attribute solves this problem of acquiring preimages in the following
## way: Its value must be a function, taking the recognition
## node <A>ri</A> as first argument, and a list <A>origgens</A> of
## preimages of the
## original generators of the current node, and has to
## return corresponding preimages of the nice generators. Usually this
## task can be done by storing a straight line program writing the
## nice generators in terms of the original generators and executing
## this with inputs <A>origgens</A>. Therefore the default value of
## this attribute is the function <Ref Func="CalcNiceGensGeneric"/>
## described below.
## Stores a function <C>func(ri2, gens2)</C> which computes group elements
## of <C>ri2</C> by evaluating words in <C>gens2</C>.
## These words must be chosen such that, if <C>ri2</C> is equal to
## <A>ri</A> and <C>gens2</C> is equal to
## <C>GeneratorsOfGroup(Grp(ri))</C>, then <C>func</C> returns the nice
## generators of <A>ri</A>.
## Correspondingly, if <C>gens2</C> is another list of group elements, then
## the words which yield the nice generators of <A>ri</A> are evaluated in
## <C>gens2</C>.
## <P/>
## This us used by the recursive group recognition to compute preimages of
## nice generators as follows:
## if <C>imagenode</C> is the image node of a node <C>node</C> and
## <C>nodegens</C> are the generators of <C>Grp(node)</C>,
## then <C>func(imagenode, nodegens)</C> computes the preimages of the
## nice generators of <C>imagenode</C>.
## <P/>
## Usually <C>func</C> stores a straight line program writing the nice
## generators in terms of the generators of the group represented
## by <A>ri</A> and executes this with inputs <A>gens2</A>.
## <P/>
## The default values of this attribute are the functions
## <Ref Func="CalcNiceGensGeneric"/> and
## <Ref Func="CalcNiceGensHomNode"/>.
## </Description>
## </ManSection>
## <#/GAPDoc>
Expand Down Expand Up @@ -547,18 +557,6 @@ DeclareGlobalFunction( "TryFindHomMethod" );

# Helper functions for the generic part:

## <#GAPDoc Label="CalcNiceGens">
## <ManSection>
## <Func Name="CalcNiceGens" Arg="ri, origgens"/>
## <Returns>a list of preimages of the nice generators</Returns>
## <Description>
## This is a wrapper function which extracts the value of the attribute
## <Ref Attr="calcnicegens"/> and calls that function with the arguments
## <A>ri</A> and <A>origgens</A>.
## </Description>
## </ManSection>
## <#/GAPDoc>
DeclareGlobalFunction( "CalcNiceGens" );
DeclareGlobalFunction( "ValidateHomomInput" );

## <#GAPDoc Label="CalcNiceGensGeneric">
Expand Down
70 changes: 44 additions & 26 deletions gap/base/recognition.gi
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ RECOG_ViewObj := function( level, ri )
if IsReady(ri) then
Print("<recognition node ");
else
Print("<failed recognition node ");
Print("<unfinished recognition node ");
fi;
if IsBound(ri!.projective) and ri!.projective then
Print("(projective) ");
Expand Down Expand Up @@ -56,7 +56,7 @@ RECOG_ViewObj := function( level, ri )
Print(" Field=",Size(ri!.field));
fi;
if not IsLeaf(ri) then
Print("\n",String("",level)," F:");
Print("\n",String("",level)," I:");
if HasImageRecogNode(ri) then
RECOG_ViewObj(level+3, ImageRecogNode(ri));
else
Expand All @@ -81,6 +81,18 @@ InstallMethod( ViewObj, "for recognition nodes", [IsRecogNode],
RECOG_ViewObj(0, ri);
end);

InstallMethod( NiceGens, "for a recognition node",
[IsRecogNode],
function(ri)
return NiceGens(ri, GeneratorsOfGroup(Grp(ri)));
end );

InstallOtherMethod( NiceGens, "for a recognition node and a list",
[IsRecogNode, IsList],
function(ri,origgens)
return calcnicegens(ri)(ri,origgens);
end );


#############################################################################
# The main recursive function:
Expand Down Expand Up @@ -446,7 +458,6 @@ InstallGlobalFunction( RecogniseGeneric,
else
ri := EmptyRecognitionInfoRecord(knowledge,H,false);
fi;
# was here earlier: Setcalcnicegens(ri,CalcNiceGensGeneric);
Setmethodsforfactor(ri,methoddb);

# Find a possible homomorphism (or recognise this group as leaf)
Expand Down Expand Up @@ -530,12 +541,12 @@ InstallGlobalFunction( RecogniseGeneric,
return fail;
fi;

Add(depthString,'F');
Add(depthString,'I');
rifac := RecogniseGeneric(
Group(List(GeneratorsOfGroup(H), x->ImageElm(Homom(ri),x))),
methodsforfactor(ri), depthString, forfactor(ri) ); # TODO: change forfactor to hintsForFactor??)
methodsforfactor(ri), depthString, forfactor(ri) );
Remove(depthString);
PrintTreePos("F",depthString,H);
PrintTreePos("I",depthString,H);
SetImageRecogNode(ri,rifac);
SetRIParent(rifac,ri);

Expand All @@ -555,7 +566,7 @@ InstallGlobalFunction( RecogniseGeneric,

# Now we want to have preimages of the new generators in the image:
Info(InfoRecog,2,"Calculating preimages of nice generators.");
ri!.pregensfacwithmem := CalcNiceGens(rifac, ri!.gensHmem);
ri!.pregensfacwithmem := NiceGens(rifac, ri!.gensHmem);
Setpregensfac(ri, StripMemory(ri!.pregensfacwithmem));

# Now create the kernel generators with the stored method:
Expand Down Expand Up @@ -654,14 +665,8 @@ InstallGlobalFunction( RecogniseGeneric,
fi;
until done;

if IsReady(riker) then # we are only ready when the kernel is
# Now make the two projection slps:
SetNiceGens(ri,Concatenation(pregensfac(ri), NiceGens(riker)));
#ll := List([1..Length(NiceGens(rifac))],i->[i,1]);
#ri!.proj1 := StraightLineProgramNC([ll],Length(NiceGens(ri)));
#ll := List([1..Length(NiceGens(riker))],
# i->[i+Length(NiceGens(rifac)),1]);
#ri!.proj2 := StraightLineProgramNC([ll],Length(NiceGens(ri)));
# we are only ready when the kernel is
if IsReady(riker) then
SetFilterObj(ri,IsReady);
fi;
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
Expand All @@ -678,11 +683,6 @@ InstallGlobalFunction( ValidateHomomInput,
fi;
end );

InstallGlobalFunction( CalcNiceGens,
function(ri,origgens)
return calcnicegens(ri)(ri,origgens);
end );

InstallGlobalFunction( CalcNiceGensGeneric,
# generic function using an slp:
function(ri,origgens)
Expand All @@ -696,16 +696,32 @@ InstallGlobalFunction( CalcNiceGensGeneric,
InstallGlobalFunction( CalcNiceGensHomNode,
# function for the situation on a homomorphism node (non-Leaf):
function(ri, origgens)
local nicegens, kernelgens;
local nicegens, nicekernelgens, x, kernelgens;
# compute preimages of the nicegens of the image group
nicegens := CalcNiceGens(ImageRecogNode(ri), origgens);
nicegens := NiceGens(ImageRecogNode(ri), origgens);
# Is there a non-trivial kernel? then add its nicegens
if HasKernelRecogNode(ri) and KernelRecogNode(ri) <> fail then
# we cannot just use gensN(KernelRecogNode(ri)) here, as those values are defined
# relative to the original generators we used during recognition; but
# the origgens passed to this function might differ
kernelgens := ResultOfStraightLineProgram(gensNslp(ri), origgens);
Append(nicegens, CalcNiceGens(KernelRecogNode(ri), kernelgens));
if origgens = GeneratorsOfGroup(Grp(ri)) then
# Print("HIT\n");
#Error("break");
nicekernelgens := NiceGens(KernelRecogNode(ri));
if IsObjWithMemory(origgens[1]) then
nicekernelgens := GeneratorsWithMemory(nicekernelgens);
# HACK!
for x in nicekernelgens do
x!.slp := origgens[1]!.slp;
od;
fi;
else
# when recognizing, origgens have memory. When recognition is finished,
# these are usually without memory?
kernelgens := ResultOfStraightLineProgram(gensNslp(ri), origgens);
nicekernelgens := NiceGens(KernelRecogNode(ri), kernelgens);
fi;
Append(nicegens, nicekernelgens);
fi;
return nicegens;
end );
Expand Down Expand Up @@ -858,7 +874,7 @@ InstallGlobalFunction( "SLPforNiceGens", function(ri)
local l,ll,s;
l := List( [1..Length(GeneratorsOfGroup(Grp(ri)))], x->() );
l := GeneratorsWithMemory(l);
ll := CalcNiceGens(ri,l);
ll := NiceGens(ri,l);
s := SLPOfElms(ll);
if s <> fail then
SlotUsagePattern(s);
Expand Down Expand Up @@ -955,7 +971,9 @@ RECOG.TestGroup := function(g,proj,size, optionlist...)
if IsEmpty(gens) then
gens := [One(g)];
fi;
l := CalcNiceGens(ri,gens);
l := NiceGens(ri,gens);
l := NiceGens(ri,gens);
# Test whether SLPForNiceGens gives the same slps
repeat
count := count + 1;
#Print(".\c");
Expand Down
4 changes: 2 additions & 2 deletions gap/generic/KnownNilpotent.gi
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ RECOG.CalcNiceGensKnownNilpotent := function(ri,origgens)
local kernelgens;
kernelgens := List([1..Length(ri!.decompositionExponents)],
i -> origgens[i]^ri!.decompositionExponents[i]);
return Concatenation(CalcNiceGens(ImageRecogNode(ri), origgens),
CalcNiceGens(KernelRecogNode(ri), kernelgens));
return Concatenation(NiceGens(ImageRecogNode(ri), origgens),
NiceGens(KernelRecogNode(ri), kernelgens));
end;

#! @BeginChunk KnownNilpotent
Expand Down
2 changes: 1 addition & 1 deletion misc/colva/DPleaf.g
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ SolveLeafDP := function(ri,rifac,name)
blkdata := RecogniseLeaf(riH1,blk,name);;

# Get the inverse images of the nice generators of blk in H1
invims := CalcNiceGens(blkdata,GeneratorsOfGroup(H1));
invims := NiceGens(blkdata,GeneratorsOfGroup(H1));
Yhat := ShallowCopy(invims);
blktoH1 := GroupHomomorphismByFunction(blk,Grp(ri),g->
ResultOfStraightLineProgram( SLPforElement(blkdata,g),invims));
Expand Down
2 changes: 1 addition & 1 deletion misc/colva/Evaluate.g
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ InstallGlobalFunction( NormalTree,
# Now we want to have preimages of the new generators in the image:
if not IsBound(ri!.pregensfac) then
Info(InfoRecognition,1,"Calculating preimages of nice generators.");
Setpregensfac( ri, CalcNiceGens(rifac,GeneratorsOfGroup(H)));
Setpregensfac( ri, NiceGens(rifac,GeneratorsOfGroup(H)));
fi;
Setcalcnicegens(ri,CalcNiceGensHomNode);

Expand Down
4 changes: 4 additions & 0 deletions misc/colva/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This is probably an attempt by Colva Roney-Dougal to port an implementation of
Mark Stather (a PhD Student of Derek Holt) for computing sylow subgroups of
matrix groups. That may have needed "normal trees" and chief series. The main
file might be `NSM.g`?
12 changes: 6 additions & 6 deletions tst/working/quick/bugfix.tst
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,27 @@ gap> old:=InfoLevel(InfoRecog);;
gap> SetInfoLevel(InfoRecog, 0);
gap> RecogniseGroup(SL(2,2));
<recognition node GoProjective Dim=2 Field=2
F:<recognition node (projective) ClassicalNatural_PSL2Even Size=6 Dim=
I:<recognition node (projective) ClassicalNatural_PSL2Even Size=6 Dim=
2 Field=2>
K:<trivial kernel>
gap> RecogniseGroup(SL(2,3));
<recognition node GoProjective Dim=2 Field=3
F:<recognition node (projective) ClassicalNatural_PSL2Odd Size=12 Dim=
I:<recognition node (projective) ClassicalNatural_PSL2Odd Size=12 Dim=
2 Field=3>
K:<recognition node DiagonalMatrices Dim=2 Field=3
F:<recognition node Scalar Dim=1 Field=3>
I:<recognition node Scalar Dim=1 Field=3>
K:<trivial kernel>>
gap> RecogniseGroup(SL(2,4));
<recognition node GoProjective Dim=2 Field=4
F:<recognition node (projective) ClassicalNatural_PSL2Even Simple Size=
I:<recognition node (projective) ClassicalNatural_PSL2Even Simple Size=
60 Dim=2 Field=4>
K:<trivial kernel>
gap> RecogniseGroup(SL(2,5));
<recognition node GoProjective Dim=2 Field=5
F:<recognition node (projective) ClassicalNatural_PSL2Odd Simple Size=60 Dim=
I:<recognition node (projective) ClassicalNatural_PSL2Odd Simple Size=60 Dim=
2 Field=5>
K:<recognition node DiagonalMatrices Dim=2 Field=5
F:<recognition node Scalar Dim=1 Field=5>
I:<recognition node Scalar Dim=1 Field=5>
K:<trivial kernel>>
gap> SetInfoLevel(InfoRecog, old);

Expand Down