@@ -91,25 +91,25 @@ InstallMethod( ViewObj, "for recognition nodes", [IsRecogNode],
9191
9292InstallGlobalFunction( RecognisePermGroup,
9393 function (G )
94- return RecogniseGeneric(G, FindHomDbPerm, " " , rec ());
94+ return RecogniseGeneric(G, FindHomDbPerm, " " , rec (), fail );
9595 end );
9696
9797InstallGlobalFunction( RecogniseMatrixGroup,
9898 function (G )
99- return RecogniseGeneric(G, FindHomDbMatrix, " " , rec ());
99+ return RecogniseGeneric(G, FindHomDbMatrix, " " , rec (), fail );
100100 end );
101101
102102InstallGlobalFunction( RecogniseProjectiveGroup,
103103 function (G )
104- return RecogniseGeneric(G, FindHomDbProjective, " " , rec ());
104+ return RecogniseGeneric(G, FindHomDbProjective, " " , rec (), fail );
105105 end );
106106
107107InstallGlobalFunction( 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+
438440InstallGlobalFunction( 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 ;
10531155end ;
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