Skip to content

Add approval+runoff and blanket primary variants (issue #17)#44

Open
endolith wants to merge 10 commits into
masterfrom
cursor/issue-17-blanket-primary-cf84
Open

Add approval+runoff and blanket primary variants (issue #17)#44
endolith wants to merge 10 commits into
masterfrom
cursor/issue-17-blanket-primary-cf84

Conversation

@endolith

@endolith endolith commented May 11, 2026

Copy link
Copy Markdown
Owner

Closes #17.

Summary

Adds elsim.methods.blanket_primary with two-round reform methods:

Method Primary General
approval_runoff Top-two approval (Unified Primary) Contingent vote on ranked ballots
top_n_irv Top-n first preferences (sntv) IRV among finalists
top_n_runoff Top-n first preferences Contingent vote among finalists
top_n_condorcet Top-n first preferences Condorcet among finalists
irv_primary_top_n_runoff irv(..., n_winners=n) Contingent vote among finalists

Also extends irv with n_winners=... for ranked primaries that eliminate to a slate without majority short-circuit.

API uses top_n_* with n=4 (Top Four) or n=5 (Final Five) rather than separate top_four_* / top_five_* wrappers. Docstrings use Unified Primary, Top Four, and Final Five naming and describe the general election as a contingent vote where applicable.

Tests

  • 262 tests pass (CI green).
  • New review-pass coverage: Tennessee benchmarks for all variants (including n=5), semantic regressions showing primary narrowing can change outcomes vs plain runoff, helper unit tests, docstring examples, and hypothesis property tests for top_n_runoff, top_n_condorcet, and irv_primary_top_n_runoff.

Human review checklist

API & naming

  • Public exports in elsim.methods.__init__ match intended surface (approval_runoff, top_n_irv, top_n_runoff, top_n_condorcet, irv_primary_top_n_runoff).
  • top_n_* + n=4 / n=5 naming is clear enough vs Alaska Top Four / Final Five reform packages.
  • irv(..., n_winners=k) keyword-only API and return type (int vs set vs None) read correctly in docs.

Electoral semantics

  • Unified Primary (approval_runoff): top-two by approval tallies, then pairwise majority on ranked ballots (contingent vote).
  • Top-n plurality primary (top_n_irv, top_n_runoff, top_n_condorcet): same sntv rule as existing sntv; ballots restricted to finalists before the general.
  • top_n_runoffrunoff: general counts first preferences among finalists only (see Tennessee n=3 test: Knoxville vs Nashville).
  • irv_primary_top_n_runoff: primary is IRV elimination to n survivors (no majority stop); general is contingent vote on restricted ballots.
  • top_n_condorcet general: no tiebreaker in Condorcet stage (matches condorcet); returns None on cycles.

Tie-breaking

  • Primary-stage ties use order / random / None consistently with sntv and irv.
  • approval_runoff breaks primary and general ties via the same tiebreaker argument.
  • Unbroken ties return None (not an arbitrary winner).

Docs & references

  • Wikipedia / FairVote / Alaska / Delemazure citations are appropriate and links resolve.
  • Docstrings distinguish contingent vote from supplementary vote where relevant.
  • Doctests / examples in docstrings match implementation.

Edge cases

  • Single-candidate and degenerate elections (test_methods unanimity / single-candidate).
  • n >= n_candidates advances everyone without error.
  • Invalid approval ballots (max > 1) and row-count mismatch raise ValueError.
  • n_winners < 1 raises ValueError.

Code quality

  • _restrict_ballots remaps candidate IDs correctly when finalists are a non-contiguous subset.
  • No unnecessary duplication with runoff / irv / condorcet internals.
  • Import style (relative imports in __init__.py) matches project preference.
Open in Web Open in Cursor 

@what-the-diff

what-the-diff Bot commented May 11, 2026

Copy link
Copy Markdown

PR Summary

  • Enhanced Election Methods
    We've added new capabilities related to election systems and blanket primaries. New functions include candidate elimination, tiebreaking, and others to provide advanced functionalities, which you can access in the newly developed blanket_primary.py file.
  • New File Creation
    The blanket_primary.py file is a fresh addition to our suite. It's equipped with implementations for two-round election systems and provides options for tiebreakers and determining the winner.
  • Updated Imports
    To make the election methods from blanket_primary.py readily useful in other parts of our application, we updated the __init__.py file to include these methods.
  • Testing for New Functionality
    We've ensured the correctness of the new election systems by creating the test_blanket_primary.py file. This file houses several test cases, aiding in validating the functionality of the new methods.
  • Test Method Adjustments
    The existing test_methods.py file has been refined. We've incorporated the new blanket primary methods to ensure that it covers them, thus validating correct error handling for tied elections and mismatched dimensions in approval ballots.

@codecov

codecov Bot commented May 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.18%. Comparing base (69d45f3) to head (82bba94).
⚠️ Report is 6 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master      #44      +/-   ##
==========================================
+ Coverage   96.37%   97.18%   +0.81%     
==========================================
  Files          17       18       +1     
  Lines         496      640     +144     
==========================================
+ Hits          478      622     +144     
  Misses         18       18              
Flag Coverage Δ
no-numba 96.71% <100.00%> (+0.95%) ⬆️
numba 90.78% <100.00%> (+2.67%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

cursoragent and others added 8 commits May 15, 2026 00:37
Implement top-n plurality primaries with IRV, contingent runoff, or
Condorcet generals (Final Four/Five and table variants), IRV-to-slate
primaries with IRV or runoff generals, and approval primary with ranked
pairwise general (unified primary). Export from elsim.methods and extend
tests.

Co-authored-by: endolith <endolith@gmail.com>
Add unit tests for primary ties, Condorcet cycles, runoff/IRV None paths,
approval runoff edges, and IRV-to-slate primaries. Drop unreachable
approval validation and IRV primary inner break; duplicate checks lived
only in approval_runoff.

Co-authored-by: endolith <endolith@gmail.com>
Use Find-the-winner openings, borda-style ballot descriptions, full
tiebreaker and Returns wording, and explicit Wikipedia hyperlinks in RST
(including section fragments) instead of :wikipedia: roles where anchors
apply. Add Examples to irv_primary_top_n_* wrappers; expand module docstring.

Co-authored-by: endolith <endolith@gmail.com>
Cite IJCAI approval-with-runoff (DOI), Alaska Division of Elections RCV page,
FairVote Top Four PDF, St. Louis sample ballot PDF, Gehl & Porter HBS report,
Condorcet 1785 (BnF Gallica), Hare 1859 (Internet Archive), and Electoral
Reform Society supplementary vote page. Expand module docstring and wrapper
references to match.

Co-authored-by: endolith <endolith@gmail.com>
Remove prose about how references are organized; tighten Condorcet and
Final Five narrative lines.

Co-authored-by: endolith <endolith@gmail.com>
Fold sequential IRV slate selection into irv as a keyword-only parameter.
Remove irv_eliminate_to_n and irv_primary_top_n_irv (same outcome as irv).
Clarify top_n_runoff versus runoff on the full field; fix doc references and
remove St. Louis / mismatched Alaska prose.

Co-authored-by: endolith <endolith@gmail.com>
…ases

Rename irv(..., n_survivors=) to n_winners. Capitalize reform names in docs,
spell out contingent vote, add Unified Primary synonym to approval_runoff.
Remove top_four_* and top_five_* wrappers; use top_n_* with n=4 or 5.
Replace supplementary-vote ref with contingent vote for top_n_runoff.

Co-authored-by: endolith <endolith@gmail.com>
@endolith endolith force-pushed the cursor/issue-17-blanket-primary-cf84 branch from c1023db to 094a181 Compare May 15, 2026 04:41
_irv_eliminate_until_n_winners_remain passed a set to _inc_rank_idx, which
expects a 1D boolean ndarray (same as the main irv path). This caused
TypeError on all Python versions when blanket-primary tests exercised
irv(..., n_winners=k).

Co-authored-by: endolith <endolith@gmail.com>
@cursor cursor Bot marked this pull request as ready for review June 12, 2026 04:43
Add Tennessee checks for top_n_condorcet and n=5 variants, regression
tests showing primary narrowing can change contingent-vote outcomes vs
plain runoff, direct helper tests, docstring examples, and hypothesis
property tests for remaining ranked blanket methods.

Co-authored-by: endolith <endolith@gmail.com>
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.

Add Approval+Runoff

2 participants