interregnum.methods package

Methods allocate seats from votes.

  • Inputs: each allocator defines which types of input admits. See types.Input and inputs for a detailed list of inputs.

  • Output: an allocator returns a types.Result, which contains the seats allocation and other additional information.

  • Events provide information about what the allocator internally did (events).

  • Filters (types.CandidateFilter, filters) are useful to add constraints to the allocation process (for example, when some contenders can’t win more than a limited number of seats).

Allocators are grouped by their main input’s type:

Creating new methods

New methods should inherit the classes types.Allocator or types.NonDeterministicAllocator. Then, that method can be added to the allocators collection.


class interregnum.methods.BiproportionalAllocator(round_f, nice_quota=True, sort_parties=False)

Bases: Allocator[AnyName, BAPResultData[PartyName, DistrictName]]

Bi-proportional allocator.

Allocates seats based on two proportional allocations: one for parties and one for districts.

See [Zachariasen:2006], [Pukelsheim:2013], [Oelbermann:2016]

allocators collection keys:

  • biproportional

  • alternate_scaling

  • alternate_scaling_tie_transfer

Create a bi-proportional allocator.

round_f

round function with associated signpost sequence

nice_quota

when True, pick a human readable quota from the valid range

sort_parties

Sort parties for the sake of reproducibility.

Parameters:
calc(party_seats, district_seats, candidates, exclude_candidates=None, party_name_f=None, district_name_f=None, candidate_name_f=None)

Allocate seats to candidates.

Parameters:
  • party_seats (Iterable[tuple[PartyName, int]]) – seats allocated to parties globally

  • district_seats (Iterable[tuple[DistrictName, int]]) – seats allocated to districts

  • candidates (Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]) – list of candidates votes with names composed of party and district

  • exclude_candidates (Iterable[AnyName] | None) – exclude candidates in this list from winning seats

  • party_name_f (Callable[[AnyName], PartyName] | None) – function to extract party names

  • district_name_f (Callable[[AnyName], DistrictName] | None) – function to extract district names

  • candidate_name_f (Callable[[tuple[PartyName, DistrictName]], AnyName] | None) – function to create a candidate name from party and district

  • provided (When no name manipulation function is)

  • condidered (candidates are)

  • name (to be provided with names composed as tuples (party)

  • name). (district)

Return type:

Result[AnyName, BAPResultData[PartyName, DistrictName]]

nice_quota: bool = True
round_f: str | RoundingWithSignpost
sort_parties: bool = False
class interregnum.methods.NoopAllocator(skip_initial_seats=False)

Bases: Allocator[AnyName, EventLog]

Do nothing.

Generate result from the input.

allocators collection keys:

  • noop

  • no-op

  • nop

  • copy

Create a noop allocator.

Parameters:

skip_initial_seats (bool)

calc(candidates, initial_seats=None, exclude_candidates=None, seats=0, skip_initial_seats=None)

Return a result with the provided candidates.

Seats in initial_seats will be preserved.

Candidates in exclude_candidates will win no seats.

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

  • initial_seats (Iterable[tuple[AnyName, int]] | None)

  • exclude_candidates (Iterable[AnyName] | None)

  • seats (int)

  • skip_initial_seats (bool | None)

Return type:

Result[AnyName, EventLog]

Subpackages

Submodules

interregnum.methods.events module

Common allocation log events.

class interregnum.methods.events.Event

Bases: object

Log event data.

EVENT: ClassVar[str]

Event type

class interregnum.methods.events.EventLog(log=<factory>)

Bases: object

Data with event log info.

Parameters:

log (list[Event])

log: list[Event]

An event list

class interregnum.methods.events.IneligibleEvent(target, criterion, condition=None)

Bases: Event

Ineligible candidate event.

Parameters:
  • target (Any)

  • criterion (str)

  • condition (Any | None)

EVENT: ClassVar[str] = 'ineligible'

Event type

condition: Any | None = None

Condition related to the tie.

criterion: str

Criterion that caused the event.

target: Any

Ineligible candidate

