Tutorial 8: Compensatory systems with re-apportionment

In this tutorial we will learn how to re-locate seats obtained in compensatory districts to the original districts.

Norway - Stortinget

The country is divided among 19 multi-seat constituencies using the highest averages method with modified Sainte-Laguë divisors (first divisor 1.4).

A compensatory district based on special mixed member system will allocate a maximum of 169 seats:

  • Each constituency can only be adjusted by 1 extra seat.

  • A party must reach a 4% of the valid vote and must be present in th 19 constituencies.

  • Seats won by any excluded party will be subtracted from the levelling seats.

  • If a party gains more seats than the ones indicated by the mixed member allocation (overhang seats), that party is excluded, and the extra seats will be subtracted from the levelling seats.

  • The adjustment allocation will be repeated until no party is excluded.

  • The adjustment will re-use the first vote aggregated by name and alliance.

Once the levelling seats have been computed, the system requires the seats to be re-apportioned to the original constituencies. The seats are reallocated using the original Sainte-Laguë divisor method. Instead of absolute votes, this step uses the party/district votes divided by the district quota.

  1. Define the multi-seat constituencies: the property max_adjustment_seats is set to 1 to limit the number of seats the district will be compensated with.

     1- name: valgdistrikter
     2  type: group
     3  aggregate: true
     4  divisions:
     5  - name: : Østfold [1]
     6    seats: 8
     7    max_adjustment_seats: 1
     8    candidates: ...
     9  ...
    10  - name: Finnmark Finnmárku [20]
    11    seats: 4
    12    max_adjustment_seats: 1
    13    candidates: ...
    
  2. Add the compensatory district:

    1- name: compensatory
    2  type: compensatory
    3  mode: exclude_overhang_parties
    4  exclude: any{ valid_votes < 4% | valgdistrikter.districts < 19 => id }
    5  first_vote: id[valgdistrikter:-1]
    6  candidates: id[valgdistrikter:-1]
    7  seats: 169
    8  skip_initial_seats: yes
    9  subtract_excluded_candidates: yes
    

    The mode EXCLUDE_OVERHANG_PARTIES will exclude partis with overhang seats from the compensatory allocation. This is complemented with subtract_excluded_candidates, which will subtract the seats obtained by parties excluded by restrictions.

  3. Now, the seats computed in the compensatory district need to be assigned to the original constituencies. We will use a node of type reapportionment:

     1- name: reapportionment
     2  type: reapportionment
     3  method: highest_averages
     4  method_params:
     5    divisor_f: sainte_lague
     6  # the score is votes / district quota
     7  relative: quota
     8  # the quota is relative to valid vote
     9  total_votes: valid_votes
    10  # look for adjustment seats in the node `compensatory`
    11  adjustment: compensatory
    12  # look for the original candidates in `valgdistrikter`
    13  candidates: valgdistrikter
    14  # use this node to compute the score
    15  first_vote: valgdistrikter
    
  4. That’s it, we can compose the full schema:

     1name: Stortinget 2021
     2type: group
     3method: highest_averages
     4method_params:
     5  divisor_f: sainte_lague_1.4
     6divisions:
     7
     8- name: compensatory
     9  type: compensatory
    10  mode: exclude_overhang_parties
    11  exclude: any{ valid_votes < 4% | valgdistrikter.districts < 19 => id }
    12  first_vote: id[valgdistrikter:-1]
    13  candidates: id[valgdistrikter:-1]
    14  seats: 169
    15  skip_initial_seats: yes
    16  subtract_excluded_candidates: yes
    17
    18- name: reapportionment
    19  type: reapportionment
    20  method: highest_averages
    21  method_params:
    22    divisor_f: sainte_lague
    23  # the score is votes / district quota
    24  relative: quota
    25  # the quota is relative to valid vote
    26  total_votes: valid_votes
    27  # look for adjustment seats in the node `compensatory`
    28  adjustment: compensatory
    29  # look for the original candidates in `valgdistrikter`
    30  candidates: valgdistrikter
    31  # use this node to compute the score
    32  first_vote: valgdistrikter
    33
    34- name: valgdistrikter
    35  type: group
    36  aggregate: true
    37  divisions:
    38  - name: : Østfold [1]
    39    seats: 8
    40    max_adjustment_seats: 1
    41    candidates: ...
    42  ...
    43  - name: Finnmark Finnmárku [20]
    44    seats: 4
    45    max_adjustment_seats: 1
    46    candidates: ...
    

Iceland - Alþingi

