Skip to content

Commit

Permalink
make smith_minimax func behavior consistent with others,
Browse files Browse the repository at this point in the history
add multiwinner support.
  • Loading branch information
johnh865 committed Mar 3, 2021
1 parent 4f671fb commit 206e081
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 15 deletions.
46 changes: 39 additions & 7 deletions votesim/votemethods/condorcet.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,38 @@
'smith_score']


def smith_minimax(ranks=None, numwin=1, matrix=None):
@multi_win_eliminate_decorator
def smith_minimax(data, numwin=1):
"""Condorcet Smith Minimax voting algorithm for ranked ballots.
Parameters
----------
ranks : (a, b) array
Election voter rankings, from [1 to b].
Data composed of candidate rankings, with
- Voters as the rows
- Candidates as the columns.
Use 0 to specify unranked (and therefore not to be counted) ballots.
- a : number of voters dimension. Voters assign ranks for each candidate.
- b : number of candidates. A score is assigned for each candidate
from 0 to b-1.
Returns
-------
winners : array of shape (numwin,)
Winning candidates index.
ties : array of shape (tienum,)
Tied candidates index for the last round, numbering `tienum`.
output : dict
Additional method outputs
"""
return smith_minimax_matrix(data=data)


def smith_minimax_matrix(data=None, matrix=None):
"""Condorcet Smith Minimax voting algorithm for ranked ballots.
Parameters
Expand Down Expand Up @@ -53,8 +84,8 @@ def smith_minimax(ranks=None, numwin=1, matrix=None):
Tied candidates index for the last round, numbering `tienum`.
"""
m = None
if ranks is not None:
m = pairwise_rank_matrix(ranks)
if data is not None:
m = pairwise_rank_matrix(data)
win_losses = m - m.T
elif matrix is not None:
win_losses = np.array(matrix)
Expand Down Expand Up @@ -87,7 +118,7 @@ def smith_minimax(ranks=None, numwin=1, matrix=None):


@multi_win_eliminate_decorator
def ranked_pairs(ranks, numwin=1,):
def ranked_pairs(data, numwin=1,):
"""Ranked-pairs or Tideman election system.
Parameters
Expand Down Expand Up @@ -127,6 +158,7 @@ def ranked_pairs(ranks, numwin=1,):
- column 1 = losing candidate
- column 2 = margin of victory
"""
ranks = data
m = pairwise_rank_matrix(ranks)
win_losses = m - m.T
cnum = len(m)
Expand Down Expand Up @@ -305,9 +337,9 @@ def smith_score(data, numwin=1,):


@multi_win_eliminate_decorator
def black(ranks, numwin=1):
def black(data, numwin=1):
"""Condorcet-black."""
m = pairwise_rank_matrix(ranks)
m = pairwise_rank_matrix(data)
win_losses = m - m.T
winners, ties, scores = condorcet_winners_check(matrix=win_losses)
output = {}
Expand All @@ -316,7 +348,7 @@ def black(ranks, numwin=1):
if len(winners) > 0:
return winners, ties, output
else:
winners, ties, b_output = borda(ranks, numwin=1)
winners, ties, b_output = borda(data, numwin=1)
output.update(b_output)
return winners, ties, output

Expand Down
10 changes: 6 additions & 4 deletions votesim/votemethods/irv.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
import logging
from votesim.votemethods.tools import (rcv_reorder,
droop_quota,
winner_check)
winner_check,
multi_win_eliminate_decorator
)

__all__ = [
'irv',
Expand All @@ -28,7 +30,7 @@ def hare_quota(votes, seats):




@multi_win_eliminate_decorator
def top2runoff(data, numwin=1):
"""
Emulate top two runoff using ranked data
Expand Down Expand Up @@ -61,8 +63,8 @@ def top2runoff(data, numwin=1):
"""

### round #1
if numwin > 1:
raise ValueError('Only numwinner=1 supported')
# if numwin > 1:
# raise ValueError('Only numwinner=1 supported')

data = np.array(data)
candidate_num = data.shape[1]
Expand Down
8 changes: 4 additions & 4 deletions votesim/votemethods/tests/test_condorcet_minimax.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_smith_minimax1(self):


d = np.array(d)
w, t, o = condorcet.smith_minimax(matrix=d)
w, t, o = condorcet.smith_minimax_matrix(matrix=d)
self.assertTrue(0 in w)
self.assertTrue(len(t) == 0)
return
Expand All @@ -46,7 +46,7 @@ def test_smith_minimax2(self):


d = np.array(d)
w, t, o = condorcet.smith_minimax(matrix=d)
w, t, o = condorcet.smith_minimax_matrix(matrix=d)
self.assertTrue(2 in w)
self.assertTrue(len(t) == 0)
return
Expand All @@ -61,7 +61,7 @@ def test_smith_minimax3(self):


d = np.array(d)
w, t, o = condorcet.smith_minimax(matrix=d)
w, t, o = condorcet.smith_minimax_matrix(matrix=d)
self.assertTrue(3 in w)
self.assertTrue(len(t) == 0)
return
Expand All @@ -87,7 +87,7 @@ def tests_minimax_condorcet(self):
d = rs.randint(1, 5, size=(4,4))
i1 = condorcet.condcalcs.condorcet_check_one(ranks=d)
if i1 != -1:
w,t, *args = condorcet.smith_minimax(ranks=d)
w,t, *args = condorcet.smith_minimax(data=d)
self.assertEqual(w[0], i1)
print('seed %d, winner=%d' % (seed, i1))
else:
Expand Down

0 comments on commit 206e081

Please sign in to comment.