interregnum.district package

Multi-district electoral systems.

class interregnum.district.Compensatory(type='compensatory', name=None, key=None, candidates=None, alliances=None, preferences=None, seats=None, mode=CompensatoryType.ADDITIONAL_MEMBER, max_seats=None, first_vote=None, subtract_excluded_candidates=False, propagate_initial_seats=False, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: BallotsNode

A node for compensatory systems.

Parameters:
__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

get_seats()

Return seats to allocate.

Return type:

int | ReferenceSet[GroupableReference]

grouping()

Return a grouping criterion for this node.

Return type:

Literal[GroupBy.CANDIDATE]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node | Reference] | None

first_vote: Node | ReferenceSet[GroupableReference] | None = None

child node or reference where the first vote is extracted from

max_seats: int | None = None

max number of seats the allocation can use (for growing allocations)

mode: CompensatoryType = 1

allocation mode

propagate_initial_seats: bool = False

propagate candidates’ initial seats to the inner method

seats: int | ReferenceSet[GroupableReference] | None = None

levelling seats

subtract_excluded_candidates: bool = False

exclude seats for excluded candidates due to restrictions

type: Literal['compensatory'] = 'compensatory'
class interregnum.district.District(type='district', name=None, key=None, candidates=None, alliances=None, preferences=None, seats=None, party_seats=None, district_seats=None, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: BallotsNode

An electoral district or constituency.

This node supports methods, candidates and preferences.

Parameters:
__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

get_seats()

Return seats to allocate.

Return type:

int | ReferenceSet[GroupableReference]

grouping()

Return a grouping criterion for this node.

Return type:

Literal[GroupBy.CANDIDATE]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node | Reference] | None

district_seats: Node | ReferenceSet[GroupableReference] | None = None

seats allocated by district (used by bi-proportional methods), extracted from a node result

party_seats: Node | ReferenceSet[GroupableReference] | None = None

seats allocated by party (used by bi-proportional methods), extracted from a node result

seats: int | ReferenceSet[GroupableReference] | None = None

number of seats to allocate (default = 1)

type: Literal['district'] = 'district'
class interregnum.district.Group(type='group', name=None, key=None, aggregate=False, groupby=None, divisions=<factory>, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: Node

A group of electoral districts.

Parameters:
  • type (Literal['group'])

  • name (str | None)

  • key (str | None)

  • aggregate (bool)

  • groupby (GroupBy | None)

  • divisions (Sequence[Node])

  • total_votes (TotalVotes | None)

  • resume_allocation (bool | None)

  • skip_initial_seats (bool | None)

  • exclude (RestrictionList | None)

  • include (RestrictionList | None)

  • initial_seats (int | InitialSeatsSource)

  • method (str | Callable[[...], Allocator[ContenderId, Any]] | None)

  • method_params (dict[str, Any] | None)

  • random_seed (int | None)

  • groups (Sequence[str] | None)

  • result (Result[ContenderId, Any] | None)

  • max_adjustment_seats (int | None)

  • ignore (Sequence[str] | None)

  • map_districts (Mapping[str | None, str | None] | None)

  • meta (dict[str, Any] | None)

__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

get_seats()

Return 0 (no seats are associated to groups).

Return type:

Literal[0]

grouping()

Return a grouping criterion for this node (default: GroupBy.CANDIDATE).

Return type:

GroupBy

local_alliances()

Return node alliances or None.

Return type:

Literal[None]

local_candidates()

Return node local candidates or None.

Return type:

Literal[None]

local_candidates_references()

Return references to local candidates defined elsewhere.

If no references but local candidates exist, return True

Return type:

Literal[False]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node]

local_preferences(candidates)

Return node local preferential votes or None.

Parameters:

candidates (Iterable[ContenderId])

Return type:

Literal[None]

local_preferences_references()

Return references to local preferences defined elsewhere.

If no references but local preferences exist, return True

Return type:

Literal[False]

update_candidates(candidates)

Set these candidates as local candidates.

Parameters:

candidates (Sequence[Contender])

Return type:

None

aggregate: bool = False

if True, aggregate children results as this node result

divisions: Sequence[Node]

list of children nodes

groupby: GroupBy | None = None

candidate id transformation applied to this node results

type: Literal['group'] = 'group'
class interregnum.district.Node(type, name=None, key=None, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: NodeContext

An electoral node.

A node represents an allocation unit in an electoral system.

Parameters:
  • type (str)

  • name (str | None)

  • key (str | None)

  • total_votes (TotalVotes | None)

  • resume_allocation (bool | None)

  • skip_initial_seats (bool | None)

  • exclude (RestrictionList | None)

  • include (RestrictionList | None)

  • initial_seats (int | InitialSeatsSource)

  • method (str | Callable[[...], Allocator[ContenderId, Any]] | None)

  • method_params (dict[str, Any] | None)

  • random_seed (int | None)

  • groups (Sequence[str] | None)

  • result (Result[ContenderId, Any] | None)

  • max_adjustment_seats (int | None)

  • ignore (Sequence[str] | None)

  • map_districts (Mapping[str | None, str | None] | None)

  • meta (dict[str, Any] | None)

__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

build()

Build an allocation context.

Return type:

AllocationContext

calculate()

Build an allocation context from this node and calculate.

Return type:

None

clear_data()

Clear results, ballots and meta.

Return type:

None

find_district(district_id)

Find a district by identifier and return a reference to it.

District(id) or None

Parameters:

district_id (str)

Return type:

Node | None

find_level(level)

Iterate nodes at a given level from this node.

Positive levels will look levels from this node. Negative levels will look levels from a leaf node.

Parameters:

level (int)

Return type:

Iterator[Node]

get_id()

Return a unique identifier for this node.

If a key is present, use it. Otherwise, use name or return a generated id.

Return type:

str

get_seats()

Return seats to allocate.

Return type:

int | ReferenceSet[GroupableReference]

grouping()

Return a grouping criterion for this node.

Return type:

GroupBy

ignore_compute_dependency()

Ignore these nodes when computing result.

Return type:

Sequence[str] | None

iter_leaves()

Iterate leaf nodes.

Return type:

Iterator[Node]

local_alliances()

Return node alliances or None.

Return type:

Sequence[Alliance] | ReferenceSet[GroupableReference] | None

local_candidates()

Return node local candidates or None.

Return type:

Ballots | ReferenceSet[GroupableReference] | None

local_candidates_references()

Return references to local candidates defined elsewhere.

If no references but local candidates exist, return True

Return type:

ReferenceSet[GroupableReference] | bool

local_children()

Return local divisions that are not references.

Return type:

Iterator[Node]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node | Reference] | None

local_preferences(candidates)

Return node local preferential votes or None.

Parameters:

candidates (Iterable[ContenderId])

Return type:

Iterator[Preference[ContenderId]] | ReferenceSet[GroupableReference] | None

local_preferences_references()

Return references to local preferences defined elsewhere.

If no references but local preferences exist, return True

Return type:

ReferenceSet[GroupableReference] | bool

transform_contender(contender)

Transform contender using the district mapping.

Parameters:

contender (Contender)

Return type:

Contender

transform_contender_id(contender_id)

Transform contender_id using the district mapping.

Parameters:

contender_id (ContenderId)

Return type:

ContenderId

update_candidates(candidates)

Set these candidates as local candidates.

Parameters:

candidates (Sequence[Contender])

Return type:

None

groups: Sequence[str] | None = None

tags useful for finding node groups

ignore: Sequence[str] | None = None

ignore these node when computing dependencies on results

key: str | None = None

human readable node name (must be unique)

map_districts: Mapping[str | None, str | None] | None = None

map for changing district names when collecting candidates

max_adjustment_seats: int | None = None

