Anti-Harassment Tools/SecurePoll Improvements/Test Results/20 6 5000 1048374110

Comments
Case: All but one seat filled, rest of candidates hopeful. All surplus votes transferred to candidate 17.

OpenSTV and SecurePoll agree on results.

Election setup

 * Candidates: 20
 * Seats: 6
 * Votes: 5000

Actual
Output from SecurePoll : array(3) { ["elected"]=> array(6) { [0]=>   int(2) [1]=>   int(4) [2]=>   int(6) [3]=>   int(8) [4]=>   int(19) [5]=>   int(17) } ["eliminated"]=> array(4) { [0]=>   int(12) [1]=>   int(10) [2]=>   int(15) [3]=>   int(5) } ["rounds"]=> array(4) { [0]=>   array(8) { ["round"]=> int(1) ["surplus"]=> int(0) ["rankings"]=> array(20) { [1]=>       array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }       [2]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(800) ["total"]=> int(800) }       [3]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }       [4]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(800) ["total"]=> int(800) }       [5]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(66) ["total"]=> int(66) }       [6]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(800) ["total"]=> int(800) }       [7]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }       [8]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(800) ["total"]=> int(800) }       [9]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }       [10]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(66) ["total"]=> int(66) }       [11]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }       [12]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(66) ["total"]=> int(66) }       [13]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }       [14]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }       [15]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(66) ["total"]=> int(66) }       [16]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }       [17]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(66) ["total"]=> int(66) }       [18]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }       [19]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(800) ["total"]=> int(800) }       [20]=>        array(3) { ["votes"]=> int(0) ["earned"]=> int(67) ["total"]=> int(67) }     }      ["totalVotes"]=> int(5000) ["keepFactors"]=> array(20) { [1]=>       int(1) [2]=>       int(1) [3]=>       int(1) [4]=>       int(1) [5]=>       int(1) [6]=>       int(1) [7]=>       int(1) [8]=>       int(1) [9]=>       int(1) [10]=>       int(1) [11]=>       int(1) [12]=>       int(1) [13]=>       int(1) [14]=>       int(1) [15]=>       int(1) [16]=>       int(1) [17]=>       int(1) [18]=>       int(1) [19]=>       int(1) [20]=>       int(1) }     ["quota"]=> int(715) ["elected"]=> array(0) { }     ["eliminated"]=> array(0) { }   }    [1]=>    array(8) { ["round"]=> int(2) ["elected"]=> array(5) { [0]=>       int(2) [1]=>       int(4) [2]=>       int(6) [3]=>       int(8) [4]=>       int(19) }     ["eliminated"]=> array(0) { }     ["surplus"]=> int(425) ["keepFactors"]=> array(20) { [1]=>       int(1) [2]=>       int(1) [3]=>       int(1) [4]=>       int(1) [5]=>       int(1) [6]=>       int(1) [7]=>       int(1) [8]=>       int(1) [9]=>       int(1) [10]=>       int(1) [11]=>       int(1) [12]=>       int(1) [13]=>       int(1) [14]=>       int(1) [15]=>       int(1) [16]=>       int(1) [17]=>       int(1) [18]=>       int(1) [19]=>       int(1) [20]=>       int(1) }     ["quota"]=> int(715) ["rankings"]=> array(20) { [1]=>       array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [2]=>        array(3) { ["votes"]=> int(800) ["earned"]=> int(0) ["total"]=> int(800) }       [3]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [4]=>        array(3) { ["votes"]=> int(800) ["earned"]=> int(0) ["total"]=> int(800) }       [5]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(0) ["total"]=> int(66) }       [6]=>        array(3) { ["votes"]=> int(800) ["earned"]=> int(0) ["total"]=> int(800) }       [7]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [8]=>        array(3) { ["votes"]=> int(800) ["earned"]=> int(0) ["total"]=> int(800) }       [9]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [10]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(0) ["total"]=> int(66) }       [11]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [12]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(0) ["total"]=> int(66) }       [13]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [14]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [15]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(0) ["total"]=> int(66) }       [16]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [17]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(0) ["total"]=> int(66) }       [18]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [19]=>        array(3) { ["votes"]=> int(800) ["earned"]=> int(0) ["total"]=> int(800) }       [20]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }     }      ["totalVotes"]=> int(5000) }   [2]=>    array(8) { ["round"]=> int(3) ["elected"]=> array(0) { }     ["eliminated"]=> array(4) { [0]=>       int(12) [1]=>       int(10) [2]=>       int(15) [3]=>       int(5) }     ["surplus"]=> float(0) ["keepFactors"]=> array(20) { [1]=>       int(1) [2]=>       float(0.89375) [3]=>       int(1) [4]=>       float(0.89375) [5]=>       int(1) [6]=>       float(0.89375) [7]=>       int(1) [8]=>       float(0.89375) [9]=>       int(1) [10]=>       int(1) [11]=>       int(1) [12]=>       int(1) [13]=>       int(1) [14]=>       int(1) [15]=>       int(1) [16]=>       int(1) [17]=>       int(1) [18]=>       int(1) [19]=>       float(0.89375) [20]=>       int(1) }     ["quota"]=> int(715) ["rankings"]=> array(20) { [1]=>       array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [2]=>        array(3) { ["votes"]=> int(800) ["earned"]=> float(-85) ["total"]=> float(715) }       [3]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [4]=>        array(3) { ["votes"]=> int(800) ["earned"]=> float(-85) ["total"]=> float(715) }       [5]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(0) ["total"]=> int(66) }       [6]=>        array(3) { ["votes"]=> int(800) ["earned"]=> float(-85) ["total"]=> float(715) }       [7]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [8]=>        array(3) { ["votes"]=> int(800) ["earned"]=> float(-85) ["total"]=> float(715) }       [9]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [10]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(0) ["total"]=> int(66) }       [11]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [12]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(0) ["total"]=> int(66) }       [13]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [14]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [15]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(0) ["total"]=> int(66) }       [16]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [17]=>        array(3) { ["votes"]=> int(66) ["earned"]=> float(425) ["total"]=> float(491) }       [18]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [19]=>        array(3) { ["votes"]=> int(800) ["earned"]=> float(-85) ["total"]=> float(715) }       [20]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }     }      ["totalVotes"]=> float(5000) }   [3]=>    array(8) { ["round"]=> int(4) ["elected"]=> array(1) { [4]=>       int(17) }     ["eliminated"]=> array(0) { }     ["surplus"]=> float(40) ["keepFactors"]=> array(20) { [1]=>       int(1) [2]=>       float(0.89375) [3]=>       int(1) [4]=>       float(0.89375) [5]=>       int(0) [6]=>       float(0.89375) [7]=>       int(1) [8]=>       float(0.89375) [9]=>       int(1) [10]=>       int(0) [11]=>       int(1) [12]=>       int(0) [13]=>       int(1) [14]=>       int(1) [15]=>       int(0) [16]=>       int(1) [17]=>       int(1) [18]=>       int(1) [19]=>       float(0.89375) [20]=>       int(1) }     ["quota"]=> int(715) ["rankings"]=> array(20) { [1]=>       array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [2]=>        array(3) { ["votes"]=> float(715) ["earned"]=> float(0) ["total"]=> float(715) }       [3]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [4]=>        array(3) { ["votes"]=> float(715) ["earned"]=> float(0) ["total"]=> float(715) }       [5]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(-66) ["total"]=> int(0) }       [6]=>        array(3) { ["votes"]=> float(715) ["earned"]=> float(0) ["total"]=> float(715) }       [7]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [8]=>        array(3) { ["votes"]=> float(715) ["earned"]=> float(0) ["total"]=> float(715) }       [9]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [10]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(-66) ["total"]=> int(0) }       [11]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [12]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(-66) ["total"]=> int(0) }       [13]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [14]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [15]=>        array(3) { ["votes"]=> int(66) ["earned"]=> int(-66) ["total"]=> int(0) }       [16]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [17]=>        array(3) { ["votes"]=> float(491) ["earned"]=> float(264) ["total"]=> float(755) }       [18]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }       [19]=>        array(3) { ["votes"]=> float(715) ["earned"]=> float(0) ["total"]=> float(715) }       [20]=>        array(3) { ["votes"]=> int(67) ["earned"]=> int(0) ["total"]=> int(67) }     }      ["totalVotes"]=> float(5000) } } }

