The single transferable vote (STV) method of conducting an election exists in a number of different formulations in different countries. Most of the methods are designed to be practicable when counting is by hand, and this necessarily enforces simplicity even at the expense of not always getting the best possible answer.
Meek[1,2] considered the question of the best possible method, within the STV framework, when a computer is available to do the counting, and it is his method that we present here. The method was rediscovered, in a different formulation, by Woodall[4]. However, neither Meek nor Woodall dealt with certain detailed points, such as how to resolve a `tie', so we have had to extend the system to be complete. The algorithm as given here has been adopted by the Royal Statistical Society for its Council elections.
The basis of any STV system consists of the following. (1) Voting by order of preference of candidates, the first choice being marked 1, the second 2, and so on, on the ballot papers. (Meek also considered an alternative formulation in which voters would be allowed to indicate equal preference for some candidates instead of a strict ordering; we have not implemented this alternative.) (2) A quota for election, calculated from the number of votes and the number of seats to be filled. (3) A first counting by first preferences only, and the election of any candidate who equals or exceeds the quota (except in the special case of a multi-way tie). (4) Redistribution of surplus votes (above the quota) for any candidate, in accordance with the voters' further preferences, and election of any who now reach the quota. (5) When no further redistribution of surpluses is possible, the exclusion of the candidate who then has the fewest votes, and redistribution of those papers. (6) Further counting, election, redistribution of surpluses and exclusion as necessary, until all seats are filled.
In the Meek formulation the rule for redistributing surpluses is that, at every stage, if a candidate has votes totalling k times the quota, then he (or she) keeps 1/k of each of those votes and passes (k-1)/k on to the next candidate on the voter's list. This same fraction applies also to portions of votes received as parts of other surpluses. This requires the iterative solution of non-linear equations. It is proved in Section 4 below that a solution always exists and is unique.
It should be emphasised that the results will not always be the same as by manual counting methods. The algorithm deliberately uses the power of the computer to get better results than are easily achievable by hand.
A fraction (1-wa)(1-wb)(1-wc) remains and this goes to `excess'. (Note that if a hopeful candidate appears in the list, all the fractions beyond that point automatically become 0).
We have allowed for up to 40 candidates, but the necessary change to allow a larger number is trivial.
The data file should be held on disc, or other device that allows quick `rewinding', because it has to be read many times during program execution.
Its form should be as follows:
4 2 -2 3 1 3 4 0 4 1 3 2 0 2 4 1 3 0 1 2 0 2 2 4 3 1 0 1 3 4 2 0 0 "Adam" "Basil" "Charlotte" "Donald" "Title"
The first line means that there are 4 candidates for 2 seats. The second line means that candidate number 2 withdrew before the count. As many candidates as necessary may be included in this line, each preceded by a minus sign. If no candidate withdrew, the line should be omitted entirely. The third line means that 3 voters put candidate 1 first, candidate 3 second, candidate 4 third, and no more. Each such list must end with a zero. The final zero ends the votes. The subsequent lines name the candidates, in the order of candidate numbers as used in the votes, and finally give a title for the election. If any of these names, or the title, is longer than 20 characters, only the first 20 will be used.
For elections on any substantial scale, further programs are desirable to get the data into this required form. Machine-readable ballot papers would obviously be a great help if a suitable system can be devised.
The only ties that can occur in this system are as follows. (1) If n + 1 candidates all exactly equal the quota, where only n seats are available. One of these candidates must then be excluded (together with all other candidates, who necessarily have zero votes) and the other n elected. (2) If the candidate with fewest votes must be excluded and two or more have equal fewest. In both these cases a pseudo-random procedure is used, on the grounds that `if they are equal, they are equal' and any procedure to choose one must be arbitrary. Alternatives are sometimes recommended, such as excluding the one who had fewer votes the first time they were different, or the last time they were different, or whatever, but such rules add much complication for no real advantage, so simplicity is preferable.
The pseudo-random generator is derived, with permission, from Applied Statistics algorithm AS 183[3]. This needs three seeds to initialise it, and these are formed from data items for the particular election. This leaves it sufficiently nearly random that nobody can manipulate it to favour a particular candidate, yet has the advantage that, for a given election, there is always a unique result. Running it on a different day, or using a different computer, will make no change - in the unlikely event that a random choice is needed, the same thing will always happen for any given data set. If a tie does occur and a random choice has to be made, a warning message is printed.
It should be emphasised that a tie that actually influences the result is a very rare event.
There is no compulsion on voters to give a complete listing of candidates. They may stop short if desired. If they do so and the use of their vote `runs off the end' we allow it to do so, but adjust the quota to allow for the fact that there are now fewer remaining usable votes. This treats the partial abstention in such a way as to be fair to all remaining candidates.
This usage is different from that adopted in most manual counting systems where, under such circumstances, votes are divided into `transferable' and `non-transferable' and no quota adjustment is made. We are convinced that, within Meek's system, our approach is right, but it has to be made clear that we are in dispute over this with the council of the Electoral Reform Society. We have held up publication of the algorithm in the hope of resolving the difficulty, but now feel that we can wait no longer. Unfortunately, it is therefore necessary to warn potential users that they may be told by others that our method is undesirable in this particular.
The algorithm is presented in standard Pascal. On some machines small, non-standard, changes may be required in the method of accessing the data file. We have used upper-case letters for Pascal word-symbols, lower-case or mixed-case for identifiers.
PROGRAM stvpas(datafile, output);
{This program counts the votes in a Single Transferable Vote election,
using Meek's method, and reports the results}
{If there are more than 40 candidates an increase in the size of
MaxCandidates is the only change needed}
CONST MaxCandidates = 40;
NameLength = 20;
TYPE Candidates = 1 .. MaxCandidates;
CandRange = 0 .. MaxCandidates;
name = PACKED ARRAY [1 .. NameLength] OF char;
VAR NumCandidates, NumSeats: Candidates;
candidate, NumElected, NumExcluded,
multiplier, ignored: CandRange;
Droop, excess, quota, total: real;
faulty, SomeoneElected, RandomUsed: Boolean;
FracDigits: 1 .. 4;
table, seed1, seed2, seed3: integer;
datafile: text;
title: name;
votes, weight: ARRAY [Candidates] OF real;
status: ARRAY [Candidates] OF (Hopeful, Elected, NewlyElected,
Almost, Excluded, ToBeExcluded, NotUsed, Used);
names: ARRAY [Candidates] OF name;
FUNCTION InInteger: integer;
{Reads the next integer from datafile and returns its value}
VAR i: integer;
BEGIN
read(datafile, i);
InInteger := i
END; {InInteger}
PROCEDURE PrintOut;
{Updates the table number and prints out the current results}
VAR arg: real;
cand: Candidates;
BEGIN
table := table + 1;
writeln;
writeln(' ': 20, title);
writeln;
write('Table: ', table: 1);
writeln(' Quota: ', quota: 1: FracDigits);
writeln;
{The numbers of blanks following Candidate, Retain and
Transfer are 12, 3 and 3 respectively}
writeln('Candidate Retain Transfer Votes');
writeln;
FOR cand := 1 TO NumCandidates DO
BEGIN
write(names[cand]);
IF status[cand] = ToBeExcluded THEN
arg := 100.0 ELSE arg := 100.0 * weight[cand];
write(arg: 6: 1, '%');
write(100.0 - arg: 8: 1, '%');
{If it is valid to do so, print quota instead of votes[cand]
because the latter might have a small rounding error that
would confuse unsophisticated users}
IF status[cand] = Elected THEN arg := votes[cand] / quota
ELSE arg := 0.0;
IF (arg >= 0.99999) AND (arg <= 1.00001) THEN arg := quota
ELSE arg := votes[cand];
write(arg: 10: FracDigits, ' ');
IF status[cand] = Excluded THEN write('Excluded')
ELSE IF status[cand] = Elected THEN write('Elected')
ELSE IF status[cand] = NewlyElected THEN write('Newly Elected')
ELSE IF status[cand] = ToBeExcluded THEN
BEGIN
write('To be Excluded');
status[cand] := Excluded
END;
writeln;
IF (NumCandidates > 9) AND (cand MOD 5 = 0) AND
(cand <> NumCandidates) THEN writeln
END;
writeln;
writeln('Excess', excess: 40: FracDigits);
writeln;
writeln('Total ', total: 40: FracDigits);
writeln;
writeln
END; {PrintOut}
PROCEDURE elect(cand: Candidates);
BEGIN
status[cand] := NewlyElected;
NumElected := NumElected + 1
END; {elect}
PROCEDURE exclude(cand: Candidates);
BEGIN
status[cand] := ToBeExcluded;
weight[cand] := 0.0;
NumExcluded := NumExcluded + 1;
IF RandomUsed THEN
BEGIN
writeln;
writeln;
writeln('Random choice used to exclude ', names[cand])
END
END; {exclude}
FUNCTION LowestCandidate: CandRange;
{Returns the candidate number of the candidate who currently has the
lowest number of votes. If two or more are equal lowest, then a
pseudo-random choice is made between them}
VAR cand: Candidates;
LowCand: CandRange;
FUNCTION random: real;
{Returns a pseudo-random number rectangularly distributed
between 0 and 1. Based on Wichmann and Hill, Algorithm
AS 183, Appl. Statist. (1982) 31, 188 - 190}
VAR rndm: real;
BEGIN
{ If seeds have not been set, then set them}
IF seed1 = 0 THEN
BEGIN
seed1 := NumCandidates;
seed2 := NumSeats + 10000;
rndm := total + 20000.0;
WHILE rndm > 30322.5 DO rndm := rndm - 30322.0;
seed3 := round(rndm)
END;
seed1 := 171 * (seed1 MOD 177) - 2 * (seed1 DIV 177);
seed2 := 172 * (seed2 MOD 176) - 35 * (seed2 DIV 176);
seed3 := 170 * (seed3 MOD 178) - 63 * (seed3 DIV 178);
IF seed1 < 0 THEN seed1 := seed1 + 30269;
IF seed2 < 0 THEN seed2 := seed2 + 30307;
IF seed3 < 0 THEN seed3 := seed3 + 30323;
rndm := seed1 / 30269.0 + seed2 / 30307.0 + seed3 / 30323.0;
random := rndm - trunc(rndm)
END; {random}
FUNCTION lower(cand, lowest: CandRange): Boolean;
{Find whether cand has fewer votes than lowest, and also
reports whether a random choice had to be made}
VAR lowly: Boolean;
BEGIN
IF lowest = 0 THEN
BEGIN
RandomUsed := false;
lower := true
END
ELSE IF votes[cand] = votes[lowest] THEN
BEGIN
RandomUsed := true;
{Multiplier is used to make all equally-lowest candidates
equally likely to be chosen, even though they are
considered serially and not simultaneously}
lower := (multiplier * random < 1.0)
END
ELSE
BEGIN
lowly := (votes[cand] < votes[lowest]);
lower := lowly;
IF lowly THEN RandomUsed := false
END;
IF RandomUsed THEN multiplier := multiplier + 1
ELSE multiplier := 2
END; {lower}
BEGIN
LowCand := 0;
FOR cand := 1 TO NumCandidates DO
IF (status[cand] = Hopeful) OR (status[cand] = Almost) THEN
IF lower(cand, LowCand) THEN LowCand := cand;
LowestCandidate := LowCand
END; {LowestCandidate}
PROCEDURE compute;
{This is the heart of the program, which counts the votes, taking
the current weights into account, and adjusts the weights and
the quota iteratively to attain the required solution}
{MaxIterations is the maximum number of iterations allowed in
calculating the weights. It is unlikely that so many will
ever be used, but its value may be increased if desired}
CONST MaxIterations = 500;
VAR temp, value: real;
count, iteration: integer;
cand: CandRange;
converged, ended: Boolean;
PROCEDURE Rewind;
{Returns to the beginning of datafile, and ignores the first two
numbers on it. These are the number of candidates and the
number of seats, whose values are not needed again. Numbers
indicating withdrawn candidates are also ignored}
VAR ig, ignore: integer;
BEGIN
reset (datafile);
FOR ig := -1 TO ignored DO ignore := InInteger
END; {Rewind}
BEGIN
iteration := 1;
REPEAT
Rewind;
excess := 0.0;
FOR cand := 1 TO NumCandidates DO votes[cand] := 0.0;
count := InInteger;
WHILE count > 0 DO
BEGIN
value := count;
cand := InInteger;
ended := false;
WHILE cand>0 DO
BEGIN
IF NOT ended AND (weight[cand] > 0.0) THEN
BEGIN
ended := (status[cand] = Hopeful);
IF ended THEN
BEGIN
votes[cand] := votes[cand] + value;
value := 0.0
END
ELSE
BEGIN
votes[cand] := votes[cand] + value * weight[cand];
value := value * (1.0 - weight[cand])
END
END;
cand := InInteger
END;
excess := excess + value;
count := InInteger
END;
quota := (total - excess) * Droop;
{The next statement is unlikely ever to be used, but is a
safeguard against certain pathological test data}
IF quota < 0.0001 THEN quota := 0.0001;
converged := true;
FOR cand := 1 TO NumCandidates DO
IF status[cand] = Elected THEN
BEGIN
temp := quota / votes[cand];
IF (temp > 1.00001) OR (temp < 0.99999) THEN
converged := false;
temp := weight[cand] * temp;
weight[cand] := temp;
{The next statement is unlikely ever to be used, but is
a safeguard agalast certaln pathological test data}
IF temp > 1.0 THEN weight[cand] := 1.0
END;
iteration := iteration + 1
UNTIL (iteration = MaxIterations) OR converged;
IF NOT converged THEN
BEGIN
{The "Failure to converge" message is unlikely ever to appear.
If it does, increasing MaxIterations will probably cure it}
writeln;
writeln;
writeln('Failure to converge');
writeln
END;
count := 0;
FOR cand := 1 TO NumCandidates DO
IF (status[cand] = Hopeful) AND (votes[cand] >= quota) THEN
BEGIN
status[cand] := Almost;
count := count + 1
END;
{Allow for the special case where there is a multi-way tie and
too many candidates reach the quota simultaneously}
WHILE NumElected + count > NumSeats DO
BEGIN
PrintOut;
RandomUsed := false;
FOR cand := 1 TO NumCandidates DO
IF status[cand] = Hopeful THEN exclude(cand);
exclude(LowestCandidate);
count := count - 1
END;
SomeoneElected := false;
FOR cand := 1 TO NumCandidates DO
IF status[cand] = Almost THEN
BEGIN
elect(cand);
SomeoneElected := true
END;
IF SomeoneElected THEN PrintOut;
FOR cand := 1 TO NumCandidates DO
IF status[cand] = NewlyElected THEN
BEGIN
IF NumElected < NumSeats THEN
weight[cand] := quota / votes[cand];
status[cand] := Elected
END
END; {compute}
PROCEDURE complete;
{Used to elect all remaining candidates if the number
remaining equals the number of seats remaining}
VAR cand: Candidates;
BEGIN
FOR cand := 1 TO NumCandidates DO
IF status[cand] = Hopeful THEN elect(cand)
END; {complete}
PROCEDURE Preliminaries;
{Checks datafile for errors and sets initial values of variables}
VAR cand, count, LineNo: integer;
PROCEDURE error(cand: integer; TooBig: Boolean);
BEGIN
writeln;
write ('On line ' , LineNo: 1, ', Candidate ', cand: 1);
IF TooBig THEN write (' exceeds maximum')
ELSE write (' is repeated');
writeln;
faulty := true
END; {error}
PROCEDURE ReadName(VAR n: name);
{Reads the name ot a candidate, or reads a title, and stores
it for later use. If the name has more than NameLength
characters the excess ones will be disregarded. If it
has fewer than NameLength characters blanks will be used
to extend it}
VAR i: integer;
ch: char;
BEGIN
REPEAT
read(datafile, ch)
UNTIL ch = '"';
i := 0;
read(datafile, ch);
WHILE ch <> '"' DO
BEGIN
IF i < NameLength THEN
BEGIN
i := i + 1;
n[i] := ch
END;
read(datafile, ch)
END;
WHILE i < NameLength DO
BEGIN
i := i + 1;
n[i] := ' '
END
END; {ReadName}
BEGIN
Droop := 1.0/(NumSeats + 1);
LineNo := 1;
seed1 := 0;
total := 0.0;
table := 0;
NumElected := 0;
NumExcluded := 0;
ignored := 0;
FOR cand := 1 TO NumCandidates DO weight[cand] := 1.0;
count := InInteger;
{Deal wlth withdrawals, if any}
WHILE count < 0 DO
BEGIN
weight[-count] := 0.0;
count := InInteger
END;
WHILE count > 0 DO
BEGIN
LineNo := LineNo + 1;
total := total + count;
FOR cand := 1 TO NumCandidates DO status[cand] := NotUsed;
cand := InInteger;
WHILE cand > 0 DO
BEGIN
IF cand > NumCandidates THEN error(cand, true)
ELSE IF status[cand] = Used THEN error(cand, false)
ELSE status[cand] := Used;
cand := InInteger
END;
count := InInteger
END;
FOR cand := 1 TO NumCandidates DO
BEGIN
ReadName(names[cand]);
status[cand] := Hopeful;
IF weight[cand] < 0.5 THEN
BEGIN
status[cand] := Excluded;
NumExcluded := NumExcluded + 1;
ignored := ignored + 1
END
END;
ReadName(title);
IF NOT faulty THEN
BEGIN
{FracDigits controls the number of digits beyond the decimal
point that will be printed in the output tables}
FracDigits := 4;
IF total > 999.5 THEN FracDigits := FracDigits - 1;
IF total > 99.5 THEN FracDigits := FracDigits - 1;
IF total > 9.5 THEN FracDigits := FracDigits - 1
END
END; {Preliminaries}
{Start of main program}
BEGIN
reset(datafile);
NumCandidates := InInteger;
NumSeats := InInteger;
writeln;
writeln;
writeln('Number of Candidates = ', NumCandidates: 1);
writeln ('Number of seats = ', NumSeats: 1);
IF NumCandidates < NumSeats THEN writeln('All candidates elected') ELSE
BEGIN
faulty := false;
Preliminaries;
IF NumCandidates <= NumSeats + NumExcluded THEN
writeln('All non-withdrawn candidates elected') ELSE
BEGIN
{The Preliminaries procedure will have reset faulty to true if
the data contain errors}
IF NOT faulty THEN
BEGIN
REPEAT
{Count votes and elect candidates, transferrlng
surpluses until no more can be done or all
seats are filled}
REPEAT
compute
UNTIL NOT SomeoneElected OR (NumElected >= NumSeats);
{Unless the election is finished, someone must
now be excluded}
IF NumElected < Numseats THEN
BEGIN
PrintOut;
exclude(LowestCandidate);
IF NumCandidates - NumExcluded = NumSeats
THEN complete ELSE PrintOut
END
UNTIL NumElected = NumSeats;
{Now that all seats are filled, exclude any candidates not
already elected, and print out the final table}
RandomUsed := false;
FOR candidate := 1 TO NumCandidates DO
IF status[candidate] = Hopeful THEN exclude(candidate);
PrintOut
END
END
END
END.
We prove in this section that the equations that need to be solved at each stage of Meek's method have a unique solution.
At each stage, each candidate is in one of three states, called ` elected', `excluded' and `hopeful'. It is explained in Section 2 how a candidate arrives in one of these states; but for the purposes of the formal proof it is irrelevant: we may suppose that each candidate is assigned to one of these states at random, subject to the condition that the number m of `elected' candidates is non-zero and does not exceed the number s of seats to be filled: 1 £ m £ s. We also require the following non-triviality condition: there is at least one ballot paper that contains the name of a `hopeful' candidate in its list of preferences. These conditions would certainly be fulfilled in a real election (in which no equation needs to be solved until some candidate is declared `elected').
Let the `elected' candidates be C1, ..., Cm. Let the weight assigned to candidate X (as in Section 2.3) be wx (0 £ wx £ 1). Since each `excluded' candidate always receives weight 0 and each `hopeful' candidate receives weight 1, the assigned weights are specified uniquely by the m-vector w = (w1, . . ., wm), in which wj is the weight assigned to Cj for each j (j = 1, . . ., m).
In the situation described by the m-vector w, let Vx(w) denote the vote for candidate X (that is, the sum of the part-votes that X receives from all the electors); for convenience, write VCj(w) as Vj(w). Let E(w) denote the total excess vote, and define the quota Q(w) to be (V-E(w))/(s+1), where V is the total number of votes (ballot papers). The effect of the non-triviality condition mentioned above is to ensure that Q(w) ³ 1/(s+ 1) > 0 for all w, since if a ballot paper contains the name of a `hopeful' candidate among its preferences then no part of that vote can be lost to the excess vote, and so V-E(w) ³ 1.
We shall make extensive use of the following facts, which are obvious from the above definitions and from Section 2.4, and in which we use the terms `increases' and `decreases' in the weak sense (that is, both terms correctly describe a number that does not change): if one component wj of w is decreased whilst all the other components are unchanged, then:
Let an m-vector w be called feasible if 0 £ wj £ 1 and Vj(w) ³ Q(w) for each j, and be called a solution vector if 0 £ wj £ 1 and Vj(w) = Q(w) for each j (j = 1, ..., m). The purpose of this section is to prove that if there is a feasible vector, then there is a unique solution vector. We note in passing that, in a real election, the existence of a feasible vector is assured, since the solution vector at each stage of the counting yields a feasible vector for the next stage.
We shall use the following algorithm which, starting with a feasible vector, will construct a solution vector. (This is the algorithm described in Section 2.9.)
Algorithm: Let w0 = (w01, ..., w0m ) be a feasible vector. Given wi, define wi+1 by the rule
|
for each j (j = 1, ..., m).
Theorem 1. This Algorithm constructs a sequence of feasible vectors that converges to a solution vector.
Proof. Suppose that wi is a feasible vector, so that Vj(wi) ³ Q(wi) > 0 and so wij > 0 for each j. Then to convert wi into wi+1 we must (weakly) decrease each of its components. Fix j, and let w¢ be the vector obtained from wi by replacing the one component wij by wi+1j. By (2), (1), (6) and (5),
|
|
This holds for each j, and so wi+1 is a feasible vector. Since w0 is feasible by hypothesis, it follows by induction that wi is feasible for all i.
It follows from this that, for each fixed j, the sequence
|
is a monotonic decreasing sequence that is bounded below (by 0), and so converges. Thus there is a limit vector w¥ = (w¥1,. ...., w¥m). We must prove that w¥ is a solution vector. By the feasibility of wi and (7),
|
|
since decreasing wj by d cannot decrease Vj(w) by more than Vd (V being the total number of ballot papers). But, as i ® ¥, wij-wi+1j ® 0, and since Vj(w) and Q(w) are continuous functions of w it follows that Vj(w¥) = Q(w¥). This holds for each j, and so w¥ is a solution vector, as required. [¯]
Theorem 2. The solution vector, whose existence was proved in Theorem 1, is unique.
Proof. Let w = (w¥1, ¼, w¥m) and w* = (w*1, ..., w*m) be two solution vectors and define w0 = (w01, ..., w0m) by
|
for each j. For a fixed j suppose without loss of generality that w0j = wj, and note that, by (2) and (5)
|
This holds for each j, and so w0 is a feasible vector. By Theorem 1 we can apply the Algorithm to w0 to construct a solution vector w¥ = (w¥0 ..., w¥m) such that
|
for each j. We shall prove that w¥ = w, from which it will immediately follow that w = w0 = w*, as required.
We prove first that Q(w¥) = Q(w). By (5), Q(w¥) £ Q(w). By the same argument that is used to derive (5) from (3),
|
|
|
since w and w¥ are both solution vectors. Since m £ s, Q(w)-Q(w¥) £ 0. Thus Q(w¥) = Q(w), and
|
for each j.
Finally, let S denote the set of candidates Cj (if any) for whom wj¥ < wj, and suppose that S is non-empty. Since wj¥ < 1 for each such j and Vj(w¥) = Q(w¥) > 0, it is not difficult to see (by considering each ballot paper) that the sum of the votes for all the candidates in S is a strictly increasing function of the weight assigned to each such candidate, and so must strictly increase when the vector w¥ is replaced by w. But this violates (8). So S must be empty and w¥ = w. This completes the proof that there can be at most one solution vector w. [¯]
Scanned and converted to LATEX, November 1999.
The second paragraph of section 4 states: there is at least one ballot paper that contains the name of a `hopeful' candidate in its list of preferences. The program does not check this! This error was corrected in the versions of Meek in actual use in 1999.
The program as published above produces quite voluminous output in relation to the standard `result sheet' that the Electoral Reform Society uses for STV elections. Versions of Meek used in real elections therefore summarise the output in some way - which can even be to produce a conventional result sheet.
1 Clinical Research Centre, Harrow, Middlesex, HA1 3UJ
2 5 Ellis Farm Close, Woking, GU22 9QN
3 Department of Mathematics, University of Nottingham, Nottingham NG7 2RD