maximum number of additional seats this node can win in systems with adjustment seats (such as levelling seats or mixed-member systems)

meta: dict[str, Any] | None = None

additional data

name: str | None = None

type of node

result: Result[ContenderId, Any] | None = None

allocation result

type: str
class interregnum.district.Reapportionment(type='reapportionment', name=None, key=None, candidates=None, alliances=None, preferences=None, strategy=<GroupBy.DISTRICT: 4>, relative=None, adjustment=None, first_vote=None, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: BallotsNode

Re-apportionment system.

Use to project adjustment seats allocated by compensatory systems to final districts which already have initial seats, using the votes provided by the field candidates.

Negative levelling seats are supported.

See [Denmark:2011], [Iceland:2013], [Norway:2023], [Germany:2025].

Parameters:
__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

get_seats()

Return seats to allocate.

Return type:

Literal[0]

grouping()

Return a grouping criterion for this node.

Return type:

Literal[GroupBy.CANDIDATE]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node | Reference] | None

update_candidates(candidates)

Set these candidates as local candidates.

Parameters:

candidates (Sequence[Contender])

Return type:

None

adjustment: Node | ReferenceSet[GroupableReference] | None = None

adjustment seats that will be projected to the new districts

first_vote: Node | ReferenceSet[GroupableReference] | None = None

districts where the seats will be projected

relative: RelativeDivisor | None = None

reference numbers (score used as votes for the allocation):

  • None: use absolute votes for party and district

  • RelativeDivisor: make a relative score using this divisor

strategy: Literal['parallel'] | GroupBy = 4

how to split allocations:

  • parallel ([Iceland:2013]) will allocate each compensatory seat in

    the order it was won (requires a method that produces WinnerEvent for each seat)

  • GroupBy: split the allocations by the given criterion (for example,

    party names or districts)

type: Literal['reapportionment'] = 'reapportionment'
interregnum.district.to_serializable(data, decimals)

Serialize objects.

Parameters:
  • decimals (int | None) – rounding precision

  • data (Any)

Return type:

Any

interregnum.district.unserialize_node(data: Mapping[str, Any] | str, cwd: Path | None, groupby: Literal[False] = False) Node | ReferenceSet[Reference]
interregnum.district.unserialize_node(data: Mapping[str, Any] | str, cwd: Path | None, groupby: Literal[True]) Node | ReferenceSet[GroupableReference]

Convert a mapping to a node.

The field fill_candidates will be interpreted as a CandidatesFile and rows will be injected to nodes.

Parameters:
  • data (Mapping[str, Any] | str) – source data: if data is a string instead of a mapping, a reference will be returned

  • cwd (Path | None) – working directory. Used by file readers.

  • groupby (bool) – use GroupableReference instead of Reference

Return type:

Node | ReferenceSet[Reference] | ReferenceSet[GroupableReference]

Submodules

interregnum.district.compensatory module

Compensatory systems.

class interregnum.district.compensatory.Compensatory(type='compensatory', name=None, key=None, candidates=None, alliances=None, preferences=None, seats=None, mode=CompensatoryType.ADDITIONAL_MEMBER, max_seats=None, first_vote=None, subtract_excluded_candidates=False, propagate_initial_seats=False, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: BallotsNode

A node for compensatory systems.

Parameters:
__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

get_seats()

Return seats to allocate.

Return type:

int | ReferenceSet[GroupableReference]

grouping()

Return a grouping criterion for this node.

Return type:

Literal[GroupBy.CANDIDATE]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node | Reference] | None

first_vote: Node | ReferenceSet[GroupableReference] | None = None

child node or reference where the first vote is extracted from

max_seats: int | None = None

max number of seats the allocation can use (for growing allocations)

mode: CompensatoryType = 1

allocation mode

propagate_initial_seats: bool = False

propagate candidates’ initial seats to the inner method

seats: int | ReferenceSet[GroupableReference] | None = None

levelling seats

subtract_excluded_candidates: bool = False

exclude seats for excluded candidates due to restrictions

type: Literal['compensatory'] = 'compensatory'
class interregnum.district.compensatory.CompensatoryType(*values)

Bases: Enum

Types of compensatory systems.

classmethod parse(value)

Parse from string format.

Parameters:

value (str | CompensatoryType | None)

Return type:

CompensatoryType | None

__str__()

Return the attribute as a string key.

Return type:

str

to_mode()

Return an associated mode for the allocator.

Return type:

OverhangMode

ABSORB_OVERHANG = 3

Allocate and subtract the seats won by first vote. The allocated seats are incremented until no overhang seats exist

ADDITIONAL_MEMBER = 1

Resume allocation from the seats won by first vote

EXCLUDE_OVERHANG_PARTIES = 4

Subtract the overhang seats and exclude those parties from the compensatory allocation.

MIXED_MEMBER = 2

Allocate and subtract the seats won by first vote. Any party with overhang seats will will get no new seat.

SUBTRACT_OVERHANG_SEATS = 5

Allocate and subtract the already won seats. Any party with overhang seats will win negative seats in order to compensate the overhang seats

interregnum.district.compensatory.unserialize_compensatory_dict(data, cwd)

Unserialize Compensatory fields.

Parameters:
  • data (Mapping[str, Any])

  • cwd (Path | None)

Return type:

dict[str, Any]

interregnum.district.contenders module

Structures and functions to store and manipulate election contenders.

class interregnum.district.contenders.Alliance(name, district=None, max_seats=None, groups=<factory>, meta=None)

Bases: object

Alliance information.

Parameters:
  • name (str)

  • district (str | None)

  • max_seats (int | None)

  • groups (tuple[str, ...])

  • meta (dict[str, Any] | None)

static make(data)

Construct a list of alliances from items.

Parameters:

data (Iterable[Alliance | Mapping[str, Any]])

Return type:

list[Alliance]

static merge_collection(batches, by=None)

Merge a collection of collections of alliances using a name transformation.

Parameters:
Return type:

list[Alliance]

get_id()

Return the alliance ContenderId.

Return type:

ContenderId

merge(other)

Merge this alliance with another.

Parameters:

other (Alliance)

Return type:

Alliance

with_id(cid)

Return this alliance with a different ContenderId.

Parameters:

cid (ContenderId)

Return type:

Alliance

district: str | None

alliance district scope

groups: tuple[str, ...]

tags

max_seats: int | None

maximum number of seats the members of this allliance can win in district.

meta: dict[str, Any] | None

additional information

name: str

alliance id

class interregnum.district.contenders.Contender(name, alliance=None, district=None, votes=None, seats=None, min_seats=0, max_seats=None, groups=<factory>, meta=None)

Bases: object

Information for a node contender.

Parameters:
  • name (str)

  • alliance (str | None)

  • district (str | None)

  • votes (int | Fraction | None)

  • seats (int | None)

  • min_seats (int | None)

  • max_seats (int | None)

  • groups (tuple[str, ...])

  • meta (dict[str, Any] | None)

classmethod from_candidate(candidate, *groups)

Convert a Candidate object to a Contender.

Parameters:
Return type:

Contender

static from_dict(items)

Create a contender from a mapping.

Parameters:

items (Mapping[str, str | None])

Return type:

Contender

static make(data)

Make contender objects from a sequence of items.

Parameters:

data (Iterable[Contender | Mapping[str, Any]])

Return type:

list[Contender]

static merge_collection(batches, by=<GroupBy.CANDIDATE: 7>)

Merge contenders grouped on batches using a name transformation.

Parameters:
Return type:

list[Contender]

add_groups(*groups)

Return a new contender with these groups.

Parameters:

groups (str)

Return type:

Contender

candidate(initial_seats)

Return a Candidate object associated to this contender with initial_seats.

Parameters:

initial_seats (int | None)

Return type:

Candidate[ContenderId]