Elected
Election for 6 seats with 20 candidates. Total 5,000 votes.


 * 1) "2"
 * 2) "4"
 * 3) "6"
 * 4) "8"
 * 5) "19"
 * 6) "17"

Eliminated/Not elected

 * "12"
 * "10"
 * "15"
 * "5"
 * "1"
 * "3"
 * "7"
 * "9"
 * "11"
 * "13"
 * "14"
 * "16"
 * "18"
 * "20"

Rounds table
The following table describes the calculations that happened in order to achieve the result above. In each round of calculation, the candidate(s) who achieved more votes than the quota are declared elected. Their surplus votes above the quota are redistributed to the remaining candidates. If nobody achieves the quota, the lowest ranking candidate is eliminated and their votes are redistributed to the remaining candidates. To understand this better, please refer to this link. (Results from 14:25, 31 August 2021)

Expected
Output from OpenSTV: Loading ballots from file 20_6_5000_1048374110.blt. Ballot file contains 20 candidates and 5000 ballots. No candidates have withdrawn. Ballot file contains 5000 non-empty ballots.

Counting votes for ElectionTitle using Meek STV. 20 candidates running for 6 seats.

R|1         |2          |3          |4          |5          |6 |---+---+---+---+---+--- |7          |8          |9          |10         |11         |12           |---+---+---+---+---+---  |13         |14         |15         |16         |17         |18           |---+---+---+---+---+---  |19         |20         |Exhausted  |Surplus    |Threshold

