Пример #1
0
def test_abcrules_weightsconsidered(rule_id, algorithm, resolute):
    profile = Profile(3)
    profile.add_voter(Voter([0]))
    profile.add_voter(Voter([0]))
    profile.add_voter(Voter([1], 5))
    profile.add_voter(Voter([0]))
    committeesize = 1

    if "monroe" in rule_id or rule_id in [
        "lexminimaxav",
        "rule-x",
        "rule-x-without-phragmen-phase",
        "phragmen-enestroem",
    ]:
        with pytest.raises(ValueError):
            abcrules.compute(rule_id, profile, committeesize, algorithm=algorithm)
        return

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

    if rule_id == "minimaxav":
        # Minimax AV ignores weights by definition
        if resolute:
            assert result == [{0}] or result == [{1}] or result == [{2}]
        else:
            assert result == [{0}, {1}, {2}]
    else:
        assert len(result) == 1
        assert result[0] == {1}
Пример #2
0
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)
Пример #3
0
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)
Пример #4
0
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}]
Пример #5
0
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")
Пример #6
0
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)
Пример #7
0
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
                    )
Пример #8
0
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
Пример #9
0
def test_read_and_write_abc_yaml_file():
    currdir = os.path.dirname(os.path.abspath(__file__))
    filename = currdir + "/data/test6.abc.yaml"
    profile1 = Profile(6)
    profile1.add_voters([[3], [4, 1, 5], [0, 2], [], [0, 1, 2, 3, 4, 5], [5],
                         [1], [1]])
    committeesize1 = 3
    compute_instances1 = [
        {
            "rule_id": "pav",
            "resolute": True
        },
        {
            "rule_id": "seqphragmen",
            "algorithm": "float-fractions"
        },
        {
            "rule_id": "equal-shares",
            "algorithm": "standard-fractions",
            "skip_phragmen_phase": True,
        },
    ]

    fileio.write_abcvoting_instance_to_yaml_file(
        filename,
        profile1,
        committeesize=committeesize1,
        compute_instances=compute_instances1)

    profile2, committeesize2, compute_instances2, _ = fileio.read_abcvoting_yaml_file(
        filename)
    assert committeesize1 == committeesize2
    assert len(profile1) == len(profile2)
    for i, voter in enumerate(profile1):
        assert voter.weight == profile2[i].weight
        assert voter.approved == set(profile2[i].approved)
    for i in range(len(compute_instances1)):
        assert abcrules.compute(profile=profile1,
                                committeesize=committeesize1,
                                **compute_instances1[i]) == abcrules.compute(
                                    **compute_instances2[i])
    for compute_instance in compute_instances2:
        compute_instance.pop("profile")
        compute_instance.pop("committeesize")
    assert compute_instances1 == compute_instances2
Пример #10
0
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)
Пример #11
0
def test_abcrules__toofewcandidates(rule_id, algorithm, resolute):
    profile = Profile(5)
    committeesize = 4
    approval_sets = [{0, 1, 2}, {1}, {1, 2}, {0}]
    profile.add_voters(approval_sets)

    with pytest.raises(ValueError):
        abcrules.compute(
            rule_id,
            profile,
            committeesize,
            algorithm=algorithm,
            resolute=resolute,
        )
    with pytest.raises(ValueError):
        abcrules.get_rule(rule_id).compute(
            profile,
            committeesize,
            algorithm=algorithm,
            resolute=resolute,
        )
Пример #12
0
def test_abcrules_handling_empty_ballots(rule_id, algorithm, resolute):
    profile = Profile(4)
    profile.add_voters([{0}, {1}, {2}])
    committeesize = 3

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

    assert committees == [{0, 1, 2}]

    profile.add_voters([[]])

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

    if rule_id == "rule-x-without-phragmen-phase":
        assert committees == [set()]
    else:
        assert committees == [{0, 1, 2}]
Пример #13
0
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]
Пример #14
0
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]]
Пример #15
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}]
Пример #16
0
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
Пример #17
0
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
Пример #18
0
def calculate_committees(election: ApprovalElection,
                         resolute=False,
                         committee_size: int = 10,
                         rule_name=None) -> set:
    profile = preferences.Profile(num_cand=election.num_candidates)
    profile.add_voters(election.votes)
    try:
        committees = abcrules.compute(rule_name,
                                      profile,
                                      committee_size,
                                      resolute=resolute)
    except Exception:
        committees = {}

    return committees
Пример #19
0
def test_abcrules_correct(rule_instance, verbose, instance):
    rule_id, algorithm, resolute = rule_instance
    profile, exp_results, committeesize = instance
    print(profile)
    committees = abcrules.compute(rule_id,
                                  profile,
                                  committeesize,
                                  algorithm=algorithm,
                                  verbose=verbose,
                                  resolute=resolute)
    if resolute:
        assert len(committees) == 1
        assert committees[0] in exp_results[rule_id]
    else:
        assert committees == exp_results[rule_id]
