From 81315b284104267a6d6202313f86ed23562c6559 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 11 Oct 2026 23:31:29 +0200 Subject: [PATCH] Fix tuple counts for reordered character tables NumberGeneratingTuples took class positions from ConjugacyClasses(G) and passed them to TotalNumberOfTuples, which reads them as positions in CharacterTable(G). The two lists need not agree (GAP reference manual, "The Interface between Character Tables and Groups"): they differ when the class list stored in the group does not start with the identity class, and for non-supersolvable groups once the CCTab package is loaded. The count was then wrong, and GeneratingMCOrbits, which samples until it has accounted for that many tuples, returned too few orbits or did not terminate. Take the classes from the character table, both for the group and for its maximal subgroups. Assisted-by: Claude Code (Opus 5.5) --- lib/newgeneratingtuples.gi | 10 ++++++---- tst/ClassOrder.tst | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 tst/ClassOrder.tst diff --git a/lib/newgeneratingtuples.gi b/lib/newgeneratingtuples.gi index 64a4bcf..d408005 100644 --- a/lib/newgeneratingtuples.gi +++ b/lib/newgeneratingtuples.gi @@ -18,10 +18,12 @@ InstallGlobalFunction(NumberGeneratingTuples,function(group,p,t,g) full:=[]; sz:=Size(group); - cc:=ConjugacyClasses(group); + # class positions are passed to TotalNumberOfTuples, so they must refer to + # the classes of the character table, whose order may differ from the group's + ct:=CharacterTable(group); + cc:=ConjugacyClasses(ct); oc:=List(t,s->Filtered([1..Length(cc)],i->s in cc[i])); - ct:=CharacterTable(group); str:=TotalNumberOfTuples(ct,g,List(oc,c->c[1])); Add(full,rec(gp:=group,sz:=sz,cc:=cc,oc:=oc,str:=str,pr:=0,nx:=0)); @@ -55,11 +57,11 @@ InstallGlobalFunction(NumberGeneratingTuples,function(group,p,t,g) fi; od; if not fl then - mcc:=ConjugacyClasses(m); + ct:=CharacterTable(m); + mcc:=ConjugacyClasses(ct); moc:=List(oc,s-> Union(List(s, n-> Filtered([1..Length(mcc)],i -> Representative(mcc[i]) in cc[n])))); if not ([] in moc) then - ct:=CharacterTable(m); str:=0; t:=List(tp,c->1); repeat diff --git a/tst/ClassOrder.tst b/tst/ClassOrder.tst new file mode 100644 index 0000000..febb81e --- /dev/null +++ b/tst/ClassOrder.tst @@ -0,0 +1,38 @@ +gap> START_TEST("MapClass package: ClassOrder.tst"); + +# A character table may list the conjugacy classes in another order than +# its group does. Here the group and each subgroup returned by +# MaximalSubgroupClassReps store the identity class last, whereas a character +# table has it first. +gap> IdLast:=function(G) +> local reps,H; +> reps:=List(ConjugacyClasses(G),Representative); +> reps:=Concatenation(reps{[2..Length(reps)]},reps{[1]}); +> H:=GroupWithGenerators(GeneratorsOfGroup(G),One(G)); +> SetConjugacyClasses(H,List(reps,x->ConjugacyClass(H,x))); +> SetMaximalSubgroupClassReps(H,List(MaximalSubgroupClassReps(G),IdLast)); +> return H; +> end;; +gap> G:=IdLast(SymmetricGroup(4));; +gap> ForAll(Concatenation([G],MaximalSubgroupClassReps(G)), +> H->IdentificationOfConjugacyClasses(CharacterTable(H)) +> <>[1..NrConjugacyClasses(H)]); +true +gap> t7:=ListWithIdenticalEntries(7,(1,2));; +gap> t8:=ListWithIdenticalEntries(8,(1,2));; +gap> NumberGeneratingTuples(G,[7],t7,0); +0 +gap> NumberGeneratingTuples(G,[8],t8,0); +131040 +gap> NumberGeneratingTuples(G,[2,2],[(1,2),(1,2),(1,2,3),(1,2,3)],0); +144 +gap> NumberGeneratingTuples(G,[1],[(1,2,3)],1); +216 +gap> orbs:=GeneratingMCOrbits(G,0,t7:OutputStyle:="silent");; +gap> Length(orbs); +0 +gap> orbs:=GeneratingMCOrbits(G,0,[(1,2),(1,2),(1,2,3),(1,2,3)]: +> OutputStyle:="silent");; +gap> List(orbs,o->Length(o.TupleTable)); +[ 6 ] +gap> STOP_TEST( "ClassOrder.tst" );