The Icelandic system is similar to the one used in Norway, with some differences:

  • There are 6 multi-seat constituencies, allocated by d’Hondt divisors method.

  • There are 9 levelling seats that are allocated resuming the previous allocation.

  • Any party that reaches the 5% of total vote can partipate in the adjustment process.

  • The re-apportionment of a seats occurs just after a new levelling seat is allocated.

  • The re-apportionment score is relative to the district vote.

  1. Define the multi-seat constituencies: the property max_adjustment_seats is set to 1 to limit the number of seats the district will be compensated with.

     1- name: kjördæmi
     2  type: group
     3  aggregate: yes
     4  divisions:
     5
     6  - name: Norðvesturkjördæmi [Northwest]
     7    seats: 7
     8    max_adjustment_seats: 1
     9    candidates: ...
    10  ...
    11  - name: Reykjavíkurkjördæmi Norður [Reykjavik North]
    12    seats: 9
    13    max_adjustment_seats: 2
    14    candidates: ...
    
  2. Add the compensatory district:

    1- name: compensatory district
    2  type: compensatory
    3  mode: additional_member
    4  seats: 9
    5  skip_initial_seats: yes
    6  exclude: votes < 5%
    7  first_vote: alliance[kjördæmi:-1]
    8  candidates: alliance[kjördæmi]
    
  3. Add the re-apportionment district:

    1- name: adjustment seats to constituencies
    2  type: reapportionment
    3  # seats are re-located one by one
    4  strategy: parallel
    5  # score relative to district vote
    6  relative: votes
    7  adjustment: compensatory district
    8  candidates: kjördæmi
    9  first_vote: kjördæmi
    
  4. Now, the full schema:

     1name: Alþingi Íslendinga - 2013
     2type: group
     3method: highest_averages
     4method_params:
     5    divisor_f: dhondt
     6divisions:
     7
     8- name: compensatory district
     9  type: compensatory
    10  mode: additional_member
    11  seats: 9
    12  skip_initial_seats: yes
    13  exclude: votes < 5%
    14  first_vote: alliance[kjördæmi:-1]
    15  candidates: alliance[kjördæmi]
    16
    17- name: adjustment seats to constituencies
    18  type: reapportionment
    19  # seats are re-located one by one
    20  strategy: parallel
    21  # score relative to district vote
    22  relative: votes
    23  adjustment: compensatory district
    24  candidates: kjördæmi
    25  first_vote: kjördæmi
    26
    27- name: kjördæmi
    28  type: group
    29  aggregate: yes
    30  divisions:
    31
    32  - name: Norðvesturkjördæmi [Northwest]
    33    seats: 7
    34    max_adjustment_seats: 1
    35    candidates: ...
    36  ...
    37  - name: Reykjavíkurkjördæmi Norður [Reykjavik North]
    38    seats: 9
    39    max_adjustment_seats: 2
    40    candidates: ...
    

Denmark - Folketing

The Danish system uses two levels of districts: provinces and constituencies.

The first step allocates seats at each constituency using the d’Hondt divisors method. No threshold restrictions apply. Independent candidates are allowed.

The levelling seats will compensate for the whole country using the largest remainder method with a Hare quota. In order to participate in the process, a candidate must comply some restrictions:

  • The party must reach 2% of vote.

  • If a party has won 1 constituency seat, it will be allowed to participate.

  • If a party reaches a Hare quota in 2 of the 3 provinces (at least the provincial votes/seats ratio), it will be allowed to participate.

Those levelling seats will be re-apportioned to provinces first, and then from provinces to constituencies.

The re-apportionment from levelling seats to provinces will use the Sainte-Laguë divisors methods, and each province is limited to a maximum of adjustment seats. The score is not relative. There is one step per district:

leveling seats

provinces

party 1

party 1 @ province 1

party 1 @ province N

party P

party P @ province N

The re-apportionment from provinces to constituencies will use the Danish divisors method. There is one step per candidate.

provinces

district

party 1 @ province 1

party 1 @ district 1.1

party 1 @ district 1.D

party 2 @ province 1

party 2 @ district 1.1

party P @ province N