Пример #20
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
Пример #21
0
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]
        )
Пример #22
0
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_voters(
        [[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}]
Пример #23
0
def test_geometric_rules_with_arbitrary_parameter(parameter, prefix, algorithm, resolute):
    profile = Profile(4)
    profile.add_voters([{0}, {1}, {2}, {3}])
    committeesize = 2

    rule_id = f"{prefix}geom{parameter}"
    committees = abcrules.compute(
        rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute
    )
    if resolute:
        assert len(committees) == 1
    else:
        assert len(committees) == 6

    rule = abcrules.get_rule(rule_id)
    committees = rule.compute(profile, committeesize, algorithm=algorithm, resolute=resolute)
    if resolute:
        assert len(committees) == 1
    else:
        assert len(committees) == 6
Пример #24
0
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]]
Пример #25
0
def test_abcrules_correct(rule_id, algorithm, resolute, profile, exp_results, committeesize):
    if rule_id.startswith("geom") and rule_id != "geom2":
        return  # correctness tests only for geom2
    if rule_id.startswith("seq") and rule_id not in ("seqpav", "seqslav", "seqcc"):
        return  # correctness tests only for selected sequential rules
    if rule_id.startswith("revseq") and rule_id != "revseqpav":
        return  # correctness tests only for selected reverse sequential rules (only for revseqpav)
    print(profile)
    committees = abcrules.compute(
        rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute
    )
    print(f"output: {committees}")
    print(f"expected: {exp_results[rule_id]}")
    if resolute:
        assert len(committees) == 1
        assert committees[0] in exp_results[rule_id]
    else:
        # test unordered equality, this requires sets of sets, only possible with frozensets
        committees_ = {frozenset(committee) for committee in committees}
        exp_results_ = {frozenset(committee) for committee in exp_results[rule_id]}
        assert committees_ == exp_results_
Пример #26
0
for inst in manipulations:
    print(misc.header(abcrules.Rule(inst.rule_id).longname, "-"))

    profile = Profile(num_cand, cand_names=cand_names)
    profile.add_voters(inst.approval_sets)
    truepref = profile[0].approved
    print(profile.str_compact())

    parameters = {}
    if inst.rule_id == "leximaxphragmen":
        parameters["lexicographic_tiebreaking"] = True

    committees = abcrules.compute(inst.rule_id,
                                  profile,
                                  inst.committeesize,
                                  resolute=True,
                                  **parameters)
    committee1 = committees[0]
    print("original winning committee:\n " +
          misc.str_set_of_candidates(committee1, cand_names))

    # verify correctness
    assert (
        committee1 in inst.committees_first
    ), f"({inst.rule_id}) {committees[0]} not in {inst.committees_first}"

    print("\nManipulation by voter 0: " +
          misc.str_set_of_candidates(inst.approval_sets[0], cand_names) +
          " --> " +
          misc.str_set_of_candidates(inst.manipulated_vote, cand_names))
def generate_abc_yaml_testinstances(
    batchname,
    committeesizes,
    num_voters_values,
    num_cand_values,
    prob_distributions,
    av_neq_pav=False,
):
    generate.rng = np.random.default_rng(24121838)  # seed for numpy RNG

    parameter_tuples = []
    for committeesize, num_voters, num_cand, prob_distribution in product(
        committeesizes, num_voters_values, num_cand_values, prob_distributions
    ):
        if committeesize >= num_cand:
            continue
        parameter_tuples.append((num_voters, num_cand, prob_distribution, committeesize))
    parameter_tuples.sort(key=itemgetter(1))

    print(f"Generating {len(parameter_tuples)} instances for batch {batchname}...")
    num_instances = 0

    for index, (num_voters, num_cand, prob_distribution, committeesize) in enumerate(
        parameter_tuples
    ):
        num_instances += 1

        # write instance to .abc.yaml file
        currdir = os.path.dirname(os.path.abspath(__file__))
        filename = currdir + f"/instance{batchname}{index:04d}.abc.yaml"

        print(f"generating {filename} ({prob_distribution})")
        while True:
            profile = generate.random_profile(num_voters, num_cand, prob_distribution)
            committees_av = abcrules.compute("av", profile, committeesize, resolute=False)
            committees_pav = abcrules.compute("pav", profile, committeesize, resolute=False)
            if not av_neq_pav:
                break
            intersection = set(tuple(sorted(committee)) for committee in committees_pav) & set(
                tuple(sorted(committee)) for committee in committees_av
            )
            if not intersection:
                break

        rule_instances = []
        for rule_id in abcrules.MAIN_RULE_IDS:
            rule = abcrules.Rule(rule_id)

            # if irresolute (resolute = False) is supported, then "result" should be
            # the list of committees returned for resolute=False.
            if False in rule.resolute_values:
                resolute = False
            else:
                resolute = True

            if rule_id == "rsd":
                committees = None  # result is random, not sensible for unit tests
            elif rule_id == "leximaxphragmen" and (num_cand > 7 or num_voters > 8):
                committees = None  # too slow
            else:
                committees = abcrules.compute(rule_id, profile, committeesize, resolute=resolute)

            for resolute in rule.resolute_values:
                rule_instances.append(
                    {"rule_id": rule_id, "resolute": resolute, "result": committees}
                )

        fileio.write_abcvoting_instance_to_yaml_file(
            filename,
            profile,
            committeesize=committeesize,
            description=(
                f"profile generated via prob_distribution={prob_distribution}, "
                f"num_voters={num_voters}, "
                f"num_cand={num_cand}"
            ),
            compute_instances=rule_instances,
        )

    print("Done.")
