コード例 #1
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_abcrules_correct_simple(rule_id, algorithm, resolute):
    def simple_checks(_committees):
        if rule_id == "rule-x-without-phragmen-phase":
            assert _committees == [set()]
            return
        if resolute:
            assert len(_committees) == 1
        else:
            assert len(_committees) == 6

    profile = Profile(4)
    profile.add_voters([{0}, {1}, {2}, {3}])
    committeesize = 2

    committees = abcrules.compute(
        rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute
    )
    simple_checks(committees)

    # call abcrules function differently, results should be the same
    committees = abcrules.get_rule(rule_id).compute(
        profile,
        committeesize,
        algorithm=algorithm,
        resolute=resolute,
    )
    simple_checks(committees)

    # using the default algorithm
    committees = abcrules.compute(rule_id, profile, committeesize, resolute=resolute)
    simple_checks(committees)
コード例 #2
0
ファイル: genprofiles.py プロジェクト: lumbric/abcvoting
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.0
    approval_sets = []
    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.0:
            # base case: sample uniformly at random
            party = random.choice(parties)
            randpartyset = list(party_cands[party])
            approval_sets.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:
                    approval_sets.append(list(party_cands[party]))
                    break
                else:
                    r -= count
    profile = Profile(num_cand)
    profile.add_voters(approval_sets)
    return profile
コード例 #3
0
ファイル: genprofiles.py プロジェクト: lumbric/abcvoting
def random_urn_profile(num_cand, num_voters, setsize, replace):
    """Generate Polya Urn profile with fixed size approval sets."""
    currsize = 1.0
    approval_sets = []
    replacedsets = {}

    for _ in range(num_voters):
        r = random.random() * currsize
        if r < 1.0:
            # base case: sample uniformly at random
            randset = random.sample(range(num_cand), setsize)
            approval_sets.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 approval_set in replacedsets:
                count = replacedsets[approval_set]
                if r <= count:
                    approval_sets.append(list(approval_set))
                    break
                else:
                    r -= count
    profile = Profile(num_cand)
    profile.add_voters(approval_sets)
    return profile
コード例 #4
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_cvxpy_cant_compute_av():
    profile = Profile(4)
    profile.add_voters([[0, 1], [1, 2]])
    committeesize = 2

    with pytest.raises(ValueError):
        cvxpy_thiele_methods(profile, committeesize, "av", resolute=False, solver_id="glpk_mi")
コード例 #5
0
ファイル: rules.py プロジェクト: szufix/mapel
def compute_abcvoting_rule(experiment=None,
                           rule_name=None,
                           committee_size=1,
                           printing=False,
                           resolute=False):
    all_winning_committees = {}
    for election in experiment.instances.values():
        if printing:
            print(election.election_id)
        profile = Profile(election.num_candidates)
        if experiment.instance_type == 'ordinal':
            profile.add_voters(election.approval_votes)
        elif experiment.instance_type == 'approval':
            profile.add_voters(election.votes)
        try:
            winning_committees = abcrules.compute(rule_name,
                                                  profile,
                                                  committee_size,
                                                  algorithm="gurobi",
                                                  resolute=resolute)
            # print(winning_committees)
        except Exception:
            try:
                winning_committees = abcrules.compute(rule_name,
                                                      profile,
                                                      committee_size,
                                                      resolute=resolute)
            except:
                winning_committees = {}
        all_winning_committees[election.election_id] = winning_committees
    store_committees_to_file(experiment.experiment_id, rule_name,
                             all_winning_committees)
コード例 #6
0
def random_ic_fixed_size_profile(num_voters, num_cand, setsize):
    """
    Generate a random profile using the *IC with fixed-size approval sets* distribution.

    Parameters
    ----------
        num_voters : int
            The desired number of voters in the profile.

        num_cand : int
            The desired number of candidates in the profile.

        setsize : int
            Number of candidates that each voter approves.

    Returns
    -------
        abcvoting.preferences.Profile
    """
    approval_sets = []
    for _ in range(num_voters):
        randset = list(range(num_cand))
        rng.shuffle(randset)
        randset = randset[:setsize]
        approval_sets.append(randset)
    profile = Profile(num_cand)
    profile.add_voters(approval_sets)
    return profile
