@xnotx123/ranked-pairs
v0.1.0
Published
Ranked pairs voting (Tideman) with a fixed four-level deterministic tiebreaker cascade: margin, winning votes, beatpath, lexicographic.
Maintainers
Readme
ranked-pairs
A ranked pairs voting implementation (the Tideman method).
Edges are sorted by a fixed four-level cascade:
- Margin — larger (winning − losing) locks first.
- Winning votes — the edge with more active support for the winner locks first.
- Beatpath — Schulze-style strongest-path strength (over margins) from winner to loser; larger locks first. Preferred over a pure lexicographic tiebreak because it uses information from the full pairwise matrix rather than candidate input order.
- Lexicographic — final deterministic fallback using candidate input order.
Install
npm install @xnotx123/ranked-pairsUsage
import { runRankedPairs } from '@xnotx123/ranked-pairs';
const result = runRankedPairs({
candidates: ['Alice', 'Bob', 'Carol'],
ballots: [
{ ranking: [['Alice'], ['Bob'], ['Carol']] },
{ ranking: [['Bob'], ['Alice'], ['Carol']] },
{ ranking: [['Carol'], ['Alice'], ['Bob']] },
],
});
console.log(result.ranking);
// [['Alice'], ['Bob'], ['Carol']]Ballot format
ranking is an array of tiers. Each tier is an array of candidates considered equal. Candidates omitted from the ballot are treated as ranked below all listed candidates and equal to each other (margins-style truncation handling).
{ ranking: [['A', 'B'], ['C']] }means "A and B are tied for first; C is third."
Result
type ElectionResult = {
ranking: string[][]; // tiers from winner to last place
lockedEdges: Edge[]; // edges added to the DAG
droppedEdges: Edge[]; // edges that would have created a cycle
pairwise: PairwiseMatrix; // raw pairwise tally
unknownCandidates: string[]; // names referenced in ballots but not in candidates
};Algorithm
- Build the pairwise preference matrix from ballots.
- For each pair where one candidate beats the other, build an edge with
(margin, winningVotes, losingVotes). - Sort edges by margin, then winning votes, then beatpath strength, then lexicographic candidate order.
- Lock edges into a DAG one at a time, skipping any that would create a cycle.
- Derive the ranking by repeatedly extracting candidates with no incoming locked edges.
License
MIT
