From 42c7303432f4d59fd1c6bd88ae38bb8a4e0e110e Mon Sep 17 00:00:00 2001 From: Torben Wiedemann PC Date: Tue, 10 Feb 2026 12:21:33 +0100 Subject: [PATCH 01/13] Add FindCycles (not yet used) --- gap/perm/giant.gi | 238 +++++++++++++++++++++---------- tst/working/quick/FindCycles.tst | 49 +++++++ 2 files changed, 214 insertions(+), 73 deletions(-) create mode 100644 tst/working/quick/FindCycles.tst diff --git a/gap/perm/giant.gi b/gap/perm/giant.gi index 8427b52b..647c8438 100644 --- a/gap/perm/giant.gi +++ b/gap/perm/giant.gi @@ -247,91 +247,183 @@ end; ######################################################################### -## -#F NiceGeneratorsAnOdd(,,) . . . . find (n-2)-cycle, 3-cycle -## -## - -RECOG.NiceGeneratorsAnOdd := function ( mp, grp, N ) +## For a permutation group grp on n points and a list lenList of integers, +## returns a list cycList such that cycList[i] is a cycle of length lenList[i] +## for all 1 <= i <= Length(lenList). +## Each entry of lenList must be either a prime number or n. +## If no such list can be constructed in a random search with at most N tries +## or if lenList[i]>n for some i, then returns fail. +RECOG.FindCycles := function ( grp, lenList, N ) - local l, t, cyclen, a, b, i, suppb, suppc, suppca, imc, h, g, n; + local mp, n, cycList, rand, cyclen, i, k, orders, finished; + mp := MovedPoints(grp); n := Length(mp); - l := One(grp); + cycList := []; - while N > 0 do + finished := false; + while N > 0 and not finished do N := N - 1; - t := PseudoRandom( grp ); - # was: cyclen := Collected( CycleLengths( t, [1..n] ) ); - cyclen := CycleStructurePerm(t); - - if IsBound(a) = false and IsBound(cyclen[n-1]) then - # we found an $n$-cycle - a := t; - fi; - - if IsBound(b) = false and IsBound(cyclen[2]) and cyclen[2] = 1 and - # was: Filtered( cyclen, x -> x[1] mod 3 = 0 ) = [ [ 3,1 ] ] - ForAll( [2..QuoInt(n,3)], x->not IsBound(cyclen[3*x-1]) ) - then - # we can get a $3$-cycle - #b := t^(Lcm(List(cyclen,x->x[1]))/3); - b := t^(Lcm(Filtered([2..n],x->IsBound(cyclen[x-1])))/3); - fi; - - if IsBound(a) and IsBound(b) then - i := 10*n; - suppb := MovedPoints( b ); - while i > 0 do - i := i-1; - t := PseudoRandom( grp ); - - suppc := List( suppb, x -> x^t ); - # support of c=b^t, say [i,j,k] - - suppca := List( suppc, x -> x^a ); - # support of c^a, so [i^a,j^a,k^a] - - imc := List( suppc, x -> ((x^(t^-1))^b)^t ); - # [i^c,j^c,k^c] - - if Length( Intersection( suppc, suppca ) ) = 2 then - # so c=b^t moves three consecutive points of a - if suppca[1] = imc[1] or - suppca[2] = imc[2] or - suppca[3] = imc[3] then - # so c moves points in same order as a - h := b^t; - else - # so c moves points in opposite order to a - h := (b^2)^t; - fi; - elif Length( Intersection( suppc, suppca ) ) = 1 then - # so c=b^t moves only two consecutive points of a - if suppca[1] = imc[1] or - suppca[2] = imc[2] or - suppca[3] = imc[3] then - # so c moves points in same order as a - h := b^t; - h := Comm( h^2, h^a ); + rand := PseudoRandom( grp ); + # If cyclen[i] is bound, it is the number of cycles of length i+1 in rand. + # Otherwise rand has no cycle of length i+1. + cyclen := CycleStructurePerm(rand); + # If finished is not changed to false in the following loop, then we are done + finished := true; + for i in [1..Length(lenList)] do + if not IsBound(cycList[i]) then # no cycle of desired length has been found yet + k := lenList[i]; + # Check that rand contains exactly one cycle of length k and + # no cycle whose length is a proper multiple of k + if IsBound(cyclen[k-1]) and cyclen[k-1] = 1 then + if k = n then + # The existence of a full cycle in rand guarantees that + # rand is equal to this full cycle. + cycList[i] := rand; else - # so c moves points in opposite order to a - h := b^t; - h := Comm( h, (h^a)^2 ); + # orders is a the list of all l>=2 such that rand contains a l-cycle and + # l<>k. Since rand contains a k-cycle, we only have to check up to n-k. + orders := Filtered([2..n-k],x->IsBound(cyclen[x-1]) and x<>k); + if ForAll(orders, x->(x=k) or (x mod k <> 0)) then + if IsEmpty(orders) then + cycList[i] := rand; # rand is a k-cycle + else + # Raising to the power of Lcm(orders) kills all cycles of rand + # whose length is not k. Further, the condition that k + # is a prime guarantees that every non-trivial power of + # a k-cycle is a k-cycle. Thus rand^(Lcm(orders)) + # is a k-cycle. + cycList[i] := rand^(Lcm(orders)); + fi; + fi; fi; fi; - - if IsBound( h ) then - g := a * h^2; - return [ g, h ]; + if not IsBound(cycList[i]) then + finished := false; fi; + fi; + od; + od; - od; # while + if finished then + return cycList; + else + return fail; + fi; +end; - return fail; - fi; +######################################################################### +## +#F NiceGeneratorsAnOdd(,,) . . . . find (n-2)-cycle, 3-cycle +## +## +## For a permutation group grp on n points, this function returns either fail +## or a list [ longCycle, shortCycle ] such that the following hold: +## - n > 4 and n is odd. +## - longCycle is an (n-2)-cycle. +## - shortCycle is a 3-cycle. +## - The supports of longCycle and shortCycle intersect in a single point. In +## other words, longCycle = (3,...,n) and shortCycle=(1,2,3) up to renaming +## the n points. +## The conditions on [ longCycle, shortCycle ] imply that grp is the full alternating +## group on n points. Thus the function always returns fail if grp is not the +## full alternating group, and also if n <= 4. +## longCycle, shortCycle are found by a random search, drawing at most N random +## elements from grp. +## Thus if grp is the full alternating group on an odd number of points, then the +## function does not return fail with a probability that grows as N grows. - od; # loop over random elements +RECOG.NiceGeneratorsAnOdd := function ( grp, N ) + + local mp, l, t, cyclen, nCyc, shCyc, rand, i, suppb, suppc, suppca, imc, h, g, n, orders; + + mp := MovedPoints(grp); + n := Length(mp); + l := One(grp); + + # Random search for an n-cycle (not an (n-2)-cycle!) and a 3-cycle + nCyc := fail; + shCyc := fail; + # while N > 0 do + # N := N - 1; + # rand := PseudoRandom( grp ); + # # If cyclen[i] is bound, it is the number of cycles of length i+1 in rand. + # # Otherwise rand has no cycle of length i+1. + # cyclen := CycleStructurePerm(rand); + # # Is rand an n-cycle? + # # Check that at least one n-cycle appears in the cycle decomposition of rand. + # # In this case, rand must be equal to this n-cycle. + # if nCyc <> fail and IsBound(cyclen[n-1]) then + # # we found an n-cycle + # nCyc := rand; + # fi; + # # Can we construct a 3-cycle from rand? + # # Check that the cycle decomposition of rand contains exactly one 3-cycle + # # and no cycle of length k where k is a multiple of 3 and 6<=k fail and IsBound(cyclen[2]) and cyclen[2] = 1 then + # # orders is a the list of all k>3 such that rand contains a k-cycle. + # # Since rand contains a 3-cycle, we only have to check up to n-3. + # orders := Filtered([3..n-3],x->IsBound(cyclen[x-1])); + # and + # ForAll( [2..QuoInt(n,3)], x->not IsBound(cyclen[3*x-1]) ) + # then + # # we can get a $3$-cycle + # #b := rand^(Lcm(List(cyclen,x->x[1]))/3); + # shCyc := rand^(Lcm(Filtered([2..n],x->IsBound(cyclen[x-1])))/3); + # fi; + # od; + + # if nCyc <> fail and shCyc <> fail then + # i := 10*n; + # suppb := MovedPoints( b ); + # while i > 0 do + # i := i-1; + # t := PseudoRandom( grp ); + + # suppc := List( suppb, x -> x^rand ); + # # support of c=b^rand, say [i,j,k] + + # suppca := List( suppc, x -> x^nCyc ); + # # support of c^nCyc, so [i^nCyc,j^nCyc,k^nCyc] + + # imc := List( suppc, x -> ((x^(rand^-1))^b)^rand ); + # # [i^c,j^c,k^c] + + # if Length( Intersection( suppc, suppca ) ) = 2 then + # # so c=b^rand moves three consecutive points of a + # if suppca[1] = imc[1] or + # suppca[2] = imc[2] or + # suppca[3] = imc[3] then + # # so c moves points in same order as a + # h := b^rand; + # else + # # so c moves points in opposite order to a + # h := (b^2)^rand; + # fi; + # elif Length( Intersection( suppc, suppca ) ) = 1 then + # # so c=b^rand moves only two consecutive points of a + # if suppca[1] = imc[1] or + # suppca[2] = imc[2] or + # suppca[3] = imc[3] then + # # so c moves points in same order as a + # h := b^rand; + # h := Comm( h^2, h^a ); + # else + # # so c moves points in opposite order to a + # h := b^rand; + # h := Comm( h, (h^a)^2 ); + # fi; + # fi; + + # if IsBound( h ) then + # g := a * h^2; + # return [ g, h ]; + # fi; + + # od; # while + + # return fail; + # fi; return fail; diff --git a/tst/working/quick/FindCycles.tst b/tst/working/quick/FindCycles.tst new file mode 100644 index 00000000..294ec7d7 --- /dev/null +++ b/tst/working/quick/FindCycles.tst @@ -0,0 +1,49 @@ +# +gap> START_TEST("FindCycles.tst"); +gap> testFindCyclesNoFail := function(G, lenList, N) +> local cycles, n, i, cyclen, j; +> cycles := RECOG.FindCycles(G, lenList, N); +> n := Length(MovedPoints(G)); +> if cycles = fail then +> Display("Error"); +> fi; +> for i in [1..Length(lenList)] do +> cyclen := CycleStructurePerm(cycles[i]); +> for j in [2..n] do +> if j <> lenList[i] and IsBound(cyclen[j-1]) then +> Display("Result contains a cycle of incorrect length"); +> elif j = lenList[i] and IsBound(cyclen[j-1]) and cyclen[j-1] <> 1 then +> Display("Result is not a cycle of correct length"); +> fi; +> od; +> od; +> end;; +gap> testFindCyclesFail := function(G, lenList, N) +> local cycles; +> cycles := RECOG.FindCycles(G, lenList, N); +> if cycles <> fail then +> Display("We found a cycle which does not lie in the input group"); +> fi; +> end;; + +# Test groups where we should find all cycles (with very high probability) +gap> for i in [1..5] do +> testFindCyclesNoFail(SymmetricGroup(3), [2,3], 10000); +> testFindCyclesNoFail(SymmetricGroup(5), [3,5], 10000); +> testFindCyclesNoFail(SymmetricGroup(10), [2,3,5,7,10], 10000); +> testFindCyclesNoFail(SymmetricGroup(53), [3,11,23,53], 10000); +> testFindCyclesNoFail(AlternatingGroup(3), [3], 10000); +> testFindCyclesNoFail(AlternatingGroup(5), [3,5], 10000); +> testFindCyclesNoFail(AlternatingGroup(10), [3,5,7], 10000); +> testFindCyclesNoFail(AlternatingGroup(53), [3,11,23,53], 10000); +> od; + +# Test groups where no cycle of the desired length exists +gap> testFindCyclesFail(AlternatingGroup(5), [2], 10000); +gap> testFindCyclesFail(AlternatingGroup(55), [2], 10000); +gap> testFindCyclesFail(Group((1,2,3,4,5)), [3], 10000); +gap> testFindCyclesFail(Group((1,2,3,4,5)), [4], 10000); +gap> testFindCyclesFail(Group((1,2,3)), [2], 10000); + +# +gap> STOP_TEST("PermNiceGens.tst"); From b301f546a0697aff2c20087f047371856770a3b9 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann PC Date: Tue, 10 Feb 2026 22:30:33 +0100 Subject: [PATCH 02/13] Document NiceGeneratorsAnOdd, change variable names, use FindCycles --- gap/perm/giant.gi | 368 ++++++++++++++++++++-------------------------- 1 file changed, 157 insertions(+), 211 deletions(-) diff --git a/gap/perm/giant.gi b/gap/perm/giant.gi index 647c8438..6bbbed9c 100644 --- a/gap/perm/giant.gi +++ b/gap/perm/giant.gi @@ -20,6 +20,71 @@ DeclareInfoClass( "InfoGiants" ); SetInfoLevel( InfoGiants, 1 ); +######################################################################### +## For a permutation group grp on n points and a list lenList of integers, +## returns a list cycList such that cycList[i] is a cycle of length lenList[i] +## for all 1 <= i <= Length(lenList). +## Each entry of lenList must be either a prime number or n. +## If no such list can be constructed in a random search with at most N tries +## or if lenList[i]>n for some i, then returns fail. +RECOG.FindCycles := function ( grp, lenList, N ) + + local mp, n, cycList, rand, cyclen, i, k, orders, finished; + + mp := MovedPoints(grp); + n := Length(mp); + cycList := []; + + finished := false; + while N > 0 and not finished do + N := N - 1; + rand := PseudoRandom( grp ); + # If cyclen[i] is bound, it is the number of cycles of length i+1 in rand. + # Otherwise rand has no cycle of length i+1. + cyclen := CycleStructurePerm(rand); + # If `finished` is not changed to false in the following loop, then we are done + finished := true; + for i in [1..Length(lenList)] do + if not IsBound(cycList[i]) then # no cycle of desired length has been found yet + k := lenList[i]; + # Check that rand contains exactly one cycle of length k and + # no cycle whose length is a proper multiple of k + if IsBound(cyclen[k-1]) and cyclen[k-1] = 1 then + if k = n then + # The existence of a full cycle in rand guarantees that + # rand is equal to this full cycle. + cycList[i] := rand; + else + # orders is a the list of all l>=2 such that rand contains a l-cycle and + # l<>k. Since rand contains a k-cycle, we only have to check up to n-k. + orders := Filtered([2..n-k],x->IsBound(cyclen[x-1]) and x<>k); + if ForAll(orders, x->(x=k) or (x mod k <> 0)) then + if IsEmpty(orders) then + cycList[i] := rand; # rand is a k-cycle + else + # Raising to the power of Lcm(orders) kills all cycles of rand + # whose length is not k. Further, the condition that k + # is a prime guarantees that every non-trivial power of + # a k-cycle is a k-cycle. Thus rand^(Lcm(orders)) + # is a k-cycle. + cycList[i] := rand^(Lcm(orders)); + fi; + fi; + fi; + fi; + if not IsBound(cycList[i]) then + finished := false; + fi; + fi; + od; + od; + + if finished then + return cycList; + else + return fail; + fi; +end; ####################################################################### ## @@ -43,7 +108,7 @@ SetInfoLevel( InfoGiants, 1 ); RECOG.NiceGeneratorsSn := function ( grp, N ) local cyclen, fullCycle, transp, rand, orders, i, supp, suppNew, n, mp, - numTries; + numTries, cycles; mp := MovedPoints(grp); n := Length(mp); @@ -53,58 +118,30 @@ RECOG.NiceGeneratorsSn := function ( grp, N ) fi; # Random search for an n-cycle and a transposition in grp - fullCycle := fail; - transp := fail; - while (fullCycle = fail or transp = fail) and N > 0 do - N := N - 1; - rand := PseudoRandom( grp ); - # If cyclen[i] is bound, it is the number of cycles of length i+1 in rand. - # Otherwise rand has no cycle of length i+1. - cyclen := CycleStructurePerm(rand); - # Is rand an n-cycle? - # Check that at least one n-cycle appears in the cycle decomposition of rand. - # In this case, rand must be equal to this n-cycle. - if fullCycle = fail and IsBound(cyclen[n-1]) then - fullCycle := rand; - fi; - # Can we construct a transposition from rand? - # Check that the cycle decomposition of rand contains exactly one 2-cycle - # and no cycle of length k where k is even and 4<=k2 such that rand contains a k-cycle. - # Since rand contains a 2-cycle, we only have to check up to n-2. - orders := Filtered([3..n-2],x->IsBound(cyclen[x-1])); - if ForAll(orders, IsOddInt) then - if IsEmpty(orders) then # rand is a 2-cycle - transp := rand; - else - # Raising to the power of Lcm(orders) kills all cycles of - # odd length. The single 2-cycle in rand remains - transp := rand^(Lcm(orders)); - fi; - fi; - fi; - od; + cycles := RECOG.FindCycles(grp, [2, n], N); + if cycles = fail then + return fail; + fi; + fullCycle := cycles[2]; + transp := cycles[1]; # Conjugate transp by random elements until we obtain a transposition that # interchanges successive elements of fullCycle. - if fullCycle <> fail and transp <> fail then - numTries := 10*n; # TODO: Why do we choose this constant? - supp := MovedPoints( transp ); # Support of transp - while numTries > 0 do - numTries := numTries-1; - rand := PseudoRandom( grp ); - suppNew := List(supp, x->x^rand); # Support of transp^rand - # Check that transp^rand interchanges successive points of fullCycle, - # or equivalently, that fullCycle moves one point of transp^rand - # to the other one. - if suppNew[1]^fullCycle = suppNew[2] - or suppNew[2]^fullCycle = suppNew[1] - then - return [ fullCycle, transp^rand ]; - fi; - od; - fi; + numTries := 10*n; # TODO: Why do we choose this constant? + supp := MovedPoints( transp ); # Support of transp + while numTries > 0 do + numTries := numTries-1; + rand := PseudoRandom( grp ); + suppNew := List(supp, x->x^rand); # Support of transp^rand + # Check that transp^rand interchanges successive points of fullCycle, + # or equivalently, that fullCycle moves one point of transp^rand + # to the other one. + if suppNew[1]^fullCycle = suppNew[2] + or suppNew[2]^fullCycle = suppNew[1] + then + return [ fullCycle, transp^rand ]; + fi; + od; return fail; @@ -186,10 +223,11 @@ end; ## ## -RECOG.NiceGeneratorsAnEven := function ( mp, grp, N ) +RECOG.NiceGeneratorsAnEven := function ( grp, N ) - local l, t, cyclen, a, b, c, i, fp, suppb, others, g, h, n; + local mp, l, t, cyclen, a, b, c, i, fp, suppb, others, g, h, n; + mp := MovedPoints(grp); n := Length(mp); l := One(grp); @@ -245,73 +283,6 @@ RECOG.NiceGeneratorsAnEven := function ( mp, grp, N ) end; - -######################################################################### -## For a permutation group grp on n points and a list lenList of integers, -## returns a list cycList such that cycList[i] is a cycle of length lenList[i] -## for all 1 <= i <= Length(lenList). -## Each entry of lenList must be either a prime number or n. -## If no such list can be constructed in a random search with at most N tries -## or if lenList[i]>n for some i, then returns fail. -RECOG.FindCycles := function ( grp, lenList, N ) - - local mp, n, cycList, rand, cyclen, i, k, orders, finished; - - mp := MovedPoints(grp); - n := Length(mp); - cycList := []; - - finished := false; - while N > 0 and not finished do - N := N - 1; - rand := PseudoRandom( grp ); - # If cyclen[i] is bound, it is the number of cycles of length i+1 in rand. - # Otherwise rand has no cycle of length i+1. - cyclen := CycleStructurePerm(rand); - # If finished is not changed to false in the following loop, then we are done - finished := true; - for i in [1..Length(lenList)] do - if not IsBound(cycList[i]) then # no cycle of desired length has been found yet - k := lenList[i]; - # Check that rand contains exactly one cycle of length k and - # no cycle whose length is a proper multiple of k - if IsBound(cyclen[k-1]) and cyclen[k-1] = 1 then - if k = n then - # The existence of a full cycle in rand guarantees that - # rand is equal to this full cycle. - cycList[i] := rand; - else - # orders is a the list of all l>=2 such that rand contains a l-cycle and - # l<>k. Since rand contains a k-cycle, we only have to check up to n-k. - orders := Filtered([2..n-k],x->IsBound(cyclen[x-1]) and x<>k); - if ForAll(orders, x->(x=k) or (x mod k <> 0)) then - if IsEmpty(orders) then - cycList[i] := rand; # rand is a k-cycle - else - # Raising to the power of Lcm(orders) kills all cycles of rand - # whose length is not k. Further, the condition that k - # is a prime guarantees that every non-trivial power of - # a k-cycle is a k-cycle. Thus rand^(Lcm(orders)) - # is a k-cycle. - cycList[i] := rand^(Lcm(orders)); - fi; - fi; - fi; - fi; - if not IsBound(cycList[i]) then - finished := false; - fi; - fi; - od; - od; - - if finished then - return cycList; - else - return fail; - fi; -end; - ######################################################################### ## #F NiceGeneratorsAnOdd(,,) . . . . find (n-2)-cycle, 3-cycle @@ -325,8 +296,8 @@ end; ## - The supports of longCycle and shortCycle intersect in a single point. In ## other words, longCycle = (3,...,n) and shortCycle=(1,2,3) up to renaming ## the n points. -## The conditions on [ longCycle, shortCycle ] imply that grp is the full alternating -## group on n points. Thus the function always returns fail if grp is not the +## The conditions on [ longCycle, shortCycle ] imply that grp contains the full alternating +## group on n points. Thus the function always returns fail if grp does not contain the ## full alternating group, and also if n <= 4. ## longCycle, shortCycle are found by a random search, drawing at most N random ## elements from grp. @@ -335,98 +306,73 @@ end; RECOG.NiceGeneratorsAnOdd := function ( grp, N ) - local mp, l, t, cyclen, nCyc, shCyc, rand, i, suppb, suppc, suppca, imc, h, g, n, orders; + local cyclen, cycN, cyc3, cyc3Cons, cyc3New, cyc3NewNew, rand, supp3, supp3New, + supp3NewShifted, numConsecutives, cycles, numTries, n; - mp := MovedPoints(grp); - n := Length(mp); - l := One(grp); + n := Length(MovedPoints(grp)); # Random search for an n-cycle (not an (n-2)-cycle!) and a 3-cycle - nCyc := fail; - shCyc := fail; - # while N > 0 do - # N := N - 1; - # rand := PseudoRandom( grp ); - # # If cyclen[i] is bound, it is the number of cycles of length i+1 in rand. - # # Otherwise rand has no cycle of length i+1. - # cyclen := CycleStructurePerm(rand); - # # Is rand an n-cycle? - # # Check that at least one n-cycle appears in the cycle decomposition of rand. - # # In this case, rand must be equal to this n-cycle. - # if nCyc <> fail and IsBound(cyclen[n-1]) then - # # we found an n-cycle - # nCyc := rand; - # fi; - # # Can we construct a 3-cycle from rand? - # # Check that the cycle decomposition of rand contains exactly one 3-cycle - # # and no cycle of length k where k is a multiple of 3 and 6<=k fail and IsBound(cyclen[2]) and cyclen[2] = 1 then - # # orders is a the list of all k>3 such that rand contains a k-cycle. - # # Since rand contains a 3-cycle, we only have to check up to n-3. - # orders := Filtered([3..n-3],x->IsBound(cyclen[x-1])); - # and - # ForAll( [2..QuoInt(n,3)], x->not IsBound(cyclen[3*x-1]) ) - # then - # # we can get a $3$-cycle - # #b := rand^(Lcm(List(cyclen,x->x[1]))/3); - # shCyc := rand^(Lcm(Filtered([2..n],x->IsBound(cyclen[x-1])))/3); - # fi; - # od; - - # if nCyc <> fail and shCyc <> fail then - # i := 10*n; - # suppb := MovedPoints( b ); - # while i > 0 do - # i := i-1; - # t := PseudoRandom( grp ); - - # suppc := List( suppb, x -> x^rand ); - # # support of c=b^rand, say [i,j,k] - - # suppca := List( suppc, x -> x^nCyc ); - # # support of c^nCyc, so [i^nCyc,j^nCyc,k^nCyc] - - # imc := List( suppc, x -> ((x^(rand^-1))^b)^rand ); - # # [i^c,j^c,k^c] - - # if Length( Intersection( suppc, suppca ) ) = 2 then - # # so c=b^rand moves three consecutive points of a - # if suppca[1] = imc[1] or - # suppca[2] = imc[2] or - # suppca[3] = imc[3] then - # # so c moves points in same order as a - # h := b^rand; - # else - # # so c moves points in opposite order to a - # h := (b^2)^rand; - # fi; - # elif Length( Intersection( suppc, suppca ) ) = 1 then - # # so c=b^rand moves only two consecutive points of a - # if suppca[1] = imc[1] or - # suppca[2] = imc[2] or - # suppca[3] = imc[3] then - # # so c moves points in same order as a - # h := b^rand; - # h := Comm( h^2, h^a ); - # else - # # so c moves points in opposite order to a - # h := b^rand; - # h := Comm( h, (h^a)^2 ); - # fi; - # fi; - - # if IsBound( h ) then - # g := a * h^2; - # return [ g, h ]; - # fi; - - # od; # while - - # return fail; - # fi; - - return fail; + cycles := RECOG.FindCycles(grp, [3, n], N); + if cycles = fail then + return fail; + fi; + cyc3 := cycles[1]; # 3-cycle + cycN := cycles[2]; # n-cycle + + # Random search for cyc3Cons, a 3-cycle that moves 3 consecutive points of cycN. + # In the following comments, we assume that the points in mp are renamed + # so that cycN = (1,...,n). We look for a cycle of the form (i,i+1,i+2) (mod n). + numTries := 10*n; # TODO: Why do we choose this constant? + supp3 := MovedPoints( cyc3 ); + cyc3Cons := fail; + while numTries > 0 and cyc3Cons = fail do + numTries := numTries-1; + rand := PseudoRandom( grp ); + # support of cyc3New:=cyc3^rand, say [i,j,k]. + # We will compute cyc3New only later because we might not need it. + supp3New := List( supp3, x -> x^rand ); + # support of cyc3New^cycN, so [i,j,k]^cycN=[i+1,j+1,k+1] (mod n) + supp3NewShifted := List( supp3New, x -> x^cycN ); + # Number of p \in [i,j,k] s.t. p+1 \in [i,j,k] (mod n) + numConsecutives := Length( Intersection( supp3New, supp3NewShifted ) ); + if numConsecutives = 2 then + # In this case, {i,j,k} = {p,p+1,p+2} for some p. + # Thus cyc3New is either (p,p+1,p+2) or (p,p+2,p+1) (mod n). + cyc3New := cyc3^rand; + if ForAny(supp3New, x->x^cycN=x^cyc3New) then + # In this case, cyc3New = (p,p+1,p+2) (mod n). + # I.e. cyc3New moves points in same order as cycN. + cyc3Cons := cyc3New; + else + # In this case, cyc3New = (p,p+2,p+1) (mod n). + cyc3Cons := cyc3New^2; # = cyc3New^-1 + fi; + elif numConsecutives = 1 then + # In this case, {i,j,k}={p,p+1,q} (mod n) for some p,q + # with q not in [p-1,p+2] (mod n). + # Again, cyc3New is either (p,p+1,q) or (p,q,p+1) (mod n). + cyc3New := cyc3^rand; + # We define cyc3NewNew to be (p,p+1,q): + if ForAny(supp3New, x->x^cycN=x^cyc3New) then + # In this case, cyc3New = (p,p+1,q) (mod n) + cyc3NewNew := cyc3^rand; + else + # In this case, cyc3New = (p,q,p+1) (mod n) + cyc3NewNew := (cyc3^rand)^2; + fi; + cyc3Cons := Comm( cyc3NewNew^2, cyc3NewNew^cycN ); + # = cyc3NewNew^-2 * (cyc3NewNew^2)^(cyc3NewNew^cycN) + # = (p,p+1,q)*(p,q,p+2) = (p,p+1,p+2) + fi; + od; + if cyc3Cons <> fail then + # cycN * cyc3Cons^2 = (1,...,n)*(p,p+2,p+1)=(1,...,p-1,p+2,p+3,...,n) + # = (n-2)-cycle whose support intersects [p,p+1,p+2] is one point. + return [ cycN * cyc3Cons^2, cyc3Cons]; + else + return fail; + fi; end; @@ -545,9 +491,9 @@ RECOG.RecogniseAn := function( mp, grp, eps ) N := Int(24 * (4/3)^3 * le * 6 * n); if n mod 2 = 0 then - gens := RECOG.NiceGeneratorsAnEven( mp, grp, N ); + gens := RECOG.NiceGeneratorsAnEven( grp, N ); else - gens := RECOG.NiceGeneratorsAnOdd( mp, grp, N ); + gens := RECOG.NiceGeneratorsAnOdd( grp, N ); fi; if gens = fail then From dd6c44ccee209665ea1a75340c6a7fa269a95af5 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann PC Date: Tue, 10 Feb 2026 22:30:46 +0100 Subject: [PATCH 03/13] Add tests for NiceGeneratorsAnOdd --- tst/working/quick/PermNiceGens.tst | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tst/working/quick/PermNiceGens.tst b/tst/working/quick/PermNiceGens.tst index 7b10b761..093cead4 100644 --- a/tst/working/quick/PermNiceGens.tst +++ b/tst/working/quick/PermNiceGens.tst @@ -1,5 +1,7 @@ # gap> START_TEST("PermNiceGens.tst"); + +####### Test NiceGeneratorsSn ######## gap> testNiceGeneratorsSn := function(grp) > local Sn, m, niceGens, fullCycle, transp, cyclen1, x, y, i; > m := Size(MovedPoints(grp)); @@ -46,5 +48,46 @@ gap> for G in grps do if RECOG.NiceGeneratorsSn(G, 10000) <> fail then > Print("NiceGeneratorsSn should not succeed for ", G, "\n"); > fi; od; +####### Test NiceGeneratorsAn ######## +gap> testNiceGeneratorsAn := function(grp) +> local m, niceGens, longPerm, shortPerm, cyclenShort, cyclenLong; +> m := Size(MovedPoints(grp)); +> if IsOddInt(m) then +> niceGens := RECOG.NiceGeneratorsAnOdd(grp, 10000); +> else +> niceGens := RECOG.NiceGeneratorsAnEven(grp, 10000); +> fi; +> if niceGens <> fail then +> longPerm := niceGens[1]; +> shortPerm := niceGens[2]; +> cyclenShort := CycleStructurePerm(shortPerm); +> cyclenLong := CycleStructurePerm(longPerm); +> if IsOddInt(m) then +> if ForAny(Union([1], [3..m]), i->IsBound(cyclenShort[i])) or cyclenShort[2] <> 1 then +> Display("Short permutation is not a 3-cycle for m odd"); +> fi; +> if ForAny([1..m-4], i->IsBound(cyclenLong[i])) or cyclenLong[m-3] <> 1 then +> Display("Long permutation is not an (m-2)-cycle for m odd"); +> fi; +> if Size(Intersection(MovedPoints(longPerm), MovedPoints(shortPerm))) <> 1 then +> Display("Supports of 3-cycle and (m-2)-cycle do not intersect in one point for m odd"); +> fi; +> fi; + +# Test for even m is still missing +> fi; +> end;; + +# Test that NiceGeneratorsAn works for AlternatingGroup +gap> for m in [3..5] do +> testNiceGeneratorsAn(AlternatingGroup(m)); +> od; + +# Test that NiceGeneratorsAn returns fail for some non-alternating groups +gap> for G in [Group((1,2,3,4)), Group((1,2),(3,4)), Group((1,2,3,4), (5,6,7))] do +> if RECOG.NiceGeneratorsAnEven(G, 1000) <> fail or RECOG.NiceGeneratorsAnOdd(G, 1000) <> fail then +> Display("Group is not alternating"); +> fi; od; + # gap> STOP_TEST("PermNiceGens.tst"); From a042f932733ad8c75e9ce93eb6d4ab4f3fc0b493 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann PC Date: Tue, 10 Feb 2026 22:32:13 +0100 Subject: [PATCH 04/13] Fix typo --- gap/perm/giant.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/perm/giant.gi b/gap/perm/giant.gi index 6bbbed9c..a766f869 100644 --- a/gap/perm/giant.gi +++ b/gap/perm/giant.gi @@ -368,7 +368,7 @@ RECOG.NiceGeneratorsAnOdd := function ( grp, N ) if cyc3Cons <> fail then # cycN * cyc3Cons^2 = (1,...,n)*(p,p+2,p+1)=(1,...,p-1,p+2,p+3,...,n) - # = (n-2)-cycle whose support intersects [p,p+1,p+2] is one point. + # = (n-2)-cycle whose support intersects [p,p+1,p+2] in one point. return [ cycN * cyc3Cons^2, cyc3Cons]; else return fail; From 7c9ce195e52c3f967a1c313575cbfb6746eb1c89 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann PC Date: Tue, 10 Feb 2026 22:39:42 +0100 Subject: [PATCH 05/13] Clarify documentation of FindCycles --- gap/perm/giant.gi | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gap/perm/giant.gi b/gap/perm/giant.gi index a766f869..3a2f93cf 100644 --- a/gap/perm/giant.gi +++ b/gap/perm/giant.gi @@ -22,11 +22,13 @@ SetInfoLevel( InfoGiants, 1 ); ######################################################################### ## For a permutation group grp on n points and a list lenList of integers, -## returns a list cycList such that cycList[i] is a cycle of length lenList[i] -## for all 1 <= i <= Length(lenList). +## returns either a list cycList such that cycList[i] is a cycle of length lenList[i] +## for all 1 <= i <= Length(lenList), or fail. ## Each entry of lenList must be either a prime number or n. -## If no such list can be constructed in a random search with at most N tries -## or if lenList[i]>n for some i, then returns fail. +## The desired circles are found by a random search, drawing at most N random +## elements from grp. +## Thus if grp actually contains cycles of the desired shape, then the function does not +## return fail with a probability that grows as N grows. RECOG.FindCycles := function ( grp, lenList, N ) local mp, n, cycList, rand, cyclen, i, k, orders, finished; From 55cd955cf13c399ff709071b64d3f9fcf674f3a0 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann <7226617+TWiedemann@users.noreply.github.com> Date: Fri, 13 Feb 2026 09:51:18 +0100 Subject: [PATCH 06/13] Add TODO-comment Co-authored-by: Max Horn --- tst/working/quick/PermNiceGens.tst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tst/working/quick/PermNiceGens.tst b/tst/working/quick/PermNiceGens.tst index 093cead4..0fb797cf 100644 --- a/tst/working/quick/PermNiceGens.tst +++ b/tst/working/quick/PermNiceGens.tst @@ -74,7 +74,7 @@ gap> testNiceGeneratorsAn := function(grp) > fi; > fi; -# Test for even m is still missing +# TODO: Test for even m is still missing > fi; > end;; From 0fbffa4962b9afb2fb5da40fed298d5dd7419e67 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann <7226617+TWiedemann@users.noreply.github.com> Date: Fri, 13 Feb 2026 09:52:34 +0100 Subject: [PATCH 07/13] Clarify documentation Co-authored-by: Max Horn --- gap/perm/giant.gi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gap/perm/giant.gi b/gap/perm/giant.gi index 3a2f93cf..40706cc9 100644 --- a/gap/perm/giant.gi +++ b/gap/perm/giant.gi @@ -22,8 +22,8 @@ SetInfoLevel( InfoGiants, 1 ); ######################################################################### ## For a permutation group grp on n points and a list lenList of integers, -## returns either a list cycList such that cycList[i] is a cycle of length lenList[i] -## for all 1 <= i <= Length(lenList), or fail. +## returns either a list cycList of equal length such that cycList[i] is a +## cycle of length lenList[i] for all 1 <= i <= Length(lenList), or fail. ## Each entry of lenList must be either a prime number or n. ## The desired circles are found by a random search, drawing at most N random ## elements from grp. From 4cba3964513fa2b5c8d6b6ff92a663d46f3bb8fa Mon Sep 17 00:00:00 2001 From: Torben Wiedemann <7226617+TWiedemann@users.noreply.github.com> Date: Fri, 13 Feb 2026 09:53:06 +0100 Subject: [PATCH 08/13] Fix typo Co-authored-by: Max Horn --- gap/perm/giant.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/perm/giant.gi b/gap/perm/giant.gi index 40706cc9..b1e4a2e5 100644 --- a/gap/perm/giant.gi +++ b/gap/perm/giant.gi @@ -25,7 +25,7 @@ SetInfoLevel( InfoGiants, 1 ); ## returns either a list cycList of equal length such that cycList[i] is a ## cycle of length lenList[i] for all 1 <= i <= Length(lenList), or fail. ## Each entry of lenList must be either a prime number or n. -## The desired circles are found by a random search, drawing at most N random +## The desired cycles are found by a random search, drawing at most N random ## elements from grp. ## Thus if grp actually contains cycles of the desired shape, then the function does not ## return fail with a probability that grows as N grows. From ef7003aaf41fed264d811e34d2fa850ea9f5ce36 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann <7226617+TWiedemann@users.noreply.github.com> Date: Fri, 13 Feb 2026 09:53:30 +0100 Subject: [PATCH 09/13] Simplify language Co-authored-by: Max Horn --- gap/perm/giant.gi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gap/perm/giant.gi b/gap/perm/giant.gi index b1e4a2e5..4584d415 100644 --- a/gap/perm/giant.gi +++ b/gap/perm/giant.gi @@ -27,8 +27,8 @@ SetInfoLevel( InfoGiants, 1 ); ## Each entry of lenList must be either a prime number or n. ## The desired cycles are found by a random search, drawing at most N random ## elements from grp. -## Thus if grp actually contains cycles of the desired shape, then the function does not -## return fail with a probability that grows as N grows. +## Thus if grp actually contains cycles of the desired shape, then the function +## succeeds with a probability that grows as N grows. RECOG.FindCycles := function ( grp, lenList, N ) local mp, n, cycList, rand, cyclen, i, k, orders, finished; From 6a7b2eeda3f5e8d7aa3a48fc3486c2a5005d2e9e Mon Sep 17 00:00:00 2001 From: Torben Wiedemann <7226617+TWiedemann@users.noreply.github.com> Date: Fri, 13 Feb 2026 09:56:44 +0100 Subject: [PATCH 10/13] Clarify comment Co-authored-by: Max Horn --- gap/perm/giant.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/perm/giant.gi b/gap/perm/giant.gi index 4584d415..bfbd00e3 100644 --- a/gap/perm/giant.gi +++ b/gap/perm/giant.gi @@ -57,7 +57,7 @@ RECOG.FindCycles := function ( grp, lenList, N ) # rand is equal to this full cycle. cycList[i] := rand; else - # orders is a the list of all l>=2 such that rand contains a l-cycle and + # set orders to the list of all l>=2 such that rand contains an l-cycle and # l<>k. Since rand contains a k-cycle, we only have to check up to n-k. orders := Filtered([2..n-k],x->IsBound(cyclen[x-1]) and x<>k); if ForAll(orders, x->(x=k) or (x mod k <> 0)) then From 4d121652b94f24f1cb293d3a7c3244e9f77cc1c2 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann <7226617+TWiedemann@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:11:33 +0100 Subject: [PATCH 11/13] Make PSL(2,23)-test more robust --- tst/working/combined/MoreNaming.tst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tst/working/combined/MoreNaming.tst b/tst/working/combined/MoreNaming.tst index 82e1c047..fad671a9 100644 --- a/tst/working/combined/MoreNaming.tst +++ b/tst/working/combined/MoreNaming.tst @@ -344,7 +344,7 @@ gap> grp := Group( > [ 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), > Z(2)^0, 0*Z(2), Z(2)^0 ] ] ] );; gap> ri := RecogniseClassical(grp);; -gap> "PSL(2,23)" in ri.possibleNearlySimple; +gap> Number([1..100], i -> "PSL(2,23)" in ri.possibleNearlySimple) >= 90; true # PSL(2,23) 22a From 8c6518303fcefc6f6a58d3f27a967df9a1686c5e Mon Sep 17 00:00:00 2001 From: Torben Wiedemann <7226617+TWiedemann@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:46:01 +0100 Subject: [PATCH 12/13] Add NiceGeneratorsAnEven --- gap/perm/giant.gi | 111 ++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 54 deletions(-) diff --git a/gap/perm/giant.gi b/gap/perm/giant.gi index bfbd00e3..3fbe357b 100644 --- a/gap/perm/giant.gi +++ b/gap/perm/giant.gi @@ -24,7 +24,8 @@ SetInfoLevel( InfoGiants, 1 ); ## For a permutation group grp on n points and a list lenList of integers, ## returns either a list cycList of equal length such that cycList[i] is a ## cycle of length lenList[i] for all 1 <= i <= Length(lenList), or fail. -## Each entry of lenList must be either a prime number or n. +## Each entry of lenList must be either a prime number or n or n-1. Further, +## each entry must be at least 2. ## The desired cycles are found by a random search, drawing at most N random ## elements from grp. ## Thus if grp actually contains cycles of the desired shape, then the function @@ -52,7 +53,7 @@ RECOG.FindCycles := function ( grp, lenList, N ) # Check that rand contains exactly one cycle of length k and # no cycle whose length is a proper multiple of k if IsBound(cyclen[k-1]) and cyclen[k-1] = 1 then - if k = n then + if k = n-1 or k = n then # The existence of a full cycle in rand guarantees that # rand is equal to this full cycle. cycList[i] := rand; @@ -221,73 +222,75 @@ end; ######################################################################## ## -#F NiceGeneratorsAnEven(,,) . . find (2,n-2)-cycle, 3-cycle +#F NiceGeneratorsAnEven(,) . . ## ## +## For a permutation group grp on n points, this function returns either fail +## or a list [ longPerm, cyc3 ] such that the following hold: +## - n > 3 and n is even. +## - longPerm is the product of a 2-cycle and an (n-2)-cycle that are disjoint. +## - cyc3 is a 3-cycle. +## - The support of the 2-cycle in longPerm is contained in the support of cyc3. +## In other words, longPerm = (1,2)(3,...,n) and cyc3=(1,2,3) up to renaming +## the n points. +## The conditions on [ longPerm, cyc3 ] imply that grp contains the full alternating +## group on n points. Thus the function always returns fail if grp does not contain the +## full alternating group, and also if n <= 3. +## long, cyc3 are found by a random search, drawing at most N random +## elements from grp. +## Thus if grp contains the full alternating group on an even number of points, then the +## function succeeds with a probability that grows as N grows. RECOG.NiceGeneratorsAnEven := function ( grp, N ) - local mp, l, t, cyclen, a, b, c, i, fp, suppb, others, g, h, n; + local mp, fp, supp3, others, n, cycles, cyc3, cyc3New, cycNm1, numTries, rand, a, b; mp := MovedPoints(grp); n := Length(mp); - l := One(grp); - - while N > 0 do - N := N - 1; - t := PseudoRandom( grp ); - # was: cyclen := Collected( CycleLengths( t, [1..n] ) ); - cyclen := CycleStructurePerm(t); - - # was: if IsBound(a) = false and [n-1,1] in cyclen then - if IsBound(a) = false and IsBound(cyclen[n-2]) then - # we found an $n-1$-cycle - a := t; - fi; - if IsBound(b) = false and IsBound(cyclen[2]) and cyclen[2] = 1 and - # Filtered( cyclen, x -> x[1] mod 3 = 0 ) = [ [ 3,1 ] ] - ForAll( [2..QuoInt(n,3)], x->not IsBound(cyclen[3*x-1]) ) - then - # we can get a $3$-cycle - #b := t^(Lcm(List(cyclen,x->x[1]))/3); - b := t^(Lcm(Filtered([2..n],x->IsBound(cyclen[x-1])))/3); - fi; - - if IsBound(a) and IsBound(b) then - i := 10*n; - fp := Difference( mp, MovedPoints(a) )[1]; - suppb:= MovedPoints( b ); - while i > 0 do - i := i-1; - t := PseudoRandom( grp ); - if fp in List( suppb, x -> x^t ) then - c := b^t; - others := [ fp^c, (fp^c)^c ]; - if others[1]^a = others[2] then - h := c; - elif others[2]^a = others[1] then - h := c^2; - else - h := Comm(c^a,c); # h = (1,i,i+1) - fi; - g := a * h; - return [ g, h ]; - fi; - od; # while + # Random search for an (n-1)-cycle (not an (n-2)-cycle!) and a 3-cycle + cycles := RECOG.FindCycles(grp, [3, n-1], N); + if cycles = fail then + return fail; + fi; + cyc3 := cycles[1]; # 3-cycle + cycNm1 := cycles[2]; # (n-1)-cycle ("Nm1" = "n minus 1") - return fail; + # Random search for a permutation rand such that the support of + # cyc3^rand contains the fixed point of cycNm1 + numTries := 10*n; # TODO: Why do we choose this constant? + fp := Difference( mp, MovedPoints(cycNm1) )[1]; # Fixed point of cycNm1 + supp3 := MovedPoints( cyc3 ); # Support of cyc3 + while numTries > 0 do + numTries := numTries-1; + rand := PseudoRandom( grp ); + if fp in List( supp3, x -> x^rand ) then # if fp in support of cyc3^rand + cyc3 := cyc3^rand; # We found the desired 3-cycle + # Define points a,b such that cyc3 = (fp, a, b) + a := fp^cyc3; + b := a^cyc3; + # Define a new 3-cycle cyc3New of the form (fp, c, d) for points c,d with c^cycNm1=d + if a^cycNm1 = b then + cyc3New := cyc3; + elif b^cycNm1 = a then + cyc3New := cyc3^2; # = (fp, b, a) + else + # In this case, g := cyc3^cycNm1 has the form (fp, p, q) + # where {p=a^cycNm1,q^cycNm1} is disjoint from {a,b}. Hence + # [g,cyc3] = g^-1 g^cyc3 = (fp,q,p) (a,p,q)=(fp,a,p). + cyc3New := Comm(cyc3^cycNm1,cyc3); + fi; + # Rename points so that fp=1, c=2, d=3, cycNm1=(2,...,n). Then + # cyc3New = (1,2,3), cycNm1*cyc3New=(2,...,n)*(1,2,3)=(1,2)(3,...,n). + return [ cycNm1 * cyc3New, cyc3New ]; fi; - - od; # loop over random elements - + od; return fail; - end; ######################################################################### ## -#F NiceGeneratorsAnOdd(,,) . . . . find (n-2)-cycle, 3-cycle +#F NiceGeneratorsAnOdd(,) . . . . find (n-2)-cycle, 3-cycle ## ## ## For a permutation group grp on n points, this function returns either fail @@ -303,7 +306,7 @@ end; ## full alternating group, and also if n <= 4. ## longCycle, shortCycle are found by a random search, drawing at most N random ## elements from grp. -## Thus if grp is the full alternating group on an odd number of points, then the +## Thus if grp contains the full alternating group on an odd number of points, then the ## function does not return fail with a probability that grows as N grows. RECOG.NiceGeneratorsAnOdd := function ( grp, N ) From 5d49fbfb2262b066f3a762a8da129061af4b56e1 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann <7226617+TWiedemann@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:51:40 +0100 Subject: [PATCH 13/13] Update tests --- tst/working/quick/FindCycles.tst | 8 ++++---- tst/working/quick/PermNiceGens.tst | 26 +++++++++++++++++--------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/tst/working/quick/FindCycles.tst b/tst/working/quick/FindCycles.tst index 294ec7d7..279f76e3 100644 --- a/tst/working/quick/FindCycles.tst +++ b/tst/working/quick/FindCycles.tst @@ -29,12 +29,12 @@ gap> testFindCyclesFail := function(G, lenList, N) # Test groups where we should find all cycles (with very high probability) gap> for i in [1..5] do > testFindCyclesNoFail(SymmetricGroup(3), [2,3], 10000); -> testFindCyclesNoFail(SymmetricGroup(5), [3,5], 10000); -> testFindCyclesNoFail(SymmetricGroup(10), [2,3,5,7,10], 10000); -> testFindCyclesNoFail(SymmetricGroup(53), [3,11,23,53], 10000); +> testFindCyclesNoFail(SymmetricGroup(5), [3,4,5], 10000); +> testFindCyclesNoFail(SymmetricGroup(10), [2,3,5,7,9,10], 10000); +> testFindCyclesNoFail(SymmetricGroup(53), [3,11,23,52,53], 10000); > testFindCyclesNoFail(AlternatingGroup(3), [3], 10000); > testFindCyclesNoFail(AlternatingGroup(5), [3,5], 10000); -> testFindCyclesNoFail(AlternatingGroup(10), [3,5,7], 10000); +> testFindCyclesNoFail(AlternatingGroup(10), [3,5,7,9], 10000); > testFindCyclesNoFail(AlternatingGroup(53), [3,11,23,53], 10000); > od; diff --git a/tst/working/quick/PermNiceGens.tst b/tst/working/quick/PermNiceGens.tst index 0fb797cf..5cdda094 100644 --- a/tst/working/quick/PermNiceGens.tst +++ b/tst/working/quick/PermNiceGens.tst @@ -58,35 +58,43 @@ gap> testNiceGeneratorsAn := function(grp) > niceGens := RECOG.NiceGeneratorsAnEven(grp, 10000); > fi; > if niceGens <> fail then -> longPerm := niceGens[1]; -> shortPerm := niceGens[2]; +> # Up to renaming points, the following permutations should be... +> longPerm := niceGens[1]; # =(1,2)(3,...,m) for even m and =(3,...,m) for odd m +> shortPerm := niceGens[2]; # =(1,2,3) > cyclenShort := CycleStructurePerm(shortPerm); > cyclenLong := CycleStructurePerm(longPerm); +> if ForAny(Union([1], [3..m]), i->IsBound(cyclenShort[i])) or cyclenShort[2] <> 1 then +> Display("Short permutation is not a 3-cycle for m odd"); +> fi; > if IsOddInt(m) then -> if ForAny(Union([1], [3..m]), i->IsBound(cyclenShort[i])) or cyclenShort[2] <> 1 then -> Display("Short permutation is not a 3-cycle for m odd"); -> fi; > if ForAny([1..m-4], i->IsBound(cyclenLong[i])) or cyclenLong[m-3] <> 1 then > Display("Long permutation is not an (m-2)-cycle for m odd"); > fi; > if Size(Intersection(MovedPoints(longPerm), MovedPoints(shortPerm))) <> 1 then > Display("Supports of 3-cycle and (m-2)-cycle do not intersect in one point for m odd"); > fi; +> else +> if (m > 4 and (cyclenLong[1] <> 1 or cyclenLong[m-3] <> 1)) +> or (m=4 and cyclenLong[1] <> 2) then +> Display("Long permutation is not 2-cycle times (m-2)-cycle for m even"); +> fi; +> if not ForAny(MovedPoints(shortPerm), x -> x=(x^longPerm)^longPerm) then +> Display(Concatenation("Support of 2-cycle in long permutation is not ", +> "contained in support of short permutation")); +> fi; > fi; - -# TODO: Test for even m is still missing > fi; > end;; # Test that NiceGeneratorsAn works for AlternatingGroup -gap> for m in [3..5] do +gap> for m in [3..50] do > testNiceGeneratorsAn(AlternatingGroup(m)); > od; # Test that NiceGeneratorsAn returns fail for some non-alternating groups gap> for G in [Group((1,2,3,4)), Group((1,2),(3,4)), Group((1,2,3,4), (5,6,7))] do > if RECOG.NiceGeneratorsAnEven(G, 1000) <> fail or RECOG.NiceGeneratorsAnOdd(G, 1000) <> fail then -> Display("Group is not alternating"); +> Display("Nice generators found for group that is not alternating"); > fi; od; #