コード例 #7
0
def test_thiele_scores(scorefct_id, score, num_cand):
    profile = Profile(num_cand)
    approval_sets = [[0, 1], [1], [1, 3], [4], [1, 2, 3, 4, 5], [1, 5, 3], [0, 1, 2, 4, 5]]
    profile.add_voters(approval_sets)
    committee = [6, 7]
    assert scores.thiele_score(scorefct_id, profile, committee) == 0
    committee = [1, 2, 3, 4]
    assert scores.thiele_score(scorefct_id, profile, committee) == score
コード例 #8
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_monroe_indivisible(algorithm):
    profile = Profile(4)
    profile.add_voters([[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}]
コード例 #9
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_seqphragmen_irresolute():
    profile = Profile(3)
    profile.add_voters([[0, 1], [0, 1], [0], [1, 2], [2]])
    committeesize = 2
    committees = abcrules.compute("seqphragmen", profile, committeesize, resolute=False)
    assert committees == [{0, 1}, {0, 2}]

    committees = abcrules.compute("seqphragmen", profile, committeesize, resolute=True)
    assert committees == [{0, 2}]
コード例 #10
0
def random_mallows_profile(num_voters, num_cand, setsize, dispersion):
    """
    Generate a random profile using the *Truncated Mallows* probability distribution.

    Based on the definition for the repeated insertion model (RIM) in
    https://icml.cc/2011/papers/135_icmlpaper.pdf

    Parameters
    ----------
        num_voters : int
            The desired number of voters in the profile.

        num_cand : int
            The desired number of candidates in the profile.

        setsize : int
            Number of candidates that each voter approves.

        dispersion : float in [0, 1]
            Dispersion parameter of the Mallows model.

    Returns
    -------
        abcvoting.preferences.Profile
    """
    def _select_pos(distribution):
        """Returns a randomly selected value with the help of the distribution."""
        if round(sum(distribution), 10) != 1.0:
            raise Exception("Invalid Distribution", distribution, "sum:",
                            sum(distribution))
        r = round(rng.random(), 10)  # or random.uniform(0, 1)
        pos = -1
        s = 0
        for p in distribution:
            pos += 1
            s += p
            if s >= r:
                return pos

        return pos  # in case of rounding errors

    if not 0 < dispersion <= 1:
        raise Exception("Invalid dispersion, needs to be in (0, 1].")
    reference_ranking = list(range(num_cand))
    rng.shuffle(reference_ranking)
    insert_dist = _compute_mallows_insert_distributions(num_cand, dispersion)
    approval_sets = []
    for _ in range(num_voters):
        vote = []
        for i, distribution in enumerate(insert_dist):
            pos = _select_pos(distribution)
            vote.insert(pos, reference_ranking[i])

        approval_sets.append(vote[:setsize])
    profile = Profile(num_cand)
    profile.add_voters(approval_sets)
    return profile
コード例 #11
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_gurobi_cant_compute_av():
    profile = Profile(4)
    profile.add_voters([[0, 1], [1, 2]])
    committeesize = 2

    scorefct = scores.get_scorefct("av", committeesize)

    with pytest.raises(ValueError):
        _gurobi_thiele_methods(profile, committeesize, scorefct, resolute=False)
コード例 #12
0
def random_urn_fixed_size_profile(num_voters, num_cand, setsize, replace):
    """
    Generate a random profile using the *Polya Urn with fixed-size approval sets* distribution.

    Parameters
    ----------
        num_voters : int
            The desired number of voters in the profile.

        num_cand : int
            The desired number of candidates in the profile.

        setsize : int
            Number of candidates that each voter approves.

        replace : float
            New balls added to the urn in each iteration, relative to the original number.

            The urn starts with (`num_cand` choose `setsize`) balls, each representing a set
            of candidates with size `setsize`. This quantity is normalized to `1.0`.
            The `replace` value is a float that indicates how many balls are added using this
            normalization. Specifically, `replace` *  (`num_cand` choose `setsize`) are added
            in each iteration.

    Returns
    -------
        abcvoting.preferences.Profile
    """
    currsize = 1.0
    approval_sets = []
    replacedsets = {}

    for _ in range(num_voters):
        r = rng.random() * currsize
        if r < 1.0:
            # base case: sample uniformly at random
            randset = list(range(num_cand))
            rng.shuffle(randset)
            randset = randset[:setsize]
            approval_sets.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 = rng.integers(0, sum(replacedsets.values()))
            for approval_set, count in replacedsets.items():
                if r <= count:
                    approval_sets.append(list(approval_set))
                    break
                r -= count
    profile = Profile(num_cand)
    profile.add_voters(approval_sets)
    return profile
コード例 #13
0
ファイル: genprofiles.py プロジェクト: lumbric/abcvoting
def random_IC_profile(num_cand, num_voters, setsize):
    """Generates profile with random assignment of candidates to
    the fix size of setsize."""
    approval_sets = []
    for _ in range(num_voters):
        randset = random.sample(range(num_cand), setsize)
        approval_sets.append(randset)
    profile = Profile(num_cand)
    profile.add_voters(approval_sets)
    return profile
コード例 #14
0
def test_dominate():
    profile = Profile(6)
    profile.add_voters([[0, 1], [0, 1], [1, 2, 3], [2, 3]])
    assert not misc.dominate(profile, {0, 2}, {1, 3})
    assert not misc.dominate(profile, {0, 2}, {1, 2})
    assert misc.dominate(profile, {1, 3}, {0, 2})
    assert misc.dominate(profile, {1, 2}, {0, 2})
    assert not misc.dominate(profile, {0, 2}, {0, 2})
    assert not misc.dominate(profile, {1}, {2})
    assert not misc.dominate(profile, {2}, {1})
コード例 #15
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_fastest_available_algorithm(rule_id):
    profile = Profile(4)
    profile.add_voters([[0, 1], [1, 2], [0, 2, 3]])
    committeesize = 2
    algorithm = abcrules.get_rule(rule_id).fastest_available_algorithm
    if algorithm is None:
        pytest.skip("no supported algorithms for " + abcrules.get_rule(rule_id).shortname)
    for resolute in abcrules.get_rule(rule_id).resolute_values:
        abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute)
    # second possibility
    abcrules.compute(rule_id, profile, committeesize, algorithm="fastest")
