Skip to content

Multi-member ReCom#461

Open
peterrrock2 wants to merge 6 commits into
tech-debt/finish-fixing-typesfrom
feat/multi-member-recom
Open

Multi-member ReCom#461
peterrrock2 wants to merge 6 commits into
tech-debt/finish-fixing-typesfrom
feat/multi-member-recom

Conversation

@peterrrock2

@peterrrock2 peterrrock2 commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Don't worry about the docs failing for now.

Restores ReCom support for plans whose districts elect different fixed numbers of members, rebuilt
on the current GerryChain contracts. Adds a parallel proposal API, a per-member population
constraint, documentation, and reproducible asset generation, leaving the single-member API
untouched. Stacks on tech-debt/finish-fixing-types.

Why

Multi-member ReCom existed in a separate branch before the RustworkX migration but needed migration
following the rewrite.

Each district label carries a positive integer member count, and its population target is
pop_target * members_per_district[label], where pop_target is the target for a single member.

Changes

  • Added multi_member_recom, build_multi_member_recom_proposal_fn, and the non-instantiable
    MultiMemberReCom namespace (four non-reversible variants) in
    gerrychain/proposals/multi_member_tree_proposals.py, exported from gerrychain.proposals.
  • Added epsilon_tree_bipartition_multi_member, a proposal-level wrapper that computes the feasible
    population interval for the two merged labels, converts it to the scalar symmetric form
    bipartition_tree already accepts, and calls it with single_district_cut=True. An empty
    interval raises PopulationBalanceError immediately rather than retrying trees or reselecting
    pairs, since a different tree cannot make the numeric interval feasible.
  • Added within_percent_of_ideal_population_per_member, which bounds each district's population per
    member around the plan-wide ideal (total population / total members).
  • Added a worked multi-member section to docs/user/recom.ipynb using the per-member constraint.
  • Added a make docs-recom-assets target and extended docs/generate_recom_assets.py to regenerate
    every static Gerrymandria plan image reproducibly; the regenerated assets are included.

Testing

  • Tests pass locally
  • Added/updated tests
  • Type checks pass locally

tests/test_proposals.py covers exact and epsilon-tolerant splits, per-label bounds preserved
across a seeded chain, mixed-type labels, seeded-trajectory reproducibility, all four namespace
variants matching direct calls, region-surcharge plumbing, pair reselection, infeasible-interval
PopulationBalanceError, and the full validation matrix. tests/constraints/test_validity.py and
tests/typing_assertions.py cover the constraint and its typing contract. Verified with
make test, make lint, make type-check, and make docs.

Reviewer Notes

  • Member counts are fixed to district labels for the whole chain; the mapping keys must equal the
    partition's labels exactly, and every count must be a positive integer (booleans rejected).
  • The design deliberately avoids touching _PopulatedGraph, the cut finders, or the tree protocols.
    Unequal-target support is confined to the new proposal-level wrapper.
  • The multi-member caveats are documented beside the example: the equal-district population
    constraint is not appropriate, pair selection is not seat-weighted, and there is no reversible
    variant (reversible multi-member ReCom needs a separate mathematical design).
  • Random multi-member seed generation is left for a future release: users can just merge
    single-member districts for now.

@peterrrock2
peterrrock2 requested a review from chief-dweeb July 19, 2026 21:06
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