Fix Hare Quota#562
Conversation
Rearranged the code of setWinningThreshold(). This should be logically equivalent to before, unless hare quota is used.
|
This addresses #557 |
Fixed typos fore hare quota fix.
tarheel
left a comment
There was a problem hiding this comment.
Thanks for the contribution! I think your logic looks right... but this part of the code is always tricky to reason about. Have you been able to get the test suite working? We already have tests for non-Hare configs (test_set_multi_winner_fractional_threshold and test_set_multi_winner_whole_threshold), but we don't have one for Hare yet (which helps to explain why this bug exists in the first place).
Also, were you able to apply Checkstyle to your changes? I don't see anything that's clearly inconsistent, but sometimes it's hard to predict what it will do...
HEdingfield
left a comment
There was a problem hiding this comment.
Echoing @tarheel's comment, I'd appreciate it if you also included a test that fails with the status quo and passes once this fix is applied.
No need to worry too much about Checkstyle though, as I run this before we do any merging to our main branch.
No. I have found the TabulatorTests class is source, but I don't know how to run the tests. |
|
@HEdingfield @moldover do you know how to run the tests from the command line? We should figure that out and add it to the README. |
|
|
When calculating `augend`, the decimal precision is only set to what is required, rather than the `config.divide()` settings.
|
I successfully ran the tests, but most of them failed. That was because the outputted threshold had trailing zeros that the reference did not have. Commit 6214e5f fixed this. After that only one test failed: test Hare quota (i.e. 2013 Minneapolis park hare quota). That output a different result in the way it was supposed to, by using first integer greater than or equal to rather than greater than. All I need to do is change the expected output for the unit test, and I will have
|
|
Updated the unit test test in c4a04c7! Try |
Wrapped some lines to be compliant with Google style.
|
As of a3f4884, the pull request passes Now all of @tarheel and @HEdingfield's recommendations are accounted for. |
|
Don't wait for me to pull it, I don't have write access. |

Background: In most variants of RCV, a candidates tally must exceed (i.e. greater than) the threshold to automatically win. Hare quota is an exception, where the tally must meet or exceed (greater than or equal to) the threshold. Internally, the tabulator sets the variable
winningThresholdwith the functionsetWinningThreshold(). The program determines a candidate to be a winner if the tally is greater than or equal towinningThreshold. Note that the tally is always a discreet value in this software, even if it is a decimal.Since the tally is measured to a certain precision, it can be thought of as on a discreet number line. If we aren't using the hare quota, then we want to set
winningThresholdto a value where the tally>= winningThresholdif and only if the tally is greater than the actual threshold. We achieve this by finding the first point on the number line that is to the right of the exact threshold, and settingwinningThresholdto that. However, before this commit,setWinningThreshold()worked the same way for hare quotient. For hare quotas, we should choose the first value on the number line that is on or to the right of the exact threshold to find ourwinningThreshold.(Note that an exception is if nonIntegerWinningThreshold is false. In this case the tally may exceed the exact threshold being less than
winningThreshold; but, since this is an explicit user configuration, it is still correct.)augendis the distance between each point on the number line.decimalsalso indicates the precision of the number line, set in the config file.RoundingMode.UPmeans round up andRoundingMode.DOWNmeans round down.a.divide(b, ...)means a divided by b, with the specified rounding. In this case a/b is the exact threshold.For non-hare quotas, this expression finds winningThreshold on line 387:
winningThreshold = currentRoundTotalVotes.divide(divisor, decimals, RoundingMode.DOWN).add(augend);and hare on 383:
winningThreshold = currentRoundTotalVotes.divide(divisor, decimals, RoundingMode.UP);This pull request changes the code for handling
nonIntegerWinningThreshold. Previously there were two separate paths in an if else statement depending on the value ofnonIntegerWinningThreshold. This commit consolidates the two paths. If the variable is true, thendecimalsis set to zero, and it is as if the number line only had integers. Otherwisedecimalsis set todecimalPlacesForVoteArithmetic. This is done in lines 370-373.