=
============================================================= 1| 67.000000| 800.000000|  67.000000| 800.000000|  66.000000| 800.000000  |  67.000000| 800.000000|  67.000000|  66.000000|  67.000000|  66.000000  |  67.000000|  67.000000|  66.000000|  67.000000|  66.000000|  67.000000  | 800.000000|  67.000000|   0.000000| 428.571425| 714.285715  |---  | Count of first choices. Candidates 2, 4, 6, 8, and 19 have reached the | threshold and are elected.

=
============================================================= 2| 67.000000| 714.286400|  67.000000| 714.286400|  66.000000| 714.286400  |  67.000000| 714.286400|  67.000000|  66.000000|  67.000000|  66.000000  |  67.000000|  67.000000|  66.000000|  67.000000| 494.568000|  67.000000  | 714.286400|  67.000000|   0.000000|   0.003425| 714.285715  |---  | Count after transferring surplus votes. Keep factors of candidates who | have exceeded the threshold: 2, 0.892858; 4, 0.892858; 6, 0.892858; 8, | 0.892858; and 19, 0.892858.

=
============================================================= 3| 67.000000| 714.286400|  67.000000| 714.286400|  66.000000| 714.286400  |  67.000000| 714.286400|  67.000000|  66.000000|  67.000000|  66.000000  |  67.000000|  67.000000|  66.000000|  67.000000| 494.568000|  67.000000  | 714.286400|  67.000000|   0.000000|   0.003425| 714.285715  |---  | Count after transferring surplus votes. Keep factors of candidates who | have exceeded the threshold: 2, 0.892858; 4, 0.892858; 6, 0.892858; 8, | 0.892858; and 19, 0.892858.

=
============================================================= 4| 67.000000| 714.286400|  67.000000| 714.286400|           | 714.286400  |  67.000000| 714.286400|  67.000000|  66.000000|  67.000000|  66.000000  |  67.000000|  67.000000|  66.000000|  67.000000| 560.568000|  67.000000  | 714.286400|  67.000000|   0.000000|   0.003425| 714.285715  |---  | Count after eliminating 5 and transferring votes. Candidates tied | within precision of computations. Candidates 5, 10, 12, and 15 were | tied when choosing candidates to eliminate. Candidate 5 was chosen by | breaking the tie randomly.

=
============================================================= 5| 67.000000| 714.286400|  67.000000| 714.286400|           | 714.286400  |  67.000000| 714.286400|  67.000000|  66.000000|  67.000000|  66.000000  |  67.000000|  67.000000|  66.000000|  67.000000| 560.568000|  67.000000  | 714.286400|  67.000000|   0.000000|   0.003425| 714.285715  |---  | Count after transferring surplus votes. Keep factors of candidates who | have exceeded the threshold: 2, 0.892858; 4, 0.892858; 6, 0.892858; 8, | 0.892858; and 19, 0.892858.

=
============================================================= 6| 67.000000| 714.286400|  67.000000| 714.286400|           | 714.286400  |  67.000000| 714.286400|  67.000000|           |  67.000000|  66.000000  |  67.000000|  67.000000|  66.000000|  67.000000| 626.568000|  67.000000  | 714.286400|  67.000000|   0.000000|   0.003425| 714.285715  |---  | Count after eliminating 10 and transferring votes. Candidates tied | within precision of computations. Candidates 10, 12, and 15 were tied | when choosing candidates to eliminate. Candidate 10 was chosen by | breaking the tie randomly.

