Weight ballots by their their best option
If the only options left are ones where a person can't make it, their ballot shouldn't influence the result any more. Similarily when there are only options which are questionable that ballot should have a lower weight. We do this by attaching a weight to each option, where real choices get a weight of 1 and pseudo-choices (like "none of the above") get a lower weight (theoretically that should be 0, but let's keep that configurable). When constructing the ballots each vote gets a monotonically decreasing weight. As options are eliminated in each round, the weight of the ballot is recalculated as the maximum weight of all remaining options. So this starts at 1 for all ballots, but drops as more favourable options are eliminated, possibly down to 0 where a ballot ceases to have an effect.
This commit is contained in:
parent
34f361a4a6
commit
187718f360
6
app.py
6
app.py
|
@ -412,7 +412,8 @@ def get_ballots(meet_id, kind):
|
|||
csr = get_cursor()
|
||||
|
||||
q = f"""
|
||||
select {kind}.*, bod, position, email
|
||||
select {kind}.*, bod, position, email,
|
||||
min(w) over(partition by bod order by position) as vote_w
|
||||
from {kind}
|
||||
join {kind}_vote on {kind}.id = {kind}_vote.{kind}
|
||||
join bod on bod = bod.id
|
||||
|
@ -447,11 +448,12 @@ def runoff(ballots):
|
|||
count[r.id] = [0] * len(ballot)
|
||||
candidates[r.id] = r
|
||||
for ballot in ballots:
|
||||
weight = max(r.vote_w for r in ballot)
|
||||
for pos, r in enumerate(ballot):
|
||||
log.debug("count = %s", count)
|
||||
log.debug("r.id = %s", r.id)
|
||||
log.debug("pos = %s", pos)
|
||||
count[r.id][pos] += 1
|
||||
count[r.id][pos] += weight
|
||||
log.debug("count[%d][%d]) = %d", r.id, pos, count[r.id][pos])
|
||||
if direction == "backward":
|
||||
result = sorted(count.keys(), key=lambda i: list(reversed(count[i])), reverse=True)
|
||||
|
|
|
@ -21,7 +21,8 @@ def get_ballots():
|
|||
|
||||
kind = args.kind
|
||||
q = f"""
|
||||
select {kind}.*, bod, position
|
||||
select {kind}.*, bod, position,
|
||||
min(w) over(partition by bod order by position) as vote_w
|
||||
from {kind} join {kind}_vote on {kind}.id = {kind}_vote.{kind}
|
||||
where meet = %s
|
||||
order by bod, position
|
||||
|
@ -52,8 +53,9 @@ def runoff(ballots):
|
|||
count[r.id] = [0] * len(ballot)
|
||||
candidates[r.id] = r
|
||||
for ballot in ballots:
|
||||
weight = max(r.vote_w for r in ballot)
|
||||
for pos, r in enumerate(ballot):
|
||||
count[r.id][pos] += 1
|
||||
count[r.id][pos] += weight
|
||||
if args.reverse:
|
||||
result = sorted(count.keys(), key=lambda i: list(reversed(count[i])), reverse=True)
|
||||
else:
|
||||
|
|
Loading…
Reference in New Issue