Skip to content

Onset set of refiners#87

Merged
ChrisJefferson merged 8 commits into
masterfrom
onset-set-of-refiners
Jul 1, 2026
Merged

Onset set of refiners#87
ChrisJefferson merged 8 commits into
masterfrom
onset-set-of-refiners

Conversation

@ChrisJefferson

Copy link
Copy Markdown
Collaborator

No description provided.

VoleRefiner.SetOf([r1, ..., rk]) is a combinator over other refiners: it
constrains a permutation to map the set of objects the members describe onto
another such set (members may be reordered). With normaliser/conjugacy members
this gives the setwise stabiliser (and, via Vole.CanonicalImage, canonical form)
of a set of groups under conjugation.

It reads each member's graphs through the member's own refine hooks and its
action/objects through the member's constraint, combines the per-member graphs
into a set-of-graphs widget (shared real points + per-member anchor; each graph
a member emits becomes its own private copy block, so multi-record members do
not collide), and checks/canonicalises via each member's action.

- Type-aware: images are tagged by action, since GAP represents a set {3,4} and
  a tuple [2,4] by the same list; a set is never identified with a tuple.
- Per-node recall: initialise/fixed/changed/rBaseFinished are forwarded to the
  members, so members that emit graphs during search (orbital normalisers) prune
  beyond the root. Static members stay initialise-only.
- Members are stateful, so SetOf is its own type IsVoleSetOfRefiner whose
  SaveState/RestoreState delegate to the members (the engine only saves the
  outer refiner's state).

Members must be BacktrackKit/GraphBacktracking refiners (they expose a GAP
graph); native Vole refiners build their graph in Rust and cannot be members.

tst/onset.tst covers sets/tuples/digraphs, heterogeneous families, transporter,
canonical image, and sets of groups under conjugation (simple and orbital
members), checked against GAP and brute force.
Re-sync the bundled GraphBacktracking copy with the new
Transformation/PartialPerm conjugacy refiners and the unified PermConjugacy.

VoleRefiner.FromConstraint now turns Constraint.Stabilise/Transport with
OnPoints on a transformation or partial permutation into the matching
GB_Con conjugacy refiner, so Vole.Stabilizer(G, t, OnPoints) and
Vole.RepresentativeAction(G, t1, t2, OnPoints) work directly on these
objects (previously only perms were handled). Tested in wrapper.tst.
VoleRefiner.MultisetOf (SortedList) and VoleRefiner.TupleOf join SetOf;
SetOf now rejects duplicate members with an error pointing at MultisetOf.
The combinators are made type-aware (a set member is never identified
with a tuple member describing the same GAP list) via explicit type tags.

Documentation (refiners.gd) gains a section on the three combinators and
a worked example: classifying unordered pairs of transformations up to
simultaneous conjugacy with SetOf over GB_Con.TransformationConjugacy.
It uses the "one member canonical" fact to cut |M|^2 to |singles|*|M|,
and explains why canonicalising both members in advance would miss
classes (the pair-canonicaliser need not canonise either member alone).

Benchmarks (tst/benchmarks/):
  * pairs-one-canonical.g -- the worked example as a runnable benchmark,
    GAP Orbits cross-check at n <= 4;
  * setof-pairs.g         -- brute single/ordered/unordered enumeration
    via SetOf/TupleOf/MultisetOf, checked against a published table;
  * orderly-transformations.g -- orderly generation of transformations up
    to conjugacy through partial transformations, self-checking reps =
    A126285(n) and totals = A001372(n); reaches n=13 in ~5 min.

canonical-pairs.tst validates the SetOf/TupleOf/MultisetOf pair counts
against GAP's Orbits and the partition/A001372 anchors.
Keep the forked vole process alive between searches and reuse it, instead
of forking afresh every time. This amortises the process-spawn cost, which
dominates wall-clock for small problems (~24x faster on a batch of tiny
searches). Set _Vole.UseDaemon := false to fork afresh per search.

- vole now serves problems in a loop until GAP closes the pipe (EOF), then
  shuts down cleanly; every per-problem object is rebuilt inside the loop,
  so nothing leaks between problems.
- Each problem carries a nonce that vole echoes back in its 'end' result,
  so a desynchronised daemon stream is detected and refused, not trusted.
- _Vole.inflight tracks the in-progress pipe, so a call that escapes mid-
  search -- an error here or in a GAP callback, or a break loop that was
  quit -- is reaped on the next call (with an Info warning) rather than
  wedging the session.
- release_images() drops canonical GapRef images before the end/goodbye
  handshake, so dropGapRef traffic is serviced while GAP is still in its
  read loop; a late drop would block a reused daemon.
- vole exits cleanly when a GAP request hits EOF mid-conversation (GAP has
  gone away, e.g. reaping a parked process), instead of panicking.
- Fixed an IO_close -> IO_Close typo carried into the new ClosePipe helper.
- StopDaemon: a search caches a live daemon; StopDaemon clears it (and any
  in-flight pipe), is idempotent, and a later search respawns cleanly.
- Recovery: a GAP refiner callback that errors mid-search leaves the vole
  process parked (inflight set); the next search warns, reaps it, forks
  afresh, and still answers correctly. This mirrors a user hitting an error
  inside vole and quitting the break loop.
The bettercanonical chunk (the "you may get better performance with custom
refiners, see VoleFind.Canonical and the Refiners chapter" note) was defined
but never inserted, so the canonical wrapper functions silently lacked the
note that every other Vole.* function carries, and AutoDoc warned that the
chunk was defined but never used. Insert it into the Vole.CanonicalPerm and
Vole.CanonicalImage groups, matching the betterX notes on the other functions.
@ChrisJefferson ChrisJefferson merged commit 37df590 into master Jul 1, 2026
0 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant