interregnum.methods.singlevote package

Single votes allocators.

A single vote allocator needs an input candidates.

class interregnum.methods.singlevote.HighestAveragesAllocator(divisor_f, skip_initial_seats=False)

Bases: NonDeterministicAllocator[AnyName, HAResultData]

Highest averages allocator ([Gallagher:1992], [KohlerZeh:2012]).

Implementation based on divisor series which allocates one seat at a time.

Tie-breaking follows the rules defined by the Spanish law from 1985 ([Loreg:1985]).

allocators collection keys:

  • highest_averages

  • highest-averages

Create a highest averages allocator using a divisor function or a divisor sequence.

Parameters:

Examples

>>> # use the d'Hondt divisor
>>> dhondt = HighestAveragesAllocator("dhondt")
calc(candidates, seats, random_seed=None, filter_f=None, initial_seats=None, skip_initial_seats=None)

Allocate candidates to seats.

If a candidate has initial seats, the initial divisor will be adjusted considering those seats at a starting point ([Denmark:2011]).

Distributed seats will be logged by a QuotaWinnerEvent.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates with votes. Only candidates in this list will be considered.

  • seats (int) – seats that will be computed, in addition to the initial seats

  • random_seed (int | Random | None) – used to break ties

  • filter_f (CandidateFilter[AnyName, Event] | None) – restrict allocation to filtered candidates

  • initial_seats (Iterable[tuple[AnyName, int]] | None) – seats already allocated to candidates

  • skip_initial_seats (bool | None) – add initial seats to results. If None, the value from the constructor will be used

Return type:

Result[AnyName, HAResultData]

class interregnum.methods.singlevote.IterativeDivisorAllocator(signpost_f)

Bases: Allocator[AnyName, IDResultData[AnyName]]

Iterative divisor method.

See [DorfleitnerKlein:1997] and [Zachariasen:2006]

allocators collection keys:

  • iterative_divisor

  • iterative-divisor

Create an iterative divisor allocator.

Parameters:

signpost_f (str | RoundingWithSignpost) – round function with signpost (collection signposts).

calc(candidates, seats, exclude_candidates=None)

Allocate candidates to seats.

Initial candidate seats are ignored. All won seats will be logged by SeatsEvent.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates

  • seats (int) – allocatable seats

  • exclude_candidates (Iterable[AnyName] | None) – list of candidates excluded from allocation

Return type:

Result[AnyName, IDResultData[AnyName]]

Examples

>>> # use the Jefferson method
>>> jefferson = IterativeDivisorAllocator("jefferson")
class interregnum.methods.singlevote.LargestRemainderAllocator(quota_f, fix_overflow=True, bisect_step=1, skip_initial_seats=False)

Bases: NonDeterministicAllocator[AnyName, LRResultData]

Largest remainder method.

See [Gallagher:1992], [KohlerZeh:2012] and https://en.wikipedia.org/wiki/Largest_remainder_method

allocators collection keys:

  • largest_remainder

  • largest-remainder

Create a largest remainder method using quota_f as the quota function.

While the calculated quota allocates more than the avalaible seats and fix_overflow is True, the quota will be incremented by bisect_step. The remaining seats will be assigned to the candidates with the largest remainders.

Parameters:
  • quota_f (str | QuotaFunction) – quota function or key in quotas

  • fix_overflow (bool) – adjust the quota if more seats than the required amount were allocated

  • bisect_step (int) – step used at the quota adjustment process

  • skip_initial_seats (bool)

Examples

>>> # Hare quota
>>> hare = LargestRemainderAllocator("hare")
>>> # Reinforced Imperiali quota, adjusting quota
>>> # if the allocated seats are greater than required
>>> imp3 = LargestRemainderAllocator("imperiali3")
>>> # Reinforced Imperiali quota, do not adjust quota
>>> imp3 = LargestRemainderAllocator("imperiali3", fix_overflow=False)
calc(candidates, seats, random_seed=None, total_votes=None, exclude_candidates=None, initial_seats=None, skip_initial_seats=None)

Allocates candidates to seats.

If a candidate already has initial seats, the votes used for those seats are subtracted before the allocation.

Distributed seats will be logged by QuotaWinnerEvent (seats by quota) and SeatsEvent (seats by remainders).

If a quota is discarded because of overflow, a NewQuotaEvent will be logged.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates

  • seats (int) – seats that will be computed, in addition to the initial seats

  • random_seed (int | Random | None) – used to break ties

  • total_votes (int | Fraction | None) – votes for the quota calculation, in the case it is greater than the sum of the candidates’ votes

  • initial_seats (Iterable[tuple[AnyName, int]] | None) – seats already allocated to candidates

  • skip_initial_seats (bool | None) – add initial seats to results. If None, the value from the constructor will be used

  • exclude_candidates (Iterable[AnyName] | None)

Return type:

NonDeterministicResult[AnyName, LRResultData]

class interregnum.methods.singlevote.LimitedVotingAllocator

Bases: MultiWinnerAdapter[AnyName, MultiWinnerResultData, Sequence[Candidate[AnyName]], Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]]

Limited voting / Partial block voting.

Given that there are N available seats, the N most voted candidates win a seat each one.

Used in the election to the Spanish Senate.

See [Loreg:1985] and https://en.wikipedia.org/wiki/Limited_voting

allocators collection keys:

  • limited_voting

  • partial_block_voting

Create a limited voting allocator.

Examples

>>> limited_voting = LimitedVotingAllocator()
calc(candidates, seats, random_seed=None, filter_f=None, **ranking_args)

Allocate candidates to seats.

Initial seats will be ignored.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates

  • seats (int) – number of expected winners

  • random_seed (int | Random | None) – used to break ties

  • filter_f (CandidateFilter[AnyName, Event] | None) – restrict to filtered candidates

  • ranking_args (Any)

Return type:

NonDeterministicResult[AnyName, MultiWinnerResultData]

class interregnum.methods.singlevote.WinnerTakesAllAllocator

Bases: WinnerTakesAllAdapter[AnyName, MultiWinnerResultData, Sequence[Candidate[AnyName]], Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]]

Winner-Takes-All / First past the post.

Each seat will be assigned to the most voted candidate in different rounds.

The winner will take all the seats.

allocators collection keys:

  • winner_takes_all

  • first_past_the_post

Create a First Past The Post allocator.

Examples

>>> wta = WinnerTakesAllAllocator()
calc(candidates, seats=1, random_seed=None, **kwargs)

Allocate candidates to seats.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates

  • seats (int) – seats to allocate

  • random_seed (int | Random | None) – used to break ties

  • kwargs (Any)

Return type:

NonDeterministicResult[AnyName, MultiWinnerResultData]

Submodules

interregnum.methods.singlevote.highest_averages module

Highest averages method for proportional apportionments.

References


class interregnum.methods.singlevote.highest_averages.CandidateState(candidate, divisor, quotient, last_tie_victory=-1)

Bases: Generic[AnyName]

Candidate internal state.

Parameters:
  • candidate (Candidate[AnyName])

  • divisor (Iterator[int | float | Fraction])

  • quotient (int | float | Fraction)

  • last_tie_victory (int)

classmethod init(candidate, div_f)

Init a candidate state.

Parameters:
Return type:

CandidateState[AnyName]

tie_state()

Get a candidate with the same votes and the last tie victory.

Return type:

Candidate[AnyName]

update()

Update quotient and divisor.

Return type:

None

candidate: Candidate[AnyName]
divisor: Iterator[int | float | Fraction]
last_tie_victory: int
quotient: int | float | Fraction
class interregnum.methods.singlevote.highest_averages.HAResultData(log=<factory>, max_quota=-inf, min_quota=inf, remaining_seats=0)

Bases: EventLog

Additional result data for highest averages methods.

Parameters:
  • log (list[Event])

  • max_quota (int | float | Fraction)

  • min_quota (int | float | Fraction)

  • remaining_seats (int)

new_seat(criterion, winner)

Log new seat allocated to winner by criterion.

Parameters:
Return type:

None

max_quota: int | float | Fraction = -inf

Maximum allowed quota

min_quota: int | float | Fraction = inf

Minimum allowed quota

remaining_seats: int = 0

Seats not allocated yet

class interregnum.methods.singlevote.highest_averages.HAState(data=<factory>, *, random_seed)

Bases: NonDeterministicState

Calculation state for Highest Average Allocator.

Parameters:
  • data (HAResultData)

  • random_seed (dataclasses.InitVar[Union[int, random.Random, NoneType]])

break_tie(candidates)

Resolve a tie affecting candidates.

Three strategies are applied in the following order ([Loreg:1985]):

  • tie_break_most_voted Choose the candidate with most votes.

  • tie_break_older_random_winner Choose the candidate the older non deterministic tie-winning candidate.

  • tie_break_random Choose a candidate randomly.

