示例#1
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")
示例#2
0
    def __init__(self):
        self.rule_algorithm_resolute = []
        self.rule_algorithm_onlyresolute = []
        self.rule_algorithm_onlyirresolute = []
        for rule_id in abcrules.MAIN_RULE_IDS:
            rule = abcrules.get_rule(rule_id)
            for algorithm in list(rule.algorithms) + ["fastest"]:
                for resolute in rule.resolute_values:
                    if algorithm in MARKS:
                        if algorithm == "fastest":
                            actual_algorithm = rule.fastest_available_algorithm
                            if actual_algorithm is None:
                                continue
                        else:
                            actual_algorithm = algorithm
                        instance = pytest.param(
                            rule_id, algorithm, resolute, marks=MARKS[actual_algorithm]
                        )
                        instance_no_resolute_param = pytest.param(
                            rule_id, algorithm, marks=MARKS[actual_algorithm]
                        )
                    else:
                        raise ValueError(
                            f"Algorithm {algorithm} (for {rule_id}) "
                            f"not known in unit tests "
                            f"(pytest marks are missing)."
                        )

                    self.rule_algorithm_resolute.append(instance)
                    if resolute:
                        self.rule_algorithm_onlyresolute.append(instance_no_resolute_param)
                    else:
                        self.rule_algorithm_onlyirresolute.append(instance_no_resolute_param)
示例#3
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)
示例#4
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,
        )
示例#5
0
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,
        )
示例#6
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
                    )
示例#7
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
示例#8
0
def _list_abc_yaml_compute_instances():
    _abc_yaml_instances = []
    currdir = os.path.dirname(os.path.abspath(__file__))
    filenames = [
        currdir + "/test_instances/" + filename
        for filename in os.listdir(currdir + "/test_instances/")
        if filename.endswith(".abc.yaml")
    ]
    for filename in filenames:
        for rule_id in abcrules.MAIN_RULE_IDS:
            rule = abcrules.get_rule(rule_id)
            for algorithm in rule.algorithms:
                if "instanceS" in filename:
                    marks = []  # small instances, rather fast
                elif "instanceVL" in filename:
                    marks = [pytest.mark.slow, pytest.mark.veryslow]  # very large instances
                elif rule_id == "monroe" and algorithm in ["mip_cbc"]:
                    marks = [pytest.mark.slow, pytest.mark.veryslow]
                else:
                    marks = [pytest.mark.slow]
                _abc_yaml_instances.append(
                    pytest.param(filename, rule_id, algorithm, marks=marks + MARKS[algorithm])
                )
    return filenames, _abc_yaml_instances
示例#9
0
            {1, 2, 3},
        ],
        {2},
        [{0, 1, 3}],
        [{1, 2, 4}],
    ),
    # ("minimaxphragmen", True, 3, [{a, b}] + [{b, c, d}] * 3, [a}, {{b, c, d}}, {{a, b, c}]),
    # this does not work because minimax-Phragmen does not support a specified tiebreaking
    # 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
示例#10
0
def test_output(capfd, rule_id, algorithm, resolute, verbosity):
    if algorithm == "fastest":
        return
        # not necessary, output for "fastest" is the same as
        # whatever algorithm is selected as fastest
        # (and "fastest" depends on the available solvers)

    if algorithm == "cvxpy_glpk_mi":
        # TODO unfortunately GLPK_MI prints "Long-step dual simplex will be used" to stderr and it
        #  would be very complicated to capture this on all platforms reliably, changing
        #  sys.stderr doesn't help.
        #  This seems to be fixed in GLPK 5.0 but not in GLPK 4.65. For some weird reason this
        #  test succeeds and does not need to be skipped when using conda-forge, although the
        #  version from conda-forge is given as glpk 4.65 he80fd80_1002.
        #  This could help to introduce a workaround: https://github.com/xolox/python-capturer
        #  Sage math is fighting the same problem: https://trac.sagemath.org/ticket/24824
        pytest.skip("GLPK_MI prints something to stderr, not easy to capture")

    output.set_verbosity(verbosity=verbosity)

    try:
        profile = Profile(2)
        profile.add_voters([[0]])
        committeesize = 1

        committees = abcrules.compute(
            rule_id, profile, committeesize, algorithm=algorithm, resolute=resolute
        )
        out = str(capfd.readouterr().out)

        # remove unwanted solver output
        out = remove_solver_output(out)

        if verbosity >= WARNING:
            assert out == ""
        else:
            assert len(out) > 0
            rule = abcrules.get_rule(rule_id)
            start_output = misc.header(rule.longname) + "\n"
            if resolute and rule.resolute_values[0] == False:
                # only if irresolute is default but resolute is chosen
                start_output += "Computing only one winning committee (resolute=True)\n\n"
            if not resolute and rule.resolute_values[0] == True:
                # only if resolute is default but resolute=False is chosen
                start_output += (
                    "Computing all possible winning committees for any tiebreaking order\n"
                    " (aka parallel universes tiebreaking) (resolute=False)\n\n"
                )
            if verbosity <= DETAILS:
                start_output += "Algorithm: " + abcrules.ALGORITHM_NAMES[algorithm] + "\n"
            if verbosity <= DEBUG:
                assert start_output in out
            else:
                assert out.startswith(start_output)
            end_output = (
                f"{misc.str_committees_header(committees, winning=True)}\n"
                f"{misc.str_sets_of_candidates(committees, cand_names=profile.cand_names)}\n"
            )
            if verbosity == INFO:
                assert out.endswith(end_output)
            else:
                assert end_output in out

    finally:
        output.set_verbosity(verbosity=WARNING)
示例#11
0
    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}]


@pytest.mark.parametrize(
    "algorithm",
    [
        pytest.param(algorithm, marks=MARKS[algorithm])
        for algorithm in abcrules.get_rule("monroe").algorithms
    ],
)
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}]


@pytest.mark.parametrize(
    "algorithm",
    [
示例#12
0
        [{1, 2, 3, 6, 7}],
    ),
]

for inst in monotonicity_instances:
    (
        rule_id,
        committeesize,
        approval_sets,
        addvoter,
        new_approval_set,
        commsfirst,
        commsafter,
    ) = inst

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

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

    # irresolute if possible
    if False in abcrules.get_rule(rule_id).resolute_values:
        resolute = False
    else:
        resolute = True

    committees = abcrules.compute(rule_id,
                                  profile,
                                  committeesize,
示例#13
0
def generate_abc_yaml_testinstances(
    batchname,
    committeesizes,
    num_voters_values,
    num_cand_values,
    prob_distributions,
    approval_setsizes,
    av_neq_pav=False,
):
    random.seed(24121838)

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

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

    for index, (committeesize, num_voters, num_cand, prob_distribution,
                setsize) 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_profile(num_voters, num_cand, committeesize,
                                       prob_distribution, setsize)
            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.get_rule(rule_id)
            # if rule_id == "minimaxphragmen":
            #     algorithm = "mip_gurobi"
            # else:
            #     algorithm = "fastest"

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

            for resolute in rule.resolute_values:
                rule_instances.append({
                    "rule_id": rule_id,
                    "resolute": resolute,
                    "expected_committees": 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}, "
                f"setsize={setsize}"),
            compute_instances=rule_instances,
        )

    print("Done.")
示例#14
0
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.get_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"