def __monroe_bruteforce(profile, committeesize, resolute): """Brute-force computation of Monroe's rule""" opt_committees = [] opt_monroescore = -1 for comm in combinations(list(range(profile.num_cand)), committeesize): score = scores.monroescore(profile, comm) if score > opt_monroescore: opt_committees = [comm] opt_monroescore = score elif scores.monroescore(profile, comm) == opt_monroescore: opt_committees.append(comm) committees = sort_committees(opt_committees) if resolute: committees = [committees[0]] return committees
def compute_monroe(profile, committeesize, algorithm="brute-force", resolute=False, verbose=0): """Monroe's rule""" enough_approved_candidates(profile, committeesize) # optional output if verbose: print(header(rules["monroe"].longname)) if resolute: print("Computing only one winning committee (resolute=True)\n") if verbose >= 3: if algorithm == "gurobi": print("Using the Gurobi ILP solver\n") if algorithm == "brute-force": print("Using a brute-force algorithm\n") # end of optional output if not profile.has_unit_weights(): raise ValueError(rules["monroe"].shortname + " is only defined for unit weights (weight=1)") if algorithm == "gurobi": committees = abcrules_gurobi.__gurobi_monroe( profile, committeesize, resolute) committees = sort_committees(committees) elif algorithm == "brute-force": committees = __monroe_bruteforce( profile, committeesize, resolute) else: raise NotImplementedError( "Algorithm " + str(algorithm) + " not specified for compute_monroe") # optional output if verbose: print("Optimal Monroe score: " + str(scores.monroescore(profile, committees[0])) + "\n") print(str_committees_header(committees, winning=True)) print(str_candsets(committees, names=profile.names)) # end of optional output return committees
"""Example 7 (Greedy Monroe) from the survey: "Approval-Based Multi-Winner Voting: Axioms, Algorithms, and Applications" by Martin Lackner and Piotr Skowron """ from __future__ import print_function import sys sys.path.insert(0, '..') from abcvoting import abcrules from survey import example01 as ex1 from abcvoting.scores import monroescore from abcvoting import misc print(misc.header("Example 7", "*")) print(misc.header("Input (election instance from Example 1):")) print(ex1.profile.str_compact()) committees = abcrules.compute_greedy_monroe(ex1.profile, 4, verbose=2) # verify correctness a, b, c, d, e, f, g = list(range(7)) # a = 0, b = 1, c = 2, ... assert committees == [[a, c, d, f]] assert monroescore(ex1.profile, committees[0]) == 10
{a, b}, {a, c}, {a, c}, {a, c}, {a, d}, {a, d}, {b, c, f}, {e}, {f}, {g}, ] profile = Profile(num_cand, cand_names="abcdefgh") profile.add_voters(approval_sets) committeesize = 4 # print(misc.header("Example 7", "*")) print(misc.header("Input (election instance from Example 1):")) print(profile.str_compact()) committees = abcrules.compute_monroe(profile, 4) # verify correctness a, b, c, d, e, f, g = range(7) # a = 0, b = 1, c = 2, ... assert len(committees) == 6 # Monroe-score of all committees is the same score = monroescore(profile, committees[0]) for committee in committees: assert score == monroescore(profile, committee)
def compute_greedy_monroe(profile, committeesize, algorithm="standard", resolute=True, verbose=0): """"Greedy Monroe""" enough_approved_candidates(profile, committeesize) if not profile.has_unit_weights(): raise ValueError(rules["greedy-monroe"].shortname + " is only defined for unit weights (weight=1)") if not resolute: raise NotImplementedError( "compute_greedy_monroe does not support resolute=False.") if algorithm != "standard": raise NotImplementedError( "Algorithm " + str(algorithm) + " not specified for compute_greedy_monroe") num_voters = len(profile) committee = [] # remaining voters remaining_voters = list(range(num_voters)) remaining_cands = set(range(profile.num_cand)) assignment = [] for t in range(committeesize): maxapprovals = -1 selected = None for c in remaining_cands: approvals = len([i for i in remaining_voters if c in profile[i]]) if approvals > maxapprovals: maxapprovals = approvals selected = c # determine how many voters are removed (at most) if t < num_voters - committeesize * (num_voters // committeesize): num_remove = num_voters // committeesize + 1 else: num_remove = num_voters // committeesize # only voters that approve the chosen candidate # are removed to_remove = [i for i in remaining_voters if selected in profile[i]] if len(to_remove) > num_remove: to_remove = to_remove[:num_remove] assignment.append((selected, to_remove)) remaining_voters = [i for i in remaining_voters if i not in to_remove] committee.append(selected) remaining_cands.remove(selected) committees = sort_committees([committee]) # optional output if verbose: print(header(rules["greedy-monroe"].longname)) if verbose >= 2: score1 = scores.monroescore(profile, committees[0]) score2 = len(profile) - len(remaining_voters) print("The Monroe assignment computed by Greedy Monroe") print("has a Monroe score of " + str(score2) + ".") if score1 > score2: print("Monroe assignment found by Greedy Monroe is not " + "optimal for the winning committee,") print("i.e., by redistributing voters to candidates a higher " + "satisfaction is possible " + "(without changing the committee).") print("Optimal Monroe score of the winning committee is " + str(score1) + ".") # build actual Monroe assignment for winning committee for t, district in enumerate(assignment): cand, voters = district if t < num_voters - committeesize * (num_voters // committeesize): missing = num_voters // committeesize + 1 - len(voters) else: missing = num_voters // committeesize - len(voters) for _ in range(missing): v = remaining_voters.pop() voters.append(v) print("Assignment (unsatisfatied voters marked with *):\n") for cand, voters in assignment: print(" candidate " + profile.names[cand] + " assigned to: ", end="") output = "" for v in sorted(voters): output += str(v) if cand not in profile[v].approved: output += "*" output += ", " print(output[:-2]) print() if verbose: print(str_committees_header(committees, winning=True)) print(str_candsets(committees, names=profile.names)) # end of optional output return committees