class interregnum.methods.events.NewAllocationEvent(criterion, data=None)

Bases: Event

A new allocation is needed to fulfill requirements.

Parameters:
  • criterion (str)

  • data (Any | None)

EVENT: ClassVar[str] = 'new allocation'

Event type

criterion: str

Criterion for re-allocation

data: Any | None = None

Additional data

class interregnum.methods.events.QuotaWinnerEvent(target, criterion, quota)

Bases: WinnerEvent

Winner event for quota reached.

Parameters:
  • target (Any)

  • criterion (str)

  • quota (int | float | Fraction)

quota: int | float | Fraction

Quota reached by the winner

class interregnum.methods.events.SeatsEvent(target, seats, criterion)

Bases: Event

Seats allocated event.

Parameters:
  • target (Any)

  • seats (int)

  • criterion (str)

EVENT: ClassVar[str] = 'seats'

Event type

criterion: str

Allocation criterion

seats: int

Allocated seats

target: Any

Seats winner

class interregnum.methods.events.TieEvent(candidates, condition=None)

Bases: Event

Tie event.

Parameters:
  • candidates (Sequence[Any])

  • condition (Any | None)

EVENT: ClassVar[str] = 'tie'

Event type

candidates: Sequence[Any]

Candidates affected by the tie

condition: Any | None = None

Condition related to the tie

class interregnum.methods.events.TransferredVotesEvent(source, target, votes)

Bases: Event

Transferred votes event.

Parameters:
  • source (Any)

  • target (Any)

  • votes (int | Fraction)

EVENT: ClassVar[str] = 'transferred votes'

Event type

source: Any

Source candidate

target: Any

Target candidate

votes: int | Fraction

Transferred votes

class interregnum.methods.events.WinnerEvent(target, criterion)

Bases: Event

Winner event.

Parameters:
  • target (Any)

  • criterion (str)

EVENT: ClassVar[str] = 'winner'

Event type

criterion: str

Criterion that triggered the event

target: Any

Winner

interregnum.methods.filters module

Candidate filters used to exclude candidates by allocators that allocate one seat at a time.

class interregnum.methods.filters.ChainCandidateFilter(*filters)

Bases: CandidateFilter[AnyName, AnyEvent]

Compose a candidate filter using several chained filters.

Create a chain filter from a list of filters.

Parameters:

filters (CandidateFilter[AnyName, AnyEvent]) – list of filters

exclusion_list()

Return the list of excluded candidates at the current allocation stage.

Return type:

Collection[AnyName]

is_valid(name)

Check if a candidate can continue in the allocation.

Parameters:

name (AnyName)

Return type:

bool

start()

Start the filter.

Return type:

Sequence[AnyEvent]

update(cand)

Update candidate seats.

Parameters:

cand (Candidate[AnyName])

Return type:

Sequence[AnyEvent]

class interregnum.methods.filters.ContenderSetFilter(contenders)

Bases: CandidateFilter[AnyName, AnyEvent]

Simple candidate filter based on an exclusion list.

Create a contender set filter from a collection of contenders.

Everyone in the collection will be excluded from allocation.

Parameters:

contenders (Collection[AnyName]) – list of excluded contenders

exclusion_list()

Return the list of excluded candidates at the current allocation stage.

Return type:

Collection[AnyName]

is_valid(name)

Check if a candidate can continue in the allocation.

Parameters:

name (AnyName) – A candidate name

Returns:

Return True if the candidate identified by name is not excluded from the allocation.

Return type:

bool

start()

Start this filter.

Returns:

A sequence of events associated to this action.

Return type:

Sequence[Never]

update(cand)

Update candidate seats.

Returns:

A sequence of events associated to this action.

Parameters:

cand (Candidate[AnyName])

Return type:

Sequence[Never]

interregnum.methods.filters.exclude_candidates(allocator, params, exclusion)

Add standard arguments to params for excluding candidates in exclusion.

Parameters:
Returns:

updated inputs

Return type:

InputDict[AnyName, AnyEvent]

interregnum.methods.inputs module

Pre-defined arguments for calc methods in allocators.

class interregnum.methods.inputs.BipropInputDict

Bases: InputDict[AnyName, AnyEvent], Generic[AnyName, AnyEvent, DistrictName, PartyName]

Allowed bi-proportional allocator inputs.

candidate_list: Iterable[AnyName]
candidate_name_f: Callable[[tuple[PartyName, DistrictName]], AnyName]

Function to get a name from a party name and a district name.

>>> # name for a party at district is (party, district)
>>> inputs["candidate_name_f"] = lambda p, d: (p, d)
candidates: Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]
constraints: Sequence[tuple[int, Sequence[AnyName]]]
district_name_f: Callable[[AnyName], DistrictName]

Function to convert names to district names.

Examples

>>> # name for a party at district is (party, district)
>>> inputs["district_name_f"] = lambda x: x[1]
district_seats: Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]
exclude_candidates: Iterable[AnyName]
filter_f: CandidateFilter[AnyName, AnyEvent]
initial_seats: Iterable[tuple[AnyName, int]]
inner_initial_seats: Iterable[tuple[AnyName, int]]
max_ballots_size: int
max_seats: int
party_name_f: Callable[[AnyName], PartyName]

Function to convert names to party names.

Examples

>>> # name for a party at district is (party, district)
>>> inputs["party_name_f"] = lambda x: x[0]
party_seats: Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]
preferences: Iterable[Preference[AnyName] | PrefDict[AnyName] | tuple[int | Fraction, Sequence[AnyName | Tuple[AnyName, ...] | list[AnyName]] | tuple[AnyName | Tuple[AnyName, ...] | list[AnyName], ...]]]
random_seed: int | Random | None
seats: int
skip_initial_seats: bool
total_votes: int | Fraction
class interregnum.methods.inputs.DistrictName

District name type

alias of TypeVar(‘DistrictName’)

class interregnum.methods.inputs.InputDict

Bases: TypedDict, Generic[AnyName, AnyEvent]

Allowed allocator inputs.

candidate_list: Iterable[AnyName]

Whole list of candidates.

Examples

>>> inputs["candidate_list"] = ["A", "B"]
candidates: Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]

List of candidates with names and votes.

Examples

  1. two candidates (A: 200 votes; B: 150 votes)

    >>> inputs["candidates"] = [("A", 200), ("B", 150)]
    
  2. using the types.Candidate class

    >>> from interregnum.types import Candidate
    >>> inputs["candidates"] = [
    >>>    Candidate(name="A", votes=200),
    >>>    Candidate(name="B", votes=150),
    >>> ]
    
constraints: Sequence[tuple[int, Sequence[AnyName]]]

Seats constraints for groups of candidates.

Examples

>>> inputs["constraints"] = [
>>>     # Mom from MomCorp is an independent candidate, so she can only win 1 seat
>>>     (1, ["Mom"]),
>>>     # the members of the alliance "Futurama" can only win 2 seats
>>>     (2, ["Fry", "Leela", "Bender"]),
>>> ]
district_seats: Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]

Seats already allocated to districts.

Examples

>>> inputs["district_seats"] = [("D1", 20), ("D2", 15)]
exclude_candidates: Iterable[AnyName]

List of candidates excluded from winning seats.

Examples

>>> inputs["exclude_candidates"] = ["B", "C"]
filter_f: CandidateFilter[AnyName, AnyEvent]

Filter function to exclude candidates from winning seats.

Examples

>>> # using a filter based on an exclusion list
>>> from interregnum.methods.filters import ContenderSetFilter
>>> # exclude candidates B and C
>>> inputs["filter_f"] = ContenderSetFilter(["B", "C"])
initial_seats: Iterable[tuple[AnyName, int]]

List of seats candidates have before the allocation.

Examples

>>> # A: 1, B: 2
>>> inputs["initial_seats"] = [("A", 1), ("B", 2)]
inner_initial_seats: Iterable[tuple[AnyName, int]]

List of seats candidates have before the allocation (used by adapters).

Examples

>>> # A: 1, B: 2
>>> inputs["initial_seats"] = [("A", 1), ("B", 2)]
max_ballots_size: int

Maximum size a ranked vote ballot can have.

Examples

>>> # 10 candidates can be selected on each ballot
>>> inputs["max_ballots_size"] = 10
max_seats: int

Maximum number of seats that can be allocated.

Examples

>>> inputs["max_seats"] = 100
party_seats: Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]

Seats already allocated to parties.

Examples

>>> inputs["party_seats"] = [("P1", 10), ("P2", 8)]
preferences: Iterable[Preference[AnyName] | PrefDict[AnyName] | tuple[int | Fraction, Sequence[AnyName | Tuple[AnyName, ...] | list[AnyName]] | tuple[AnyName | Tuple[AnyName, ...] | list[AnyName], ...]]]

Preferential votes ballots.

Examples

  1. using tuples

    >>> inputs["preferences"] = [
    >>>     (200, ["A", "B", "C"]),
    >>>     (150, ["C", "B"])
    >>> ]
    
  2. using the preferential.Preference

    >>> from interregnum.preferential import Preference
    >>> inputs["preferences"] = Preference.make_input([
    >>>     (200, ["A", "B", "C"]),
    >>>     (150, ["C", "B"])
    >>> ])
    
random_seed: int | Random | None

A random generator seed.

Examples

  1. Integer seed

    >>> inputs["random_seed"] = 42
    
  2. Random generator

    >>> inputs["random_seed"] = random.Random(42)
    
seats: int

Seats to allocate.

Examples

>>> inputs["seats"] = 64
skip_initial_seats: bool

Do not include initial seats in the result.

total_votes: int | Fraction

Total number of tallied votes.

Examples

>>> inputs["total_votes"] = 12561
class interregnum.methods.inputs.PartyName

Party name type

alias of TypeVar(‘PartyName’)

interregnum.methods.inputs.ICandidates

Iterable of candidate-like structures (name, votes)

alias of Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]

interregnum.methods.inputs.IConstraints

Sequence of seats constraints (name1 + … + nameN <= max seats)

alias of Sequence[tuple[int, Sequence[AnyName]]]

interregnum.methods.inputs.IDistrictNameFunction

A function that transforms a name to a district name

alias of Callable[[AnyName], DistrictName]

interregnum.methods.inputs.INameFunction

A function that create a name from a party name and a district name

alias of Callable[[tuple[PartyName, DistrictName]], AnyName]

interregnum.methods.inputs.INamedSeats

Iterable of (name, seats)

alias of Iterable[tuple[AnyName, int]]

interregnum.methods.inputs.INames

Iterable of names

alias of Iterable[AnyName]

interregnum.methods.inputs.IPartyNameFunction

A function that transforms a name to a party name

alias of Callable[[AnyName], PartyName]

interregnum.methods.inputs.IPreferences

Iterable of preferences

alias of Iterable[Preference[AnyName] | PrefDict[AnyName] | tuple[int | Fraction, Sequence[AnyName | Tuple[AnyName, …] | list[AnyName]] | tuple[AnyName | Tuple[AnyName, …] | list[AnyName], …]]]

interregnum.methods.inputs.ISeats

Iterable of candidate-like structures (name, seats)

alias of Iterable[tuple[AnyName, int | Fraction] | tuple[AnyName, int | Fraction, int] | Candidate[AnyName]]

interregnum.methods.types module

Common structures for allocation methods.

class interregnum.methods.types.Allocator(required_input, optional_input)

Bases: Generic[AnyName, Data]

Base class for seats allocators.

An allocator creates an allocation result from the allowed inputs.

It provides __call__() as an alias to calc().

Allocator constructor.

Its calc() method requires required_input as arguments and admits optional_input.

Parameters:
  • required_input (Input) – Flags describing the types of inputs the method requires

  • optional_input (Input) – Flags describing the types of inputs the method optially admits

__call__(*args, **kwargs)

Invoke the calc() method.

Parameters:
  • args (Any)

  • kwargs (Any)

Return type:

Result[AnyName, Data]

get_model_params()

Return formal parameters.

Return type:

Iterator[tuple[str, Any]]

property admitted_input: Input

Return all the arguments that the method calc() admits.

calc: Callable[[...], Result[AnyName, Data]]

A method that returns an allocation result.

property optional_input: Input

Return optional arguments for the method calc().

property required_input: Input

Return required arguments for the method calc().

class interregnum.methods.types.AnotherName

Alternative type for names

alias of TypeVar(‘AnotherName’, bound=SortHash)

class interregnum.methods.types.AnyEvent

Alternative type for events

alias of TypeVar(‘AnyEvent’)

class interregnum.methods.types.AnyName

A type for names

alias of TypeVar(‘AnyName’, bound=SortHash)

class interregnum.methods.types.AnyResult

A result type

alias of TypeVar(‘AnyResult’, bound=Result[Any, Any])

class interregnum.methods.types.CalculationState

Bases: object

A calculation state for an allocator.

make_result(result, data)

Return a result structure with an allocation and additional info.

Parameters:
Return type:

Result[AnyName, Data]

class interregnum.methods.types.Candidate(name, votes, seats=0)

Bases: Generic[AnyName]

A candidate for allocations based on single votes.

Parameters:
  • name (AnyName)

  • votes (int | Fraction)

  • seats (int)

static make_input(candidates, initialized=False)

Make candidates from an iterable of iterables.

Parameters:
  • candidates (Iterable[tuple[AnotherName, int | Fraction] | tuple[AnotherName, int | Fraction, int] | Candidate[AnotherName]]) – Iterable of structures compatible with Candidate.

  • initialized (bool) – If False, a warning will be emitted if any candidate has seats

Return type:

Sequence[Candidate[AnotherName]]

add_seats(increment)

Return a candidate with seats plus increment.

Parameters:

increment (int) – seats increment relative to the current seats.

Return type:

Candidate[AnyName]

merge(other)

Return this candidate with the votes and seats summed to other.

Parameters:

other (Candidate[AnyName]) – second candidate

Return type:

Candidate[AnyName]

with_name(name)

Return the same candidate with a different name.

Parameters:

name (AnotherName) – new name

Return type:

Candidate[AnotherName]

with_seats(seats)

Return the same candidate with the provided seats.

Parameters:

seats (int) – new number of seats

Return type:

Candidate[AnyName]

with_votes(votes)

Return the same candidate with a different number of votes.

Parameters:

votes (int | Fraction) – new number of votes

Return type:

Candidate[AnyName]

name: AnyName

Candidate identifier

seats: int

Candidate allocated seats

votes: int | Fraction

Candidate received votes

class interregnum.methods.types.CandidateFilter

Bases: Generic[AnyName, AnyEvent]

Candidate filter for restrictions in methods that allocate one seat at a time.

exclusion_list()

Return the list of excluded candidates at the current allocation stage.

Return type:

Collection[AnyName]

is_valid(name)

Check if a candidate can continue in the allocation.

Parameters:

name (AnyName) – A candidate name

Returns:

Return True if the candidate identified by name is not excluded from the allocation.

Return type:

bool

start()

Start this filter.

Returns:

A sequence of events associated to this action.

Return type:

Sequence[AnyEvent]

update(cand)

Update candidate seats.

Returns:

A sequence of events associated to this action.

Parameters:

cand (Candidate[AnyName])

Return type:

Sequence[AnyEvent]

class interregnum.methods.types.Data

A type for data

alias of TypeVar(‘Data’)

class interregnum.methods.types.Input(*values)

Bases: Flag

Standard input arguments for methods.

__invert__()
CANDIDATES = 4
CANDIDATE_LIST = 8
CANDIDATE_NAME_F = 131072
CONSTRAINTS = 16384
DISTRICT_NAME_F = 65536
DISTRICT_SEATS = 64
EXCLUDE_CANDIDATES = 4096
FILTER_F = 1024
INITIAL_SEATS = 128
INNER_INITIAL_SEATS = 256
MAX_BALLOTS_SIZE = 262144
MAX_SEATS = 8192
NONE = 0
PARTY_NAME_F = 32768
PARTY_SEATS = 32
PREFERENCES = 16
RANDOM_SEED = 1
SEATS = 2
SKIP_INITIAL_SEATS = 512
TOTAL_VOTES = 2048
property param_name: str

Get the associated param name.

class interregnum.methods.types.NonDeterministicAllocator(required_input, optional_input)

Bases: Allocator[AnyName, Data]

Non deterministic method.

Allocator constructor.

Its calc() method requires required_input as arguments and admits optional_input.

Parameters:
  • required_input (Input) – Flags describing the types of inputs the method requires

  • optional_input (Input) – Flags describing the types of inputs the method optially admits

rng: Dice

A random generator

class interregnum.methods.types.NonDeterministicResult(allocation, data=None, deterministic=True, random_state=None)

Bases: Result[AnyName, Data]

Result data for non deterministic allocators.

Parameters:
  • allocation (Sequence[Candidate[AnyName]])

  • data (Data | None)

  • deterministic (bool)

  • random_state (Any | None)

deterministic: bool = True

True if the allocation result was deterministic

random_state: Any | None = None

Initial random state used by the random generator

class interregnum.methods.types.NonDeterministicState(*, random_seed)

Bases: CalculationState

A calculation state for a non-deterministic allocator.

Parameters:

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

make_result(result, data)

Return a result stricture with an allocation and additional info.

Information related to non-deterministic methods are included in the result.

Parameters:
Return type:

NonDeterministicResult[AnyName, Data]

random_tie_break(candidates, limit)

Choose candidates randomly.

Parameters:
  • candidates (Iterable[_Tied]) – list ofcandidates

  • limit (int) – number of candidates to be chosen

Returns:

Winners grouped by criterion

Return type:

dict[str, list[_Tied]]

random_seed: dataclasses.InitVar[Union[int, random.Random, NoneType]]
rng: Dice
class interregnum.methods.types.Result(allocation, data=None)

Bases: Generic[AnyName, Data]

Result information returned by an allocation method.

Parameters:
allocation: Sequence[Candidate[AnyName]]

Allocation result

data: Data | None = None

Additional data

class interregnum.methods.types.Summary(names, votes, seats)

Bases: Generic[AnyName]

A summary for an allocation list.

Parameters:
  • names (set[AnyName])

  • votes (int | Fraction)

  • seats (int)

static build(candidates=None)

Build a summary for candidates.

Parameters:

candidates (Iterable[tuple[AnotherName, int | Fraction] | tuple[AnotherName, int | Fraction, int] | Candidate[AnotherName]] | None) – list of candidates

Return type:

Summary[AnotherName]

names: set[AnyName]

Set of contenders’ ids

seats: int

Total number of seats

votes: int | Fraction

Total number of votes

interregnum.methods.types.check_inputs(required, flags)

Raise a PreconditionError if flags does not contain required.

Parameters:
Return type:

None

interregnum.methods.types.check_seats(seats, threshold=1)

Raise a PreconditionError if there is an invalid seats value.

A seats value is considered invalid if \(seats \le 0\).

Parameters:
  • seats (int)

  • threshold (int)

Return type:

None

interregnum.methods.types.choose_randomly(rng, candidates, limit)

Choose limit candidates randomly using the rng dice.

Parameters:
  • rng (Dice) – a random generator

  • candidates (Iterable[_Tied]) – list of candidates

  • limit (int) – number of candidates to be chosen

Returns:

winners grouped by criterion

Return type:

dict[str, list[_Tied]]

interregnum.methods.types.CandLike

A Candidate or something convertible to a candidate.

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

interregnum.methods.types.CandTuple = tuple[~AnyName, int | fractions.Fraction] | tuple[~AnyName, int | fractions.Fraction, int]

A tuple with candidate information (name, votes, and ocassionally, initial seats)

interregnum.methods.types.allocators: FunctionCollection[Callable[[...], Allocator[Any, Any]]] = <interregnum.collections.FunctionCollection object>

Allocators collection