iconEuler Examples

d'Hondt and Hare-Niemeyer

The file hondt.e contains an implementation of the d'Hondt and the
Hare-Niemeyer procedures for elections.

See: hondt.e.html
>load hondt;
Let us start with a simple example. Assume the votes are the
following.
>v=[24,27,5]
[ 24  27  5 ]
Now we have 10 seats. How would distribute these seats?

The d'Hondt method does the following.
>hondt(v,10)
[ 4  5  1 ]
The result of the Hare-Niemeyer method is the same in this case.
>hnbest(v,10)
[ 4  5  1 ]

Explanation

The d'Hondt method divides the seats by 1, 2, 3, ... and sorts the
results. Then it takes the highest n numbers to determine the seats.

Let us simulate that. First we divide v by 1 to 10 and put that into
one vector.
>k=10; vh=redim(v/(1:k)',1,k*3)
[ 24  27  5  12  13.5  2.5  8  9  1.66666666667  6  6.75  1.25  4.8  5.4
1  4  4.5  0.833333333333  3.42857142857  3.85714285714
0.714285714286  3  3.375  0.625  2.66666666667  3  0.555555555556  2.4
2.7  0.5 ]
Here are the numbers of the parties for each entry of vh.
>ph=redim(dup(1:3,k),1,k*3)
[ 1  2  3  1  2  3  1  2  3  1  2  3  1  2  3  1  2  3  1  2  3  1  2  3
1  2  3  1  2  3 ]
Now we sort vh.
>{vhs,is}=sort(vh); vhs
[ 0.5  0.555555555556  0.625  0.714285714286  0.833333333333  1  1.25
1.66666666667  2.4  2.5  2.66666666667  2.7  3  3  3.375
3.42857142857  3.85714285714  4  4.5  4.8  5  5.4  6  6.75  8  9  12
13.5  24  27 ]
The parties which these numbers belong to, are the following.
>ph[is]
[ 3  3  3  3  3  3  3  3  1  3  1  2  2  1  2  1  2  1  2  1  3  2  1  2
1  2  1  2  1  2 ]
Since the sorting is ascending, we need to take the last 10 values of
the vector, determine the parties of these indices, and count the
number of times a party occurs.
>is=flipx(is[-10:-1]), ps=ph[is], getmultiplicities(1:3,ps)
[ 2  1  5  4  8  7  11  10  14  3 ]
[ 2  1  2  1  2  1  2  1  2  3 ]
[ 4  5  1 ]
It is not obvious, why this works. All we have is the following
relation.

dHondt and Hare-Niemeyer

for all i,j, where p_i are the fractions of votes for i, and n_i are
the number of seats. Thus it can be derived that for large n_i the
proportion of the seats is approximately the proportion of the votes.

There is also an obvious monotonicity: If some parties get more votes
and others get less, then the number of seats change into the same
direction. Moreover, if the total number of seats increases or
decreases, the number n of seats for each party can only change in the
same direction. Using this, we get.

dHondt and Hare-Niemeyer

Hare-Niemeyer works with a different, and less obscure trick. First we
determine the fractional number of seats each party should get.
>s=v/sum(v)*10
[ 4.28571428571  4.82142857143  0.892857142857 ]
This is of course not possible. Therefore, we give the parties the
integer part of this, thus

dHondt and Hare-Niemeyer

>sp=floor(s)
[ 4  4  0 ]
We have 2 seats left. Now we determine the errors for each party and
add 1 seat for the highest 2 errors.
>s-sp, {h,i}=sort(s-sp); i=i[-2:-1],
[ 0.285714285714  0.821428571429  0.892857142857 ]
[ 2  3 ]
Party 2 and 3 have the largest error. So we reduct this error the
most, if we add one seat to 2 and 3.
>sp[i]=sp[i]+1; sp,
[ 4  5  1 ]

Checking the Results

For a comparison, we assume two parties, where one gets p percent of
the votes, and k seats. Then we can write a function for the number of
seats the party gets.
>function map shondt (p) := hondt([p,1-p],k)[1]
Then we can plot the number of seats the party gets versus the number
of seats it should get (in red).
>k=10; plot2d("k*x",0,1,color=red); ...
>plot2d("shondt",>add); insimg;

dHondt and Hare-Niemeyer

This tends to put the smaller party at a disadvantage.

Let us try the same with Hare-Niemeyer.
>function map shn (p) := hnbest([p,1-p],k)[1]
>k=10; plot2d("k*x",0,1,color=red); ...
>plot2d("shn",>add); insimg;

dHondt and Hare-Niemeyer

This clearly looks much better. In fact, it rounds the fractional
number of seats to the next integer.

We can do the same for three parties with an equal share of votes for
the other two.
>function map shondt (p) := hondt([p,1-p/2,1-p/2],k)[1]
>k=10; plot2d("k*x/2",0,1,color=red); ...
>plot2d("shondt",>add); insimg;

dHondt and Hare-Niemeyer

>function map shn (p) := hnbest([p,1-p/2,1-p/2],k)[1]
>k=10; plot2d("k*x/2",0,1,color=red); ...
>plot2d("shn",>add); insimg;

dHondt and Hare-Niemeyer

Again the small party clearly gets a fair share.

Examples Homepage