in monitoring/stv_tool.py [0:0]
def run_stv(names: list, ordered_votes: list, num_seats: int):
# Note: ORDERED_VOTES is a list of lists. The interior lists are a list
# of candidate (human) NAMES, as ordered by the voter. The outer list is
# simply all the votes that were recorded.
# NOTE: files use labels such as "a" or "f", but this STV algorithm
# works with the human names. Cuz why not.
# NOTE: NAMES must be a list for repeatability purposes. It does not
# need to obey any particular ordering rules, but when re-running
# tallies, NAMES must be presented with the same ordering.
assert len(set(names)) == len(names), "duplicates present!"
assert num_seats > 0
candidates = CandidateList(names)
# name -> Candidate
remap = dict((c.name, c) for c in candidates.l)
# We can test that ordering of voters has no bearing. Perform runs
# and alter the .seed() value.
#ordered_votes = list(ordered_votes); random.seed(1); random.shuffle(ordered_votes); print('VOTE:', ordered_votes[0])
# VOTES is a list of ordered-lists of Candidate objects
votes = [[remap[n] for n in choices] for choices in ordered_votes]
if candidates.count(ELECTED + HOPEFUL) <= num_seats:
dbg('All candidates elected')
candidates.change_state(HOPEFUL, ELECTED)
return candidates
quota = None # not used on first pass
iteration = 1
while candidates.count(ELECTED) < num_seats:
dbg('Iteration %d', iteration)
iteration += 1
quota = iterate_one(quota, votes, candidates, num_seats)
candidates.reverse_random()
dbg('All seats full')
candidates.change_state(HOPEFUL, ELIMINATED)
return candidates