Skip to content

Commit 2c4b084

Browse files
fingolfinssiccha
authored andcommitted
WIP: mandarins
1 parent c9824a3 commit 2c4b084

File tree

2 files changed

+123
-54
lines changed

2 files changed

+123
-54
lines changed

gap/base/recognition.gd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,12 @@ BindGlobal( "SLPforElementFuncsGeneric", rec() );
445445

446446
DeclareGlobalFunction( "EmptyRecognitionInfoRecord" );
447447

448+
# TODO Document mandarins
449+
# Refer to overview paper by Baarnhielm, Holt, Charles, Eamonn, sections "5.2
450+
# The main algorithm" and "5.4 Crisis management".
451+
# Explain safe and unsafe nodes.
452+
BindGlobal("MANDARIN_CRISIS", MakeImmutable("MANDARIN_CRISIS"));
453+
448454
## <#GAPDoc Label="RecognisePermGroup">
449455
## <ManSection>
450456
## <Func Name="RecognisePermGroup" Arg="H"/>

gap/base/recognition.gi

Lines changed: 117 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,25 @@ InstallMethod( ViewObj, "for recognition nodes", [IsRecogNode],
9191

9292
InstallGlobalFunction( RecognisePermGroup,
9393
function(G)
94-
return RecogniseGeneric(G, FindHomDbPerm, "", rec());
94+
return RecogniseGeneric(G, FindHomDbPerm, "", rec(), fail);
9595
end);
9696

9797
InstallGlobalFunction( RecogniseMatrixGroup,
9898
function(G)
99-
return RecogniseGeneric(G, FindHomDbMatrix, "", rec());
99+
return RecogniseGeneric(G, FindHomDbMatrix, "", rec(), fail);
100100
end);
101101

102102
InstallGlobalFunction( RecogniseProjectiveGroup,
103103
function(G)
104-
return RecogniseGeneric(G, FindHomDbProjective, "", rec());
104+
return RecogniseGeneric(G, FindHomDbProjective, "", rec(), fail);
105105
end);
106106

107107
InstallGlobalFunction( RecogniseGroup,
108108
function(G)
109109
if IsPermGroup(G) then
110-
return RecogniseGeneric(G, FindHomDbPerm, "", rec());
110+
return RecogniseGeneric(G, FindHomDbPerm, "", rec(), fail);
111111
elif IsMatrixGroup(G) then
112-
return RecogniseGeneric(G, FindHomDbMatrix, "", rec());
112+
return RecogniseGeneric(G, FindHomDbMatrix, "", rec(), fail);
113113
else
114114
ErrorNoReturn("Only matrix and permutation groups are supported");
115115
fi;
@@ -435,22 +435,33 @@ InstallGlobalFunction( PrintTreePos,
435435
fi;
436436
end );
437437

438+
NUM_MANDARINS := 100;
439+
438440
InstallGlobalFunction( RecogniseGeneric,
439-
function(H, methoddb, depthString, knowledge)
441+
function(H, methoddb, depthString, knowledge, mandarins)
440442
# Assume all the generators have no memory!
441-
local N,depth,done,i,l,ll,allmethods,
442-
hint,
443-
proj1,proj2,ri,rifac,riker,s,x,y,z,succ,counter;
443+
TODO
444444

445445
depth := Length(depthString);
446446

447447
PrintTreePos("E",depthString,H);
448448
Info(InfoRecog,4,"Recognising: ",H);
449449

450450
if Length(GeneratorsOfGroup(H)) = 0 then
451+
# FIXME: shouldn't we just, like, finish here immediately?
451452
H := Group([One(H)]);
452453
fi;
453454

455+
if mandarins = fail then
456+
Assert(0, depth = 0);
457+
# HACK: We don't want the mandarins to be reused by any computation.
458+
# Since PseudoRandom is hacked, it is important that we generate the
459+
# mandarins before calling EmptyRecognitionInfoRecord. Otherwise the
460+
# mandarins would be reused by RandomElm and RandomElmOrd.
461+
mandarins := List([1..NUM_MANDARINS], i -> PseudoRandom(H));
462+
fi;
463+
464+
454465
# Set up the record and the group object:
455466
if IsIdenticalObj( methoddb, FindHomDbProjective ) then
456467
ri := EmptyRecognitionInfoRecord(knowledge,H,true);
@@ -504,6 +515,16 @@ InstallGlobalFunction( RecogniseGeneric,
504515
SetNiceGens(ri,GeneratorsOfGroup(H));
505516
fi;
506517
fi;
518+
519+
# TODO: store the mandarins and their SLPs?
520+
# check mandarins now
521+
for x in mandarins do
522+
s := SLPforElement(ri, x);
523+
if s = fail then
524+
return MANDARIN_CRISIS;
525+
fi;
526+
od;
527+
507528
# these two were set correctly by FindHomomorphism
508529
if IsLeaf(ri) then SetFilterObj(ri,IsReady); fi;
509530
# FIXME: settle what IsReady means *exactly*;
@@ -517,6 +538,21 @@ InstallGlobalFunction( RecogniseGeneric,
517538

518539
# The non-leaf case:
519540
# In that case we know that ri now knows: homom plus additional data.
541+
542+
# Compute the mandarins of the factor
543+
for x in mandarins do
544+
if not ValidateHomomInput(ri, x) then
545+
# TODO
546+
return MANDARIN_CRISIS;
547+
fi;
548+
od;
549+
factorMandarins := [];
550+
for x in mandarins do
551+
y := ImageElm(Homom(ri), x);
552+
Assert(2, y <> fail);
553+
Add(factorMandarins, y);
554+
od;
555+
# TODO: sort the factorMandarins and remove duplicates and trivials
520556

521557
# Try to recognise the image a few times, then give up:
522558
counter := 0;
@@ -538,14 +574,23 @@ InstallGlobalFunction( RecogniseGeneric,
538574
fi;
539575
if ForAny(GeneratorsOfGroup(H), x->not ValidateHomomInput(ri, x)) then
540576
# Our group fails to contain some of the generators of H!
541-
return fail;
577+
# We handle this in the same way as if a ValidateHomomInpu had
578+
# returned fail for a mandarin.
579+
return MANDARIN_CRISIS;
542580
fi;
543581

544582
Add(depthString,'F');
545583
rifac := RecogniseGeneric(
546584
Group(List(GeneratorsOfGroup(H), x->ImageElm(Homom(ri),x))),
547-
methodsforimage(ri), depthString, InitialDataForImageRecogNode(ri) ); # TODO: change InitialDataForImageRecogNode to hintsForFactor??)
585+
methodsforimage(ri), depthString, InitialDataForImageRecogNode(ri)
586+
factorMandarins);
548587
Remove(depthString);
588+
# According to the mandarins, there was an error in a kernel generation
589+
# higher up in the recognition tree. Since rifac was a factor node, it
590+
# must have been `not safe`.
591+
if rifac = MANDARIN_CRISIS then
592+
return MANDARIN_CRISIS;
593+
fi;
549594
PrintTreePos("F",depthString,H);
550595
SetImageRecogNode(ri,rifac);
551596
SetParentRecogNode(rifac,ri);
@@ -558,7 +603,11 @@ InstallGlobalFunction( RecogniseGeneric,
558603
Info(InfoRecog,2,"Back from image (depth=",depth,").");
559604
fi;
560605

606+
# TODO: I think we should get rid of all the IsReady stuff. The
607+
# manual says it's "mainly set for debugging purposes". Then why does
608+
# it influence how often we try recognising the factor?
561609
if not IsReady(rifac) then
610+
# FIXME: why should we give up here?
562611
# the recognition of the image failed, also give up here:
563612
if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi;
564613
return ri;
@@ -569,6 +618,8 @@ InstallGlobalFunction( RecogniseGeneric,
569618
ri!.pregensfacwithmem := CalcNiceGens(rifac, ri!.gensHmem);
570619
Setpregensfac(ri, StripMemory(ri!.pregensfacwithmem));
571620

621+
# TODO: If mapping the mandarins failed, then we need to backtrack to
622+
# the last safe node and then add more kernel generators here (I think).
572623
# Now create the kernel generators with the stored method:
573624
succ := CallFuncList(findgensNmeth(ri).method,
574625
Concatenation([ri],findgensNmeth(ri).args));
@@ -585,7 +636,7 @@ InstallGlobalFunction( RecogniseGeneric,
585636
Sort(l,SortFunctionWithMemory); # this favours "shorter" memories!
586637
# FIXME: For projective groups different matrices might stand
587638
# for the same element, we might overlook this here!
588-
# remove duplicates:
639+
# remove duplicates and trivial entries:
589640
ll := [];
590641
for i in [1..Length(l)] do
591642
if not isone(ri)(l[i]) and
@@ -595,13 +646,40 @@ InstallGlobalFunction( RecogniseGeneric,
595646
od;
596647
SetgensN(ri,ll);
597648
fi;
649+
# evaluate mandarins to get kernel mandarins
650+
# TODO: something is suuper iffy about the method BlocksModScalars, which
651+
# is called by BlockDiagonal.
652+
# Apparently its input is neither to be understood as a projective nor as a
653+
# matrix group, but rather as a "all block-scalars being trivial" group.
654+
# That ofc completely wrecks the mandarins, since they assume the group to
655+
# be projective.
656+
kernelMandarins := [];
657+
for i in [1..Length(mandarins)] do
658+
x := mandarins[i];
659+
y := factorMandarins[i];
660+
s := SLPforElement(rifac, y);
661+
# TODO: these SLPs should be stored when they are computed for the
662+
# first time.
663+
if s = fail then
664+
Error("TODO: no SLP for factor");
665+
fi;
666+
z := ResultOfStraightLineProgram(s, pregensfac(ri));
667+
if not ri!.isequal(x, z) then
668+
Add( kernelMandarins, x / z );
669+
fi;
670+
od;
671+
# TODO: sort the kernelMandarins and remove duplicates and trivials
672+
598673
if IsEmpty(gensN(ri)) and immediateverification(ri) then
599674
# Special case, for an explanation see the source of the called function.
600675
RECOG_HandleSpecialCaseKernelTrivialAndMarkedForImmediateVerification(ri);
601676
fi;
602677
if IsEmpty(gensN(ri)) then
603-
# We found out that N is the trivial group!
604-
# In this case we do nothing, kernel is fail indicating this.
678+
# We found out that N is the trivial group! If the mandarins agree, we
679+
# do nothing. Set the kernel to fail to indicate this.
680+
if Length(kernelMandarins) <> 0 then
681+
return MANDARIN_CRISIS;
682+
fi;
605683
Info(InfoRecog,2,"Found trivial kernel (depth=",depth,").");
606684
SetKernelRecogNode(ri,fail);
607685
# We have to learn from the image, what our nice generators are:
@@ -613,6 +691,8 @@ InstallGlobalFunction( RecogniseGeneric,
613691
fi;
614692

615693
Info(InfoRecog,2,"Going to the kernel (depth=",depth,").");
694+
# If we do immediate verification, then we may have to recognise the kernel
695+
# several times.
616696
repeat
617697
# Now we go on as usual:
618698
SetgensNslp(ri,SLPOfElms(gensN(ri)));
@@ -622,8 +702,22 @@ InstallGlobalFunction( RecogniseGeneric,
622702
N := Group(StripMemory(gensN(ri)));
623703

624704
Add(depthString,'K');
625-
riker := RecogniseGeneric( N, methoddb, depthString, InitialDataForKernelRecogNode(ri) );
705+
riker := RecogniseGeneric( N, methoddb, depthString,
706+
InitialDataForKernelRecogNode(ri),
707+
kernelMandarins );
626708
Remove(depthString);
709+
# According to the mandarins, there was an error in the kernel
710+
# generation of the current node or higher up in the recognition tree.
711+
# We have to backtrack to the highest unsafe node.
712+
if riker = MANDARIN_CRISIS and not IsSafeRI(RIParent) then
713+
return MANDARIN_CRISIS;
714+
elif riker = MANDARIN_CRISIS and IsSafeRI(RIParent) then;
715+
# b) we are the "highest" unsafe node. TODO:
716+
# - cut off the part of the tree rooted in the current node,
717+
# - add generators to the kernel
718+
# - restart the kernel recognition
719+
ErrorNoReturn("TODO");
720+
fi;
627721
PrintTreePos("K",depthString,H);
628722
SetKernelRecogNode(ri,riker);
629723
SetParentRecogNode(riker,ri);
@@ -634,7 +728,15 @@ InstallGlobalFunction( RecogniseGeneric,
634728
Info(InfoRecog,2,"Doing immediate verification (depth=",
635729
depth,").");
636730
done := ImmediateVerification(ri);
731+
# TODO: If immediate verification fails because of image
732+
# computations, then:
733+
# return MANDARIN_CRISIS;
637734
fi;
735+
for x in kernelMandarins do
736+
if SLPforElement(ri, x) = fail then
737+
return MANDARIN_CRISIS;
738+
fi;
739+
od;
638740
until done;
639741

640742
if IsReady(riker) then # we are only ready when the kernel is
@@ -1051,42 +1153,3 @@ RECOG.testAllSubgroups := function(g, options...)
10511153
CallFuncList(RECOG.TestGroup, Concatenation([sub, false, Size(sub)],options));
10521154
od;
10531155
end;
1054-
1055-
1056-
RECOG.TestRecognitionNode := function(ri,stop,recurse)
1057-
local err, grp, x, slp, y, ef, ek, i;
1058-
err := 0;
1059-
grp := Grp(ri);
1060-
for i in [1..100] do
1061-
x := PseudoRandom(grp);
1062-
slp := SLPforElement(ri,x);
1063-
if slp <> fail then
1064-
y := ResultOfStraightLineProgram(slp,NiceGens(ri));
1065-
fi;
1066-
if slp = fail or not ri!.isone(x/y) then
1067-
if stop then ErrorNoReturn("ErrorNoReturn found, look at x, slp and y"); fi;
1068-
err := err + 1;
1069-
Print("X\c");
1070-
else
1071-
Print(".\c");
1072-
fi;
1073-
od;
1074-
Print("\n");
1075-
if err > 0 and recurse then
1076-
if IsLeaf(ri) then
1077-
return rec(err := err, badnode := ri);
1078-
fi;
1079-
ef := RECOG.TestRecognitionNode(ImageRecogNode(ri),stop,recurse);
1080-
if IsRecord(ef) then
1081-
return ef;
1082-
fi;
1083-
if KernelRecogNode(ri) <> fail then
1084-
ek := RECOG.TestRecognitionNode(KernelRecogNode(ri),stop,recurse);
1085-
if IsRecord(ek) then
1086-
return ek;
1087-
fi;
1088-
fi;
1089-
return rec( err := err, badnode := ri, factorkernelok := true );
1090-
fi;
1091-
return err;
1092-
end;

0 commit comments

Comments
 (0)