def random_urn_profile(num_cand, num_voters, setsize, replace): """Generate Polya Urn profile with fixed size approval sets.""" currsize = 1. apprsets = [] replacedsets = {} for _ in range(num_voters): r = random.random() * currsize if r < 1.: # base case: sample uniformly at random randset = random.sample(range(num_cand), setsize) apprsets.append(randset) key = tuple(set(randset)) if key in replacedsets: replacedsets[key] += 1 else: replacedsets[key] = 1 currsize += replace else: # sample from one of the replaced ballots r = random.randint(0, sum(replacedsets.values())) for apprset in replacedsets: count = replacedsets[apprset] if r <= count: apprsets.append(list(apprset)) break else: r -= count profile = Profile(num_cand) profile.add_preferences(apprsets) return profile
def random_2d_points_party_list_profile(num_cand, num_voters, num_parties, partypointmode, voterpointmode, sigma, uniform=False): """Generates profiles from randomly generated 2d points according to some distributions with the given sigma. This selects parties for each voter, the parties are either uniform (equal size) or randomly generated (at least 1) candidate lists.""" parties = list(range(num_parties)) party_cands = __distribute_candidates_to_parties(num_cand, parties, uniform=uniform) voters = list(range(num_voters)) voter_points = __generate_2d_points(voters, voterpointmode, sigma) party_points = __generate_2d_points(parties, partypointmode, sigma) party_sets = __get_profile_from_points(voters, parties, voter_points, party_points, 1.0) apprsets = [] for p in party_sets: apprsets.append(party_cands[p[0]]) profile = Profile(num_cand) profile.add_preferences(apprsets) return profile
def test_iterate(num_cand): profile = Profile(num_cand) profile.add_preferences(DichotomousPreferences([1, 3, 5], 3)) profile.add_preferences([0, 4, 5]) assert len(profile) == 2 for p in profile: assert isinstance(p, DichotomousPreferences)
def test_fastest_algorithms(rule, resolute): profile = Profile(4) profile.add_preferences([[0, 1], [1, 2], [0, 2, 3]]) committeesize = 2 algo = rule.fastest_algo() if algo is None: pytest.skip("no supported algorithms for " + rule.shortname) rule.compute(profile, committeesize, algorithm=algo, resolute=resolute)
def test_thiele_scores(scorefct_str, score, num_cand): profile = Profile(num_cand) preflist = [[0, 1], [1], [1, 3], [4], [1, 2, 3, 4, 5], [1, 5, 3], [0, 1, 2, 4, 5]] profile.add_preferences(preflist) committee = [6, 7] assert scores.thiele_score(scorefct_str, profile, committee) == 0 committee = [1, 2, 3, 4] assert scores.thiele_score(scorefct_str, profile, committee) == score
def test_party_list(num_cand, add_pref): profile = Profile(num_cand) profile.add_preferences(DichotomousPreferences([1, 3, 5], 3)) profile.add_preferences([0, 4, 6]) profile.add_preferences([0, 4, 6]) profile.add_preferences([2, 7]) profile.add_preferences(DichotomousPreferences([1, 3, 5], 3)) assert profile.party_list() profile.add_preferences(add_pref) assert not profile.party_list()
def random_IC_profile(num_cand, num_voters, setsize): """Generates profile with random assignment of candidates to the fix size of setsize.""" apprsets = [] for _ in range(num_voters): randset = random.sample(range(num_cand), setsize) apprsets.append(randset) profile = Profile(num_cand) profile.add_preferences(apprsets) return profile
def test_unspecified_algorithms(rule, verbose, resolute): if resolute not in rule.resolute: return profile = Profile(3) profile.add_preferences([[0, 1], [1, 2]]) committeesize = 2 with pytest.raises(NotImplementedError): rule.compute(profile, committeesize, algorithm="made-up-algorithm", resolute=resolute, verbose=verbose)
def test_monroe_indivisible(algorithm): if algorithm == "gurobi": pytest.importorskip("gurobipy") profile = Profile(4) profile.add_preferences([[0], [0], [0], [1, 2], [1, 2], [1], [3]]) committeesize = 3 assert (abcrules.compute_monroe(profile, committeesize, algorithm=algorithm, resolute=False) == [[0, 1, 2], [0, 1, 3], [0, 2, 3]])
def test_tiebreaking_order(rule_instance, verbose): rule_id, algorithm = rule_instance profile = Profile(4) profile.add_preferences([[1]] * 2 + [[0]] * 2 + [[2]] * 2) committeesize = 1 committees = abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm, resolute=True, verbose=verbose) assert committees == [[0]]
def test_seqphragmen_irresolute(): profile = Profile(3) profile.add_preferences([[0, 1], [0, 1], [0], [1, 2], [2]]) committeesize = 2 committees = abcrules.rules["seqphrag"].compute(profile, committeesize, resolute=False) assert committees == [[0, 1], [0, 2]] committees = abcrules.rules["seqphrag"].compute(profile, committeesize, resolute=True) assert committees == [[0, 2]]
def test_abcrules__toofewcandidates(rule_instance, verbose): rule_id, algorithm, resolute = rule_instance profile = Profile(5) committeesize = 4 preflist = [[0, 1, 2], [1], [1, 2], [0]] profile.add_preferences(preflist) with pytest.raises(ValueError): abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute, verbose=verbose)
def test_unitweights(num_cand): profile = Profile(num_cand) profile.add_preferences([]) profile.add_preferences(DichotomousPreferences([0, 4, 5])) profile.add_preferences([0, 4, 5]) p1 = DichotomousPreferences([0, 4, 5]) p2 = DichotomousPreferences([1, 2]) profile.add_preferences([p1, p2]) assert profile.has_unit_weights() profile.add_preferences(DichotomousPreferences([0, 4, 5], 2.4)) assert not profile.has_unit_weights() assert profile.totalweight() == 6.4
def random_2d_points_profile(num_cand, num_voters, candpointmode, voterpointmode, sigma, approval_threshold): """Generates profiles from randomly generated 2d points according to some distributions with the given sigma.""" voters = list(range(num_voters)) cands = list(range(num_cand)) voter_points = __generate_2d_points(voters, voterpointmode, sigma) cand_points = __generate_2d_points(cands, candpointmode, sigma) apprsets = __get_profile_from_points(voters, cands, voter_points, cand_points, approval_threshold) profile = Profile(num_cand) profile.add_preferences(apprsets) return profile
def test_optphrag_notiebreaking(): # this test shows that tiebreaking is not (yet) # implemented for opt-Phragmen # requires Gurobi pytest.importorskip("gurobipy") profile = Profile(6) profile.add_preferences([[0], [0], [1, 3], [1, 3], [1, 4], [2, 4], [2, 5], [2, 5]]) committeesize = 3 assert len(abcrules.rules["optphrag"].compute(profile, committeesize, algorithm="gurobi", resolute=False)) == 12
def test_output(capfd, rule_instance, verbose): rule_id, algorithm, resolute = rule_instance profile = Profile(2) profile.add_preferences([[0]]) committeesize = 1 abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute, verbose=verbose) out = capfd.readouterr().out if verbose == 0: assert out == "" else: assert len(out) > 0
def test_abcrules_correct_simple(rule_instance, verbose): rule_id, algorithm, resolute = rule_instance profile = Profile(4) profile.add_preferences([[0], [1], [2], [3]]) committeesize = 2 committees = abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute, verbose=verbose) if resolute: assert len(committees) == 1 else: assert len(committees) == 6
def random_IC_party_list_profile(num_cand, num_voters, num_parties, uniform=False): """Generates profile with random assignment of parties. A party is a list of candidates. If uniform the number of candidates per party is the same, else at least 1.""" parties = list(range(num_parties)) party_cands = __distribute_candidates_to_parties(num_cand, parties, uniform=uniform) apprsets = [] for _ in range(num_voters): apprsets.append(party_cands[random.choice(parties)]) profile = Profile(num_cand) profile.add_preferences(apprsets) return profile
def test_jansonexamples(rule_id, algorithm): # example from Janson's survey (https://arxiv.org/pdf/1611.08826.pdf), # Example 3.7, 18.1 profile = Profile(6) A = 0 B = 1 C = 2 P = 3 Q = 4 R = 5 profile.add_preferences([[A, B, C]] * 1034 + [[P, Q, R]] * 519 + [[A, B, Q]] * 90 + [[A, P, Q]] * 90) committeesize = 3 committees = abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm, resolute=False) assert committees == [[A, B, Q]]
def random_mallows_profile(num_cand, num_voters, setsize, dispersion): """Generates a Mallows Profile after the definition for repeated insertion mode (RIM) in https://icml.cc/2011/papers/135_icmlpaper.pdf""" if not (0 < dispersion < 1): raise Exception("Invalid dispersion, needs to be in (0, 1].") reference_ranking = list(range(num_cand)) random.shuffle(reference_ranking) insert_dist = __compute_mallows_insert_distributions(num_cand, dispersion) apprsets = [] for _ in range(num_voters): vote = [] for i, distribution in enumerate(insert_dist): pos = __select_pos(distribution) vote.insert(pos, reference_ranking[i]) apprsets.append(vote[:setsize]) profile = Profile(num_cand) profile.add_preferences(apprsets) return profile
def random_urn_party_list_profile(num_cand, num_voters, num_parties, replace, uniform=False): """Generate Polya Urn profile from a number of parties. If uniform each party gets the same amount of candidates.""" currsize = 1. apprsets = [] replacedsets = {} parties = list(range(num_parties)) party_cands = __distribute_candidates_to_parties(num_cand, parties, uniform=uniform) for _ in range(num_voters): r = random.random() * currsize if r < 1.: # base case: sample uniformly at random party = random.choice(parties) randpartyset = list(party_cands[party]) apprsets.append(randpartyset) if party in replacedsets: replacedsets[party] += 1 else: replacedsets[party] = 1 currsize += replace else: # sample from one of the parties r = random.randint(0, sum(replacedsets.values())) for party in replacedsets: count = replacedsets[party] if r <= count: apprsets.append(list(party_cands[party])) break else: r -= count profile = Profile(num_cand) profile.add_preferences(apprsets) return profile
def test_invalidprofiles(num_cand): with pytest.raises(ValueError): Profile(0) with pytest.raises(ValueError): Profile(-8) with pytest.raises(ValueError): Profile(4, ["a", "b", "c"]) Profile(4, ["a", 3, "b", "c"]) profile = Profile(num_cand, "abcdefgh") pref = DichotomousPreferences([num_cand]) with pytest.raises(ValueError): profile.add_preferences(pref) with pytest.raises(TypeError): profile.add_preferences([0, 4, 5, "1"]) with pytest.raises(TypeError): profile.add_preferences(["1", 0, 4, 5]) with pytest.raises(TypeError): profile.add_preferences({1: [1, 2]})
def test_abcrules_weightsconsidered(rule_instance, verbose): rule_id, algorithm, resolute = rule_instance profile = Profile(3) profile.add_preferences(DichotomousPreferences([0])) profile.add_preferences(DichotomousPreferences([0])) profile.add_preferences(DichotomousPreferences([1], 5)) profile.add_preferences(DichotomousPreferences([0])) committeesize = 1 if (("monroe" in rule_id or rule_id in ["lexmav", "rule-x", "phrag-enestr"])): with pytest.raises(ValueError): abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm, verbose=verbose) elif rule_id == "mav": # Minimax AV ignores weights by definition result = abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute, verbose=verbose) if resolute: assert result == [[0]] else: assert result == [[0], [1], [2]] else: result = abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute, verbose=verbose) assert len(result) == 1 assert result[0] == [1]
def test_monroescore_matching(committee, score, num_cand): profile = Profile(num_cand) preflist = [[0, 1], [1], [1, 3], [4], [2], [1, 5, 3]] profile.add_preferences(preflist) assert monroescore_matching(profile, committee) == score
def __init__(self): self.instances = [] # first profile profile = Profile(6) preflist = [[0, 4, 5], [0], [1, 4, 5], [1], [2, 4, 5], [2], [3, 4, 5], [3]] profile.add_preferences(preflist) tests = { "seqpav": [[0, 1, 4, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "av": [[0, 1, 4, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "sav": [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5], [0, 1, 3, 4], [0, 1, 3, 5], [0, 1, 4, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "pav": [[0, 1, 4, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "geom2": [[0, 1, 2, 4], [0, 1, 2, 5], [0, 1, 3, 4], [0, 1, 3, 5], [0, 1, 4, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "revseqpav": [[0, 1, 2, 4], [0, 1, 2, 5], [0, 1, 3, 4], [0, 1, 3, 5], [0, 1, 4, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "mav": [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5], [0, 1, 3, 4], [0, 1, 3, 5], [0, 1, 4, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "lexmav": [[0, 1, 4, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "seqphrag": [[0, 1, 4, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "optphrag": [[0, 1, 2, 3]], "cc": [[0, 1, 2, 3]], "seqcc": [[0, 1, 2, 4], [0, 1, 2, 5], [0, 1, 3, 4], [0, 1, 3, 5], [0, 2, 3, 4], [0, 2, 3, 5], [1, 2, 3, 4], [1, 2, 3, 5]], "revseqcc": [[0, 1, 2, 3]], "monroe": [[0, 1, 2, 3]], "greedy-monroe": [[0, 2, 3, 4]], "slav": [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5], [0, 1, 3, 4], [0, 1, 3, 5], [0, 2, 3, 4], [0, 2, 3, 5], [1, 2, 3, 4], [1, 2, 3, 5]], "seqslav": [[0, 1, 2, 4], [0, 1, 2, 5], [0, 1, 3, 4], [0, 1, 3, 5], [0, 1, 4, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "rule-x": [[0, 1, 4, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], "phrag-enestr": [[0, 1, 4, 5], [0, 2, 4, 5], [0, 3, 4, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]], } committeesize = 4 self.instances.append((profile, tests, committeesize)) # first profile now with reversed preflist preflist.reverse() for p in preflist: p.reverse() profile = Profile(6) profile.add_preferences(preflist) # Greedy Monroe yields a different result # for a different voter ordering tests = dict(tests) tests["greedy-monroe"] = [[0, 1, 2, 4]] committeesize = 4 self.instances.append((profile, tests, committeesize)) # second profile profile = Profile(5) committeesize = 3 preflist = [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1], [3, 4], [3, 4], [3]] profile.add_preferences(preflist) tests = { "seqpav": [[0, 1, 3]], "av": [[0, 1, 2]], "sav": [[0, 1, 3]], "pav": [[0, 1, 3]], "geom2": [[0, 1, 3]], "revseqpav": [[0, 1, 3]], "mav": [[0, 1, 3], [0, 2, 3], [1, 2, 3]], "lexmav": [[0, 1, 3]], "seqphrag": [[0, 1, 3]], "optphrag": [[0, 1, 3], [0, 2, 3], [1, 2, 3]], "cc": [[0, 1, 3], [0, 2, 3], [0, 3, 4], [1, 2, 3], [1, 3, 4]], "seqcc": [[0, 1, 3], [0, 2, 3], [0, 3, 4], [1, 2, 3], [1, 3, 4]], "revseqcc": [[0, 1, 3], [0, 2, 3], [0, 3, 4], [1, 2, 3], [1, 3, 4]], "monroe": [[0, 1, 3], [0, 2, 3], [1, 2, 3]], "greedy-monroe": [[0, 1, 3]], "seqslav": [[0, 1, 3]], "slav": [[0, 1, 3]], "rule-x": [[0, 1, 3]], "phrag-enestr": [[0, 1, 3]], } committeesize = 3 self.instances.append((profile, tests, committeesize)) # and a third profile profile = Profile(6) committeesize = 4 preflist = [[0, 3, 4, 5], [1, 2], [0, 2, 5], [2], [0, 1, 2, 3, 4], [0, 3, 4], [0, 2, 4], [0, 1]] profile.add_preferences(preflist) tests = { "seqpav": [[0, 1, 2, 4]], "av": [[0, 1, 2, 4], [0, 2, 3, 4]], "sav": [[0, 1, 2, 4]], "pav": [[0, 1, 2, 4]], "geom2": [[0, 1, 2, 4]], "revseqpav": [[0, 1, 2, 4]], "mav": [[0, 1, 2, 3], [0, 1, 2, 4], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5]], "lexmav": [[0, 1, 2, 4]], "seqphrag": [[0, 1, 2, 4]], "optphrag": [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5]], "cc": [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5]], "seqcc": [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5]], "revseqcc": [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5]], "monroe": [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5], [0, 2, 3, 4], [0, 2, 3, 5], [0, 2, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5]], "greedy-monroe": [[0, 1, 2, 4]], "seqslav": [[0, 1, 2, 4]], "slav": [[0, 1, 2, 4]], "rule-x": [[0, 1, 2, 4]], "phrag-enestr": [[0, 1, 2, 4]], } committeesize = 4 self.instances.append((profile, tests, committeesize)) # and a fourth profile profile = Profile(4) committeesize = 2 preflist = [[0, 1, 3], [0, 1], [0, 1], [0, 3], [2, 3]] profile.add_preferences(preflist) tests = { "seqpav": [[0, 3]], "av": [[0, 1], [0, 3]], "sav": [[0, 1], [0, 3]], "pav": [[0, 3]], "geom2": [[0, 3]], "revseqpav": [[0, 3]], "mav": [[0, 3], [1, 3]], "lexmav": [[0, 3]], "seqphrag": [[0, 3]], "optphrag": [[0, 3], [1, 3]], "cc": [[0, 2], [0, 3], [1, 3]], "seqcc": [[0, 2], [0, 3]], "revseqcc": [[0, 2], [0, 3], [1, 3]], "monroe": [[0, 3], [1, 3]], "greedy-monroe": [[0, 3]], "seqslav": [[0, 3]], "slav": [[0, 3]], "rule-x": [[0, 3]], "phrag-enestr": [[0, 3]], } committeesize = 2 self.instances.append((profile, tests, committeesize))
sys.path.insert(0, '..') from abcvoting import abcrules from abcvoting.preferences import Profile, DichotomousPreferences from abcvoting import misc print(misc.header("Example 5", "*")) # Approval profile num_cand = 4 a, b, c, d = list(range(4)) # a = 0, b = 1, c = 2, ... names = "abcd" apprsets = [[a, b]] * 3 + [[a, d]] * 6 + [[b]] * 4 + [[c]] * 5 + [[c, d]] * 5 profile = Profile(num_cand, names=names) profile.add_preferences(apprsets) print(misc.header("Input:")) print(profile.str_compact()) committees_pav = abcrules.compute_pav(profile, 2, verbose=2) committees_seqpav = abcrules.compute_seqpav(profile, 2, verbose=2) committees_revseqpav = abcrules.compute_revseqpav(profile, 2, verbose=2) # verify correctness assert committees_pav == [[a, c]] assert committees_seqpav == [[c, d]] assert committees_revseqpav == [[c, d]]
""" Compute all implemented ABC rules for a profile """ from __future__ import print_function import sys sys.path.insert(0, '..') from abcvoting.preferences import Profile from abcvoting import abcrules from abcvoting.misc import str_candsets # Compute all implemented ABC rules with the default algorithms # and resolute=True num_cand = 6 profile = Profile(num_cand) profile.add_preferences([[0, 4, 5], [0], [1, 4, 5], [1], [2, 4, 5], [2], [3, 4, 5], [3]]) committeesize = 4 """Prints the winning committees for all implemented rules""" for rule in abcrules.rules.values(): print(rule.longname + ":") committees = rule.compute(profile, committeesize, resolute=True) print(str_candsets(committees))
""" Very simple example (compute PAV) """ from __future__ import print_function import sys sys.path.insert(0, '..') from abcvoting.preferences import Profile from abcvoting import abcrules num_cand = 5 profile = Profile(num_cand) profile.add_preferences([[0, 1, 2], [0, 1], [0, 1], [1, 2], [3, 4], [3, 4]]) committeesize = 3 print("Computing a committee of size", committeesize) print("with the Proportional Approval Voting (PAV) rule") print("given a", profile) committees = abcrules.compute_pav(profile, committeesize) print("\nOutput: " + str(committees))
from __future__ import print_function import sys sys.path.insert(0, '..') from abcvoting import abcrules from abcvoting.preferences import Profile from abcvoting import misc print("Remark 2:\n*********\n") # Approval profile num_cand = 3 a, b, c = list(range(3)) # a = 0, b = 1, c = 2 apprsets = [[a]] * 99 + [[a, b, c]] names = "abc" profile = Profile(num_cand, names=names) profile.add_preferences(apprsets) print(misc.header("Input:")) print(profile.str_compact()) committees_mav = abcrules.compute_mav(profile, 1, verbose=2) committees_lexmav = abcrules.compute_lexmav(profile, 1, verbose=2) # verify correctness assert committees_mav == [[a], [b], [c]] assert committees_lexmav == [[a]]
def read_preflib_file(filename, setsize=1, appr_percent=None): """Reads a single preflib file (soi, toi, soc or toc). Parameters: filename: str Name of the preflib file. setsize: int Number of top-ranked candidates that voters approve. In case of ties, more than setsize candidates are approved. setsize is ignored if appr_percent is used. appr_percent: float in (0, 1] Indicates which percentage of candidates of the ranking are approved (rounded up). In case of ties, more candidates are approved. E.g., if a voter has 10 candidates and this value is 0.75, then the approval set contains the top 8 candidates. Returns: profile: Profile Preference profile extracted from preflib file, including names of candidates """ if setsize <= 0: raise ValueError("Parameter setsize <= 0") if appr_percent and (appr_percent <= 0. or appr_percent > 1.): raise ValueError("Parameter appr_percent not in interval (0, 1]") with open(filename, "r") as f: line = f.readline() num_cand = int(line.strip()) candidate_map = {} for _ in range(num_cand): parts = f.readline().strip().split(",") candidate_map[int(parts[0].strip())] = \ ",".join(parts[1:]).strip() parts = f.readline().split(",") try: voter_count, _, unique_orders = [int(p.strip()) for p in parts] except Exception: raise PreflibException("Number of voters ill specified, " + str(parts) + " should be triple of integers") appr_sets = [] lines = [line.strip() for line in f.readlines() if line.strip()] if len(lines) != unique_orders: raise PreflibException("Number of unique orders should be " + str(unique_orders) + " but is " + str(len(lines))) for line in lines: parts = line.split(",") if len(parts) < 1: continue try: count = int(parts[0]) except ValueError: raise PreflibException("Each ranking must start with count (" + str(line) + ")") ranking = parts[1:] # ranking starts after count if len(ranking) == 0: raise PreflibException("Empty ranking: " + str(line)) if appr_percent: num_appr = int(ceil(len(ranking) * appr_percent)) else: num_appr = setsize appr_set = get_appr_set(num_appr, ranking, candidate_map) for _ in range(count): appr_sets.append(appr_set) # normalize candidates to 0, 1, 2, ... names = [] normalize_map = {} for c in candidate_map.keys(): names.append(candidate_map[c]) normalize_map[c] = len(names) - 1 profile = Profile(num_cand, names) for appr_set in appr_sets: norm_appr_set = [] for c in appr_set: norm_appr_set.append(normalize_map[c]) profile.add_preferences(norm_appr_set) if len(profile) != voter_count: raise PreflibException("Missing voters.") return profile