Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/recognition.xml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ known. A recognition node always represents a whole binary tree of such
records, see the attributes <Ref Attr="ImageRecogNode"/> and <Ref Attr="KernelRecogNode"/>
below. <P/>

Recognition nodes can be created via:

<#Include Label="RecogNode">

The following filters are defined for recognition nodes:

<#Include Label="IsLeaf">
Expand Down
48 changes: 35 additions & 13 deletions gap/base/recognition.gd
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,29 @@ BindGlobal( "RecogNodeFamily",
NewFamily("RecogNodeFamily", IsRecogNode));
DeclareObsoleteSynonym( "RecognitionInfoFamily", "RecogNodeFamily" );
# The type:
BindGlobal( "RecognitionInfoType",
BindGlobal( "RecogNodeType",
NewType(RecogNodeFamily, IsRecogNode and IsAttributeStoringRep));

## <#GAPDoc Label="RecogNode">
## <ManSection>
## <Oper Name="RecogNode" Arg="H[, projective][, r]"/>
## <Oper Name="RecogNode" Arg="r, H, projective"/>
## <Returns>a recognition node.</Returns>
## <Description>
## Create an <Ref Filt="IsRecogNode"/> object <C>node</C> representing the
## group <A>H</A>.
## The optional boolean <A>projective</A> defaults to false and specifies,
## in the case that <A>H</A> is a matrix group, whether <A>H</A> is to be
## interpreted as a projective group.
## The optional record <A>r</A> defaults to an empty record and is used to
## initialize the returned <C>node</C>.
## <P/>
## For backwards-compatibility, also the order of arguments
## <C>r, H, projective</C> is accepted.
## </Description>
## </ManSection>
## <#/GAPDoc>
DeclareOperation( "RecogNode", [ IsGroup, IsBool, IsRecord ]);

# The info class:
DeclareInfoClass( "InfoRecog" );
Expand Down Expand Up @@ -59,18 +79,22 @@ DeclareFilter( "IsLeaf" );
## <ManSection>
## <Filt Name="IsReady" Type="Flag"/>
## <Description>
## This flag indicates during the recognition procedure, whether a node in
## the recognition tree was recognized completely. For leaves this means that
## recognition terminated without throwing errors. For non-leaf nodes this
## means that a homomorphism was computed and both image and kernel nodes are
## ready or non-existent (if the kernel is trivial).
## This flag is set for a <Ref Filt="IsRecogNode"/> object <C>node</C> by <Ref
## Func="RecogniseGeneric"/>, if recognition of the <E>subtree</E> rooted in
## <C>node</C> finished successfully.
## Recognition of a node is considered successful, if two conditions hold.
## First, the call of <Ref Func="CallMethods"/> for this node reports
## <K>Success</K>, that is a method from the respective method database (see
## Section <Ref Sect="methoddatabases"/>) was successful.
## Secondly, the construction of the kernel generators was successful.
## <P/>
## This does not mean, that the result of the recognition procedure was
## verified and proven to be mathematically correct!
## Thus, if the <Ref Filt="IsReady"/> flag is set, this does not necessarily
## mean, that the result of the recognition procedure was verified and proven
## to be mathematically correct!
## <P/>
## In particular, computing <Ref Oper="Size"/> and member ship test via <Ref
## Oper="\\in"/> can only be done for <Ref Filt="IsRecogNode"/> objects which
## have <Ref Filt="IsReady"/> set.
## In particular, any computations using the datastructure set up by the
## recognition procedure, like <Ref Oper="Size"/> and membership testing via
## <Ref Oper="\\in"/>, will error if <Ref Filt="IsReady"/> is not set.
## </Description>
## </ManSection>
## <#/GAPDoc>
Expand Down Expand Up @@ -449,8 +473,6 @@ BindGlobal( "SLPforElementFuncsGeneric", rec() );

# Our global functions for the main recursion:

DeclareGlobalFunction( "EmptyRecognitionInfoRecord" );

## <#GAPDoc Label="RecognisePermGroup">
## <ManSection>
## <Func Name="RecognisePermGroup" Arg="H"/>
Expand Down
76 changes: 49 additions & 27 deletions gap/base/recognition.gi
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ InstallGlobalFunction( RecogniseGroup,
InstallGlobalFunction( TryFindHomMethod,
function( g, method, projective )
local result,ri;
ri := EmptyRecognitionInfoRecord(rec(),g,projective);
ri := RecogNode(g,projective);
Unbind(g!.pseudorandomfunc);
result := method(ri,g);
if result in [TemporaryFailure, NeverApplicable] then
Expand All @@ -141,11 +141,13 @@ InstallGlobalFunction( TryFindHomMethod,
fi;
end );

InstallGlobalFunction( EmptyRecognitionInfoRecord,
function(r,H,projective)
InstallMethod( RecogNode,
"standard method",
[ IsGroup, IsBool, IsRecord ],
function(H,projective,r)
local ri;
ri := ShallowCopy(r);
Objectify( RecognitionInfoType, ri );
Objectify( RecogNodeType, ri );
SetGrp(ri,H);
Setslpforelement(ri,SLPforElementGeneric);
SetgensN(ri,[]); # this will grow over time
Expand Down Expand Up @@ -212,6 +214,20 @@ InstallGlobalFunction( EmptyRecognitionInfoRecord,
return ri;
end );

InstallOtherMethod( RecogNode,
"for a group",
[ IsGroup ],
function(H)
return RecogNode(H, false, rec());
end );

InstallOtherMethod( RecogNode,
"for a group and a boolean",
[ IsGroup, IsBool ],
function(H, projective)
return RecogNode(H, projective, rec());
end );

# Sets the stamp used by RandomElm, RandomElmOrd, and related functions.
RECOG.SetPseudoRandomStamp := function(g,st)
if IsBound(g!.pseudorandomfunc) then
Expand All @@ -229,9 +245,9 @@ end;
# if called with stamp := "B".
#
# The components of the recog record involved are explained in
# EmptyRecognitionInfoRecord.
# RecogNode.
#
# HACK: For recog records created by EmptyRecognitionInfoRecord the method
# HACK: For recog records created by RecogNode the method
# RandomElm is by default stored in the component ri!.Grp!.pseudorandomfunc.
# A method for PseudoRandom is installed such that it calls
# RandomElm(ri, "PseudoRandom", false).
Expand Down Expand Up @@ -452,35 +468,38 @@ InstallGlobalFunction( RecogniseGeneric,
fi;

# Set up the record and the group object:
if IsIdenticalObj( methoddb, FindHomDbProjective ) then
ri := EmptyRecognitionInfoRecord(knowledge,H,true);
else
ri := EmptyRecognitionInfoRecord(knowledge,H,false);
fi;
ri := RecogNode(
H,
IsIdenticalObj( methoddb, FindHomDbProjective ),
knowledge
);
# was here earlier: Setcalcnicegens(ri,CalcNiceGensGeneric);
Setmethodsforimage(ri,methoddb);

# Find a possible homomorphism (or recognise this group as leaf)
# Combine database of find homomorphism methods with hints
allmethods := methoddb;
if IsBound(knowledge.hints) then
allmethods := Concatenation(allmethods, knowledge.hints);
SortBy(allmethods, a -> -a.rank);
fi;

# verify no rank occurs more than once
Assert(0, Length(Set(allmethods, m->m.rank)) = Length(allmethods));

# Find a possible homomorphism (or recognise this group as leaf)
Setfhmethsel(ri, CallMethods( allmethods, 10, ri, H ));
# TODO: extract the value 10 into a named constant, and / or make it
# an option parameter to the func

# Reset the pseudo random stamp:
RECOG.SetPseudoRandomStamp(Grp(ri),"PseudoRandom");

# Handle the unfinished case:
if fhmethsel(ri).result = TemporaryFailure then
# FIXME: shouldn't we print an error here? at least if the user called us...
# Perhaps yes: this is an ri which does NOT have IsReady set, and may be useful for debugging...
SetFilterObj(ri,IsLeaf);
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
Info(InfoRecog, 1,
"RecogNode <ri> could not be recognised,",
" IsReady(<ri>) is not set, recognition aborts");
return ri;
fi;

Expand All @@ -504,10 +523,9 @@ InstallGlobalFunction( RecogniseGeneric,
SetNiceGens(ri,GeneratorsOfGroup(H));
fi;
fi;
# these two were set correctly by FindHomomorphism
if IsLeaf(ri) then SetFilterObj(ri,IsReady); fi;
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
# StopStoringRandEls(ri);
SetFilterObj(ri,IsReady);
return ri;
fi;

Expand All @@ -519,8 +537,10 @@ InstallGlobalFunction( RecogniseGeneric,
repeat
counter := counter + 1;
if counter > 10 then
Info(InfoRecog,1,"Giving up desperately...");
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
Info(InfoRecog, 1,
"ImageRecogNode of RecogNode <ri> could not be recognised,",
" IsReady(<ri>) is not set, recognition aborts");
return ri;
fi;

Expand All @@ -540,7 +560,7 @@ InstallGlobalFunction( RecogniseGeneric,
Add(depthString,'F');
rifac := RecogniseGeneric(
Group(List(GeneratorsOfGroup(H), x->ImageElm(Homom(ri),x))),
methodsforimage(ri), depthString, InitialDataForImageRecogNode(ri) ); # TODO: change InitialDataForImageRecogNode to hintsForFactor??)
methodsforimage(ri), depthString, InitialDataForImageRecogNode(ri) );
Remove(depthString);
PrintTreePos("F",depthString,H);
SetImageRecogNode(ri,rifac);
Expand All @@ -555,7 +575,7 @@ InstallGlobalFunction( RecogniseGeneric,
fi;

if not IsReady(rifac) then
# the recognition of the image failed, also give up here:
# IsReady was not set, thus abort the whole computation.
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we print here some information that the computation is aborted?

Suggested change
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
Info(InfoRecog, 1,
"ImageRecogNode of node <ri> could not be recognised,",
" IsReady(<ri>) is not set!");

Copy link
Collaborator Author

@ssiccha ssiccha Jan 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'll add such an info message to the "unfinished case". And now that I think about it, we don't need to print anything in the "image" or "kernel" parts of RecogniseGeneric, since the warning message is printed in the "unfinished case" part already.

Nvm, I was thinking about the mandarins. I'll update both warning messages.

return ri;
fi;
Expand All @@ -576,8 +596,8 @@ InstallGlobalFunction( RecogniseGeneric,
fi;

# Do a little bit of preparation for the generators of N:
l := gensN(ri);
if not IsBound(ri!.leavegensNuntouched) then
l := gensN(ri);
Sort(l,SortFunctionWithMemory); # this favours "shorter" memories!
# FIXME: For projective groups different matrices might stand
# for the same element, we might overlook this here!
Expand All @@ -602,9 +622,9 @@ InstallGlobalFunction( RecogniseGeneric,
SetKernelRecogNode(ri,fail);
# We have to learn from the image, what our nice generators are:
SetNiceGens(ri,pregensfac(ri));
SetFilterObj(ri,IsReady);
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
# StopStoringRandEls(ri);
SetFilterObj(ri,IsReady);
return ri;
fi;

Expand All @@ -625,20 +645,22 @@ InstallGlobalFunction( RecogniseGeneric,
SetParentRecogNode(riker,ri);
Info(InfoRecog,2,"Back from kernel (depth=",depth,").");

if not IsReady(riker) then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the same, maybe we should print something here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to print something here, since we're only "exiting". The warning message was already printed in one of the "failed cases" that is in the "unfinished case" part or in the "recognise the image" part.

# IsReady is not set, thus the whole computation aborts.
return ri;
fi;
done := true;
if IsReady(riker) and immediateverification(ri) then
if immediateverification(ri) then
Info(InfoRecog,2,"Doing immediate verification (depth=",
depth,").");
done := ImmediateVerification(ri);
fi;
until done;

if IsReady(riker) then # we are only ready when the kernel is
SetNiceGens(ri,Concatenation(pregensfac(ri), NiceGens(riker)));
SetFilterObj(ri,IsReady);
fi;
SetNiceGens(ri,Concatenation(pregensfac(ri), NiceGens(riker)));
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
# StopStoringRandEls(ri);
SetFilterObj(ri,IsReady);
return ri;
end);

Expand Down
2 changes: 1 addition & 1 deletion gap/projective/almostsimple.gi
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ RECOG.ProduceTrivialStabChainHint := function(name,reps,maxes)
for m in [1..Length(maxes)] do
Print("Doing maximal subgroup #",m,"\n");
hint := rec( name := name, size := size, usemax := [m] );
ri := EmptyRecognitionInfoRecord(rec(),g,true);
ri := RecogNode(rec(),g,true);
t := Runtime();
res := DoHintedStabChain(ri,g,hint);
t := Runtime() - t;
Expand Down
2 changes: 1 addition & 1 deletion misc/colva/DPleaf.g
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ SolveLeafDP := function(ri,rifac,name)
blk := GroupWithGenerators(List(GeneratorsOfGroup(H1),x->ImageElm(H1toblk,x)));

riH1 := rec();
Objectify(RecognitionInfoType,riH1);;
Objectify(RecogNodeType,riH1);;

SetGrp(riH1,H1);
blkdata := RecogniseLeaf(riH1,blk,name);;
Expand Down
6 changes: 3 additions & 3 deletions misc/colva/Evaluate.g
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ end;

# lri := []; rri := [];
# lri[1] := rec();
# Objectify(RecognitionInfoType,lri[1]);;
# Objectify(RecogNodeType,lri[1]);;

# SetGrp(lri[1],Grp(ri));

Expand Down Expand Up @@ -125,7 +125,7 @@ end;
# b := Basis(B,VV);
# VPc := ElementaryAbelianGroup(p^Length(b));
# rri[count] := rec();
# Objectify(RecognitionInfoType,rri[count]);;
# Objectify(RecogNodeType,rri[count]);;
# SetGrp(rri[count],VPc);
# Solve the rewriting problem with these gens
# P := Pcgs(VPc);
Expand Down Expand Up @@ -186,7 +186,7 @@ InstallGlobalFunction( NormalTree,

# Set up the record and the group object:
ri := ShallowCopy(knowledge);
Objectify( RecognitionInfoType, ri );;
Objectify( RecogNodeType, ri );;
ri!.depth := depth;
ri!.nrgensH := Length(GeneratorsOfGroup(H));
Setovergroup(ri,nsm!.Group);
Expand Down
8 changes: 4 additions & 4 deletions misc/colva/Rearrange.g
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ end);

# setup the new record for the factor - this is the product of ImageRecogNode(ri) and ImageRecogNode(riker)
nrifac := rec();
Objectify( RecognitionInfoType, nrifac );;
Objectify( RecogNodeType, nrifac );;

#new factor group is direct product of old factor groups, both are now in the socle.
SetGrp(nrifac,D);
Expand All @@ -366,7 +366,7 @@ end);
# setup the new record for the subgroup - nri will take the place of the old ri, but iwth
#ker(riker) as its kernel and nrifac, the new socle, as its factor.
nri := rec();
Objectify( RecognitionInfoType, nri );;
Objectify( RecogNodeType, nri );;
SetImageRecogNode(nri,nrifac);
SetGrp(nri,Grp(ri));
if HasParentRecogNode(ri) then
Expand Down Expand Up @@ -425,9 +425,9 @@ SwapFactors := function(ri,zeta)

# setup the new record for the factor
nri := rec();
Objectify( RecognitionInfoType, nri );;
Objectify( RecogNodeType, nri );;
nriker := rec();
Objectify( RecognitionInfoType, nriker );;
Objectify( RecogNodeType, nriker );;

SetHomom(nriker,StructuralCopy(Homom(ri)));
SetHomom(nri,zeta);
Expand Down
6 changes: 3 additions & 3 deletions misc/colva/Refine.g
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ InsertSubTree := function(ri,rifac,maps)

lri := []; rri := [];
lri[1] := rec();
Objectify(RecognitionInfoType,lri[1]);;
Objectify(RecogNodeType,lri[1]);;

SetGrp(lri[1],Grp(ri));

Expand All @@ -34,7 +34,7 @@ InsertSubTree := function(ri,rifac,maps)

for i in [1..Length(Q)] do
rri[i] := rec();
Objectify(RecognitionInfoType,rri[i]);;
Objectify(RecogNodeType,rri[i]);;
SetGrp(rri[i],Q[i]);
SetHomom(lri[i],GtoQ[i]);
SetNiceGens(rri[i],AsList(Pcgs(Q[i])));
Expand Down Expand Up @@ -66,7 +66,7 @@ InsertSubTree := function(ri,rifac,maps)
kgens := [One(overgp)];
fi;
lri[i+1] := rec();
Objectify(RecognitionInfoType,lri[i+1]);;
Objectify(RecogNodeType,lri[i+1]);;
SetGrp(lri[i+1],GroupWithGenerators(kgens));
SetKernelRecogNode(lri[i],lri[i+1]);
SetImageRecogNode(lri[i],rri[i]);
Expand Down
2 changes: 1 addition & 1 deletion misc/colva/SimpleRecog.g
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ RecogniseQuasiSimple := function(G,name)
else
# Use Shortotbits and consider the group as a perm grp
re := rec();
Objectify(RecognitionInfoType,re);;
Objectify(RecogNodeType,re);;
FindHomMethodsMatrix.ShortOrbits(re,G);
# Perm Image
GtoP := Homom(re);
Expand Down
Loading