Parameters:

candidates (Sequence[CandidateState[AnyName]]) – tied candidates

Returns:

Winners grouped by criterion.

Return type:

dict[str, list[CandidateState[AnyName]]]

break_tie_ttl(candidates, limit=1)

Resolve a tie based on the less recent victory.

The candidates that won a random tie-breaking more time ago than the others will have priority.

If not possible, fall back to random tie-break.

Return winners grouped by criterion

Parameters:
  • candidates (Sequence[Candidate[AnyName]]) – tied candidates

  • limit (int) – number of winners

Returns:

winners grouped by criterion

Return type:

dict[str, list[Candidate[AnyName]]]

data: HAResultData
class interregnum.methods.singlevote.highest_averages.HighestAveragesAllocator(divisor_f, skip_initial_seats=False)

Bases: NonDeterministicAllocator[AnyName, HAResultData]

Highest averages allocator ([Gallagher:1992], [KohlerZeh:2012]).

Implementation based on divisor series which allocates one seat at a time.

Tie-breaking follows the rules defined by the Spanish law from 1985 ([Loreg:1985]).

allocators collection keys:

  • highest_averages

  • highest-averages

Create a highest averages allocator using a divisor function or a divisor sequence.

Parameters:

Examples

>>> # use the d'Hondt divisor
>>> dhondt = HighestAveragesAllocator("dhondt")
calc(candidates, seats, random_seed=None, filter_f=None, initial_seats=None, skip_initial_seats=None)

Allocate candidates to seats.

If a candidate has initial seats, the initial divisor will be adjusted considering those seats at a starting point ([Denmark:2011]).

Distributed seats will be logged by a QuotaWinnerEvent.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates with votes. Only candidates in this list will be considered.

  • seats (int) – seats that will be computed, in addition to the initial seats

  • random_seed (int | Random | None) – used to break ties

  • filter_f (CandidateFilter[AnyName, Event] | None) – restrict allocation to filtered candidates

  • initial_seats (Iterable[tuple[AnyName, int]] | None) – seats already allocated to candidates

  • skip_initial_seats (bool | None) – add initial seats to results. If None, the value from the constructor will be used

Return type:

Result[AnyName, HAResultData]

interregnum.methods.singlevote.iterative_divisor module

Iterative divisor allocator, based on [DorfleitnerKlein:1997].

References


class interregnum.methods.singlevote.iterative_divisor.Discrepancy(*values)

Bases: IntEnum

Mark for seats discrepancies.

DECREMENTABLE = -1

A candidate can lose one seat

EXACT = 0

A candidate can not lose or wine seats

INCREMENTABLE = 1

A candidate can win one more seat

class interregnum.methods.singlevote.iterative_divisor.IDResultData(log=<factory>, max_quota=-inf, min_quota=inf, remaining_seats=0, ties=<factory>)

Bases: HAResultData, Generic[AnyName]

Result data for Iterative Divisor Allocator.

Parameters:
  • log (list[Event])

  • max_quota (int | float | Fraction)

  • min_quota (int | float | Fraction)

  • remaining_seats (int)

  • ties (dict[AnyName, Discrepancy])

ties: dict[AnyName, Discrepancy]

Candidates with ties (incrementable or decrementable)

class interregnum.methods.singlevote.iterative_divisor.IterativeDivisorAllocator(signpost_f)

Bases: Allocator[AnyName, IDResultData[AnyName]]

Iterative divisor method.

See [DorfleitnerKlein:1997] and [Zachariasen:2006]

allocators collection keys:

  • iterative_divisor

  • iterative-divisor

Create an iterative divisor allocator.

Parameters:

signpost_f (str | RoundingWithSignpost) – round function with signpost (collection signposts).

calc(candidates, seats, exclude_candidates=None)

Allocate candidates to seats.

Initial candidate seats are ignored. All won seats will be logged by SeatsEvent.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates

  • seats (int) – allocatable seats

  • exclude_candidates (Iterable[AnyName] | None) – list of candidates excluded from allocation

Return type:

Result[AnyName, IDResultData[AnyName]]

Examples

>>> # use the Jefferson method
>>> jefferson = IterativeDivisorAllocator("jefferson")
interregnum.methods.singlevote.iterative_divisor.or_inf(val)

Return val if is finite, otherwise return Infinity.

Parameters:

val (int | Fraction | None)

Return type:

int | Fraction | float

interregnum.methods.singlevote.iterative_divisor.priority_dec(round_f, cand)

Priority for decrementation.

Parameters:
Return type:

tuple[int | Fraction | float, int | Fraction, AnyName]

interregnum.methods.singlevote.iterative_divisor.priority_inc(round_f, cand)

Priority for incrementation.

Parameters:
Return type:

tuple[int | Fraction | float, int | Fraction, AnyName]

interregnum.methods.singlevote.iterative_divisor.Priority

Anything representing a priority for a candidate

alias of tuple[int | Fraction | float, int | Fraction, AnyName]

interregnum.methods.singlevote.largest_remainder module

Largest remainder method.

References


class interregnum.methods.singlevote.largest_remainder.CandidateState(candidate, remainder=None)

Bases: Generic[AnyName]

Candidate internal state.

Parameters:
candidate: Candidate[AnyName]

A candidate

remainder: int | Fraction | None

Votes remainder after applying quota

class interregnum.methods.singlevote.largest_remainder.LRResultData(log=<factory>, quota=0, remaining_seats=0)

Bases: EventLog

Additional result data for largest remainder methods.

Parameters:
  • log (list[Event])

  • quota (int | Fraction)

  • remaining_seats (int)

first_quota: int | Fraction

Initial quota before adjustment

quota: int | Fraction = 0

Current quota

remaining_seats: int = 0

Seats not allocated

class interregnum.methods.singlevote.largest_remainder.LRState(data=<factory>, total_votes=0, eligible=<factory>, *, random_seed)

Bases: NonDeterministicState, Generic[AnyName]

A calculation state for Largest Remainder Allocator.

Parameters:
  • data (LRResultData)

  • total_votes (int | Fraction)

  • eligible (Sequence[Candidate[AnyName]])

  • random_seed (dataclasses.InitVar[Union[int, random.Random, NoneType]])

break_tie(candidates, limit)

Resolve a tie choosing limit candidates.

Strategies are applied in the following order:

  • tie_break_most_voted Choose the candidate with most votes.

  • tie_break_random Choose a candidate randomly.

Parameters:
Return type:

dict[str, list[CandidateState[AnyName]]]

remove_used_votes(quota_f, seats)

Remove votes used for initial seats.

Parameters:
  • quota_f (Callable[[int | Fraction, int | Fraction], Comparison])

  • seats (int)

Return type:

None

resolve_tie_most_voted(candidates)

Choose the most voted candidate.

Parameters:

candidates (Sequence[CandidateState[AnyName]])

Return type:

Sequence[CandidateState[AnyName]]

seats_by_quota(seats, fix_overflow, bisect_step)

Allocate seats by quota.

Parameters:
  • seats (int)

  • fix_overflow (bool)

  • bisect_step (int)

Return type:

list[CandidateState[AnyName]]

seats_by_remainders(remainders)

Allocate seats by largest remainders.

Parameters:

remainders (Sequence[CandidateState[AnyName]])

Return type:

Sequence[CandidateState[AnyName]]

data: LRResultData

Result data

eligible: Sequence[Candidate[AnyName]]

Eligible candidates

total_votes: int | Fraction = 0

Total number of votes

class interregnum.methods.singlevote.largest_remainder.LargestRemainderAllocator(quota_f, fix_overflow=True, bisect_step=1, skip_initial_seats=False)

Bases: NonDeterministicAllocator[AnyName, LRResultData]

Largest remainder method.

See [Gallagher:1992], [KohlerZeh:2012] and https://en.wikipedia.org/wiki/Largest_remainder_method

allocators collection keys:

  • largest_remainder

  • largest-remainder

Create a largest remainder method using quota_f as the quota function.

While the calculated quota allocates more than the avalaible seats and fix_overflow is True, the quota will be incremented by bisect_step. The remaining seats will be assigned to the candidates with the largest remainders.

Parameters:
  • quota_f (str | QuotaFunction) – quota function or key in quotas

  • fix_overflow (bool) – adjust the quota if more seats than the required amount were allocated

  • bisect_step (int) – step used at the quota adjustment process

  • skip_initial_seats (bool)

Examples

