Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #34 +/- ##
==========================================
+ Coverage 94.05% 94.06% +0.01%
==========================================
Files 62 62
Lines 26624 26689 +65
==========================================
+ Hits 25040 25105 +65
Misses 1584 1584
🚀 New features to boost your workflow:
|
BlockCanonicalForm located an image in the orbit with Position, so
building an orbit of length n with g generators cost about n^2 g / 2
matrix comparisons. A dictionary makes that n g lookups.
The keys are compressed by ImmutableMatrix: GAP derives the hash
function of a list of vectors from the sample it is given, and returns
fail on a vector in a different representation.
Timings for AutGroupOfTable on the radical of GF(2)G, same seed:
G gl-orbit before after
SmallGroup(64,240) 2520 8.1 s 8.0 s
SmallGroup(64,264) 8680 21.8 s 12.4 s
SmallGroup(64,220) 10080 14.9 s 7.6 s
SmallGroup(64,266) 13888 35.2 s 11.1 s
SmallGroup(128,2326) 499968 - 3.2 min
Assisted-by: Claude Code (Opus 5)
VectorCanonicalForm reduces every tail modulo a fixed basis of the whole
space with SolutionMat, which echelonises that basis again on each call:
in the canonical form of a rank 7 group of order 256 that was 74000
calls and half the total time. The basis is square and invertible, so
the projection is a multiplication by the first columns of its inverse;
compute that matrix once per call.
Canonical form of A/A^4 for GF(2)G, with the dictionary of the previous
commit:
G dim before after
SmallGroup(256,26973) 81 10.0 s 4.6 s
SmallGroup(256,55626)101 29.8 s 13.2 s
SmallGroup(256,56082)127 74.9 s 33.0 s
Assisted-by: Claude Code (Opus 5)
Each entry of a tail was tested for membership in the span of the
entries chosen so far with SolutionMat, which echelonises that span
again on every test: 3.4 million calls in the canonical form of a rank 6
group of order 256. Keep the span echelonised instead, together with
the expression of each of its vectors in the chosen entries, and sift.
Canonical form of A/A^4 for GF(2)G, cumulative with the two previous
commits:
G dim master dict+proj +sift
SmallGroup(256,26973) 81 10.0 s 4.6 s 3.9 s
SmallGroup(256,55626)101 29.8 s 13.2 s 11.2 s
SmallGroup(256,56082)127 74.9 s 33.0 s 29.4 s
Assisted-by: Claude Code (Opus 5)
Every round of VectorCanonicalForm looked at the tail of every element
of the current stabiliser, although an element with a zero tail has a
zero entry, so it is neither a pivot nor multiplied by one. In the
canonical form of a rank 6 group of order 256 that was 3387904 of
3389200 visits.
Keep the elements with a nonzero tail in a list of their own. A tail
changes only when its element is multiplied or when cano moves, and the
latter did not happen once in that example.
Canonical form of A/A^4 for GF(2)G, cumulative:
G dim master 3 commits now
SmallGroup(256,26973) 81 10.0 s 3.9 s 2.5 s
SmallGroup(256,55626)101 29.8 s 11.2 s 7.1 s
SmallGroup(256,56082)127 74.9 s 29.4 s 18.2 s
Assisted-by: Claude Code (Opus 5)
The test suite reached VectorCanonicalForm, SubspaceCanonicalForm and BlockCanonicalForm only through the examples of the manual. The new tests compare them with orbits computed by GAP: the canonical form lies in the orbit and is constant on it, the orbit has length p^(|pcgs|-|stab|), and the stabilizer fixes the canonical form and has the right order. They cover a field that is not prime, elements acting trivially, and a hybrid group with and without gl part. Assisted-by: Claude Code (Fable 5.1)
NewDictionary chose the hash function from the first orbit point alone,
that is, for the field its entries generate. Over a field with more than
256 elements that is not prime, a first point with entries in a proper
subfield made every later lookup fail with an error:
gap> F := GF(2^9);; z := PrimitiveRoot( F );;
gap> g := DirectProductElement( [ 1, [ [ z^0, 0*z ], [ 0*z, z ] ] ] );;
gap> G := rec( field := F, one := g^0, glAutos := [ g ],
> glPerms := [ PermList( Concatenation( [2..511], [1] ) ) ],
> glOrder := 511, agAutos := [], size := 511 );;
gap> BlockCanonicalForm( G, [ [ z^0, z^0 ] ] );
Error, no method found! [...]
The key is now the matrix as one vector, and the dictionary is given the
row space over the field as its domain. The canonical tables of the six
benchmark group algebras are unchanged.
Assisted-by: Claude Code (Fable 5.1)
fingolfin
force-pushed
the
mh/orbit-dictionary
branch
from
September 23, 2026 19:37
62a1377 to
bc1fb67
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CanoFormWithAutGroupOfTablespends nearly all its time ingap/cfstab. Profiling showed four costs there that do not depend on the mathematics; each commit removes one. The results are unchanged.Before:
After:
The commits:
BlockCanonicalFormfound an image in the orbit withPosition, about n^2 g / 2 matrix comparisons for an orbit of length n and g generators. A dictionary makes that n g lookups. (The gl-orbit ofSmallGroup(128, 2326)has 499968 points.)VectorCanonicalFormreduced every tail modulo a fixed basis of the whole space withSolutionMat, which echelonises the basis again on every call. The basis is square, so this is a multiplication by the first columns of its inverse, computed once.SolutionMat, 3.4 million calls for one group of order 256. The span is now kept echelonised and the entries are sifted.VectorCanonicalForm,SubspaceCanonicalFormandBlockCanonicalForm(tst/cfstab.tst), which the test suite so far reached only through the examples of the manual. They compare with orbits computed by GAP: the canonical form lies in the orbit and is constant on it, the orbit has length p^(|pcgs| - |stab|), the stabiliser fixes the canonical form and has the right order. They cover GF(4), elements acting trivially, and a hybrid group with and without gl part, and pass on master as well.NewDictionarychooses its hash function for the field generated by the entries of the first key, so over a field with more than 256 elements that is not prime a later key could make the lookup fail with an error. The dictionary is now given the row space over the field as its domain.How the results were checked:
VectorCanonicalFormandSubspaceCanonicalFormreturn the same canonical form, stabiliser and transversal element as the old ones, element by element, on about 7000 random inputs over 13 fields from GF(2) to GF(65537), among them GF(4), GF(2^9) and GF(3^6); about 2700 of them were also compared with orbits computed by GAP.USE_MSERS := true.A port of
gap/cfstab/pgroup.giwith the same changes is proposed for the AutPGrp package in gap-packages/autpgrp#30, where it is tested in the same way.changes.txthas no entry yet.