def full_analysis(profile, committee): """ Test all implemented properties for the given committee. Returns a dictionary with the following keys: "pareto", "jr", "pjr", and "ejr". The values are `True` or `False`, depending on whether this property is satisfied. Parameters ---------- profile : abcvoting.preferences.Profile A profile. committee : iterable of int A committee. Returns ------- dict """ results = {} # temporarily no output current_verbosity = output.verbosity output.set_verbosity(WARNING) results["pareto"] = check_pareto_optimality(profile, committee) results["jr"] = check_JR(profile, committee) results["pjr"] = check_PJR(profile, committee) results["ejr"] = check_EJR(profile, committee) description = { "pareto": "Pareto optimality", "jr": "Justified representation (JR)", "pjr": "Proportional justified representation (PJR)", "ejr": "Extended justified representation (EJR)", } # restore output verbosity output.set_verbosity(current_verbosity) for prop, value in results.items(): output.info(f"{description[prop]:50s} : {value}")
def check_pareto_optimality(profile, committee, algorithm="fastest"): """ Test whether a committee satisfies Pareto optimality. Parameters ---------- profile : abcvoting.preferences.Profile A profile. committee : iterable of int A committee. algorithm : str, optional The algorithm to be used. Returns ------- bool References ---------- Multi-Winner Voting with Approval Preferences. Martin Lackner and Piotr Skowron. <https://arxiv.org/abs/2007.01795> Examples -------- .. doctest:: >>> from abcvoting.preferences import Profile >>> from abcvoting.output import output, DETAILS >>> profile = Profile(3) >>> profile.add_voters([[0], [0, 2], [1, 2], [1, 2]]) >>> print(profile) profile with 4 voters and 3 candidates: voter 0: {0}, voter 1: {0, 2}, voter 2: {1, 2}, voter 3: {1, 2} >>> output.set_verbosity(DETAILS) # enable output for check_pareto_optimality >>> result = check_pareto_optimality(profile, committee={0, 1}) Committee {0, 1} is not Pareto optimal. (It is dominated by the committee {0, 2}.) >>> result = check_pareto_optimality(profile, committee={0, 2}) Committee {0, 2} is Pareto optimal. .. testcleanup:: output.set_verbosity() We see that the committee {0, 2} is Pareto optimal, but not the committee {0, 1}. """ # check that `committee` is a valid input committee = CandidateSet(committee, num_cand=profile.num_cand) if algorithm == "fastest": if gb: algorithm = "gurobi" else: algorithm = "brute-force" if algorithm == "brute-force": result, detailed_information = _check_pareto_optimality_brute_force(profile, committee) elif algorithm == "gurobi": result, detailed_information = _check_pareto_optimality_gurobi(profile, committee) else: raise NotImplementedError( "Algorithm " + str(algorithm) + " not specified for check_pareto_optimality" ) if result: output.info(f"Committee {str_set_of_candidates(committee)} is Pareto optimal.") else: output.info(f"Committee {str_set_of_candidates(committee)} is not Pareto optimal.") dominating_committee = detailed_information["dominating_committee"] output.details( f"(It is dominated by the committee {str_set_of_candidates(dominating_committee)}.)" ) return result
def check_JR(profile, committee): """ Test whether a committee satisfies Justified Representation (JR). Parameters ---------- profile : abcvoting.preferences.Profile A profile. committee : iterable of int A committee. Returns ------- bool References ---------- Aziz, H., Brill, M., Conitzer, V., Elkind, E., Freeman, R., & Walsh, T. (2017). Justified representation in approval-based committee voting. Social Choice and Welfare, 48(2), 461-485. https://arxiv.org/abs/1407.8269 Examples -------- .. doctest:: >>> from abcvoting.preferences import Profile >>> from abcvoting.output import output, DETAILS >>> profile = Profile(4) >>> profile.add_voters([[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [3], [3]]) >>> print(profile) profile with 6 voters and 4 candidates: voter 0: {0, 1, 2}, voter 1: {0, 1, 2}, voter 2: {0, 1, 2}, voter 3: {0, 1, 2}, voter 4: {3}, voter 5: {3} >>> output.set_verbosity(DETAILS) # enable output for check_JR >>> result = check_JR(profile, committee={0, 1, 2}) Committee {0, 1, 2} does not satisfy JR. (The 1-cohesive group of voters {4, 5} (33.3% of all voters) jointly approve candidate 3, but none of them approve a candidate in the committee.) >>> result = check_JR(profile, committee={1, 2, 3}) Committee {1, 2, 3} satisfies JR. .. testcleanup:: output.set_verbosity() """ # check that `committee` is a valid input committee = CandidateSet(committee, num_cand=profile.num_cand) result, detailed_information = _check_JR(profile, committee) if result: output.info(f"Committee {str_set_of_candidates(committee)} satisfies JR.") else: output.info(f"Committee {str_set_of_candidates(committee)} does not satisfy JR.") cand = detailed_information["joint_candidate"] cohesive_group = detailed_information["cohesive_group"] output.details( f"(The 1-cohesive group of voters {str_set_of_candidates(cohesive_group)}" f" ({len(cohesive_group)/len(profile)*100:.1f}% of all voters)" f" jointly approve candidate {profile.cand_names[cand]}, but none of them " "approve a candidate in the committee.)" ) return result
def check_PJR(profile, committee, algorithm="fastest"): """ Test whether a committee satisfies Proportional Justified Representation (PJR). Parameters ---------- profile : abcvoting.preferences.Profile A profile. committee : iterable of int A committee. algorithm : str, optional The algorithm to be used. Returns ------- bool References ---------- Sánchez-Fernández, L., Elkind, E., Lackner, M., Fernández, N., Fisteus, J., Val, P. B., & Skowron, P. (2017). Proportional justified representation. In Proceedings of the AAAI Conference on Artificial Intelligence (Vol. 31, No. 1). https://arxiv.org/abs/1611.09928 Examples -------- .. doctest:: >>> from abcvoting.preferences import Profile >>> from abcvoting.output import output, DETAILS >>> profile = Profile(5) >>> profile.add_voters([[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [3, 4], [3, 4]]) >>> print(profile) profile with 6 voters and 5 candidates: voter 0: {0, 1, 2}, voter 1: {0, 1, 2}, voter 2: {0, 1, 2}, voter 3: {0, 1, 2}, voter 4: {3, 4}, voter 5: {3, 4} >>> output.set_verbosity(DETAILS) # enable output for check_PJR >>> result = check_PJR(profile, committee={0, 3, 4}) Committee {0, 3, 4} does not satisfy PJR. (The 2-cohesive group of voters {0, 1, 2, 3} (66.7% of all voters) jointly approve the candidates {0, 1, 2}, but they approve fewer than 2 candidates in the committee.) >>> result = check_PJR(profile, committee={1, 2, 3}) Committee {1, 2, 3} satisfies PJR. .. testcleanup:: output.set_verbosity() """ # check that `committee` is a valid input committee = CandidateSet(committee, num_cand=profile.num_cand) if algorithm == "fastest": if gb: algorithm = "gurobi" else: algorithm = "brute-force" if algorithm == "brute-force": result, detailed_information = _check_PJR_brute_force(profile, committee) elif algorithm == "gurobi": result, detailed_information = _check_PJR_gurobi(profile, committee) else: raise NotImplementedError("Algorithm " + str(algorithm) + " not specified for check_PJR") if result: output.info(f"Committee {str_set_of_candidates(committee)} satisfies PJR.") else: output.info(f"Committee {str_set_of_candidates(committee)} does not satisfy PJR.") ell = detailed_information["ell"] cands = detailed_information["joint_candidates"] cohesive_group = detailed_information["cohesive_group"] output.details( f"(The {ell}-cohesive group of voters {str_set_of_candidates(cohesive_group)}" f" ({len(cohesive_group)/len(profile)*100:.1f}% of all voters)" f" jointly approve the candidates {str_set_of_candidates(cands)}, but they " f"approve fewer than {ell} candidates in the committee.)" ) return result
def check_EJR(profile, committee, algorithm="fastest"): """ Test whether a committee satisfies Extended Justified Representation (EJR). Parameters ---------- profile : abcvoting.preferences.Profile A profile. committee : iterable of int A committee. algorithm : str, optional The algorithm to be used. Returns ------- bool References ---------- Aziz, H., Brill, M., Conitzer, V., Elkind, E., Freeman, R., & Walsh, T. (2017). Justified representation in approval-based committee voting. Social Choice and Welfare, 48(2), 461-485. https://arxiv.org/abs/1407.8269 Examples -------- .. doctest:: >>> from abcvoting.preferences import Profile >>> from abcvoting.output import output, DETAILS >>> profile = Profile(5) >>> profile.add_voters([[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [3, 4], [3, 4]]) >>> print(profile) profile with 6 voters and 5 candidates: voter 0: {0, 1, 2}, voter 1: {0, 1, 2}, voter 2: {0, 1, 2}, voter 3: {0, 1, 2}, voter 4: {3, 4}, voter 5: {3, 4} >>> output.set_verbosity(DETAILS) # enable output for check_EJR >>> result = check_EJR(profile, committee={0, 3, 4}) Committee {0, 3, 4} does not satisfy EJR. (The 2-cohesive group of voters {0, 1, 2, 3} (66.7% of all voters) jointly approve the candidates {0, 1, 2}, but none of them approves 2 candidates in the committee.) >>> result = check_EJR(profile, committee={1, 2, 3}) Committee {1, 2, 3} satisfies EJR. .. testcleanup:: output.set_verbosity() """ # check that `committee` is a valid input committee = CandidateSet(committee, num_cand=profile.num_cand) if algorithm == "fastest": if gb: algorithm = "gurobi" else: algorithm = "brute-force" if algorithm == "brute-force": result, detailed_information = _check_EJR_brute_force(profile, committee) elif algorithm == "gurobi": result, detailed_information = _check_EJR_gurobi(profile, committee) else: raise NotImplementedError("Algorithm " + str(algorithm) + " not specified for check_EJR") if result: output.info(f"Committee {str_set_of_candidates(committee)} satisfies EJR.") else: output.info(f"Committee {str_set_of_candidates(committee)} does not satisfy EJR.") ell = detailed_information["ell"] cands = detailed_information["joint_candidates"] cohesive_group = detailed_information["cohesive_group"] output.details( f"(The {ell}-cohesive group of voters {str_set_of_candidates(cohesive_group)}" f" ({len(cohesive_group)/len(profile)*100:.1f}% of all voters)" f" jointly approve the candidates {str_set_of_candidates(cands)}, but none of them " f"approves {ell} candidates in the committee.)", indent=" ", ) return result