コード例 #16
0
def test_approved_candidates():
    profile = Profile(10)
    profile.add_voter(Voter([1, 3, 5], 3))
    profile.add_voter([0])
    assert profile.approved_candidates() == {0, 1, 3, 5}
    profile.add_voter([4])
    assert profile.approved_candidates() == {0, 1, 3, 4, 5}
    profile.add_voters([[7], [1, 8]])
    assert profile.approved_candidates() == {0, 1, 3, 4, 5, 7, 8}
    profile[0].approved = [1, 5]
    assert profile.approved_candidates() == {0, 1, 4, 5, 7, 8}
コード例 #17
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_abcrules_return_lists_of_sets(rule_id, algorithm, resolute):
    profile = Profile(4)
    profile.add_voters([{0}, [1], [2], {3}])
    committeesize = 2

    committees = abcrules.compute(
        rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute
    )
    assert len(committees) >= 1
    for committee in committees:
        assert isinstance(committee, set)
コード例 #18
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_cvxpy_wrong_score_fct():
    profile = Profile(4)
    profile.add_voters([[0, 1], [2, 3]])
    committeesize = 1
    with pytest.raises(NotImplementedError):
        cvxpy_thiele_methods(
            profile=profile,
            committeesize=committeesize,
            scorefct_id="non_existing",
            resolute=False,
            solver_id="glpk_mi",
        )