get_alliance()

Return the alliance id.

If no alliance is defined, return the contender’s name.

Return type:

str

get_id()

Return the contender id (name, alliance, district).

Return type:

ContenderId

is_blank()

Return if this contender is storing blank votes.

Names for blank votes are prefixed with ?

Return type:

bool

is_special()

Return True if this is a special contender (blank or void votes).

Return type:

bool

is_void()

Return if this contender is storing void/null votes.

Names for void votes are prefixed with !

Return type:

bool

merge(other)

Merge this contender with another contender and return it as a new contender.

Parameters:

other (Contender)

Return type:

Contender

schema()

Return a contender without votes and seats.

Return type:

Contender

with_id(cid)

Return a new contender replacing the contender id.

Parameters:

cid (ContenderId)

Return type:

Contender

alliance: str | None

contender’s alliance id

district: str | None

contender’s electoral district

groups: tuple[str, ...]

tags for diverse uses

max_seats: int | None

maximum number of seats the contender can win

meta: dict[str, Any] | None

a dictionary of additional information

min_seats: int | None

minimum number of seats the contender can win

name: str

contender’s name

seats: int | None

seats the contender won (used mainly for testing)

votes: int | Fraction | None

contender’s votes

class interregnum.district.contenders.ContenderId(name, alliance, district=None)

Bases: object

Identifier for contenders.

Parameters:
  • name (str)

  • alliance (str)

  • district (str | None)

__contains__(other)

Return True if this is equal or a more general definition of other’s.

Examples

>>> ContenderId("A", "PARTY", "DISTRICT") in ContenderId("A", "PARTY")
True
Parameters:

other (Any)

Return type:

bool

matches(other, criterion)

Return True if other matches this using a given transformation criterion.

Examples

>>> ContenderId("A", "PARTY").matches(
>>>     ContenderId("B", "PARTY"),
>>>     GroupBy.ALLIANCE
>>> )
True
Parameters:
Return type:

bool

transform(required)

Transform this by removing parts not specified in the required elements.

Examples

>>> ContenderId(
>>>     "A", "PARTY", "DISTRICT"
>>> ).transform(GroupBy.ALLIANCE_ID)
ContenderId(name="PARTY", alliance="DISTRICT", district=None)
Parameters:

required (GroupBy)

Return type:

ContenderId

with_district(district, force=False)

Return this with the specified district.

If there is already a district, it will not be replaced unless force is True

Parameters:
  • district (str | None) – new district name

  • force (bool) – replace district always (even when the field is not empty)

Return type:

ContenderId

alliance: str

collective name for all the contender’s allies

district: str | None

district where the contender’s candidature is registered or associated to

name: str

contender’s name

class interregnum.district.contenders.GroupBy(*values)

Bases: Flag

Grouping criterion for contenders transformation.

classmethod parse(text, sep='+')

Parse GroupBy from string format.

Examples

alliance -> ALLIANCE

name+district -> NAME | DISTRICT

Parameters:
  • text (str | None)

  • sep (str)

Return type:

GroupBy | None

__invert__()
__str__()

Return string attribute representation.

Return type:

str

ALLIANCE = 2

keep the field alliance

ALLIANCE_ID = 6

keep the fields alliance and district

CANDIDATE = 7

keep all the fields

DISTRICT = 4

get the field district

ID = 3

keep the fields name and alliance

NAME = 1

keep the field name

interregnum.district.contenders.group_candidates(groupby, groups)

Merge candidates from district mapping using a name transformation.

If there is only one group, district is omitted.

Parameters:
Return type:

Generator[Candidate[ContenderId], None, None]

interregnum.district.contenders.group_preferences(groups)

Transform preferences using groupby and district.

Parameters:

groups (Sequence[tuple[GroupBy, str, Iterable[Preference[ContenderId]]]]) – (GroupBy, district, preferences)

Return type:

Generator[Preference[ContenderId], None, None]

interregnum.district.contenders.merge_candidates(contenders, groupby=None)

Merge candidates using a name transformation.

Parameters:
Return type:

Generator[Candidate[ContenderId], None, None]

interregnum.district.contenders.transform_preferences(preferences, by=<GroupBy.CANDIDATE: 7>, district=None)

Transform preferences by name and district.

Parameters:
Return type:

Generator[Preference[ContenderId], None, None]

interregnum.district.counting module

Utilities related to counting votes.

class interregnum.district.counting.Ballots(blank=0, void=0, ballots=None)

Bases: object

A collection of ballots useful for counting total votes.

Parameters:
  • blank (int | Fraction)

  • void (int | Fraction)

  • ballots (Sequence[Contender] | None)

static build(candidates)

Build a collection from a list of contenders.

Parameters:

candidates (Iterable[Contender] | None)

Return type:

Ballots

contenders_seats()

Return seats won by contenders.

Return type:

int

contenders_votes()

Return the sum of votes given to contenders.

Return type:

int | Fraction

votes()

Return a Votes object.

Return type:

Votes

ballots: Sequence[Contender] | None
blank: int | Fraction
void: int | Fraction
class interregnum.district.counting.Counting(candidates=None, preferences=None, alliances=None)

Bases: object

Collection candidates votes, preferences and alliances from a node.

Parameters:
get_bundle()

Return preferences if not empty, or candidates.

Return type:

Ballots | Sequence[Preference[ContenderId]] | None

seat_rules()

Compute seat restrictions for candidates and alliances.

Each item (Max seats, [candidate 1, ..., candidate N]) as a rule like seats(candidate1) + ... + seats(candidateN) <= Max seats

Return type:

list[tuple[int, Sequence[ContenderId]]]

total_votes()

Contender ballots, blank ballots, spoilt ballots.

Return type:

Votes

alliances: Sequence[Alliance] | None

alliances definition

candidates: Ballots | None

candidates votes

preferences: Sequence[Preference[ContenderId]] | None

preferential ballots

class interregnum.district.counting.InitialSeatsSource(*values)

Bases: Enum

Origin for initial seats.

classmethod parse(value)

Parse an InitialSeatsSource value from text.

Parameters:

value (str | InitialSeatsSource)

Return type:

InitialSeatsSource

__str__()

Return value as text.

Return type:

str

MIN_SEATS = 1

Get initial seats from the contender’s min_seats field.

Alternative names:

  • MIN_SEAT

  • FROM_MIN_SEATS

  • FROM_MIN_SEAT

RESULT = 2

Get initial seats from a node result.

Alternative names:

  • RESULTS

  • FROM_RESULT

  • FROM_RESULTS

class interregnum.district.counting.TotalVotes(*values)

Bases: Enum

How to compute total votes.

classmethod parse(value)

Parse a TotalVotes value from text.

Parameters:

value (str)

Return type:

TotalVotes

__str__()

Return this value as string.

Return type:

str

ALL = 3

total_votes is the sum of every vote, valid or not

CANDIDATES = 1

total votes is the sum of the votes given to any candidate

VALID_VOTES = 2

total_votes is the sum of the votes considered as valid

class interregnum.district.counting.Votes(candidates=0, blank=0, void=0)

Bases: object

Count of votes by origin.

Parameters:
  • candidates (int | Fraction)

  • blank (int | Fraction)

  • void (int | Fraction)

all_votes()

Return the sum of valid votes and invalid votes.

Return type:

int | Fraction

usable_votes(usable)

Return usable votes given a criterion.

Parameters:

usable (TotalVotes)

Return type:

int | Fraction

valid_votes()

Return the sum of candidates votes and blank votes.

Return type:

int | Fraction

blank: int | Fraction

blank votes

candidates: int | Fraction

votes given to candidates

void: int | Fraction

void/null votes

interregnum.district.district module

Basic district.

