Method to proportionally allocate seats among parties (or lists) and districts (or entities, regions), thus bi-proportional.

```
biproporz(
votes_matrix,
district_seats,
quorum,
use_list_votes = TRUE,
method = "round"
)
```

- votes_matrix
Vote count matrix with votes by party in rows and votes by district in columns

- district_seats
Vector defining the number of seats per district. Must be the same length as

`ncol(votes_matrix)`

. Values are name-matched to`votes_matrix`

if both are named. If the number of seats per district should be assigned according to the number of votes (not the general use case), a single number for the total number of seats can be used.- quorum
Optional list of functions which take the votes_matrix and return a logical vector that denotes for each list/party whether they reached the quorum (i.e. are eligible for seats). The easiest way to do this is via

`quorum_any()`

or`quorum_all()`

, see examples. Alternatively you can pass a precalculated logical vector. No quorum is applied if parameter is missing or`NULL`

.- use_list_votes
By default (

`TRUE`

) it's assumed that each voter in a district has as many votes as there are seats in a district. Thus, votes are weighted according to the number of available district seats with`weight_list_votes()`

. Set to`FALSE`

if`votes_matrix`

shows the number of voters (e.g. they can only cast one vote for one party).- method
Defines which method is used to assign seats. The following methods are recommended:

`round`

: Uses the Sainte-Laguë/Webster method (rounding half up) for the upper and lower apportionment which is the standard for biproportional apportionment and the only method guaranteed to terminate.`wto`

: "winner take one" works like "round" with a condition that the party that got the most votes in a district must get*at least*one seat ('Majorzbedingung') in said district. Seats in the upper apportionment are assigned with Sainte-Laguë/Webster.`votes_matrix`

must have row and column names to use this method. See`lower_apportionment()`

for more details.

It is also possible to use any divisor method name listed in

`proporz()`

. If you want to use a different method for the upper and lower apportionment, provide a list with two entries.

Matrix with the same dimension as `votes_matrix`

containing the number of seats
with the row and column divisors stored in attributes (hidden from print, see
`get_divisors()`

).

Each party nominates a candidate list for every district. The voters vote for the parties of their district. The seat allocation is calculated in two steps:

In the so called

`upper apportionment`

the number of seats for each party (over all districts) is determined. Normally, the number of seats for each region are defined before the election and are independent of the vote counts.In the so called

`lower apportionment`

the seats are distributed to the regional party list respecting the results from the upper apportionment.

Parties failing to reach quorums cannot get seats. This function does not handle seat assignment to candidates.

The iterative process in the lower apportionment is only guaranteed to terminate with the default Sainte-Laguë/Webster method.

Gaffke, Norbert; Pukelsheim, Friedrich (2008): Divisor methods for proportional representation systems: An optimization approach to vector and matrix apportionment problems. Mathematical Social Sciences, 56 (2), 166-184.

`pukelsheim()`

for biproportional apportionment with `data.frames`

as inputs.

```
votes_matrix = uri2020$votes_matrix
district_seats = uri2020$seats_vector
biproporz(votes_matrix, district_seats)
#> Altdorf Bürglen Erstfeld Schattdorf
#> CVP 5 2 2 3
#> SPGB 4 1 2 2
#> FDP 3 1 1 2
#> SVP 3 3 1 2
# apply quorum (high values for illustrative purposes)
biproporz(votes_matrix, district_seats,
quorum_all(any_district = 0.1, total = 0.25))
#> Altdorf Bürglen Erstfeld Schattdorf
#> CVP 7 5 3 6
#> SPGB 8 2 3 3
#> FDP 0 0 0 0
#> SVP 0 0 0 0
```