コード例 #19
0
ファイル: genprofiles.py プロジェクト: lumbric/abcvoting
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)
    approval_sets = []
    for _ in range(num_voters):
        approval_sets.append(party_cands[random.choice(parties)])
    profile = Profile(num_cand)
    profile.add_voters(approval_sets)
    return profile
コード例 #20
0
def test_unitweights(num_cand):
    profile = Profile(num_cand)
    profile.add_voters([])
    profile.add_voter(Voter([0, 4, 5]))
    profile.add_voter([0, 4, 5])
    p1 = Voter([0, 4, 5])
    p2 = Voter([1, 2])
    profile.add_voters([p1, p2])
    assert profile.has_unit_weights()

    profile.add_voter(Voter([0, 4, 5], 2.4))
    assert not profile.has_unit_weights()

    assert profile.totalweight() == 6.4
コード例 #21
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_unspecified_algorithms(rule_id, resolute):
    rule = abcrules.get_rule(rule_id)
    if resolute not in rule.resolute_values:
        return
    profile = Profile(3)
    profile.add_voters([[0, 1], [1, 2]])
    committeesize = 2
    with pytest.raises(NotImplementedError):
        rule.compute(
            profile,
            committeesize,
            algorithm="made-up-algorithm",
            resolute=resolute,
        )
コード例 #22
0
def test_read_and_write_preflib_file():
    currdir = os.path.dirname(os.path.abspath(__file__))
    profile1 = Profile(6)
    profile1.add_voters([[3], [4, 1, 5], [0, 2], [], [0, 1, 2, 3, 4, 5], [5],
                         [1], [1]])
    fileio.write_profile_to_preflib_toi_file(currdir + "/data/test5.toi",
                                             profile1)
    for use_weights in [True, False]:
        profile2 = fileio.read_preflib_file(currdir + "/data/test5.toi",
                                            use_weights=use_weights)
        assert len(profile1) == len(profile2)
        for i, voter in enumerate(profile1):
            assert voter.weight == profile2[i].weight
            assert voter.approved == set(profile2[i].approved)
コード例 #23
0
ファイル: partylist.py プロジェクト: szufix/mapel
def pav_time(election):

    profile = Profile(election.num_candidates)
    profile.add_voters(election.votes)
    committee_size = 10
    resolute = True
    rule_name = 'pav'
    start = time.time()
    winning_committees = abcrules.compute(rule_name,
                                          profile,
                                          committee_size,
                                          algorithm="gurobi",
                                          resolute=resolute)
    return time.time() - start
コード例 #24
0
def test_read_special_abc_yaml_file2():
    currdir = os.path.dirname(os.path.abspath(__file__))
    filename = currdir + "/data/test8.abc.yaml"

    profile1 = Profile(6)
    profile1.add_voters([{3}, {1, 4, 5}, {0, 2}, {}, {0, 1, 2, 3, 4, 5},
                         {1, 3}, {1}, {1}])

    profile2, committeesize, compute_instances, data = fileio.read_abcvoting_yaml_file(
        filename)
    assert str(profile1) == str(profile2)
    assert committeesize == 2
    assert len(compute_instances) == 1
    assert abcrules.compute(**compute_instances[0]) == [{1, 3}]
