-
Notifications
You must be signed in to change notification settings - Fork 0
/
instant_runoff.jl
70 lines (62 loc) · 2.34 KB
/
instant_runoff.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"""
InstantRunOff <: VotingSystem
An instant runoff voting system object.An instant runoff voting system iteratively eliminates the candidate with the minimum first preferences until one canidate reaches 50% first preferences.
"""
struct InstantRunOff <: VotingSystem end
"""
evaluate_winner(system::InstantRunOff, rankings::Ranks)
Returns the id of the winning candiate in an instant runoff election.
# Arguments
- `system`: an instant runoff system object
- `rankings::Ranks`: an object containing counts and unique rank orders
"""
function evaluate_winner(system::InstantRunOff, rankings::Ranks)
rank, candidates = compute_ranks(system, rankings)
return candidates[rank .== 1]
end
"""
compute_ranks(system::InstantRunOff, rankings::Ranks)
Ranks candidates using the InstantRunOff system.
# Arguments
- `system`: an InstantRunOff voting system object
- `rankings::Ranks`: an object containing counts and unique rank orders
"""
function compute_ranks(system::InstantRunOff, rankings::Ranks)
counts = deepcopy(get_counts(rankings))
uranks = deepcopy(get_uranks(rankings))
winner_idx = -100
n_votes = sum(counts)
candidates = uranks[1][:]
n_candidates = length(candidates)
max_iter = n_candidates - 1
ranked_candidates = uranks[1][:]
rank_value = fill(0, length(ranked_candidates))
i = 1
while i ≤ max_iter
#the number of first ranked votes for each candidate
n_first = map(id -> count_top_ranks(counts, uranks, id), candidates)
max_first, winner_idx = findmax(n_first)
if (max_first / n_votes) > 0.50
idx = sortperm(n_first, rev = true)
for (j, v) ∈ enumerate(idx)
ranked_candidates[j] = candidates[v]
rank_value[j] = j
end
return rank_value, ranked_candidates
end
if i < max_iter
min_val, loser_idx = findmin(n_first)
loser = candidates[loser_idx]
ridx = n_candidates - i + 1
ranked_candidates[ridx] = loser
rank_value[ridx] = ridx
remove_candidate!.(uranks, loser)
deleteat!(candidates, loser_idx)
end
i += 1
end
n_remaining = length(candidates)
ranked_candidates[1:n_remaining] .= candidates
rank_value[1:n_remaining] .= 1
return rank_value, ranked_candidates
end