Implement ERS76 rules
This commit is contained in:
parent
bc8ed9a7e0
commit
d144ab0cb4
@ -14,7 +14,8 @@ The preset dropdown allows you to choose from a hardcoded list of preloaded STV
|
|||||||
* [*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).
|
* [*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).
|
* [*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.
|
* [*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.
|
||||||
* *ERS73*: Former rules from the 1973 1st edition. The quota is calculated always to 2 decimal places – for full ERS73 compliance, set *Round quota to 0 d.p.* when the quota is 100 or more.
|
* *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.
|
||||||
|
|
||||||
This functionality is not available on the command line.
|
This functionality is not available on the command line.
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
<option value="wright">Wright STV</option>
|
<option value="wright">Wright STV</option>
|
||||||
<option value="prsa77">PRSA 1977</option>
|
<option value="prsa77">PRSA 1977</option>
|
||||||
<option value="ers97">ERS97</option>
|
<option value="ers97">ERS97</option>
|
||||||
|
<option value="ers76">ERS76</option>
|
||||||
<option value="ers73">ERS73</option>
|
<option value="ers73">ERS73</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@ -79,6 +80,7 @@
|
|||||||
<option value="static" selected>Static quota</option>
|
<option value="static" selected>Static quota</option>
|
||||||
<!--<option value="progressive">Progressive quota</option>-->
|
<!--<option value="progressive">Progressive quota</option>-->
|
||||||
<option value="ers97">Static with ERS97 rules</option>
|
<option value="ers97">Static with ERS97 rules</option>
|
||||||
|
<option value="ers76">Static with ERS76 rules</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -548,6 +548,31 @@ function changePreset() {
|
|||||||
document.getElementById('selPapers').value = 'transferable';
|
document.getElementById('selPapers').value = 'transferable';
|
||||||
document.getElementById('selExclusion').value = 'by_value';
|
document.getElementById('selExclusion').value = 'by_value';
|
||||||
document.getElementById('selTies').value = 'forwards,random';
|
document.getElementById('selTies').value = 'forwards,random';
|
||||||
|
} else if (document.getElementById('selPreset').value === 'ers76') {
|
||||||
|
document.getElementById('selQuotaCriterion').value = 'geq';
|
||||||
|
document.getElementById('selQuota').value = 'droop_exact';
|
||||||
|
document.getElementById('selQuotaMode').value = 'ers76';
|
||||||
|
document.getElementById('chkBulkElection').checked = true;
|
||||||
|
document.getElementById('chkBulkExclusion').checked = true;
|
||||||
|
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 = 'single_step';
|
||||||
|
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';
|
||||||
} else if (document.getElementById('selPreset').value === 'ers73') {
|
} else if (document.getElementById('selPreset').value === 'ers73') {
|
||||||
document.getElementById('selQuotaCriterion').value = 'geq';
|
document.getElementById('selQuotaCriterion').value = 'geq';
|
||||||
document.getElementById('selQuota').value = 'droop_exact';
|
document.getElementById('selQuota').value = 'droop_exact';
|
||||||
|
@ -104,7 +104,7 @@ struct STV {
|
|||||||
quota_criterion: String,
|
quota_criterion: String,
|
||||||
|
|
||||||
/// Whether to apply a form of progressive quota
|
/// Whether to apply a form of progressive quota
|
||||||
#[clap(help_heading=Some("QUOTA"), long, possible_values=&["static", "ers97"], default_value="static", value_name="mode")]
|
#[clap(help_heading=Some("QUOTA"), long, possible_values=&["static", "ers97", "ers76"], default_value="static", value_name="mode")]
|
||||||
quota_mode: String,
|
quota_mode: String,
|
||||||
|
|
||||||
// ------------------
|
// ------------------
|
||||||
|
@ -144,6 +144,7 @@ impl STVOptions {
|
|||||||
quota_mode: match quota_mode {
|
quota_mode: match quota_mode {
|
||||||
"static" => QuotaMode::Static,
|
"static" => QuotaMode::Static,
|
||||||
"ers97" => QuotaMode::ERS97,
|
"ers97" => QuotaMode::ERS97,
|
||||||
|
"ers76" => QuotaMode::ERS76,
|
||||||
_ => panic!("Invalid --quota-mode"),
|
_ => panic!("Invalid --quota-mode"),
|
||||||
},
|
},
|
||||||
ties: ties.into_iter().map(|t| match t.as_str() {
|
ties: ties.into_iter().map(|t| match t.as_str() {
|
||||||
@ -315,6 +316,8 @@ pub enum QuotaMode {
|
|||||||
Static,
|
Static,
|
||||||
/// Static quota with ERS97 rules
|
/// Static quota with ERS97 rules
|
||||||
ERS97,
|
ERS97,
|
||||||
|
/// Static quota with ERS76 rules
|
||||||
|
ERS76,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QuotaMode {
|
impl QuotaMode {
|
||||||
@ -323,6 +326,7 @@ impl QuotaMode {
|
|||||||
match self {
|
match self {
|
||||||
QuotaMode::Static => "--quota-mode static",
|
QuotaMode::Static => "--quota-mode static",
|
||||||
QuotaMode::ERS97 => "--quota-mode ers97",
|
QuotaMode::ERS97 => "--quota-mode ers97",
|
||||||
|
QuotaMode::ERS76 => "--quota-mode ers76",
|
||||||
}.to_string()
|
}.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -664,8 +668,8 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
|
|||||||
state.logger.log_literal(log);
|
state.logger.log_literal(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let QuotaMode::ERS97 = opts.quota_mode {
|
if opts.quota_mode == QuotaMode::ERS97 || opts.quota_mode == QuotaMode::ERS76 {
|
||||||
// ERS97 rules
|
// ERS97/ERS76 rules
|
||||||
|
|
||||||
// -------------------------
|
// -------------------------
|
||||||
// Reduce quota if allowable
|
// Reduce quota if allowable
|
||||||
@ -722,7 +726,7 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No ERS97 rules
|
// No ERS97/ERS76 rules
|
||||||
if state.vote_required_election.is_none() || opts.surplus == SurplusMethod::Meek {
|
if state.vote_required_election.is_none() || opts.surplus == SurplusMethod::Meek {
|
||||||
state.vote_required_election = state.quota.clone();
|
state.vote_required_election = state.quota.clone();
|
||||||
}
|
}
|
||||||
@ -789,10 +793,9 @@ fn elect_meeting_quota<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVO
|
|||||||
|
|
||||||
if opts.quota_mode == QuotaMode::ERS97 {
|
if opts.quota_mode == QuotaMode::ERS97 {
|
||||||
// Vote required for election may have changed
|
// Vote required for election may have changed
|
||||||
|
// This is not performed in ERS76 - TODO: Check this
|
||||||
calculate_quota(state, opts);
|
calculate_quota(state, opts);
|
||||||
}
|
|
||||||
|
|
||||||
if opts.quota_mode == QuotaMode::ERS97 {
|
|
||||||
// Repeat in case vote required for election has changed
|
// Repeat in case vote required for election has changed
|
||||||
match elect_meeting_quota(state, opts) {
|
match elect_meeting_quota(state, opts) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
|
@ -292,7 +292,7 @@ fn init_results_table<N: Number>(election: &Election<N>, opts: &stv::STVOptions)
|
|||||||
result.push_str(&format!(r#"<tr class="candidate transfers"><td rowspan="2">{}</td></tr><tr class="candidate votes"></tr>"#, candidate.name));
|
result.push_str(&format!(r#"<tr class="candidate transfers"><td rowspan="2">{}</td></tr><tr class="candidate votes"></tr>"#, candidate.name));
|
||||||
}
|
}
|
||||||
result.push_str(r#"<tr class="info transfers"><td rowspan="2">Exhausted</td></tr><tr class="info votes"></tr><tr class="info transfers"><td rowspan="2">Loss by fraction</td></tr><tr class="info votes"></tr><tr class="info transfers"><td>Total</td></tr><tr class="info transfers"><td>Quota</td></tr>"#);
|
result.push_str(r#"<tr class="info transfers"><td rowspan="2">Exhausted</td></tr><tr class="info votes"></tr><tr class="info transfers"><td rowspan="2">Loss by fraction</td></tr><tr class="info votes"></tr><tr class="info transfers"><td>Total</td></tr><tr class="info transfers"><td>Quota</td></tr>"#);
|
||||||
if opts.quota_mode == stv::QuotaMode::ERS97 {
|
if opts.quota_mode == stv::QuotaMode::ERS97 || opts.quota_mode == stv::QuotaMode::ERS76 {
|
||||||
result.push_str(r#"<tr class="info transfers"><td>Vote required for election</td></tr>"#);
|
result.push_str(r#"<tr class="info transfers"><td>Vote required for election</td></tr>"#);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -354,7 +354,7 @@ fn update_results_table<N: Number>(stage_num: usize, state: &CountState<N>, opts
|
|||||||
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(&total_vote, opts.pp_decimals)).into());
|
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(&total_vote, opts.pp_decimals)).into());
|
||||||
|
|
||||||
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(state.quota.as_ref().unwrap(), opts.pp_decimals)).into());
|
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(state.quota.as_ref().unwrap(), opts.pp_decimals)).into());
|
||||||
if opts.quota_mode == stv::QuotaMode::ERS97 {
|
if opts.quota_mode == stv::QuotaMode::ERS97 || opts.quota_mode == stv::QuotaMode::ERS76 {
|
||||||
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(state.vote_required_election.as_ref().unwrap(), opts.pp_decimals)).into());
|
result.push(&format!(r#"<td class="{}count">{}</td>"#, tdclasses2, pp(state.vote_required_election.as_ref().unwrap(), opts.pp_decimals)).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user