diff --git a/gap/base/recognition.gi b/gap/base/recognition.gi index 2a4da978..ea524ed8 100644 --- a/gap/base/recognition.gi +++ b/gap/base/recognition.gi @@ -691,33 +691,52 @@ InstallGlobalFunction( RecogniseGeneric, depth,")."); done := ImmediateVerification(ri); fi; - until done; - - # Set nice generators and CalcStdPresentation of ri - SetNiceGens(ri,Concatenation(pregensfac(ri), NiceGens(riker))); - if not HasStdPresentation(ri) and not HasCalcStdPresentation(ri) then - SetCalcStdPresentation(ri,CalcStdPresentationGenericNonLeaf); - fi; + if done then + # Set nice generators and CalcStdPresentation of ri + SetNiceGens(ri,Concatenation(pregensfac(ri), NiceGens(riker))); + if not HasStdPresentation(ri) and not HasCalcStdPresentation(ri) then + SetCalcStdPresentation(ri,CalcStdPresentationGenericNonLeaf); + fi; - # Check that all (input) generators of H lie in the group generated by - # the nice generators. - # One could argue that this step should only be performed if verification is desired, - # but [BHLO15, 5.2 (6)] suggests to always do this. - # In any case, it should be relatively cheap. - # Note that without this step, the success of CalcStdPresentation is not sufficient - # to guarantee verification, even if this is not clear from [BHLO15, 4.3, 4.5, 5.3.1]. - for h in GeneratorsOfGroup( H ) do - if SLPforElement(ri, h) = fail then - # NiceGens(ri) is too small, abort - if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi; - Info( - InfoRecog, 1, - "RecogNode could not be recognised,", - " IsReady() is not set, recognition aborts" - ); - return ri; + # Check that all (input) generators of H lie in the group generated + # by the nice generators. If a generator reveals an additional + # kernel element, add it and retry kernel recognition. + for i in [1..Length(GeneratorsOfGroup( H ))] do + h := GeneratorsOfGroup( H )[i]; + if SLPforElement(ri, h) = fail then + x := ImageElm(Homom(ri), h); + if x <> fail then + s := SLPforElement(ImageRecogNode(ri), x); + else + s := fail; + fi; + if s <> fail then + y := ResultOfStraightLineProgram(s, ri!.pregensfacwithmem); + z := ri!.gensHmem[i] * y^-1; + if not isone(ri)(z) and + not ForAny(gensN(ri), x -> isequal(ri)(x, z)) then + Add(gensN(ri), z); + Info(InfoRecog, 2, + "Final verification found extra kernel ", + "element (depth=", depth, ")."); + done := false; + fi; + fi; + if done then + # NiceGens(ri) is too small, abort + if InfoLevel(InfoRecog) = 1 and depth = 0 then + Print("\n"); + fi; + Info(InfoRecog, 1, + "RecogNode could not be recognised,", + " IsReady() is not set, recognition aborts"); + return ri; + fi; + break; + fi; + od; fi; - od; + until done; if InfoLevel(InfoRecog) = 1 and depth = 0 then Print("\n"); fi; # StopStoringRandEls(ri); diff --git a/tst/working/quick/bugfix.tst b/tst/working/quick/bugfix.tst index f5825d12..5f612728 100644 --- a/tst/working/quick/bugfix.tst +++ b/tst/working/quick/bugfix.tst @@ -440,6 +440,18 @@ gap> Size(ri); gap> IsCorrect(ri); true +# The top-level GoProjective kernel recognition can initially sample only a +# proper subgroup of the scalar kernel. Final generator verification must retry +# the kernel after adding the missing residual kernel element. +gap> seed:=234;; Reset(GlobalMersenneTwister,seed);; Reset(GlobalRandomSource,seed);; +gap> h := GL(19,5);; +gap> g := GroupWithGenerators(ProductReplacer(h)!.team);; +gap> ri := RECOG.TestGroup(g,false,Size(h));; +gap> IsReady(ri); +true +gap> Size(ri) = Size(GL(19,5)); +true + # gap> SetInfoLevel(InfoRecog, oldInfoLevel); gap> STOP_TEST("bugfix.tst");