def integration_MxN(n_candidates, n_voters, voting_scheme, seed=None): """ @param voting_scheme: one of the four voting schemes """ if seed != None: np.random.seed(seed) candidates_num = range(65, 65+n_candidates) candidates = [str(chr(i)) for i in candidates_num] pref_list = list(permutations(candidates_num)) pref_mat = np.zeros((n_candidates, n_voters), dtype=np.uint8) for i in range(n_voters): rand = np.random.randint(0, len(pref_list)) pref_mat[:, i] = np.array(pref_list[rand]) params = {"num_voters": n_voters, "num_candidates": n_candidates, "candidate_list": candidates, "pref_mat": pref_mat, "scheme": voting_scheme} pc = PC(**params) vsr = VSR() vsr.voting_simulation(pc.pref_mat, pc.scheme) tv = TV(pref_mat=pc.pref_mat, voting_outcome=vsr.results, scheme=pc.scheme) return pc, vsr, tv
def test_calculate_voter_happiness(self): pref_mat = np.array([65, 66, 67, 68]).reshape(-1, 1) voting_outcome = {66: 4, 65: 0, 67: 0, 68: 0} vsr = VSR() desired_outcome = 1 / (1 + abs(4 * (3 - 4) + 3 * (4 - 3) + 2 * (2 - 2) + 1 * (1 - 1))) self.assertEqual(vsr.get_happiness(pref_mat, voting_outcome), np.array([desired_outcome]))
def integration_voting_for_two(): """Integration test for voting_for_two""" params = {"num_voters": 3, "num_candidates": 2, "candidate_list": ["A", "B"], "pref_mat": np.array([[65, 66, 65], [66, 65, 66]]), "scheme": 1} # scheme is not 2 as in manual selection pc = PC(**params) vsr = VSR() vsr.voting_simulation(pc.pref_mat, pc.scheme) tv = TV(pref_mat=pc.pref_mat, voting_outcome=vsr.results, scheme=pc.scheme) """Expected outcome: Bullet voting as well as compromising possible for all""" return pc, vsr, tv
def __init__(self, pref_mat, voting_outcome, scheme): self.pref_mat = pref_mat self.voting_outcome = voting_outcome self.vsr = VSR() self.scheme = scheme self.n_candidates = pref_mat.shape[0] self.n_voters = pref_mat.shape[1] self.strategic_voting_options = [[] for _ in range(self.n_voters)]
if __name__ == "__main__": modes = { 1: "Manual input", 2: "Integration test: 2 candidates, 3 voters, voting for two", 3: "Integration test: M candidates, N voters, pick a voting scheme, random preferences" } for k, v in modes.items(): print("{}: {}".format(k, v)) mode = input("\nPlease choose one of the options listed [1/2/3]\n") if mode == "1": pc = PC() vsr = VSR() pc.get_preferences() vsr.voting_simulation(pc.pref_mat, pc.scheme) tv = TacticalVoting(pc.pref_mat, vsr.results, pc.scheme) elif mode == "2": pc, vsr, tv = IT.integration_voting_for_two() elif mode == "3": M = int(input("Enter number of candidates: ")) if not (isinstance(M, int)) or (not M > 0): print("Select an Integer > 0") exit() N = int(input("Enter number of voters: ")) if not (isinstance(N, int)) or (not N > 0): print("Select an Integer > 0") exit() voting_schemes = [
class TacticalVoting: def __init__(self, pref_mat, voting_outcome, scheme): self.pref_mat = pref_mat self.voting_outcome = voting_outcome self.vsr = VSR() self.scheme = scheme self.n_candidates = pref_mat.shape[0] self.n_voters = pref_mat.shape[1] self.strategic_voting_options = [[] for _ in range(self.n_voters)] def bullet_voting(self): """Calculate whether voting for just one of the alternatives can result in greater happiness""" # bullet voting can be applied, but it will not achieve anything # if self.scheme == 0: # print("Bullet voting cannot be applied to plurality voting.") happiness = self.vsr.get_happiness(self.pref_mat, self.voting_outcome) for voter in range(self.n_voters): for candidate in np.unique(self.pref_mat): # voter i attempts tactical voting for each possible candicate bullet_pref_mat = np.copy(self.pref_mat) bullet_pref_mat[1:, voter] = 0 bullet_pref_mat[0, voter] = candidate tactical_results = self.vsr.voting_simulation(bullet_pref_mat, self.scheme) try: del tactical_results[0] # Delete the '0' candidate except KeyError: pass tactical_happiness = self.vsr.get_happiness(self.pref_mat, tactical_results) happiness_gain = tactical_happiness[voter] - happiness[voter] str_tactical_results = dict(zip([chr(i) for i in tactical_results.keys()], tactical_results.values())) if happiness_gain > 0: voter_num = voter +1 print_gain = np.round(happiness_gain, 3) self.strategic_voting_options[voter].append({ "Preference list": [chr(i).replace('\x00','') for i in bullet_pref_mat[:, voter]], "Voting result": deepcopy(str_tactical_results), "New happiness": np.copy(sum(tactical_happiness)), "Description": "Happiness of voter {} increased by : {} due to voting only for {}".format( voter_num, print_gain, chr(candidate)) }) def compromising_strategy(self): """Tactical voting by ranking alternatives insincerely higher (lower)""" happiness = self.vsr.get_happiness(self.pref_mat, self.voting_outcome) for voter in range(self.n_voters): for c1 in range(self.n_candidates): # candidate 1 for c2 in range(self.n_candidates): # candidate 2 # tactic: swap candidates c1 and c2 if (c1 >= c2): continue comp_pref = np.copy(self.pref_mat) comp_pref[c1, voter], comp_pref[c2, voter] = comp_pref[c2, voter], comp_pref[c1, voter] tactical_results = self.vsr.voting_simulation(comp_pref, self.scheme) tactical_happiness = self.vsr.get_happiness(self.pref_mat, tactical_results) happiness_gain = tactical_happiness[voter] - happiness[voter] str_tactical_results = dict(zip([chr(i) for i in tactical_results.keys()], tactical_results.values())) if happiness_gain > 0: c1_name = chr(self.pref_mat[c1, voter]) c2_name = chr(self.pref_mat[c2, voter]) voter_num = voter +1 print_gain = np.round(happiness_gain, 3) self.strategic_voting_options[voter].append({ "Preference list": [chr(i) for i in comp_pref[:, voter]], "Voting results": deepcopy(str_tactical_results), "New happiness": np.copy(sum(tactical_happiness)), "Description": "Happiness of voter {} increased by {} due to swapping {} with {}".format( voter_num, print_gain, c1_name, c2_name) }) def compromising_strategy_permutations(self): """Compromising using permutations""" happiness = self.vsr.get_happiness(self.pref_mat, self.voting_outcome) for voter in range(self.n_voters): # create (n_candidates!)x(n_candidates) permutation matrix permutation_mat = np.array(list(permutations(self.pref_mat[:, voter]))) for i in range(permutation_mat.shape[0]): comp_pref = np.copy(self.pref_mat) comp_pref[:, voter] = permutation_mat[i, :] tactical_results = self.vsr.voting_simulation(comp_pref, self.scheme) tactical_happiness = self.vsr.get_happiness(comp_pref, tactical_results) happiness_gain = tactical_happiness[voter] - happiness[voter] str_tactical_results = dict(zip([chr(i) for i in tactical_results.keys()], tactical_results.values())) if happiness_gain > 0: voter_num = voter +1 print_gain = np.round(happiness_gain, 3) self.strategic_voting_options[voter].append({ "Preference list": [chr(i) for i in comp_pref[:, voter]], "Voting results": deepcopy(str_tactical_results), "New happiness": np.copy(sum(tactical_happiness)), "Description": "Happiness of voter {} increased by : {} due to reordering of preferences".format( voter_num, print_gain) })
def test_anti_plurality_voting(self): pc = simple_test_scheme() vsr = VSR() desired_outcome = {65: 4, 66: 4, 67: 4, 68: 0} self.assertEqual(vsr.anti_plurality_voting(pc.pref_mat), desired_outcome)
def test_borda_voting(self): pc = simple_test_scheme() vsr = VSR() desired_outcome = {65: 12, 66: 8, 67: 4, 68: 0} self.assertEqual(vsr.borda_voting(pc.pref_mat), desired_outcome)
def test_voting_for_two(self): pc = simple_test_scheme() vsr = VSR() desired_outcome = {65: 4, 66: 4, 67: 0, 68: 0} self.assertEqual(vsr.voting_for_two(pc.pref_mat), desired_outcome)