=
============================================================= 7| 67.000000| 714.286400|  67.000000| 714.286400|           | 714.286400  |  67.000000| 714.286400|  67.000000|           |  67.000000|  66.000000  |  67.000000|  67.000000|  66.000000|  67.000000| 626.568000|  67.000000  | 714.286400|  67.000000|   0.000000|   0.003425| 714.285715  |---  | Count after transferring surplus votes. Keep factors of candidates who | have exceeded the threshold: 2, 0.892858; 4, 0.892858; 6, 0.892858; 8, | 0.892858; and 19, 0.892858.

=
============================================================= 8| 67.000000| 714.286400|  67.000000| 714.286400|           | 714.286400  |  67.000000| 714.286400|  67.000000|           |  67.000000|             |  67.000000|  67.000000|  66.000000|  67.000000| 692.568000|  67.000000  | 714.286400|  67.000000|   0.000000|   0.003425| 714.285715  |---  | Count after eliminating 12 and transferring votes. Candidates tied | within precision of computations. Candidates 12 and 15 were tied when | choosing candidates to eliminate. Candidate 12 was chosen by breaking | the tie randomly.

=
============================================================= 9| 67.000000| 714.286400|  67.000000| 714.286400|           | 714.286400  |  67.000000| 714.286400|  67.000000|           |  67.000000|             |  67.000000|  67.000000|           |  67.000000| 758.568000|  67.000000  | 714.286400|  67.000000|   0.000000|  44.285710| 714.285715  |---  | Count after eliminating 15 and transferring votes. All losing | candidates are eliminated. Candidate 17 has reached the threshold and | is elected.

Winners are 2, 4, 6, 8, 17, and 19.

Files
array ( 7 =>   array ( 'count' => 67, 'rank' => array (     1 => 7,    ), ), '6_17' =>   array ( 'count' => 800, 'rank' => array (     1 => 6,      2 => 17,    ), ), '5_17' =>   array ( 'count' => 66, 'rank' => array (     1 => 5,      2 => 17,    ), ), '12_17' =>   array ( 'count' => 66, 'rank' => array (     1 => 12,      2 => 17,    ), ), 14 =>   array ( 'count' => 67, 'rank' => array (     1 => 14,    ), ), '8_17' =>   array ( 'count' => 800, 'rank' => array (     1 => 8,      2 => 17,    ), ), '2_17' =>   array ( 'count' => 800, 'rank' => array (     1 => 2,      2 => 17,    ), ), 16 =>   array ( 'count' => 67, 'rank' => array (     1 => 16,    ), ), 18 =>   array ( 'count' => 67, 'rank' => array (     1 => 18,    ), ), 17 =>   array ( 'count' => 66, 'rank' => array (     1 => 17,    ), ), 1 =>   array ( 'count' => 67, 'rank' => array (     1 => 1,    ), ), '15_17' =>   array ( 'count' => 66, 'rank' => array (     1 => 15,      2 => 17,    ), ), 11 =>   array ( 'count' => 67, 'rank' => array (     1 => 11,    ), ), 20 =>   array ( 'count' => 67, 'rank' => array (     1 => 20,    ), ), '4_17' =>   array ( 'count' => 800, 'rank' => array (     1 => 4,      2 => 17,    ), ), 13 =>   array ( 'count' => 67, 'rank' => array (     1 => 13,    ), ), 9 =>   array ( 'count' => 67, 'rank' => array (     1 => 9,    ), ), '10_17' =>   array ( 'count' => 66, 'rank' => array (     1 => 10,      2 => 17,    ), ), 3 =>   array ( 'count' => 67, 'rank' => array (     1 => 3,    ), ), '19_17' =>   array ( 'count' => 800, 'rank' => array (     1 => 19,      2 => 17,    ), ), )
 * blt: https://github.com/dominic998/SecurePoll-Test-Data/blob/main/test_data/20_6_5000_1048374110.blt
 * php:

Environment

 * Where you tested: local docker using phpunit
 * Version of SecurePoll: commit 271145d5f3cae3b0a1b76d0f5dfeb609615d60b7 (patch 16 from https://gerrit.wikimedia.org/r/c/mediawiki/extensions/SecurePoll/+/704454/)