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 ]
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.
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.
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
>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 ]
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;
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;
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;
>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;
Again the small party clearly gets a fair share.