party P @ district N.D’

  1. Root node: default method is defined here.

    1name: Folketing - 2015
    2type: group
    3method: highest_averages
    4method_params:
    5    divisor_f: dhondt
    6divisions:
    
  2. Provinces and constituencies. Independent candidates should set max_seats: 1.

     1- name: provinces
     2  type: group
     3  aggregate: yes
     4  divisions:
     5
     6  - name: "Hovedstaden (Capital)"
     7    key: Hovedstaden
     8    type: group
     9    aggregate: yes
    10    groupby: id
    11    max_adjustment_seats: 11
    12    divisions: ...
    13
    14  - name: "Sjælland-Syddanmark (Zealand and South Denmark)"
    15    key: Sjælland-Syddanmark
    16    type: group
    17    aggregate: yes
    18    groupby: id
    19    max_adjustment_seats: 15
    20    divisions: ...
    21
    22  - name: "Midtjylland-Nordjylland (Central and North Jutland)"
    23    key: Midtjylland-Nordjylland
    24    type: group
    25    aggregate: yes
    26    groupby: id
    27    max_adjustment_seats: 14
    28    divisions: ...
    

    Each province will generate aggregated results by party ids. A maximum number of adjustment seats is specified.

  3. Compensatory district. 175 seats will be allocated nation-wide to parties using a mixed-member strategy (allocation from scratch where already allocated seats will be subtracted).

     1- name: compensatory district
     2  type: compensatory
     3  mode: mixed_member
     4  seats: 175
     5  method: largest_remainder
     6  method_params:
     7    quota_f: hare
     8  # threshold 2
     9  exclude: votes < 2%
    10  # quota 1
    11  # hare quorum 2 (TODO)
    12  include: provinces.alliance_seats >= 1 => alliance
    13  first_vote: alliance[provinces:-1]
    14  candidates: alliance[provinces:-1]
    15  skip_initial_seats: yes
    

    The second criterion for inclusion can’t be represented as a restriction yet (my apologies), but don’t worry, it has never been used until today (as far as I know).

  4. First re-apportionment: compensatory to provinces.

     1- name: global adjustment seats to provinces
     2  key: reapp1
     3  type: reapportionment
     4  strategy: district
     5  # score is not relative
     6  relative: no
     7  method: highest_averages
     8  method_params:
     9    divisor_f: sainte_lague
    10  # levelling seats to parties
    11  adjustment: compensatory district
    12  # the score will be taken from provinces
    13  candidates: provinces
    14  # adjustment seats will be projected to provinces
    15  first_vote: provinces
    
  5. Second re-apportionment: provinces to constituencies.

     1- name: province adjustment seats to constituencies
     2  key: reapp2
     3  type: reapportionment
     4  strategy: candidate
     5  # the score is not relative
     6  relative: no
     7  method: highest_averages
     8  method_params:
     9    divisor_f: danish
    10  # we take the seats from the first re-apportionment
    11  adjustment: reapp1
    12  # the score will be taken from constituencies
    13  candidates: provinces:-1
    14  # seats will be projected to constituencies
    15  first_vote: provinces:-1
    

Final schema:

 1name: Folketing - 2015
 2type: group
 3method: highest_averages
 4method_params:
 5    divisor_f: dhondt
 6divisions:
 7
 8- name: compensatory district
 9  type: compensatory
10  mode: mixed_member
11  seats: 175
12  method: largest_remainder
13  method_params:
14    quota_f: hare
15  # threshold 2
16  exclude: votes < 2%
17  # quota 1
18  # hare quorum 2 (TODO)
19  include: provinces.alliance_seats >= 1 => alliance
20  first_vote: alliance[provinces:-1]
21  candidates: alliance[provinces:-1]
22  skip_initial_seats: yes
23
24- name: global adjustment seats to provinces
25  key: reapp1
26  type: reapportionment
27  strategy: district
28  # score is not relative
29  relative: no
30  method: highest_averages
31  method_params:
32    divisor_f: sainte_lague
33  # levelling seats to parties
34  adjustment: compensatory district
35  # the score will be taken from provinces
36  candidates: provinces
37  # adjustment seats will be projected to provinces
38  first_vote: provinces
39
40- name: province adjustment seats to constituencies
41  key: reapp2
42  type: reapportionment
43  strategy: candidate
44  # the score is not relative
45  relative: no
46  method: highest_averages
47  method_params:
48    divisor_f: danish
49  # we take the seats from the first re-apportionment
50  adjustment: reapp1
51  # the score will be taken from constituencies
52  candidates: provinces:-1
53  # seats will be projected to constituencies
54  first_vote: provinces:-1
55
56- name: provinces
57  type: group
58  aggregate: yes
59  divisions:
60
61  - name: "Hovedstaden (Capital)"
62    key: Hovedstaden
63    type: group
64    aggregate: yes
65    groupby: id
66    max_adjustment_seats: 11
67    divisions: ...
68
69  - name: "Sjælland-Syddanmark (Zealand and South Denmark)"
70    key: Sjælland-Syddanmark
71    type: group
72    aggregate: yes
73    groupby: id
74    max_adjustment_seats: 15
75    divisions: ...
76
77  - name: "Midtjylland-Nordjylland (Central and North Jutland)"
78    key: Midtjylland-Nordjylland
79    type: group
80    aggregate: yes
81    groupby: id
82    max_adjustment_seats: 14
83    divisions: ...