Пример #28
0
###

num_cand = 3
a, b, c = (0, 1, 2)
approval_sets = [{a}] * 2 + [{a, c}] * 3 + [{b, c}] * 3 + [{b}] * 2
cand_names = "abcde"
profile = Profile(num_cand, cand_names=cand_names)
profile.add_voters(approval_sets)

print(misc.header("1st profile:"))
print(profile.str_compact())

print("winning committees for k=1 and k=2:")
for rule_id in ["pav", "cc", "monroe", "minimaxphragmen", "minimaxav"]:
    comm1 = abcrules.compute(rule_id, profile, 1, resolute=True)[0]
    comm2 = abcrules.compute(rule_id, profile, 2, resolute=True)[0]
    print(" " + abcrules.Rule(rule_id).shortname + ": " +
          misc.str_set_of_candidates(comm1, cand_names) + " vs " +
          misc.str_set_of_candidates(comm2, cand_names))
    assert not all(cand in comm1 for cand in comm2)

###

num_cand = 4
a, b, c, d = 0, 1, 2, 3
approval_sets = ([{a}] * 6 + [{a, c}] * 4 + [{a, b, c}] * 2 + [{a}] * 2 +
                 [{a, d}] * 1 + [{b, d}] * 3)
cand_names = "abcde"
profile = Profile(num_cand, cand_names=cand_names)
profile.add_voters(approval_sets)
Пример #29
0
    # between committees ([a, b, c] should be prefered to [b, c, d])
]

for manip in manipulations:
    (rule_id, resolute, committeesize, approval_sets, modvote, commsfirst,
     commsafter) = manip

    print(misc.header(abcrules.get_rule(rule_id).longname, "-"))

    profile = Profile(num_cand, cand_names=cand_names)
    profile.add_voters(approval_sets)
    truepref = profile[0].approved
    print(profile.str_compact())

    committees = abcrules.compute(rule_id,
                                  profile,
                                  committeesize,
                                  resolute=resolute)
    print("original winning committees:\n" +
          misc.str_sets_of_candidates(committees, cand_names))

    # verify correctness
    assert committees == commsfirst

    print("Manipulation by voter 0: " +
          misc.str_set_of_candidates(approval_sets[0], cand_names) + " --> " +
          misc.str_set_of_candidates(modvote, cand_names))
    if not all(cand in truepref for cand in modvote):
        print(" (not a subset!)")

    approval_sets[0] = modvote
    profile = Profile(num_cand, cand_names=cand_names)
Пример #30
0
        with_additional_voter=False,
        mod_approval_set={1, 2},
        committees_first=[{1, 2}],
        committees_after=[{0, 2}],
    ),
]

for inst in monotonicity_instances:
    print(misc.header(abcrules.Rule(inst.rule_id).longname, "-"))

    profile = Profile(num_cand, cand_names=cand_names)
    profile.add_voters(inst.approval_sets)
    original_approval_set = set(inst.approval_sets[0])
    print(profile.str_compact())

    committees = abcrules.compute(inst.rule_id, profile, inst.committeesize)
    print("original winning committees:\n" +
          misc.str_sets_of_candidates(committees, cand_names))
    # verify correctness
    assert (committees == inst.committees_first
            ), f"({inst.rule_id}) {committees} != {inst.committees_first}"
    some_variant = any(
        all(cand in committee for cand in inst.mod_approval_set)
        for committee in inst.committees_first)
    all_variant = all(
        all(cand in committee for cand in inst.mod_approval_set)
        for committee in inst.committees_first)
    assert some_variant or all_variant
    if all_variant:
        assert not all(
            all(cand in committee for cand in inst.mod_approval_set)