Implement WA STV and update documentation
This commit is contained in:
parent
2ef7bf24f2
commit
3ea1eef7c5
@ -4,18 +4,31 @@
|
||||
|
||||
The preset dropdown allows you to choose from a hardcoded list of preloaded STV counting rules. These are:
|
||||
|
||||
* *OpenTally WIGM*: A recommended set of simple STV rules designed for computer counting, using the weighted inclusive Gregory method and rational arithmetic.
|
||||
* *Scottish STV*: Rules from the [*Scottish Local Government Elections Order 2011*](https://www.legislation.gov.uk/ssi/2011/399/schedule/1/made), using the weighted inclusive Gregory method. Validated against the [2007 Scottish local government election result for Linn ward](https://web.archive.org/web/20121004213938/http://www.glasgow.gov.uk/en/YourCouncil/Elections_Voting/Election_Results/ElectionScotland2007/LGWardResults.htm?ward=1&wardname=1%20-%20Linn).
|
||||
* [*Meek STV*](http://www.dia.govt.nz/diawebsite.NSF/Files/meekm/%24file/meekm.pdf): Advanced STV rules designed for computer counting, recognised by the Proportional Representation Society of Australia (Victoria–Tasmania) as the superior STV system.
|
||||
* *Meek STV (1987)* operates according to the original Hill–Wichmann–Woodall [‘Algorithm 123’](https://www.dia.govt.nz/diawebsite.NSF/Files/meekm/%24file/meekm.pdf) specification of Meek STV, with the modifications, relevant only in exceptional cases, that (a) fixed-point arithmetic with 5 decimal places is used, and (b) candidates are elected on strictly exceeding the quota. Validated against the Hill–Wichmann–Woodall implementation for ballot papers [derived from the ERS97 model election](https://yingtongli.me/blog/2021/01/04/ers97.html).
|
||||
* *Meek STV (2006)* operates according to [Hill's 2006 revisions](http://www.votingmatters.org.uk/ISSUE22/I22P2.pdf). This is the algorithm referred to in OpenSTV/OpaVote as ‘Meek STV’, and forms the basis of New Zealand's Meek STV rules. Validated against OpenSTV 1.7 for the ERS97 model election.
|
||||
* *Meek STV (New Zealand)* operates according to Schedule 1A of the [*Local Electoral Regulations 2001*](https://www.legislation.govt.nz/regulation/public/2001/0145/latest/DLM57125.html). Validated against OpenSTV 1.7, and Hill's nzmeek version 6.7.7, for the ERS97 model election.
|
||||
* *Australian Senate STV*: Rules from the [*Commonwealth Electoral Act 1918*](https://www.legislation.gov.au/Details/C2020C00400/Html/Text#_Toc59107700), using the unweighted inclusive Gregory method. Validated against the [2019 Australian Senate election result for Tasmania](https://results.aec.gov.au/24310/Website/SenateDownloadsMenu-24310-Csv.htm).
|
||||
* [*Wright STV*](https://www.aph.gov.au/Parliamentary_Business/Committees/House_of_Representatives_Committees?url=em/elect07/subs/sub051.1.pdf): Rules proposed by Anthony van der Craats designed for computer counting, involving reset and re-iteration of the count after each candidate exclusion. Validated against the [EVE Online reference implementation](https://github.com/ccpgames/ccp-wright-stv) for the [CSM 15 election](https://www.eveonline.com/news/view/meet-the-new-council).
|
||||
* [*PRSA 1977*](https://www.prsa.org.au/rule1977.htm): Simple rules designed for hand counting, using the exclusive Gregory method, with counting automatically performed in thousandths of a vote. Validated against [example 1](https://www.prsa.org.au/example1.pdf) of the PRSA's [*Proportional Representation Manual*](https://www.prsa.org.au/publicat.htm#p2).
|
||||
* [*ERS97*](https://www.electoral-reform.org.uk/latest-news-and-research/publications/how-to-conduct-an-election-by-the-single-transferable-vote-3rd-edition/): More complex rules designed for hand counting, using the exclusive Gregory method. Validated against the ERS97 model election.
|
||||
* *ERS76*: Former rules from the 1976 2nd edition. The quota is always calculated to 2 decimal places – for full ERS76 compliance, set *Round quota to 0 d.p.* when the quota is more than 100.
|
||||
* *ERS73*: Former rules from the 1973 1st edition. The quota is always calculated to 2 decimal places – for full ERS73 compliance, set *Round quota to 0 d.p.* when the quota is 100 or more.
|
||||
<table>
|
||||
<tr><th>Method</th><th>Description</th><th>Exceptions</th><th>Validated against</th></tr>
|
||||
<tr><td>OpenTally WIGM</td><td>A recommended set of simple STV rules designed for computer counting, using the weighted inclusive Gregory method and rational arithmetic.</td><td></td><td></td></tr>
|
||||
<tr><td>Scottish STV</td><td>Rules from the <a href="https://www.legislation.gov.uk/ssi/2011/399/schedule/1/made"><i>Scottish Local Government Elections Order 2011</i></a>, using the weighted inclusive Gregory method.</td><td></td><td><a href="https://web.archive.org/web/20121004213938/http://www.glasgow.gov.uk/en/YourCouncil/Elections_Voting/Election_Results/ElectionScotland2007/LGWardResults.htm?ward=1&wardname=1%20-%20Linn">2007 Linn ward local election</a> (eSTV 2.0.16)</td></tr>
|
||||
<tr><td>Meek STV</td><td>Advanced STV rules designed for computer counting, recognised by the Proportional Representation Society of Australia (Victoria–Tasmania) as the superior STV system.</td><td></td><td></td></tr>
|
||||
<tr><td>• OpenTally Meek</td><td>Operates according to the original 1987 Hill–Wichmann–Woodall <a href="https://www.dia.govt.nz/diawebsite.NSF/Files/meekm/%24file/meekm.pdf">‘Algorithm 123’</a> specification of Meek STV, except that (a) ties are broken backwards then at random, (b) fixed-point arithmetic with 5 decimal places is used, and (c) candidates are elected on strictly exceeding the quota.</td><td></td><td><a href="https://yingtongli.me/blog/2021/01/04/ers97.html">Ballot papers derived from the ERS97 model election</a> (Hill–Wichmann–Woodall implementation)</td></tr>
|
||||
<tr><td>• Meek STV (2006)</td><td>Operates according to <a href="http://www.votingmatters.org.uk/ISSUE22/I22P2.pdf">Hill's 2006 revisions</a>. This is the algorithm referred to in OpenSTV/OpaVote as ‘Meek STV’, and forms the basis of New Zealand's Meek STV rules.</td><td>[E1]</td><td><a href="https://yingtongli.me/blog/2021/01/04/ers97.html">Ballot papers derived from the ERS97 model election</a> (<a href="https://github.com/Conservatory/openstv">OpenSTV 1.7</a>)</td></tr>
|
||||
<tr><td>• Meek STV (New Zealand)</td><td>Operates according to Schedule 1A of the <a href="https://www.legislation.govt.nz/regulation/public/2001/0145/latest/DLM57125.html"><i>Local Electoral Regulations 2001</i></a>.</td><td>[E1]</td><td><a href="https://yingtongli.me/blog/2021/01/04/ers97.html">Ballot papers derived from the ERS97 model election</a> (OpenSTV 1.7, <a href="https://yingtongli.me/blog/2021/07/08/nzmeek.html">Hill's nzmeek 6.7.7</a>)</td></tr>
|
||||
<tr><td>Australian Senate STV</td><td>Rules from the <a href="https://www.legislation.gov.au/Details/C2020C00400/Html/Text#_Toc59107700"><i>Commonwealth Electoral Act 1918</i></a>, using the unweighted inclusive Gregory method.</td><td>[E2] [E3]</td><td><a href="https://results.aec.gov.au/24310/Website/SenateDownloadsMenu-24310-Csv.htm">2019 Tasmanian Senate election</a> (AEC EasyCount)</td></tr>
|
||||
<tr><td>Western Australia STV</td><td>Rules from the <a href="https://www.legislation.wa.gov.au/legislation/prod/filestore.nsf/FileURL/mrdoc_29498.pdf/$FILE/Electoral Act 1907 - [17-a0-06].pdf"><i>Electoral Act 1907</i> (WA)</a>, using the weighted inclusive Gregory method.</td><td>[E2] [E3]</td><td></td></tr>
|
||||
<tr><td><a href="https://www.aph.gov.au/Parliamentary_Business/Committees/House_of_Representatives_Committees?url=em/elect07/subs/sub051.1.pdf">Wright STV</a></td><td>Rules proposed by Anthony van der Craats designed for computer counting, involving reset and re-iteration of the count after each candidate exclusion.</td><td></td><td><a href="https://www.eveonline.com/news/view/meet-the-new-council">EVE Online CSM 15 election</a> (<a href="https://github.com/ccpgames/ccp-wright-stv">EVE reference implementation</a>)</td></tr>
|
||||
<tr><td><a href="https://www.prsa.org.au/rule1977.htm">PRSA 1977</a></td><td>Simple rules designed for hand counting, using the exclusive Gregory method, with counting performed in thousandths of a vote.</td><td></td><td><a href="https://www.prsa.org.au/example1.pdf">Example 1</a> of the PRSA's <a href="https://www.prsa.org.au/publicat.htm#p2"><i>Proportional Representation Manual</i></a></td></tr>
|
||||
<tr><td><a href="https://www.electoral-reform.org.uk/latest-news-and-research/publications/how-to-conduct-an-election-by-the-single-transferable-vote-3rd-edition/">ERS97</a></td><td>More complex rules designed for hand counting, using the exclusive Gregory method.</td><td></td><td><a href="https://yingtongli.me/blog/2021/01/04/ers97.html">Ballot papers derived from the ERS97 model election</a></td></tr>
|
||||
<tr><td>• ERS76</td><td>Former rules from the 1976 2nd edition.</td><td>[E4]</td><td></td></tr>
|
||||
<tr><td>• ERS73</td><td>Former rules from the 1973 1st edition.</td><td>[E4]</td><td></td></tr>
|
||||
<tr><td>Church of England</td><td>Rules from the Church of England <a href="https://www.churchofengland.org/sites/default/files/2020-02/STV Rules 2020 - final.pdf"><i>Single Transferable Vote Rules 2020</i></a>, similar to ERS73.</td><td></td><td></td></tr>
|
||||
</table>
|
||||
|
||||
[E1]: When generating random numbers, OpenTally uses a [deterministic random number generator based on SHA-256](rng.md), rather than the Wichmann–Hill(-based) algorithm.
|
||||
|
||||
[E2]: When breaking ties forwards/backwards, OpenTally selects the candidate who had more/fewer votes at the first/last stage when *any* tied candidate had more/fewer votes than the others, rather than when each all had unequal votes.
|
||||
|
||||
[E3]: A tie between 2 candidates for the final vacancy will be broken backwards then at random, rather than the method described in the legislation.
|
||||
|
||||
[E4]: The quota is always calculated to 2 decimal places. For full ERS76 (ERS73) compliance, set *Round quota to 0 d.p.* when the quota is more than 100 (100 or more).
|
||||
|
||||
This functionality is not available on the command line.
|
||||
|
||||
@ -202,12 +215,12 @@ When *Surplus method* is set to *Meek method*:
|
||||
* --round-tvs instead controls the rounding of each intermediate product when computing candidates' votes
|
||||
* --round-votes controls the rounding of the final number of votes credited to each candidate
|
||||
|
||||
### Sum surplus transfers (--sum-surplus-transfers)
|
||||
### (Gregory) Sum surplus transfers (--sum-surplus-transfers)
|
||||
|
||||
This option allows you to specify how the numbers of votes credited to candidates in a surplus transfer is calculated. In each case, votes are grouped according to the next available preference for a continuing candidate. Subsequently:
|
||||
|
||||
* *Single step*: The total value of all votes expressing a next available preference for that candidate is multiplied by the surplus fraction. The product is credited to that candidate.
|
||||
* *By value*: The votes expressing a next available preference for that candidate are further divided according to value. For each group of votes at a particular value, the total value of all such votes is multiplied by the surplus fraction. The product is credited to that candidate.
|
||||
* *By value*: The votes expressing a next available preference for that candidate are further divided according to value. For each group of votes at a particular value, the total value of all such votes is multiplied by the surplus fraction. The product is credited to that candidate. This is distinct to *Single step* only for weighted inclusive Gregory.
|
||||
* *Per ballot*: For each individual vote expressing a next available preference for that candidate, the value of the vote is multiplied by the surplus fraction. The product is credited to that candidate.
|
||||
|
||||
This option affects the result only insofar as rounding (due to use of fixed-precision arithmetic, or due to an explicit rounding option) is concerned.
|
||||
|
@ -38,17 +38,19 @@
|
||||
<optgroup label="Recommended methods">
|
||||
<option value="wigm" selected>OpenTally WIGM</option>
|
||||
<option value="scottish">Scottish STV</option>
|
||||
<option value="meek87">Meek STV (1987)</option>
|
||||
<option value="meek87">OpenTally Meek</option>
|
||||
</optgroup>
|
||||
<optgroup label="Other methods">
|
||||
<option value="meek06">Meek STV (2006)</option>
|
||||
<option value="meeknz">Meek STV (New Zealand)</option>
|
||||
<option value="senate">Australian Senate STV</option>
|
||||
<option value="wa">Western Australia STV</option>
|
||||
<option value="wright">Wright STV</option>
|
||||
<option value="prsa77">PRSA 1977</option>
|
||||
<option value="ers97">ERS97</option>
|
||||
<option value="ers76">ERS76</option>
|
||||
<option value="ers73">ERS73</option>
|
||||
<option value="cofe">Church of England</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</label>
|
||||
@ -247,6 +249,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<label class="col-12">
|
||||
<span class="pill-grey" title="This option has effect only if “Method” is a Gregory method">Gregory</span>
|
||||
Sum surplus transfers:
|
||||
<select id="selSumTransfers">
|
||||
<option value="single_step" selected>Single step</option>
|
||||
|
@ -435,7 +435,7 @@ function changePreset() {
|
||||
document.getElementById('selTransfers').value = 'meek';
|
||||
document.getElementById('selPapers').value = 'both';
|
||||
document.getElementById('selExclusion').value = 'single_stage';
|
||||
document.getElementById('selTies').value = 'backwards,random';
|
||||
document.getElementById('selTies').value = 'forwards,random';
|
||||
} else if (document.getElementById('selPreset').value === 'meeknz') {
|
||||
document.getElementById('selQuotaCriterion').value = 'geq';
|
||||
document.getElementById('selQuota').value = 'droop';
|
||||
@ -463,7 +463,7 @@ function changePreset() {
|
||||
document.getElementById('selTransfers').value = 'meek';
|
||||
document.getElementById('selPapers').value = 'both';
|
||||
document.getElementById('selExclusion').value = 'single_stage';
|
||||
document.getElementById('selTies').value = 'backwards,random';
|
||||
document.getElementById('selTies').value = 'forwards,random';
|
||||
} else if (document.getElementById('selPreset').value === 'senate') {
|
||||
document.getElementById('selQuotaCriterion').value = 'geq';
|
||||
document.getElementById('selQuota').value = 'droop';
|
||||
@ -487,6 +487,29 @@ function changePreset() {
|
||||
document.getElementById('selPapers').value = 'both';
|
||||
document.getElementById('selExclusion').value = 'by_value';
|
||||
document.getElementById('selTies').value = 'backwards,random';
|
||||
} else if (document.getElementById('selPreset').value === 'wa') {
|
||||
document.getElementById('selQuotaCriterion').value = 'geq';
|
||||
document.getElementById('selQuota').value = 'droop';
|
||||
document.getElementById('selQuotaMode').value = 'static';
|
||||
document.getElementById('chkBulkElection').checked = true;
|
||||
document.getElementById('chkBulkExclusion').checked = false;
|
||||
document.getElementById('chkDeferSurpluses').checked = false;
|
||||
document.getElementById('selNumbers').value = 'fixed';
|
||||
document.getElementById('txtDP').value = '5';
|
||||
document.getElementById('txtPPDP').value = '0';
|
||||
document.getElementById('chkNormaliseBallots').checked = false;
|
||||
document.getElementById('chkRoundQuota').checked = true;
|
||||
document.getElementById('txtRoundQuota').value = '0';
|
||||
document.getElementById('chkRoundVotes').checked = true;
|
||||
document.getElementById('txtRoundVotes').value = '0';
|
||||
document.getElementById('chkRoundTVs').checked = false;
|
||||
document.getElementById('chkRoundWeights').checked = false;
|
||||
document.getElementById('selSumTransfers').value = 'by_value';
|
||||
document.getElementById('selSurplus').value = 'by_order';
|
||||
document.getElementById('selTransfers').value = 'wig';
|
||||
document.getElementById('selPapers').value = 'both';
|
||||
document.getElementById('selExclusion').value = 'by_source';
|
||||
document.getElementById('selTies').value = 'backwards,random';
|
||||
} else if (document.getElementById('selPreset').value === 'wright') {
|
||||
document.getElementById('selQuotaCriterion').value = 'geq';
|
||||
document.getElementById('selQuota').value = 'droop';
|
||||
@ -609,5 +632,30 @@ function changePreset() {
|
||||
document.getElementById('selPapers').value = 'transferable';
|
||||
document.getElementById('selExclusion').value = 'by_value';
|
||||
document.getElementById('selTies').value = 'forwards,random';
|
||||
} else if (document.getElementById('selPreset').value === 'cofe') {
|
||||
document.getElementById('selQuotaCriterion').value = 'geq';
|
||||
document.getElementById('selQuota').value = 'droop';
|
||||
document.getElementById('selQuotaMode').value = 'static';
|
||||
document.getElementById('chkBulkElection').checked = true;
|
||||
document.getElementById('chkBulkExclusion').checked = false;
|
||||
document.getElementById('chkDeferSurpluses').checked = true;
|
||||
document.getElementById('selNumbers').value = 'fixed';
|
||||
document.getElementById('txtDP').value = '5';
|
||||
document.getElementById('txtPPDP').value = '2';
|
||||
document.getElementById('chkNormaliseBallots').checked = false;
|
||||
document.getElementById('chkRoundQuota').checked = true;
|
||||
document.getElementById('txtRoundQuota').value = '2';
|
||||
document.getElementById('chkRoundVotes').checked = true;
|
||||
document.getElementById('txtRoundVotes').value = '2';
|
||||
document.getElementById('chkRoundTVs').checked = true;
|
||||
document.getElementById('txtRoundTVs').value = '2';
|
||||
document.getElementById('chkRoundWeights').checked = true;
|
||||
document.getElementById('txtRoundWeights').value = '2';
|
||||
document.getElementById('selSumTransfers').value = 'per_ballot';
|
||||
document.getElementById('selSurplus').value = 'by_size';
|
||||
document.getElementById('selTransfers').value = 'eg';
|
||||
document.getElementById('selPapers').value = 'transferable';
|
||||
document.getElementById('selExclusion').value = 'by_value';
|
||||
document.getElementById('selTies').value = 'forwards,random';
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ struct STV {
|
||||
#[clap(help_heading=Some("ROUNDING"), long, value_name="dps")]
|
||||
round_quota: Option<usize>,
|
||||
|
||||
/// How to calculate votes to credit to candidates in surplus transfers
|
||||
/// (Gregory STV) How to calculate votes to credit to candidates in surplus transfers
|
||||
#[clap(help_heading=Some("ROUNDING"), long, possible_values=&["single_step", "by_value", "per_ballot"], default_value="single_step", value_name="mode")]
|
||||
sum_surplus_transfers: String,
|
||||
|
||||
@ -122,15 +122,15 @@ struct STV {
|
||||
#[clap(help_heading=Some("STV VARIANTS"), short='s', long, possible_values=&["wig", "uig", "eg", "meek"], default_value="wig", value_name="method")]
|
||||
surplus: String,
|
||||
|
||||
/// Order to distribute surpluses
|
||||
/// (Gregory STV) Order to distribute surpluses
|
||||
#[clap(help_heading=Some("STV VARIANTS"), long, possible_values=&["by_size", "by_order"], default_value="by_size", value_name="order")]
|
||||
surplus_order: String,
|
||||
|
||||
/// Examine only transferable papers during surplus distributions
|
||||
/// (Gregory STV) Examine only transferable papers during surplus distributions
|
||||
#[clap(help_heading=Some("STV VARIANTS"), long)]
|
||||
transferable_only: bool,
|
||||
|
||||
/// Method of exclusions
|
||||
/// (Gregory STV) Method of exclusions
|
||||
#[clap(help_heading=Some("STV VARIANTS"), long, possible_values=&["single_stage", "by_value", "by_source", "parcels_by_order", "wright"], default_value="single_stage", value_name="method")]
|
||||
exclusion: String,
|
||||
|
||||
|
@ -745,6 +745,7 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
|
||||
} else {
|
||||
if opts.early_bulk_elect && state.num_elected + 1 == state.election.seats {
|
||||
// Early bulk election and one seat remains: VRE is majority of total active vote
|
||||
// FIXME: This probably conflicts with constraints in some cases
|
||||
update_vre(state, opts);
|
||||
} else {
|
||||
// No use of VRE
|
||||
@ -1005,6 +1006,7 @@ where
|
||||
|
||||
if opts.early_bulk_elect {
|
||||
// Determine if the proposed exclusion would enable a bulk election
|
||||
// See comment in exclude_hopefuls as to constraints
|
||||
if can_bulk_elect(state, excluded_candidates.len()) {
|
||||
// Exclude candidates without further transfers
|
||||
let order_excluded = state.num_excluded + 1;
|
||||
@ -1106,6 +1108,7 @@ where
|
||||
|
||||
if opts.early_bulk_elect {
|
||||
// Determine if the proposed exclusion would enable a bulk election
|
||||
// This should be OK for constraints, as if the election of the remaining candidates would be invalid, the excluded candidate must necessarily have be guarded already
|
||||
if can_bulk_elect(state, excluded_candidates.len()) {
|
||||
// Exclude candidates without further transfers
|
||||
let order_excluded = state.num_excluded + 1;
|
||||
|
Loading…
Reference in New Issue
Block a user