Computing winning committees ============================ One of the main goals of `abcvoting` is to provide a simple way to compute winning committees for a given ABC rule. Here is a bit more detailed explanation of how to do this. (A first, simple explanation can be found :doc:`here `. First steps ----------- ABC rules are identified by an identifier called `rule_id`. :doc:`Here ` is a list of these identifiers. Say we are interested in Proportional Approval Voting, short: PAV. Its `rule_id` is `"pav"`. The input of an ABC rule consists of a profile and a desired committee size. Once we know the `rule_id` and have a profile and a desired committee size, we can compute the ABC rule. In the following, we use the simple example used :doc:`previously `. .. testsetup:: from abcvoting import abcrules from abcvoting.misc import CandidateSet abcrules.available_algorithms = ["brute-force", "standard", "standard-fractions"] .. doctest:: >>> from abcvoting.preferences import Profile >>> from abcvoting import abcrules >>> rule_id = "pav" >>> profile = Profile(num_cand=5) >>> profile.add_voters([{0, 1, 2}, {3}, {0, 1, 2, 3}, {0, 1, 2, 4}, {0, 1}, {4}]) >>> print(abcrules.compute("pav", profile, committeesize=3)) [CandidateSet({0, 1, 3}), CandidateSet({0, 1, 4})] The output of all ABC is rules is a list of `CandidateSet` (:class:`abcvoting.misc.CandidateSet`). This is a subclass of set and represents a set of candidates. Number of winning committees ---------------------------- Most ABC voting rules may return more than one winning committees; these committees are "tied". Sometimes one is only interested in one (or a just few) winning committees. As it is generally computationally more difficult to compute all winning committees, also runtime considerations may necessitate a limit. There are two ways how to determine the maximum number of winning committees: the parameter `resolute` and the parameter `max_num_of_committees`. Both are implemented for the `compute` functions of all ABC rules. If `resolute=True`, only one winning committee is returned. .. doctest:: >>> committees = abcrules.compute("pav", profile, committeesize=3, resolute=True) >>> len(committees) 1 If `resolute=False` (which is the default), the maximum number of winning committees is determined by `max_num_of_committees`. .. doctest:: >>> committees = abcrules.compute("pav", profile, committeesize=3, max_num_of_committees=1) >>> len(committees) 1 .. doctest:: >>> committees = abcrules.compute("pav", profile, committeesize=3, max_num_of_committees=4) >>> len(committees) 2 While most ABC rule are implemented for both `resolute=True` and `resolute=False`, for some one choice is more natural than the other. The default value for `resolute` is chosen to reflect this. For example, .. doctest:: >>> abcrules.get_rule("pav").resolute_values (False, True) The first entry in this list is the default choice. That is, if we do not provide the `resolute` parameter when computing PAV, all winning committees are computed (`resolute=False`). For sequential rules (such as Sequential PAV and Reverse Sequential PAV), the default choice is `resolute=True`. Finally, the default choice of `max_num_of_committees` is .. doctest:: >>> print(abcrules.MAX_NUM_OF_COMMITTEES_DEFAULT) None i.e., when `resolute=False`, indeed all winning committees are computed. .. important:: Note that `max_num_of_committees=None` (i.e., an unrestricted maximum number of winning committees) can lead to runtime and memory problems when there is a huge number of winning committees. Algorithms ---------- Most ABC rules can be computed with several algorithms. For example, for PAV, we have .. doctest:: >>> print(abcrules.get_rule("pav").algorithms) ('gurobi', 'pulp-highs', 'pulp-cbc', 'branch-and-bound', 'brute-force') These algorithms are sorted by speed (in approximation). By default, ABC rules are computed with `algorithm="fastest"`, which picks the first available algorithm in this list. Not all algorithms are necessarily available as some of them have optional dependencies. Let us briefly discuss these. Throughout `abcvoting`, the following kinds of algorithms are used: .. doctest:: >>> for algo_id, description in abcrules.ALGORITHM_NAMES.items(): ... print(f"{algo_id:20s} : {description}") gurobi : Gurobi ILP solver pulp-highs : ILP solver via Python PuLP library pulp-cbc : ILP solver via Python PuLP library branch-and-bound : branch-and-bound brute-force : brute-force standard : Standard algorithm standard-fractions : Standard algorithm (using standard Python fractions) gmpy2-fractions : Standard algorithm (using gmpy2 fractions) float-fractions : Standard algorithm (using floats instead of fractions) ortools-cp : OR-Tools CP-SAT solver In addition to the dependencies of abcvoting, `gmpy2-fractions` requires the Python module `gmpy2`. All other algorithms work "out of the box".