class interregnum.district.district.BallotsNode(type, name=None, key=None, candidates=None, alliances=None, preferences=None, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: Node

A node with ballots.

Parameters:
__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

local_alliances()

Return node alliances or None.

Return type:

Sequence[Alliance] | ReferenceSet[GroupableReference] | None

local_candidates()

Return node local candidates or None.

Return type:

Ballots | ReferenceSet[GroupableReference] | None

local_candidates_references()

Return references to local candidates defined elsewhere.

If no references but local candidates exist, return True

Return type:

ReferenceSet[GroupableReference] | bool

local_preferences(candidates)

Return node local preferential votes or None.

Parameters:

candidates (Iterable[ContenderId])

Return type:

Iterator[Preference[ContenderId]] | ReferenceSet[GroupableReference] | None

local_preferences_references()

Return references to local preferences defined elsewhere.

If no references but local preferences exist, return True

Return type:

ReferenceSet[GroupableReference] | bool

update_candidates(candidates)

Set these candidates as local candidates.

Parameters:

candidates (Sequence[Contender])

Return type:

None

alliances: Sequence[Alliance] | None = None

alliances definitions

candidates: Sequence[Contender] | ReferenceSet[GroupableReference] | None = None

votes for candidates

preferences: Sequence[Preference[str]] | Callable[[Callable[[str], ContenderId]], Iterator[Preference[ContenderId]]] | ReferenceSet[GroupableReference] | None = None

list of preferential ballots

class interregnum.district.district.District(type='district', name=None, key=None, candidates=None, alliances=None, preferences=None, seats=None, party_seats=None, district_seats=None, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: BallotsNode

An electoral district or constituency.

This node supports methods, candidates and preferences.

Parameters:
__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

get_seats()

Return seats to allocate.

Return type:

int | ReferenceSet[GroupableReference]

grouping()

Return a grouping criterion for this node.

Return type:

Literal[GroupBy.CANDIDATE]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node | Reference] | None

district_seats: Node | ReferenceSet[GroupableReference] | None = None

seats allocated by district (used by bi-proportional methods), extracted from a node result

party_seats: Node | ReferenceSet[GroupableReference] | None = None

seats allocated by party (used by bi-proportional methods), extracted from a node result

seats: int | ReferenceSet[GroupableReference] | None = None

number of seats to allocate (default = 1)

type: Literal['district'] = 'district'
class interregnum.district.district.Filters(context, node, key, lists=None)

Bases: object

Exclusion filters provider.

Parameters:
get_exclude_candidates()

Return the combination of exclusion and inclusion lists.

Return type:

set[ContenderId]

get_filter_f()

Return a candidate filter using the combination of exclusion and inclusion lists.

Return type:

ContenderSetFilter[ContenderId, Event]

context: AllocationContext

electoral system allocation context

key: str

working node id

lists: tuple[set[ContenderId], set[ContenderId]] | None

exlusion list and inclusion list

node: NodeContext

working node local context

interregnum.district.district.adapt_allocator(allocator, inputs, **kwargs)

Add adapters to allocator so that all inputs can be processed.

Parameters:
Return type:

Allocator[AnyName, Any]

interregnum.district.district.clean_inputs(method, inputs)

Clean superfluous inputs.

Max seats restrictions will be reduced to the subset of used candidates.

Parameters:
Return type:

InputDict[ContenderId, Event]

interregnum.district.district.expand_nodes(node)

Iterate nodes or references.

Parameters:

node (Node | Iterable[_Ref] | None)

Return type:

Iterator[Node | _Ref]

interregnum.district.district.from_biproportional_contender(contender)

Compose a contender id from party and district ids.

Parameters:

contender (tuple[ContenderId, ContenderId])

Return type:

ContenderId

interregnum.district.district.get_candidates(district, by)

Return a reference for a district.

If district is already a reference, return as is. Otherwise, compose a groupable reference.

Parameters:
Return type:

ReferenceSet[_Ref] | ReferenceSet[GroupableReference]

interregnum.district.district.input_required(method, inputs, flag)

Return True if flag is required for method.

Parameters:
Return type:

bool

interregnum.district.district.to_biproportional_contender(contender)

De-compose a contender in party and district ids.

Parameters:

contender (ContenderId)

Return type:

tuple[ContenderId, ContenderId]

interregnum.district.district.to_district(contender)

Return a district identifier from a contender id.

Parameters:

contender (ContenderId)

Return type:

ContenderId

interregnum.district.district.to_party(contender)

Return a party identifier from a contender id.

Parameters:

contender (ContenderId)

Return type:

ContenderId

interregnum.district.district.unserialize_ballotsnode_dict(data, cwd)

Unserialize fields for a BallotsNode node.

Parameters:
  • data (Mapping[str, Any])

  • cwd (Path | None)

Return type:

dict[str, Any]

interregnum.district.district.unserialize_district_dict(data, cwd)

Unserialize District fields.

Parameters:
  • data (Mapping[str, Any])

  • cwd (Path | None)

Return type:

dict[str, Any]

interregnum.district.district.unsupported_input(allocator, inputs, flag)

Return True if allocator does not allow flag as an input.

Parameters:
Return type:

bool

interregnum.district.group module

Group of electoral districts.

class interregnum.district.group.Group(type='group', name=None, key=None, aggregate=False, groupby=None, divisions=<factory>, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: Node

A group of electoral districts.

Parameters:
  • type (Literal['group'])

  • name (str | None)

  • key (str | None)

  • aggregate (bool)

  • groupby (GroupBy | None)

  • divisions (Sequence[Node])

  • total_votes (TotalVotes | None)

  • resume_allocation (bool | None)

  • skip_initial_seats (bool | None)

  • exclude (RestrictionList | None)

  • include (RestrictionList | None)

  • initial_seats (int | InitialSeatsSource)

  • method (str | Callable[[...], Allocator[ContenderId, Any]] | None)

  • method_params (dict[str, Any] | None)

  • random_seed (int | None)

  • groups (Sequence[str] | None)

  • result (Result[ContenderId, Any] | None)

  • max_adjustment_seats (int | None)

  • ignore (Sequence[str] | None)

  • map_districts (Mapping[str | None, str | None] | None)

  • meta (dict[str, Any] | None)

__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

get_seats()

Return 0 (no seats are associated to groups).

Return type:

Literal[0]

grouping()

Return a grouping criterion for this node (default: GroupBy.CANDIDATE).

Return type:

GroupBy

local_alliances()

Return node alliances or None.

Return type:

Literal[None]

local_candidates()

Return node local candidates or None.

Return type:

Literal[None]

local_candidates_references()

Return references to local candidates defined elsewhere.

If no references but local candidates exist, return True

Return type:

Literal[False]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node]

local_preferences(candidates)

Return node local preferential votes or None.

Parameters:

candidates (Iterable[ContenderId])

Return type:

Literal[None]

local_preferences_references()

Return references to local preferences defined elsewhere.

If no references but local preferences exist, return True

Return type:

Literal[False]

update_candidates(candidates)

Set these candidates as local candidates.

Parameters:

candidates (Sequence[Contender])

Return type:

None

aggregate: bool = False

if True, aggregate children results as this node result

divisions: Sequence[Node]

list of children nodes

groupby: GroupBy | None = None

candidate id transformation applied to this node results

type: Literal['group'] = 'group'
interregnum.district.group.unserialize_group_dict(data, cwd)

Serialize Group fields.

Parameters:
  • data (Mapping[str, Any])

  • cwd (Path | None)

Return type:

dict[str, Any]

interregnum.district.io module

Tools for reading ballots info.

class interregnum.district.io.CandidatesFile(path, format, encoding='utf-8', cwd=None, type='candidates-file', sep=',')

Bases: File

A file with candidates.

  • yaml, json: should be compatible with Contender

  • csv, tsv: the columns should be compatible with Contender’s properties

Parameters:
  • path (Path)

  • format (str)

  • encoding (str)

  • cwd (Path | None)

  • type (Literal['candidates-file'])

  • sep (str)

classmethod from_path(path, cwd, extension=None)

Create a CandidatesFile object from a path name.

Parameters:
  • path (Path)

  • cwd (Path | None)

  • extension (str | None)

Return type:

CandidatesFile

__call__()

Return a list of contenders.

Return type:

Generator[tuple[str | None, Contender], None, None]

write_data(nodes)

Write data to this file.

Parameters:

nodes (Iterable[tuple[str, Iterable[Candidate[ContenderId] | Contender]]])

Return type:

None

sep: str = ','
type: Literal['candidates-file'] = 'candidates-file'
class interregnum.district.io.File(path, format, encoding='utf-8', cwd=None)

Bases: object

A resource file definition.

Parameters:
  • path (Path)

  • format (str)

  • encoding (str)

  • cwd (Path | None)

cwd: Path | None = None

working directory

encoding: str = 'utf-8'

char encoding

format: str

file format

path: Path

file path

class interregnum.district.io.PreferencesFile(path, format, encoding='utf-8', cwd=None, type='preferences-file')

Bases: File

A file with preferences.

Formats:

  • pref

  • yaml: should be compatible with the preference converter

  • json: should be compatible with the preference converter

Parameters:
  • path (Path)

  • format (str)

  • encoding (str)

  • cwd (Path | None)

  • type (Literal['preferences-file'])

classmethod from_path(path, cwd, extension=None)

Create a PreferencesFile from a path.

Parameters:
  • path (Path)

  • cwd (Path | None)

  • extension (str | None)

Return type:

PreferencesFile

__call__(converter)

Read file and convert candidates names using converter.

Parameters:

converter (Callable[[str], ContenderId])

Return type:

Generator[Preference[ContenderId], None, None]

write_data(converter, preferences, contenders=None)

Write data to this file.

Parameters:
Return type:

None

type: Literal['preferences-file'] = 'preferences-file'
interregnum.district.io.open_ro(path, *args, **kwargs)

Open a text file for reading.

If path is ‘-’, use stdin

Parameters:
  • path (str | Path)

  • args (Any)

  • kwargs (Any)

Return type:

Any

interregnum.district.io.open_w(path, *args, **kwargs)

Open a file for writing.

If path is ‘-’, use stdout

Parameters:
  • path (str | Path)

  • args (Any)

  • kwargs (Any)

Return type:

Any

interregnum.district.io.unserialize_file_object(data, path)

Unserialize File fields.

Parameters:
  • data (Mapping[str, Any])

  • path (Path | None)

Return type:

dict[str, Any]

interregnum.district.io.unserialize_preferences_file(data, path)

Unserialize PreferencesFile fields.

Parameters:
  • data (Mapping[str, Any])

  • path (Path | None)

Return type:

PreferencesFile

interregnum.district.node module

Information for districts or constituencies.

class interregnum.district.node.AllocationContext(root, keys, groups, cand_cache=<factory>, alli_cache=<factory>, stats=<factory>)

Bases: object

An electoral system allocation context.

It stores information needed to access all data required at each step.

Parameters:
classmethod build(root)

Build a tree context.

Parameters:

root (Node)

Return type:

AllocationContext

__call__()

Compute allocation for all nodes in the electoral system.

Since dependencies are computed using depth first search, the electoral system must be a directed acyclic graph.

Return type:

None

build_stats(targets, requires_results)

Compute statistics for nodes, candidates and alliances.

This statistics are required for computing restrictions.

Parameters:
  • requires_results (bool) – compute statistics that requires previous results

  • targets (Reference)

Return type:

NodeStats

children(key)

Iterate key’s children node ids.

Parameters:

key (str | Node)

Return type:

Iterator[str]

dependencies(key, restrictions=True)

Return keys for nodes that must have a result before this node.

Parameters:
  • key (str | Node) – a node or a node id

  • restrictions (bool) – if True, include nodes referred in restrictions that need computed results.

Return type:

frozenset[str]

flatten_alliances(key)

Compute alliances for a node identified by key.

All references will be expanded, and alliances id will be transformed using the node names as districts.

Parameters:

key (str | Node)

Return type:

Sequence[Alliance] | None

flatten_candidates(key)

Compute candidates for a node identified by key.

All references will be expanded, and candidates id will be transformed using the node names as districts.

Parameters:

key (str | Node)

Return type:

Ballots

flatten_preferences(key)

Compute preferences for a node identified by key.

All references will be expanded, and preferences id will be transformed using the node names as districts.

Preferences are not cached because of memory consumption.

Parameters:

key (str | Node)

Return type:

list[Preference[ContenderId]] | None

group_result(reference)

Merge results from the referred nodes.

Candidate-id transformations will be applied.

Parameters:

reference (Iterable[Reference])

Return type:

Sequence[Candidate[ContenderId]]

nested_results(key)

Return ids from nodes with results, considering key as the root.

Parameters:

key (str | Node)

Return type:

list[str]

references(references)

Iterate nodes referred by a list of references.

Parameters:

references (Iterable[Reference])

Return type:

Iterator[Node]

resolve_seats(key)

Resolve referenced seats.

If the seats for a node depends on the result of other nodes, return the seats of the candidate with the same name as the node id. Otherwise return the node seats.

Parameters:

key (str | Node)

Return type:

int

resolve_threshold(key, include=False)

Resolve restrictions for a node identified by key.

Parameters:
  • include (bool) – return restrictions from include instead of exclude

  • key (str | Node)

Return type:

set[ContenderId] | None

alli_cache: dict[str, Sequence[Alliance]]

cache for computed alliances at each node

cand_cache: dict[str, Ballots]

cache for computed candidates at each node

groups: Mapping[str, set[str]]

translation of groups to sets of node ids

keys: Mapping[str, NodeOffset]

mapping of node ids and node offsets

root: str

root node id

stats: dict[Reference, tuple[NodeStats, bool]]

statistics computed for each references used by restrictions

class interregnum.district.node.Node(type, name=None, key=None, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: NodeContext

An electoral node.

A node represents an allocation unit in an electoral system.

Parameters:
  • type (str)

  • name (str | None)

  • key (str | None)

  • total_votes (TotalVotes | None)

  • resume_allocation (bool | None)

  • skip_initial_seats (bool | None)

  • exclude (RestrictionList | None)

  • include (RestrictionList | None)

  • initial_seats (int | InitialSeatsSource)

  • method (str | Callable[[...], Allocator[ContenderId, Any]] | None)

  • method_params (dict[str, Any] | None)

  • random_seed (int | None)

  • groups (Sequence[str] | None)

  • result (Result[ContenderId, Any] | None)

  • max_adjustment_seats (int | None)

  • ignore (Sequence[str] | None)

  • map_districts (Mapping[str | None, str | None] | None)

  • meta (dict[str, Any] | None)

__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

build()

Build an allocation context.

Return type:

AllocationContext

calculate()

Build an allocation context from this node and calculate.

Return type:

None

clear_data()

Clear results, ballots and meta.

Return type:

None

find_district(district_id)

Find a district by identifier and return a reference to it.

District(id) or None

Parameters:

district_id (str)

Return type:

Node | None

find_level(level)

Iterate nodes at a given level from this node.

Positive levels will look levels from this node. Negative levels will look levels from a leaf node.

Parameters:

level (int)

Return type:

Iterator[Node]

get_id()

Return a unique identifier for this node.

If a key is present, use it. Otherwise, use name or return a generated id.

Return type:

str

get_seats()

Return seats to allocate.

Return type:

int | ReferenceSet[GroupableReference]

grouping()

Return a grouping criterion for this node.

Return type:

GroupBy

ignore_compute_dependency()

Ignore these nodes when computing result.

Return type:

Sequence[str] | None

iter_leaves()

Iterate leaf nodes.

Return type:

Iterator[Node]

local_alliances()

Return node alliances or None.

Return type:

Sequence[Alliance] | ReferenceSet[GroupableReference] | None

local_candidates()

Return node local candidates or None.

Return type:

Ballots | ReferenceSet[GroupableReference] | None

local_candidates_references()

Return references to local candidates defined elsewhere.

If no references but local candidates exist, return True

Return type:

ReferenceSet[GroupableReference] | bool

local_children()

Return local divisions that are not references.

Return type:

Iterator[Node]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node | Reference] | None

local_preferences(candidates)

Return node local preferential votes or None.

Parameters:

candidates (Iterable[ContenderId])

Return type:

Iterator[Preference[ContenderId]] | ReferenceSet[GroupableReference] | None

local_preferences_references()

Return references to local preferences defined elsewhere.

If no references but local preferences exist, return True

Return type:

ReferenceSet[GroupableReference] | bool

transform_contender(contender)

Transform contender using the district mapping.

Parameters:

contender (Contender)

Return type:

Contender

transform_contender_id(contender_id)

Transform contender_id using the district mapping.

Parameters:

contender_id (ContenderId)

Return type:

ContenderId

update_candidates(candidates)

Set these candidates as local candidates.

Parameters:

candidates (Sequence[Contender])

Return type:

None

groups: Sequence[str] | None = None

tags useful for finding node groups

ignore: Sequence[str] | None = None

ignore these node when computing dependencies on results

key: str | None = None

human readable node name (must be unique)

map_districts: Mapping[str | None, str | None] | None = None

map for changing district names when collecting candidates

max_adjustment_seats: int | None = None

maximum number of additional seats this node can win in systems with adjustment seats (such as levelling seats or mixed-member systems)

meta: dict[str, Any] | None = None

additional data

name: str | None = None

type of node

result: Result[ContenderId, Any] | None = None

allocation result

type: str
class interregnum.district.node.NodeContext(*, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None)

Bases: object

Inherited node context.

Set of attributes inherited from parent context.

If a node defines any of these attribute, the own node attribute is used. Otherwise, the inherited value for the attribute from parents is used.

Parameters:
static unserialize_dict(**data)

Unserialize a node context attributes from arguments.

Parameters:

data (Any)

Return type:

dict[str, Any]

get_method()

Resolve method and return an allocator factory.

Return type:

Callable[[], Allocator[ContenderId, Any]] | None

merge_context(parent)

Merge this context with the parent context.

Local values will take precedence, and it will use the parent value as a fallback value.

Parameters:

parent (NodeContext)

Return type:

NodeContext

exclude: RestrictionList | None = None

rules for excluding contenders from allocation

include: RestrictionList | None = None

rules for including contenders in allocation (even if the contender is present in the exclusion list)

initial_seats: int | InitialSeatsSource = 1

how to calculate total votes

method: str | Callable[[...], Allocator[ContenderId, Any]] | None = None

allocation method

method_params: dict[str, Any] | None = None

arguments for the allocation method (only used if method is defined in the same node)

random_seed: int | None = None

random number generator seed passed to allocators

resume_allocation: bool | None = None

resume allocation from the initial seats

skip_initial_seats: bool | None = None

add initial seats to result

total_votes: TotalVotes | None = None

how to calculate total votes

class interregnum.district.node.NodeOffset(key, level, reverse_level, context, node)

Bases: object

Location offset of a node from the root tree.

Parameters:
  • key (str)

  • level (int)

  • reverse_level (int)

  • context (NodeContext)

  • node (Node)

classmethod walk(node, parent_level=-1)

Walk nodes from node.

Parameters:
  • parent_level (int) – parent’s computed root offset

  • node (Node)

Return type:

Generator[NodeOffset, None, None]

context: NodeContext

computed node context

key: str

node key

level: int

positive offset from the root

node: Node

node reference

reverse_level: int

negative offset from the leaf

interregnum.district.node.MethodDef

a method definition

alias of str | Callable[[…], Allocator[ContenderId, Any]]

interregnum.district.reapportionment module

Re-apportionment from one node to others.

References


exception interregnum.district.reapportionment.ParallelReapportionmentError

Bases: PreconditionError

Raised when the parallel strategy can’t be used.

class interregnum.district.reapportionment.CompositeResultData(log=<factory>, steps=None)

Bases: EventLog

A result that stores several allocation steps.

Parameters:
steps: list[Result[ContenderId, Any]] | None = None

result for each allocation step

class interregnum.district.reapportionment.Reapportionment(type='reapportionment', name=None, key=None, candidates=None, alliances=None, preferences=None, strategy=<GroupBy.DISTRICT: 4>, relative=None, adjustment=None, first_vote=None, *, total_votes=None, resume_allocation=None, skip_initial_seats=None, exclude=None, include=None, initial_seats=InitialSeatsSource.MIN_SEATS, method=None, method_params=None, random_seed=None, groups=None, result=None, max_adjustment_seats=None, ignore=None, map_districts=None, meta=None)

Bases: BallotsNode

Re-apportionment system.

Use to project adjustment seats allocated by compensatory systems to final districts which already have initial seats, using the votes provided by the field candidates.

Negative levelling seats are supported.

See [Denmark:2011], [Iceland:2013], [Norway:2023], [Germany:2025].

Parameters:
__call__(context, local_context)

Compute allocation for this tree given a context.

Parameters:
Return type:

None

get_seats()

Return seats to allocate.

Return type:

Literal[0]

grouping()

Return a grouping criterion for this node.

Return type:

Literal[GroupBy.CANDIDATE]

local_divisions()

Return node divisions or None.

Return type:

Sequence[Node | Reference] | None

update_candidates(candidates)

Set these candidates as local candidates.

Parameters:

candidates (Sequence[Contender])

Return type:

None

adjustment: Node | ReferenceSet[GroupableReference] | None = None

adjustment seats that will be projected to the new districts

first_vote: Node | ReferenceSet[GroupableReference] | None = None

districts where the seats will be projected

relative: RelativeDivisor | None = None

reference numbers (score used as votes for the allocation):

  • None: use absolute votes for party and district

  • RelativeDivisor: make a relative score using this divisor

strategy: Literal['parallel'] | GroupBy = 4

how to split allocations:

  • parallel ([Iceland:2013]) will allocate each compensatory seat in

    the order it was won (requires a method that produces WinnerEvent for each seat)

  • GroupBy: split the allocations by the given criterion (for example,

    party names or districts)

type: Literal['reapportionment'] = 'reapportionment'
class interregnum.district.reapportionment.ReapportionmentState(candidates, adjustment_seats=<factory>, initial_seats=<factory>, district_map=<factory>, rules=<factory>, excluded=<factory>)

Bases: object

Internal state for reapportionment node.

Parameters:
add_district_constraints(context)

Add constraints for districts that do no allow undetermined adjustment seats.

Parameters:

context (AllocationContext)

Return type:

None

add_party_constraints()

Add constraints for parties based on the number of adjustment seats.

Return type:

None

clean_candidates()

Remove candidates not present in adjustment_seats.

Return type:

None

compute_relative_score(context, relative, total_votes)

Compute relative score (reference number) using a divisor (votes, quota).

Parameters:
Return type:

None

pair_districts(context)

Map districts from the compensatory system to the destination districts.

Parameters:

context (AllocationContext)

Return type:

None

adjustment_seats: dict[ContenderId, int]
candidates: list[Candidate[ContenderId]]
district_map: dict[str | None, str | None]
excluded: set[ContenderId]
initial_seats: dict[ContenderId, int]
rules: list[tuple[int, Sequence[ContenderId]]]
class interregnum.district.reapportionment.RelativeDivisor(*values)

Bases: Enum

Divisor that will be used as a divisor for party/district score.

classmethod parse(value)

Parse from string format.

Parameters:

value (str)

Return type:

RelativeDivisor

__str__()

Return a formatted string.

Return type:

str

QUOTA = 2

use district votes quota

Norway ([Norway:2023]): votes / (constituency votes / number of constituency seats)

VOTES = 1

Use district votes.

Iceland ([Iceland:2013]): votes / constituency votes

interregnum.district.reapportionment.check_event_log(data)

Ensure that a result data is an instance of EventLog.

Parameters:

data (Any)

Return type:

EventLog

interregnum.district.reapportionment.unserialize_reapportionment_dict(data, cwd)

Unserialize Reapportionment fields.

Parameters:
  • data (Mapping[str, Any])

  • cwd (Path | None)

Return type:

dict[str, Any]

interregnum.district.references module

References to nodes.

class interregnum.district.references.GroupableReference(ref=None, level=None, groupby=<GroupBy.CANDIDATE: 7>)

Bases: Reference

A reference with an associated grouping criterion.

Parameters:
  • ref (str | None)

  • level (int | None)

  • groupby (GroupBy)

classmethod parse(text)

Iterate groupable references separated by | in text.

Parameters:

text (str) – a references expression

Raises:

ValueError – when text could not be parsed

Return type:

Generator[GroupableReference, None, None]

classmethod parse_item(text)

Parse a groupable reference from text.

Parameters:

text (str) –

reference expression with the following format:

Raises:

ValueError – when text could not be parsed

Return type:

GroupableReference | None

Examples

Get candidates from leaf nodes in Calabria and transform them to get only their alliance id.

alliance[Calabria:-1]

Get candidates identified by name and district from constituencies.

name+district[#constituencies]

Get candidates from constituencies without any transformation.

#constituencies
__str__()

Return a groupable reference in string format.

Return type:

str

groupby: GroupBy = 7

Candidate name transformation

class interregnum.district.references.Reference(ref=None, level=None)

Bases: object

A reference to a node or a set of nodes.

Examples

  1. Point to node ‘Cádiz’:

    >>> Reference("Cádiz")
    
  2. Use ‘Andalucía’ as reference, and get its direct child nodes:

    >>> Reference("Andalucía", 1)
    
  3. Use ‘Andalucía’ as reference, and get its leaf nodes:

    >>> Reference("Andalucía", -1)
    
  4. Point to any node in the group ‘constituency’:

    >>> Reference("#constituency")
    
Parameters:
  • ref (str | None)

  • level (int | None)

classmethod parse(text)

Iterate references separated by | in text.

Parameters:

text (str) – text references expression: references parseables by parse_reference() separated by |.

Return type:

Generator[Reference, None, None]

Examples

Input examples:

node
node:<level>
#group
#group:<level>
node:<level>|#group:<level>
classmethod parse_one(text)

Parse one reference from text.

Parameters:

text (str) – references expression: references parseables by parse_reference() separated by |.

Return type:

Reference

Examples

Input examples:

node
node:<level>
#group
#group:<level>
node:<level>|#group:<level>
Raises:

ValueError – when text could not be parsed

Parameters:

text (str)

Return type:

Reference

__str__()

Return as a formatted string.

Return type:

str

level: int | None = None

Numerical offset counting from ref (level=0). Can be positive or negative

ref: str | None = None

Node or group of nodes

class interregnum.district.references.ReferenceSet(references=<factory>)

Bases: Generic[_Ref]

An iterable reference set.

Parameters:

references (Sequence[_Ref])

__str__()

Return the reference set as a text expression.

Return type:

str

references: Sequence[_Ref]

list of references

interregnum.district.references.parse_reference(text)

Parse a single reference from text.

Parameters:

text (str) –

A text reference expression, following the format:

<node>
#<group>
<node>:<level>
#<group>:<level>

Where <node> is a node id, <group> is a group tag, and <level> is the offset from the level of <node> or <group>. Level can be positive (counting from start) or negative (counting from leaves).

Returns:

(<node> or <group>, <level>)

Return type:

tuple[str | None, int | None]

interregnum.district.references.unserialize_groupable_reference(node)

Unserialize a groupable reference set from a string or a mapping.

Parameters:

node (dict[str, Any] | str)

Return type:

ReferenceSet[GroupableReference]

interregnum.district.references.unserialize_reference(node)

Unserialize a reference set from a string or a mapping.

Parameters:

node (list[dict[str, Any]] | dict[str, Any] | str)

Return type:

ReferenceSet[Reference]

interregnum.district.restriction module

Restrictions to rule the inclusion or exclusion of candidates.

class interregnum.district.restriction.Attribute(*values)

Bases: Flag

Restriction attribute.

Candidates and alliances can be compare against these attributes.

classmethod parse(text)

Parse value from text.

Parameters:

text (str)

Return type:

Attribute

__invert__()
__str__()

Return string representation.

Return type:

str

requires_results()

Return True if this attribute depends on results.

Return type:

bool

ALLIANCE_ = 4
ALLIANCE_DISTRICTS = 517
Criterion

number of districts where the alliance contends

Total

number of districts

ALLIANCE_GROUP = 4101
Criterion

the alliance contains the group tag

Total

not applicable

ALLIANCE_QUORUM = 1030
Criterion

alliance quorum (number of districts where the alliance won seats)

Total

number of districts

ALLIANCE_RANK = 2053
Criterion

alliance rank in order of votes

Total

not applicable

ALLIANCE_SEATS = 262
Criterion

alliance seats

Total

the sum of alliance seats

ALLIANCE_TOTAL_VOTES = 149
Criterion

alliance votes

Total

the sum of alliance votes, blank votes and void votes

ALLIANCE_VALID_VOTES = 85
Criterion

alliance votes

Total

the sum of alliance votes and blank votes

ALLIANCE_VOTES = 53
Criterion

alliance votes

Total

the sum of alliance votes

CANDIDATE_ = 8
COUNTING_ = 1
DISTRICTS = 521
Criterion

number of districts where the party contends

Total

number of districts

DISTRICTS_ = 512
GROUP = 4105
Criterion

the party contains the group tag

Total

not applicable

GROUP_ = 4096
QUORUM = 1034
Criterion

party quorum (number of districts where the party won seats)

Total

number of districts

QUORUM_ = 1024
RANK = 2057
Criterion

party rank in order of votes

Total

not applicable

RANK_ = 2048
RESULTS_ = 2
SEATS = 266
Criterion

party seats

Total

the sum of party seats

SEATS_ = 256
TOTAL_VOTES = 153
Criterion

party votes

Total

the sum of party votes, blank votes and void votes

TOTAL_VOTES_ = 128
VALID_VOTES = 89
Criterion

party votes

Total

the sum of party votes and blank votes

VALID_VOTES_ = 64
VOTES = 57
Criterion

party votes

Total

the sum of party votes

VOTES_ = 32
VOTES_ANY_ = 16
class interregnum.district.restriction.ContenderStats(votes=0, seats=0, districts=<factory>, quorum=<factory>, rank=0, tags=<factory>)

Bases: object

Statistics for contenders used when applying restrictions.

Parameters:
  • votes (int | Fraction)

  • seats (int)

  • districts (set[str])

  • quorum (set[str])

  • rank (int)

  • tags (set[str])

value(attribute)

Return the value associated to the attribute.

Raises:

ValueError – if the attribute has no numeric value associated to it

Parameters:

attribute (Attribute)

Return type:

int | Fraction

districts: set[str]

districts where the contender appears

quorum: set[str]

districts where the contender won at least one seat

rank: int

contender rank in order of seats won

seats: int

seats won by the contender

tags: set[str]

tags or groups associated to the contender

votes: int | Fraction

contender votes

class interregnum.district.restriction.NodeStats(candidates_votes=0, valid_votes=0, total_votes=0, seats=0, districts=<factory>, candidates=<factory>, alliances=<factory>)

Bases: object

Statistics for nodes used when applying restrictions.

Parameters:
  • candidates_votes (int | Fraction)

  • valid_votes (int | Fraction)

  • total_votes (int | Fraction)

  • seats (int | Fraction)

  • districts (set[str])

  • candidates (dict[ContenderId, ContenderStats])

  • alliances (dict[str, ContenderStats])

usable_votes(usable)

Return usable votes given a criterion.

Parameters:

usable (TotalVotes) – criterion of inclusion (valid, invalid, etc…)

Return type:

int | Fraction

alliances: dict[str, ContenderStats]

alliances statistics

candidates: dict[ContenderId, ContenderStats]

candidates statistics

candidates_votes: int | Fraction

total votes associated to any candidate

districts: set[str]

districts associated to candidates

seats: int | Fraction

total seats allocated by the node

total_votes: int | Fraction

total votes, including invalid or null votes

valid_votes: int | Fraction

total valid votes (associated to any candidate or not)

class interregnum.district.restriction.Restriction(inequality, threshold, percentage, target, attribute, groupby=<GroupBy.CANDIDATE: 7>, tag=None)

Bases: object

A non-composite restriction definition.

String format

<attribute><opt><threshold>
<attribute><opt><threshold>%
<attribute><opt><threshold> => <groupby>
<attribute><opt><threshold>% => <groupby>
<target>.<attribute><opt><threshold>
<target>.<attribute><opt><threshold>%
<target>.<attribute><opt><threshold> => <groupby>
<target>.<attribute><opt><threshold>% => <groupby>

Where:

<attribute>

an Attribute value as string (lower or upper-cased)

<opt>

an operator (see Inequality)

<threshold>

a numeric threshold (it can be a percentage if the attribute supports total), or a string if the attribute is group or alliance_group

<target>

a Reference to the nodeset where the restriction is to be computed

<groupby>

a transformation expression applied to filtered candidates (see GroupBy)

Examples

  1. Get candidates with at least 5% of the total votes:

    valid_votes>=5%
    
  2. Get candidates who won more than 2 seats at Paris district and transform their names removing the district name:

    Paris.alliance_seats>2 => id
    
  3. Get candidates within the group ‘minority’:

    group=minority
    
__str__()

Return the restriction formatted as as string.

Return type:

str

check_any(target, ref, attribute)

Check if this restriction depends on target and attribute.

If the restriction has no target, use ref instead.

Parameters:
Return type:

bool

dependencies()

Iterate over dependencies on targets and attributes.

Yields:

(target reference, attribute)

Return type:

Iterator[tuple[Reference | None, Attribute]]

resolve(context)

Resolve this restriction for a context and return the compliant contenders.

Parameters:

context (Mapping[Reference | None, NodeStats]) – A context composed of statistics computed for nodes. It should contain stats for each possible node.

Raises:

ValueError – When the operator does not support the threshold or when the attribute could not be resolved for the context

Returns:

The set of filtered contenders ids

Return type:

set[ContenderId]

walk()

Yield this restriction.

Yields:

self

Return type:

Iterator[Restriction]

attribute: Attribute

attribute for retrieving the value to compare

groupby: GroupBy

transformation that will be applied to the filtered candidates

inequality: Inequality

(in)equality operator

percentage: bool

treat values as percentages

tag: str | None

check that the candidate is associated to this tag instead of doing a numerical comparison

target: Reference | None

node reference where the attribute is retrieved from

threshold: Decimal

reference value for the inequality

Parameters:
class interregnum.district.restriction.RestrictionList(items, disjunctive=False)

Bases: object

A set of conjunctive or disjunctive restriction clauses.

String formats

  1. conjunctive: get every candidate returned by any of these restrictions

    any{<restriction 1>|...|<restriction N>}
    
  2. disjunctive: get candidates if they are returned by all of these restrictions

    all{<restriction 1>|...!<restriction N>}
    
__str__()

Return the restrictions list formatted as as string.

Return type:

str

check_any(target, ref, attribute)

Check if this restriction depends on target and attribute.

If the restriction has no target, use ref instead.

Parameters:
Return type:

bool

dependencies()

Iterate dependencies on nodes and attributes.

Return type:

Iterator[tuple[Reference | None, Attribute]]

resolve(context)

Resolve this restriction for a context and return the compliant contenders.

Parameters:

context (Mapping[Reference | None, NodeStats]) – A context composed of statistics computed for nodes. It should contain stats for each possible node.

Raises:

ValueError – When the operator does not support the threshold or when the attribute could not be resolved for the context

Returns:

The set of filtered contenders ids

Return type:

set[ContenderId]

walk()

Recursively iterate all restrictions in this list.

Return type:

Iterator[Restriction]

disjunctive: bool

True for disjunctive, False for conjunctive

items: list[Restriction | RestrictionList]

list of restrictions

Parameters:
interregnum.district.restriction.parse_restrictions(text)

Parse restrictions from string expressions.

Parameters:

text (str)

Return type:

Restriction | RestrictionList

interregnum.district.serialize module

Serialization tools.

interregnum.district.serialize.fill_node_candidates(node, data)

Populate nodes with lists of candidates read from file.

Parameters:
Return type:

None

interregnum.district.serialize.serialize_fraction(obj, decimals)

Serialize fraction as a string or an integer.

Parameters:
  • obj (Fraction) – a Fraction

  • decimals (int | None) – number of decimals obj will be rounded to

Return type:

str | int

interregnum.district.serialize.serialize_to_str(obj)

Serialize anything to a string.

Parameters:

obj (Any)

Return type:

str

interregnum.district.serialize.serializer(*object_types)

Register a function as a serializer (decorator).

Parameters:

object_types (type)

Return type:

Callable[[Callable[[_Arg], _Ret]], Callable[[_Arg], _Ret]]

interregnum.district.serialize.to_serializable(data, decimals)

Serialize objects.

Parameters:
  • decimals (int | None) – rounding precision

  • data (Any)

Return type:

Any

interregnum.district.serialize.unserialize_dict(kwargs, cwd)

Unserialize node fields from a mapping.

Parameters:
  • cwd (Path | None) – working directory for opening files

  • kwargs (Mapping[str, Any])

Return type:

dict[str, Any]

interregnum.district.serialize.unserialize_node(data: Mapping[str, Any] | str, cwd: Path | None, groupby: Literal[False] = False) Node | ReferenceSet[Reference]
interregnum.district.serialize.unserialize_node(data: Mapping[str, Any] | str, cwd: Path | None, groupby: Literal[True]) Node | ReferenceSet[GroupableReference]

Convert a mapping to a node.

The field fill_candidates will be interpreted as a CandidatesFile and rows will be injected to nodes.

Parameters:
  • data (Mapping[str, Any] | str) – source data: if data is a string instead of a mapping, a reference will be returned

  • cwd (Path | None) – working directory. Used by file readers.

  • groupby (bool) – use GroupableReference instead of Reference

Return type:

Node | ReferenceSet[Reference] | ReferenceSet[GroupableReference]

interregnum.district.serialize.unserializer(key, factory)

Register node unserializers.

Used as a decorator.

Parameters:
  • key (str) – node type

  • factory (Callable[[...], Node]) – factory function for creating that type of node

Return type:

Callable[[Callable[[Mapping[str, Any], Path | None], dict[str, Any]]], Callable[[Mapping[str, Any], Path | None], dict[str, Any]]]