jontingvold / pyrankvote

PyRankVote is a python library for different ranked-choice voting systems, like IRV, STV and PBV. Created in June 2019.
MIT License
52 stars 16 forks source link

Droop Quota Definition not consistent with literature #3

Closed rhuffy closed 4 years ago

rhuffy commented 4 years ago

Wikipedia defines the Droop quota as

floor(valid_votes/(seats + 1)) + 1

In this package, it is defined as

votes_needed_to_win: float = voters / float((seats + 1))

Is there a reason for this?

In my testing, using your definition for Droop quota often produced election results where an election for three seats gave winners that were not a subset of the winners of an election with the same ballots but for four seats, for example.

ex:

election_results_3.get_winners() = [A, B, C]
election_results_4.get_winners() = [A, B, D, E]

I am not familiar enough with STV to know if this is intended, but after changing the Droop quota to the Wikipedia definition, I no longer observed this behavior.

jontingvold commented 4 years ago

Is this because C, D, E have equal number of votes in decisive round? Do you have an example?

I'm not sure if this is a bug or not. It might be, but most probably it is some implementation choice that I have forgotten why I made and that might have not chosen a bit too fast.

The library uses fractional vote counts/The Gregory method for distributing excess votes. It might be that I implemented this formula because [Wikipedia, SVT 4.1(https://en.wikipedia.org/wiki/Single_transferable_vote#More_refined_method%3A_setting_the_quota) says that these droop quota formulas should behave the same for fractional votes:

If fractional votes can be submitted, then the Droop quota may be modified so that the fraction is not rounded down. Major Frank Britton, of the Election Ballot Services at the Electoral Reform Society, observed that the final plus one of the Droop quota is not needed; the exact quota is then simply valid_votes / (seats + 1).

But thinking about it now, I guess this is only valid as long as candidates are only elected if number of votes > droop_quota. In my implementation number of votes >= droop_quota. (See multiple_seat_ranking_methods.py:69)

It might also be that this is actually the behavior intended. As far as I can see the behavior is now more in line with what is called the exact droop quota or the Hagenbach-Bischoff quota. It might be that I thought this would be better at the time as "Some scholars of electoral systems argue that the Hagenbach-Bischoff quota should be used for elections under the single transferable vote (STV) system, instead of the Droop quota, because in certain circumstances it is possible for the Droop quota to produce a seemingly undemocratic result."

If this is not a bug, the implementation choice probably does not matter much. It is only in a few, narrow elections these formulas will produce different results. So unless you are trying to simulate a specific parlament election and need one exact STV system it should probably be fine. However, I should probably document this better.

Can I ask what you are using the library for? And can you post the code to reproduce the result, so I can look into it?