Defer surplus distribution if not affecting bulk exclusion, even if otherwise affecting trailing 2 candidates

This commit is contained in:
RunasSudo 2022-11-20 18:58:32 +11:00
parent f7f9727146
commit 1a1153b666
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
3 changed files with 25 additions and 20 deletions

View File

@ -87,7 +87,7 @@
\fancypagestyle{plain}{\fancyhf{}}
\pagestyle{fancy}\fancyhf{}\renewcommand{\headrulewidth}{0pt}
\lhead{\textsf{\scriptsize OpenTally Functional Specifications}}
\lfoot{\textsf{\scriptsize Draft 2022-11-06}}
\lfoot{\textsf{\scriptsize Draft 2022-11-20}}
\rfoot{\textsf{\scriptsize\thepage}}
\pagenumbering{roman}
@ -226,13 +226,13 @@
\subsection If there are fewer than 2 continuing candidates, the distribution of surpluses must be deferred.
\subsection\label{bulk-exclude-xref1-s}Otherwise, if:
\subsection\label{bulk-exclude-xref1}Otherwise, if \textit{--bulk-exclude} is enabled and a bulk exclusion could be performed under section~\ref{bulk-exclude}:
\subsectionc\paragraph the total of all undistributed surpluses is less than the difference between the progress totals of the 2 continuing candidates with the lowest progress totals, and
\subsectionc\paragraph If the total of all undistributed surpluses is less than the difference between the sum of the progress totals of the continuing candidates who could be bulk excluded, and the progress total of the continuing candidate with the next lowest progress total, then the distribution of surpluses must be deferred.
\subsectionc\paragraph\label{bulk-exclude-xref1}if \textit{--bulk-exclude} is enabled and a bulk exclusion could be performed under section~\ref{bulk-exclude}, the total of all undistributed surpluses is less than the difference between the sum of the progress totals of the continuing candidates who could be bulk excluded, and the progress total of the continuing candidate with the next lowest progress total,
\subsectionc\paragraph Otherwise, the distribution of surpluses must not be deferred.
\subsectionc the distribution of surpluses must be deferred.
\subsection Otherwise, if the total of all undistributed surpluses is less than the difference between the progress totals of the 2 continuing candidates with the lowest progress totals, the distribution of surpluses must be deferred.
\subsection Otherwise, the distribution of surpluses must not be deferred.
@ -867,7 +867,7 @@
\section{Bulk exclusion}\label{bulk-exclude}
\subsection This section applies in subsections~\ref{bulk-exclude-xref1-s}\ref{bulk-exclude-xref1}, \ref{bulk-exclude-xref2-s}\ref{bulk-exclude-xref2}, \ref{bulk-exclude-xref4-s}\ref{bulk-exclude-xref4} and \ref{bulk-exclude-xref3-s}\ref{bulk-exclude-xref3}, if \textit{--bulk-exclude} is enabled, to determine which candidates (if any) can be bulk excluded.
\subsection This section applies in subsections~\ref{bulk-exclude-xref1}, \ref{bulk-exclude-xref2-s}\ref{bulk-exclude-xref2}, \ref{bulk-exclude-xref4-s}\ref{bulk-exclude-xref4} and \ref{bulk-exclude-xref3-s}\ref{bulk-exclude-xref3}, if \textit{--bulk-exclude} is enabled, to determine which candidates (if any) can be bulk excluded.
\subsection In a bulk exclusion, select for exclusion as many of the continuing candidates with the lowest progress totals as possible, provided that:

View File

