Tutorial 9: Subtractive compensatory system¶
In this tutorial we will learn how to compute and re-apportion negative adjustment seats to compensate overhang seats.
Germany 2025 - Bundestag¶
Mmmhh, err… yeah… Germany… this is gonna be hard…
Each Land is divided into one-seats constituencies where a candidate is elected using the first vote. A candidate can be allied to a party or can be independent.
1- name: Länder
2 type: group
3 method: first_past_the_post
4 meta:
5 notes: |
6 Wahlkreise.
7 First vote: mandates for state districts.
8 divisions:
9
10 - name: Schleswig-Holstein
11 type: group
12 # we will need this later
13 aggregate: yes
14 groupby: id
15 divisions:
16 - name: Flensburg – Schleswig
17 # constituencies are tagged for future references
18 groups: [mandates]
19 ...
20 ...
In a similar way to Scotland - Scottish Parliament (Highlands and Islands), each Land has a second vote where only parties can be chosen. But instead of adjusting seats at the Land level, seats will be compensated once for all Germany (known as Oberverteilung, upper distribution).
1- name: Zweistimme
2 type: group
3 method: noop
4 meta:
5 notes: |
6 second votes: party lists for each state
7 divisions:
8 - name: Landesliste - Schleswig-Holstein
9 - name: Landesliste - Hamburg
10 - name: Landesliste - Niedersachsen
11 - name: Landesliste - Bremen
12 - name: Landesliste - Nordrhein-Westfalen
13 - name: Landesliste - Hessen
14 - name: Landesliste - Rheinland-Pfalz
15 - name: Landesliste - Baden-Württemberg
16 - name: Landesliste - Bayern
17 - name: Landesliste - Saarland
18 - name: Landesliste - Berlin
19 - name: Landesliste - Brandenburg
20 - name: Landesliste - Mecklenburg-Vorpommern
21 - name: Landesliste - Sachsen
22 - name: Landesliste - Sachsen-Anhalt
23 - name: Landesliste - Thüringen
630 seats will be allocated in the upper distribution among the parties with at least 5% of votes, or parties with at least 3 constituencies or parties from minority groups.
Seats won by first vote by parties or independent candidates that can’t participate in the upper distribution will be subtracted from the initial 630 seats.
This is the definitive allocation, so if a party won more seats than the upper distribution says it should have, the seats surplus will be subtracted later.
1- name: Oberverteilung
2 type: compensatory
3 mode: mixed_member
4 seats: 630
5 exclude: votes < 5%
6 # 3 constituencies or minority groups are allowed
7 include: "any{ #mandates.alliance_quorum >= 3 => alliance | #mandates.alliance_group = minority => alliance }"
8 # mandates from first vote will be compensated
9 first_vote: "alliance[#mandates]"
10 # the adjustment process will use the aggregated second vote
11 candidates: alliance[Zweistimme]
12 # seats from non-participant candidates will be subtracted
13 subtract_excluded_candidates: yes
14 # return both the levelling seats and the mandates
15 skip_initial_seats: no
16 meta:
17 notes: |
18 Federal party seats allocation using second vote.
Once the definitive seats have been allocated to parties, it’s time to give it back to Länder and constituencies. This process is known as Unterverteilung (sub-distribution).
1- name: Unterverteilung
2 type: reapportionment
3 strategy: candidate
4 adjustment: Oberverteilung
5 # the score comes from unaggregated second vote
6 candidates: Zweistimme:-1
7 # the party vote will be injected to Länder
8 first_vote: Zweistimme:-1
9 # change the names from second vote districts to first vote districts
10 map_districts:
11 Landesliste - Schleswig-Holstein: Schleswig-Holstein
12 Landesliste - Hamburg: Hamburg
13 Landesliste - Niedersachsen: Niedersachsen
14 Landesliste - Bremen: Bremen
15 Landesliste - Nordrhein-Westfalen: Nordrhein-Westfalen
16 Landesliste - Hessen: Hessen
17 Landesliste - Rheinland-Pfalz: Rheinland-Pfalz
18 Landesliste - Baden-Württemberg: Baden-Württemberg
19 Landesliste - Bayern: Bayern
20 Landesliste - Saarland: Saarland
21 Landesliste - Berlin: Berlin
22 Landesliste - Brandenburg: Brandenburg
23 Landesliste - Mecklenburg-Vorpommern: Mecklenburg-Vorpommern
24 Landesliste - Sachsen: Sachsen
25 Landesliste - Sachsen-Anhalt: Sachsen-Anhalt
26 Landesliste - Thüringen: Thüringen
27 meta:
28 notes: |
29 State seats allocation for each party.
The attribute map_districts allows to rename districts in the result.
Once the seats have been distributed to each Land, the levelling seats are subtracted from mandates.
1- name: levelling seats
2 type: compensatory
3 # produce negative seats for overhang seats
4 mode: subtract_overhang_seats
5 # reuse what we have
6 method: noop
7 # noop needs initial seats from first vote
8 propagate_initial_seats: yes
9 # mandates
10 first_vote: Länder:1
11 # sub-distribution
12 candidates: Unterverteilung
13 # we take seats from the Unterverteilung result
14 initial_seats: from_results
15 # return new seats only
16 skip_initial_seats: yes
17 meta:
18 notes: |
19 Allocate levelling seats (subtract mandates from Unterverteilung)
Overhang seats will be subtracted from the mandates.
1- name: negative levelling seats
2 # we take parties with negative seats (overhang seats)
3 exclude: levelling seats.seats >= 0
4 include: levelling seats.seats < 0
5 # we are just filtering out
6 method: noop
7 # we use the levelling seats
8 candidates: levelling seats
9 initial_seats: from_results
10
11- name: mandates surplus
12 type: reapportionment
13 method: limited_voting
14 strategy: candidate
15 relative: votes
16 # only parties that are losing mandates
17 exclude: "#mandates.seats < 1"
18 adjustment: negative levelling seats
19 # the score
20 candidates: "#mandates"
21 # the destination
22 first_vote: "#mandates"
Now, the final schema:
1name: Bundestag 2025
2type: group
3method: iterative_divisor
4method_params:
5 signpost_f: sainte_lague
6divisions:
7
8- name: Länder
9 type: group
10 method: first_past_the_post
11 meta:
12 notes: |
13 Wahlkreise.
14 First vote: mandates for state districts.
15 divisions:
16 - name: Schleswig-Holstein
17 type: group
18 # we will need this later
19 aggregate: yes
20 groupby: id
21 divisions:
22 - name: Flensburg – Schleswig
23 # constituencies are tagged for future references
24 groups: [mandates]
25 ...
26 ...
27
28- name: Zweistimme
29 type: group
30 method: noop
31 meta:
32 notes: |
33 second votes: party lists for each state
34 divisions:
35 - name: Landesliste - Schleswig-Holstein
36 - name: Landesliste - Hamburg
37 - name: Landesliste - Niedersachsen
38 - name: Landesliste - Bremen
39 - name: Landesliste - Nordrhein-Westfalen
40 - name: Landesliste - Hessen
41 - name: Landesliste - Rheinland-Pfalz
42 - name: Landesliste - Baden-Württemberg
43 - name: Landesliste - Bayern
44 - name: Landesliste - Saarland
45 - name: Landesliste - Berlin
46 - name: Landesliste - Brandenburg
47 - name: Landesliste - Mecklenburg-Vorpommern
48 - name: Landesliste - Sachsen
49 - name: Landesliste - Sachsen-Anhalt
50 - name: Landesliste - Thüringen
51
52- name: Oberverteilung
53 type: compensatory
54 mode: mixed_member
55 seats: 630
56 exclude: votes < 5%
57 # 3 constituencies or minority groups are allowed
58 include: "any{ #mandates.alliance_quorum >= 3 => alliance | #mandates.alliance_group = minority => alliance }"
59 # mandates from first vote will be compensated
60 first_vote: "alliance[#mandates]"
61 # the adjustment process will use the aggregated second vote
62 candidates: alliance[Zweistimme]
63 # seats from non-participant candidates will be subtracted
64 subtract_excluded_candidates: yes
65 # return both the levelling seats and the mandates
66 skip_initial_seats: no
67 meta:
68 notes: |
69 Federal party seats allocation using second vote.
70
71- name: Unterverteilung
72 type: reapportionment
73 strategy: candidate
74 adjustment: Oberverteilung
75 # the score comes from unaggregated second vote
76 candidates: Zweistimme:-1
77 # the party vote will be injected to Länder
78 first_vote: Zweistimme:-1
79 # change the names from second vote districts to first vote districts
80 map_districts:
81 Landesliste - Schleswig-Holstein: Schleswig-Holstein
82 Landesliste - Hamburg: Hamburg
83 Landesliste - Niedersachsen: Niedersachsen
84 Landesliste - Bremen: Bremen
85 Landesliste - Nordrhein-Westfalen: Nordrhein-Westfalen
86 Landesliste - Hessen: Hessen
87 Landesliste - Rheinland-Pfalz: Rheinland-Pfalz
88 Landesliste - Baden-Württemberg: Baden-Württemberg
89 Landesliste - Bayern: Bayern
90 Landesliste - Saarland: Saarland
91 Landesliste - Berlin: Berlin
92 Landesliste - Brandenburg: Brandenburg
93 Landesliste - Mecklenburg-Vorpommern: Mecklenburg-Vorpommern
94 Landesliste - Sachsen: Sachsen
95 Landesliste - Sachsen-Anhalt: Sachsen-Anhalt
96 Landesliste - Thüringen: Thüringen
97 meta:
98 notes: |
99 State seats allocation for each party.
100
101- name: levelling seats
102 type: compensatory
103 # produce negative seats for overhang seats
104 mode: subtract_overhang_seats
105 # reuse what we have
106 method: noop
107 # noop needs initial seats from first vote
108 propagate_initial_seats: yes
109 # mandates
110 first_vote: Länder:1
111 # sub-distribution
112 candidates: Unterverteilung
113 # we take seats from the Unterverteilung result
114 initial_seats: from_results
115 # return new seats only
116 skip_initial_seats: yes
117 meta:
118 notes: |
119 Allocate levelling seats (subtract mandates from Unterverteilung)
120
121- name: negative levelling seats
122 # we take parties with negative seats (overhang seats)
123 exclude: levelling seats.seats >= 0
124 include: levelling seats.seats < 0
125 # we are just filtering out
126 method: noop
127 # we use the levelling seats
128 candidates: levelling seats
129 initial_seats: from_results
130
131- name: mandates surplus
132 type: reapportionment
133 method: limited_voting
134 strategy: candidate
135 relative: votes
136 # only parties that are losing mandates
137 exclude: "#mandates.seats < 1"
138 adjustment: negative levelling seats
139 # the score
140 candidates: "#mandates"
141 # the destination
142 first_vote: "#mandates"