コード例 #25
0
def run_single_experiment(varrules,
                          num_voters,
                          quality,
                          perceived_quality,
                          num_objective_voters=0):
    num_cand = len(quality)

    bestcands = [c for c in range(len(quality)) if quality[c] == max(quality)]
    assert len(bestcands) == 1

    averqual = {}
    likelibest = {}
    aversize = {}
    varsize = {}

    # generate votes
    appr_sets = []
    for i in range(0, num_voters):
        appr = []
        for c in range(num_cand):
            if i < num_objective_voters:
                # voter i is objective (uses quality)
                if random.random() < quality[c]:
                    appr.append(c)
            else:
                # voter i is objective (uses perceived_quality)
                if random.random() < perceived_quality[c]:
                    appr.append(c)
        appr_sets.append(appr)
    profile = Profile(num_cand)
    profile.add_voters(appr_sets)
    scores = shortlisting.approval_scores(profile)
    maxapprovalscore = max(scores) / len(profile)

    # compute rules
    for rule in varrules:
        comm = shortlisting.compute(rule, scores, num_voters=len(profile))
        if comm:  # comm not empty
            averqual[rule] = np.average([quality[c] for c in comm])
        else:
            averqual[rule] = 0
        if set(bestcands).issubset(comm):
            likelibest[rule] = 1
        else:
            likelibest[rule] = 0
        aversize[rule] = len(comm)
        varsize[rule] = [len(comm)]

    return averqual, likelibest, aversize, varsize, maxapprovalscore
コード例 #26
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_minimaxphragmen_does_not_use_lexicographic_optimization(algorithm):
    # this test shows that lexicographic optimization is not (yet)
    # implemented for opt-Phragmen (as it is described in
    # http://martin.lackner.xyz/publications/phragmen.pdf)

    profile = Profile(7)
    profile.add_voters([[6], [6], [1, 3], [1, 3], [1, 4], [2, 4], [2, 5], [2, 5]])
    committeesize = 3

    # without lexicographic optimization, this profile has 12 winning committees
    # (with lexicographic optimization only {1, 2, 6} is winning)
    committees = abcrules.compute(
        "minimaxphragmen", profile, committeesize, algorithm=algorithm, resolute=False
    )
    assert len(committees) == 12
コード例 #27
0
def test_read_special_abc_yaml_file1():
    currdir = os.path.dirname(os.path.abspath(__file__))
    filename = currdir + "/data/test7.abc.yaml"

    profile1 = Profile(6)
    profile1.add_voters([[3], [4, 1, 5], [0, 2], [], [0, 1, 2, 3, 4, 5], [5],
                         [1], [1]])
    fileio.write_abcvoting_instance_to_yaml_file(filename,
                                                 profile1,
                                                 description="just a profile")

    profile2, committeesize, compute_instances2, data2 = fileio.read_abcvoting_yaml_file(
        filename)
    assert str(profile1) == str(profile2)
    assert committeesize is None
    assert compute_instances2 == []
コード例 #28
0
ファイル: genprofiles.py プロジェクト: lumbric/abcvoting
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)

    approval_sets = __get_profile_from_points(
        voters, cands, voter_points, cand_points, approval_threshold
    )
    profile = Profile(num_cand)
    profile.add_voters(approval_sets)
    return profile
コード例 #29
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_resolute_parameter(rule_id):
    rule = abcrules.get_rule(rule_id)
    for algorithm in rule.algorithms:
        resolute_values = rule.resolute_values
        assert len(resolute_values) in [1, 2]
        # raise NotImplementedError if value for resolute is not implemented
        for resolute in [False, True]:
            if resolute not in resolute_values:
                profile = Profile(5)
                committeesize = 1
                approval_sets = [{0, 1, 2}, {1}, {1, 2}, {0}]
                profile.add_voters(approval_sets)

                with pytest.raises(NotImplementedError):
                    abcrules.compute(
                        rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute
                    )
コード例 #30
0
ファイル: test_abcrules.py プロジェクト: lumbric/abcvoting
def test_consensus_fails_lower_quota():
    profile = Profile(31)
    profile.add_voters(
        [[0]]
        + [[1, 2]] * 3
        + [[3, 4, 5]] * 5
        + [[6, 7, 8, 9, 10, 11, 12, 13, 14, 15]] * 18
        + [[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30]] * 27
    )
    committeesize = 30

    committees = abcrules.compute("consensus-rule", profile, committeesize, resolute=True)
    for committee in committees:
        assert not all(
            cand in committee
            for cand in [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
        )