diff --git a/pabutools/rules/exhaustion.py b/pabutools/rules/exhaustion.py index 09650713..d53c098c 100644 --- a/pabutools/rules/exhaustion.py +++ b/pabutools/rules/exhaustion.py @@ -51,6 +51,10 @@ def completion_by_rule_combination( ) if rule_params is None: rule_params = [{} for _ in rule_sequence] + for i, params in enumerate(rule_params): + if "resoluteness" in params and params["resoluteness"] != resoluteness: + raise ValueError(f"The rule parameter at position {i} sets the resoluteness parameter to a different " + "one that the resoluteness argument passed to completion_by_rule_combination.") budget_allocations = [] res = [] if initial_budget_allocation is not None: @@ -69,20 +73,24 @@ def completion_by_rule_combination( ) if resoluteness: if instance.is_exhaustive(outcome): - res.append(outcome) + return outcome else: new_budget_allocations = [outcome] else: + all_resolute = True for alloc in outcome: if instance.is_exhaustive(alloc): if alloc not in res: res.append(alloc) else: + all_resolute = False new_budget_allocations.append(alloc) + if all_resolute: + return res budget_allocations = new_budget_allocations if resoluteness: - return res[0] - return res + return budget_allocations[0] + return res + budget_allocations def exhaustion_by_budget_increase( diff --git a/pyproject.toml b/pyproject.toml index c07d1b79..3f1f2e49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi" [project] name = "pabutools" -version = "1.1.0" +version = "1.1.1" description = "Implementation of all the tools necessary to explore and analyse participatory budgeting elections" authors = [ { name = "Simon Rey", email = "reysimon@orange.fr" }, diff --git a/tests/test_rule.py b/tests/test_rule.py index dd6df037..bf99c307 100644 --- a/tests/test_rule.py +++ b/tests/test_rule.py @@ -639,3 +639,33 @@ def test_completion(self): {"sat_class": Cost_Sat}, ], ) + + p1 = Project("p1", 2) + p2 = Project("p2", 2) + p3 = Project("p3", 3) + instance = Instance([p1, p2, p3], budget_limit=4) + profile = ApprovalProfile([ + ApprovalBallot([p1]), + ApprovalBallot([p1]), + ApprovalBallot([p1]), + ApprovalBallot([p1]), + ApprovalBallot([p1]), + ApprovalBallot([p2]), + ApprovalBallot([p3]), + ApprovalBallot([p3]) + ]) + + def mes_phragmen(instance, profile, resoluteness=True): + return completion_by_rule_combination( + instance, + profile, + [method_of_equal_shares, sequential_phragmen], + [ + {"sat_class": Cost_Sat}, {} + ], + resoluteness=resoluteness + ) + + assert method_of_equal_shares(instance, profile, Cost_Sat) == [p1] + assert mes_phragmen(instance, profile) == [p1] + assert mes_phragmen(instance, profile, resoluteness=False) == [[p1]]