@ -23,9 +23,9 @@ The preset dropdown allows you to choose from a hardcoded list of preloaded STV
| Dáil Éireann STV | Rules from the [*Electoral Act 1992* (Ireland)](http://www.irishstatutebook.ie/eli/1992/act/23/enacted/en/print), using stratified random sample transfers. | [E4] [E7] | ✓ |
| [van der Craats (‘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. | | ✓ |
| [PRSA 1977](https://www.prsa.org.au/rule1977.htm) | Simple rules designed for hand counting, using the exclusive Gregory method, with counting performed in thousandths of a vote. | | ✓ |
| [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. | [E8] [E9] | ✓ |
| • ERS76 | Former rules from the 1976 2nd edition. | [E8] [E9] [E10] | ✓ |
| • ERS73 | Former rules from the 1973 1st edition. | [E8] [E9] [E10] | |
| [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. | [E8] [E9] [E10] | ✓ |
| • ERS76 | Former rules from the 1976 2nd edition. | [E8] [E9] [E10] [E11] | ✓ |
| • ERS73 | Former rules from the 1973 1st edition. | [E8] [E9] [E10] [E11] | |
| Church of England | Rules from the Church of England [*Single Transferable Vote Rules 2020*](https://www.churchofengland.org/sites/default/files/2020-02/STV%20Rules%202020%20-%20final.pdf), similar to ERS73. | [E8] | ✓ |
Exceptions:
@ -35,11 +35,12 @@ Exceptions:
* [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] Bulk exclusion is not performed, as the prescribed rules are more conservative than OpenTally's. See also the section on *Bulk exclusion* for further discussion.
* [E5] The legislation is drafted such that a consistent interpretation is impossible – see <a href="https://github.com/AndrewConway/ConcreteSTV/blob/main/nsw/NSWLocalCouncilLegislation2021Commentary.md">Conway</a> for a discussion. In practice, the New South Wales Electoral Commission has applied the ‘by parcel’ method of rounding subtransfers, which OpenTally follows.
* [E6] The ‘mathematically eliminated by the sum of all ranked-choice votes comparison’ is not implemented.
* [E6] The ‘mathematically eliminated by the sum of all ranked-choice votes comparison’ is not implemented, and undeclared write-in candidates are not distinguished.
* [E7] The ‘quarter of a quota’ provision is disregarded when determining whether to defer surplus distributions.
* [E8] The distribution of a surplus is not deferred if it exactly equals the difference between the 2 trailing continuing candidates.
* [E9] No distinction is made between stages and substages (during exclusion). This affects only the numbering of stages and not the result.
* [E10] By default, 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).
* [E9] The distribution of a surplus is not deferred if a bulk exclusion could be performed and it could not change the bulk exclusion, even if it could change which candidate is last.
* [E10] No distinction is made between stages and substages (during exclusion). This affects only the numbering of stages and not the result.
* [E11] By default, 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).
For details of validation, see [validation.md](https://yingtongli.me/git/OpenTally/about/docs/validation.md).

View File

@ -675,18 +675,14 @@ fn can_defer_surpluses<N: Number>(state: &CountState<N>, opts: &STVOptions, tota
where
for<'r> &'r N: ops::Sub<&'r N, Output=N>
{
// Do not defer if this could change the last 2 candidates
let mut hopefuls: Vec<(&Candidate, &CountCard<N>)> = state.candidates.iter()
.filter(|(_, cc)| cc.state == CandidateState::Hopeful || cc.state == CandidateState::Guarded)
.collect();
if hopefuls.len() < 2 {
return true;
}
hopefuls.sort_unstable_by(|(_, cc1), (_, cc2)| cc1.votes.cmp(&cc2.votes));
if total_surpluses >= &(&hopefuls[1].1.votes - &hopefuls[0].1.votes) {
return false;
// Surpluses can always be deferred if there is only 1 continuing candidate
if hopefuls.len() <= 1 {
return true;
}
// Do not defer if this could affect a bulk exclusion
@ -697,9 +693,17 @@ where
let total_excluded = state.total_votes_of(to_exclude.into_iter().map(|c| &state.candidates[c]));
if total_surpluses >= &(&hopefuls[num_to_exclude].1.votes - &total_excluded) {
return false;
} else {
return true;
}
}
}
// Do not defer if this could change the last 2 candidates
if total_surpluses >= &(&hopefuls[1].1.votes - &hopefuls[0].1.votes) {
return false;
}
return true;
}