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()
|
csr = get_cursor()
|
||||||
|
|
||||||
q = f"""
|
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}
|
from {kind}
|
||||||
join {kind}_vote on {kind}.id = {kind}_vote.{kind}
|
join {kind}_vote on {kind}.id = {kind}_vote.{kind}
|
||||||
join bod on bod = bod.id
|
join bod on bod = bod.id
|
||||||
|
@ -447,11 +448,12 @@ def runoff(ballots):
|
||||||
count[r.id] = [0] * len(ballot)
|
count[r.id] = [0] * len(ballot)
|
||||||
candidates[r.id] = r
|
candidates[r.id] = r
|
||||||
for ballot in ballots:
|
for ballot in ballots:
|
||||||
|
weight = max(r.vote_w for r in ballot)
|
||||||
for pos, r in enumerate(ballot):
|
for pos, r in enumerate(ballot):
|
||||||
log.debug("count = %s", count)
|
log.debug("count = %s", count)
|
||||||
log.debug("r.id = %s", r.id)
|
log.debug("r.id = %s", r.id)
|
||||||
log.debug("pos = %s", pos)
|
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])
|
log.debug("count[%d][%d]) = %d", r.id, pos, count[r.id][pos])
|
||||||
if direction == "backward":
|
if direction == "backward":
|
||||||
result = sorted(count.keys(), key=lambda i: list(reversed(count[i])), reverse=True)
|
result = sorted(count.keys(), key=lambda i: list(reversed(count[i])), reverse=True)
|
||||||
|
|
|
@ -21,7 +21,8 @@ def get_ballots():
|
||||||
|
|
||||||
kind = args.kind
|
kind = args.kind
|
||||||
q = f"""
|
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}
|
from {kind} join {kind}_vote on {kind}.id = {kind}_vote.{kind}
|
||||||
where meet = %s
|
where meet = %s
|
||||||
order by bod, position
|
order by bod, position
|
||||||
|
@ -52,8 +53,9 @@ def runoff(ballots):
|
||||||
count[r.id] = [0] * len(ballot)
|
count[r.id] = [0] * len(ballot)
|
||||||
candidates[r.id] = r
|
candidates[r.id] = r
|
||||||
for ballot in ballots:
|
for ballot in ballots:
|
||||||
|
weight = max(r.vote_w for r in ballot)
|
||||||
for pos, r in enumerate(ballot):
|
for pos, r in enumerate(ballot):
|
||||||
count[r.id][pos] += 1
|
count[r.id][pos] += weight
|
||||||
if args.reverse:
|
if args.reverse:
|
||||||
result = sorted(count.keys(), key=lambda i: list(reversed(count[i])), reverse=True)
|
result = sorted(count.keys(), key=lambda i: list(reversed(count[i])), reverse=True)
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue