Implement Wright STV
This commit is contained in:
parent
631fa432c6
commit
f8ee464421
@ -40,6 +40,7 @@
|
|||||||
<option value="scottish" selected>Scottish STV</option>
|
<option value="scottish" selected>Scottish STV</option>
|
||||||
<option value="stvc">pyRCV STV-C</option>
|
<option value="stvc">pyRCV STV-C</option>
|
||||||
<option value="senate">Australian Senate STV</option>
|
<option value="senate">Australian Senate STV</option>
|
||||||
|
<option value="wright">Wright STV</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<button id="btnAdvancedOptions" onclick="clickAdvancedOptions()">Show advanced options</button>
|
<button id="btnAdvancedOptions" onclick="clickAdvancedOptions()">Show advanced options</button>
|
||||||
@ -92,10 +93,11 @@
|
|||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Transfer value:
|
Method:
|
||||||
<select id="selTransfers">
|
<select id="selTransfers">
|
||||||
<option value="wig" selected>Weighted inclusive Gregory</option>
|
<option value="wig" selected>Weighted inclusive Gregory</option>
|
||||||
<option value="uig">Unweighted inclusive Gregory</option>
|
<option value="uig">Unweighted inclusive Gregory</option>
|
||||||
|
<option value="wright">Wright STV</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<br>
|
<br>
|
||||||
|
@ -50,11 +50,21 @@ function changePreset() {
|
|||||||
document.getElementById('selQuotaCriterion').value = 'geq';
|
document.getElementById('selQuotaCriterion').value = 'geq';
|
||||||
document.getElementById('selQuota').value = 'droop';
|
document.getElementById('selQuota').value = 'droop';
|
||||||
document.getElementById('chkProgQuota').checked = false;
|
document.getElementById('chkProgQuota').checked = false;
|
||||||
document.getElementById('chkBulkExclusion').checked = false;
|
document.getElementById('chkBulkExclusion').checked = true;
|
||||||
document.getElementById('selNumbers').value = 'int';
|
document.getElementById('selNumbers').value = 'int';
|
||||||
document.getElementById('selSurplus').value = 'order';
|
document.getElementById('selSurplus').value = 'order';
|
||||||
document.getElementById('selTransfers').value = 'uig';
|
document.getElementById('selTransfers').value = 'uig';
|
||||||
document.getElementById('selTies').value = 'backwards_random';
|
document.getElementById('selTies').value = 'backwards_random';
|
||||||
|
} else if (document.getElementById('selPreset').value === 'wright') {
|
||||||
|
document.getElementById('selQuotaCriterion').value = 'geq';
|
||||||
|
document.getElementById('selQuota').value = 'droop';
|
||||||
|
document.getElementById('chkProgQuota').checked = false;
|
||||||
|
document.getElementById('chkBulkExclusion').checked = true;
|
||||||
|
document.getElementById('selNumbers').value = 'fixed';
|
||||||
|
document.getElementById('txtDP').value = '5';
|
||||||
|
document.getElementById('selSurplus').value = 'size';
|
||||||
|
document.getElementById('selTransfers').value = 'wright';
|
||||||
|
document.getElementById('selTies').value = 'backwards_random';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,10 +41,12 @@ onmessage = function(evt) {
|
|||||||
|
|
||||||
// Create counter
|
// Create counter
|
||||||
let counter;
|
let counter;
|
||||||
if (evt.data.transfers === 'wig') {
|
if (evt.data.transfers === 'uig') {
|
||||||
counter = py.pyRCV2.method.base_stv.BaseWIGSTVCounter(election, evt.data.options);
|
|
||||||
} else {
|
|
||||||
counter = py.pyRCV2.method.base_stv.BaseUIGSTVCounter(election, evt.data.options);
|
counter = py.pyRCV2.method.base_stv.BaseUIGSTVCounter(election, evt.data.options);
|
||||||
|
} else if (evt.data.transfers === 'wright') {
|
||||||
|
counter = py.pyRCV2.method.wright.WrightSTVCounter(election, evt.data.options);
|
||||||
|
} else {
|
||||||
|
counter = py.pyRCV2.method.base_stv.BaseWIGSTVCounter(election, evt.data.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
|
@ -192,11 +192,7 @@ class BaseSTVCounter:
|
|||||||
Exclude the lowest ranked hopeful
|
Exclude the lowest ranked hopeful
|
||||||
"""
|
"""
|
||||||
|
|
||||||
hopefuls = [(c, cc) for c, cc in self.candidates.items() if cc.state == CandidateState.HOPEFUL]
|
candidate_excluded, count_card = self.candidate_to_exclude()
|
||||||
hopefuls.sort(lambda x: x[1].votes)
|
|
||||||
|
|
||||||
# TODO: Handle ties
|
|
||||||
candidate_excluded, count_card = hopefuls[0]
|
|
||||||
count_card.state = CandidateState.EXCLUDED
|
count_card.state = CandidateState.EXCLUDED
|
||||||
|
|
||||||
# Exclude this candidate
|
# Exclude this candidate
|
||||||
@ -221,6 +217,19 @@ class BaseSTVCounter:
|
|||||||
)
|
)
|
||||||
__pragma__('noopov')
|
__pragma__('noopov')
|
||||||
|
|
||||||
|
def candidate_to_exclude(self):
|
||||||
|
"""
|
||||||
|
Determine the candidate to exclude
|
||||||
|
"""
|
||||||
|
|
||||||
|
hopefuls = [(c, cc) for c, cc in self.candidates.items() if cc.state == CandidateState.HOPEFUL]
|
||||||
|
hopefuls.sort(lambda x: x[1].votes)
|
||||||
|
|
||||||
|
# TODO: Handle ties
|
||||||
|
candidate_excluded, count_card = hopefuls[0]
|
||||||
|
|
||||||
|
return candidate_excluded, count_card
|
||||||
|
|
||||||
def do_exclusion(self, candidate_excluded, count_card):
|
def do_exclusion(self, candidate_excluded, count_card):
|
||||||
"""
|
"""
|
||||||
Exclude the given candidate and transfer the votes
|
Exclude the given candidate and transfer the votes
|
||||||
|
56
pyRCV2/method/wright.py
Normal file
56
pyRCV2/method/wright.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# pyRCV2: Preferential vote counting
|
||||||
|
# Copyright © 2020 Lee Yingtong Li (RunasSudo)
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyRCV2.method.base_stv import BaseWIGSTVCounter
|
||||||
|
from pyRCV2.model import CandidateState, CountCard
|
||||||
|
from pyRCV2.safedict import SafeDict
|
||||||
|
|
||||||
|
class WrightSTVCounter(BaseWIGSTVCounter):
|
||||||
|
"""
|
||||||
|
Wright STV implementation
|
||||||
|
"""
|
||||||
|
|
||||||
|
def exclude_candidate(self):
|
||||||
|
"""
|
||||||
|
Overrides BaseSTVCounter.exclude_candidate per Wright STV
|
||||||
|
"""
|
||||||
|
|
||||||
|
candidate_excluded, count_card = self.candidate_to_exclude()
|
||||||
|
count_card.state = CandidateState.EXCLUDED
|
||||||
|
|
||||||
|
# Reset the count
|
||||||
|
new_candidates = SafeDict()
|
||||||
|
for candidate, count_card in self.candidates.items():
|
||||||
|
new_count_card = CountCard()
|
||||||
|
|
||||||
|
if count_card.state == CandidateState.WITHDRAWN:
|
||||||
|
new_count_card.state = CandidateState.WITHDRAWN
|
||||||
|
elif count_card.state == CandidateState.EXCLUDED:
|
||||||
|
new_count_card.state = CandidateState.EXCLUDED
|
||||||
|
|
||||||
|
__pragma__('opov')
|
||||||
|
new_candidates[candidate] = new_count_card
|
||||||
|
__pragma__('noopov')
|
||||||
|
|
||||||
|
self.candidates = new_candidates
|
||||||
|
self.exhausted = CountCard()
|
||||||
|
self.loss_fraction = CountCard()
|
||||||
|
self.num_elected = 0
|
||||||
|
|
||||||
|
result = self.reset()
|
||||||
|
result.comment = 'Exclusion of ' + candidate_excluded.name
|
||||||
|
|
||||||
|
return result
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import pyRCV2.blt
|
import pyRCV2.blt
|
||||||
import pyRCV2.model
|
import pyRCV2.model
|
||||||
import pyRCV2.method, pyRCV2.method.base_stv
|
import pyRCV2.method, pyRCV2.method.base_stv, pyRCV2.method.wright
|
||||||
import pyRCV2.numbers
|
import pyRCV2.numbers
|
||||||
|
|
||||||
__pragma__('js', '{}', 'export {pyRCV2, isinstance, repr, str};')
|
__pragma__('js', '{}', 'export {pyRCV2, isinstance, repr, str};')
|
||||||
|
Reference in New Issue
Block a user