v1.7.0 - rotation-based lattice enumeration
Highlights
Ships the classical Gusfield-Irving 1989 rotation algorithm for enumerating the stable-matching lattice, plus two public primitives that expose the rotation structure directly for fine-grained lattice navigation.
enumerate_stable_matchings(men_rank, women_rank, method='rotation')— default; scales comfortably past n=50 with runtime O(n² + |L|·n²), where |L| is the number of stable matchings. Replaces the vectorized brute force as the default method; the brute-force method remains available viamethod='brute'as a correctness oracle for small instances.exposed_rotations(men_rank, women_rank, matching)— returns the rotations currently applicable at a given stable matching. Each exposed rotation corresponds to a one-step move down the lattice.apply_rotation(matching, rotation)— takes that step, producing the next stable matching.
The two primitives are the building blocks for any algorithm that walks the stable-matching lattice (search, incremental maintenance under preference changes, learned policies, and so on).
Correctness
Cross-validated against the brute-force enumerator on random n=3..7 instances — full set equality in every case. New tests confirm:
exposed_rotationsis empty at the women-optimal (lattice infimum)exposed_rotationsis non-empty at the men-optimal when |L| > 1apply_rotationpreserves stability and produces a strictly different matchingapply_rotationdoes not mutate its input arrays
Scaling smoke test runs the rotation enumerator at n=20 — impossible for brute force (20! = 2.4e18 permutations).
Compatibility
Backwards-compatible — no signature changes to existing functions. Code that currently calls enumerate_stable_matchings(men_rank, women_rank) will silently switch from brute force to rotation (same output set, different algorithm).
Full changelog: v1.6.0...v1.7.0