>>> # Hare quota
>>> hare = LargestRemainderAllocator("hare")
>>> # Reinforced Imperiali quota, adjusting quota
>>> # if the allocated seats are greater than required
>>> imp3 = LargestRemainderAllocator("imperiali3")
>>> # Reinforced Imperiali quota, do not adjust quota
>>> imp3 = LargestRemainderAllocator("imperiali3", fix_overflow=False)
calc(candidates, seats, random_seed=None, total_votes=None, exclude_candidates=None, initial_seats=None, skip_initial_seats=None)

Allocates candidates to seats.

If a candidate already has initial seats, the votes used for those seats are subtracted before the allocation.

Distributed seats will be logged by QuotaWinnerEvent (seats by quota) and SeatsEvent (seats by remainders).

If a quota is discarded because of overflow, a NewQuotaEvent will be logged.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates

  • seats (int) – seats that will be computed, in addition to the initial seats

  • random_seed (int | Random | None) – used to break ties

  • total_votes (int | Fraction | None) – votes for the quota calculation, in the case it is greater than the sum of the candidates’ votes

  • initial_seats (Iterable[tuple[AnyName, int]] | None) – seats already allocated to candidates

  • skip_initial_seats (bool | None) – add initial seats to results. If None, the value from the constructor will be used

  • exclude_candidates (Iterable[AnyName] | None)

Return type:

NonDeterministicResult[AnyName, LRResultData]

class interregnum.methods.singlevote.largest_remainder.NewQuotaEvent(quota, criterion, old_quota=None, data=None)

Bases: Event

A computed quota has changed.

Parameters:
  • quota (int | Fraction)

  • criterion (str)

  • old_quota (int | Fraction | None)

  • data (Any | None)

EVENT: ClassVar[str] = 'new quota'

Event type

criterion: str

criterion for choosing the quota

data: Any | None = None

additional data

old_quota: int | Fraction | None = None

previous quota

quota: int | Fraction

current quota

interregnum.methods.singlevote.largest_remainder.apply_quota(seats, data, quota)

Apply quota to candidates.

Parameters:
  • data (Iterable[Candidate[AnyName]]) – candidates

  • quota (int | Fraction) – vote-seats quota

  • seats (int)

Returns:

(remaining seats, remainders, log)

Return type:

tuple[int, list[CandidateState[AnyName]], list[Event]]

interregnum.methods.singlevote.limited_voting module

Limited voting / Partial block voting.

References


class interregnum.methods.singlevote.limited_voting.LimitedVotingAllocator

Bases: MultiWinnerAdapter[AnyName, MultiWinnerResultData, Sequence[Candidate[AnyName]], Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]]

Limited voting / Partial block voting.

Given that there are N available seats, the N most voted candidates win a seat each one.

Used in the election to the Spanish Senate.

See [Loreg:1985] and https://en.wikipedia.org/wiki/Limited_voting

allocators collection keys:

  • limited_voting

  • partial_block_voting

Create a limited voting allocator.

Examples

>>> limited_voting = LimitedVotingAllocator()
calc(candidates, seats, random_seed=None, filter_f=None, **ranking_args)

Allocate candidates to seats.

Initial seats will be ignored.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates

  • seats (int) – number of expected winners

  • random_seed (int | Random | None) – used to break ties

  • filter_f (CandidateFilter[AnyName, Event] | None) – restrict to filtered candidates

  • ranking_args (Any)

Return type:

NonDeterministicResult[AnyName, MultiWinnerResultData]

class interregnum.methods.singlevote.limited_voting.MostVotedRanking(scores)

Bases: RankingList[AnyName]

Ranking based on votes.

Create a ranking list from a list of candidates.

Parameters:

scores (Iterable[Candidate[AnyName]])

interregnum.methods.singlevote.winner_takes_all module

First past the post.

class interregnum.methods.singlevote.winner_takes_all.WinnerTakesAllAllocator

Bases: WinnerTakesAllAdapter[AnyName, MultiWinnerResultData, Sequence[Candidate[AnyName]], Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]]

Winner-Takes-All / First past the post.

Each seat will be assigned to the most voted candidate in different rounds.

The winner will take all the seats.

allocators collection keys:

  • winner_takes_all

  • first_past_the_post

Create a First Past The Post allocator.

Examples

>>> wta = WinnerTakesAllAllocator()
calc(candidates, seats=1, random_seed=None, **kwargs)

Allocate candidates to seats.

Parameters:
  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates

  • seats (int) – seats to allocate

  • random_seed (int | Random | None) – used to break ties

  • kwargs (Any)

Return type:

NonDeterministicResult[AnyName, MultiWinnerResultData]