Rules module#
Module introducing known rules for computing the outcome of participatory budgeting elections.
The rules implemented are:
The utilitarian welfare maximiser:
max_additive_utilitarian_welfare()
The greedy approximation of the utilitarian welfare maximiser:
greedy_utilitarian_welfare()
The method of equal shares:
method_of_equal_shares()
The sequential Phragmén rule:
sequential_phragmen()
Given that some rules may not used up the budget as much as possible (notably the method of equal shares and the sequential Phragmén rule), we also implement methods to make the outcome exhaustive. Specifically, we implemented:
The completion method by rule combination:
completion_by_rule_combination()
The exhaustion method by budget increase:
exhaustion_by_budget_increase()
All rules return one or several lists of projects called budget allocations, represented by the class
BudgetAllocation
.
Budget Allocation#
- class BudgetAllocation(init: Iterable[Project] = (), details: AllocationDetails | None = None)[source]#
A budget allocation is the outcome of rule. It simply corresponds to a list of projects. Additional information can also be stored in this class, for instance for explanation purposes.
- Parameters:
init (Iterable[
Project
], optional) – An iterable ofProject
that is used an initializer for the list.details (
AllocationDetails
, optional) – Used for storing various additional information about a participatory budgeting rule run. Defaults to None.
- details#
Used for storing various additional information about a participatory budgeting rule run. Defaults to None.
- Type:
AllocationDetails
, optional
Greedy Utilitarian Rule#
- greedy_utilitarian_welfare(instance: Instance, profile: AbstractProfile, sat_class: type[SatisfactionMeasure] | None = None, sat_profile: GroupSatisfactionMeasure | None = None, is_sat_additive: bool | None = None, tie_breaking: TieBreakingRule | None = None, resoluteness: bool = True, initial_budget_allocation: Collection[Project] | None = None, analytics: bool = False) BudgetAllocation | list[BudgetAllocation] [source]#
General greedy scheme for approximating the utilitarian welfare. It selects projects in rounds, each time selecting a project that lead to the highest increase in total satisfaction divided by the cost of the project. Projects that would lead to a violation of the budget constraint are skipped.
- Parameters:
instance (
Instance
) – The instance.profile (
AbstractProfile
) – The profile.sat_class (type[
SatisfactionMeasure
]) – The class defining the satisfaction function used to measure the social welfare. It should be a class inhereting fromSatisfactionMeasure
. If no satisfaction is provided, a satisfaction profile needs to be provided. If a satisfation profile is provided, the satisfaction argument is disregarded.sat_profile (
GroupSatisfactionMeasure
) – The satisfaction profile corresponding to the instance and the profile. If no satisfaction profile is provided, but a satisfaction function is, the former is computed from the latter.is_sat_additive (bool) – A boolean indicating if the satisfaction function is additive. This is directly deducted if sat_class is provided.
initial_budget_allocation (Iterable[
Project
]) – An initial budget allocation, typically empty.tie_breaking (
TieBreakingRule
, optional) – The tie-breaking rule used. Defaults to the lexicographic tie-breaking.resoluteness (bool, optional) – Set to False to obtain an irresolute outcome, where all tied budget allocations are returned. Defaults to True.
analytics (bool, optional) – (De)Activate the calculation of analytics. Defaults to False.
- Returns:
The selected budget allocation if resolute (
resoluteness == True
), or the set of budget allocations if irresolute (resoluteness == False
).- Return type:
BudgetAllocation | Collection[BudgetAllocation]
Additive Utilitarian Welfare Maximiser#
- enum MaxAddUtilWelfareAlgo(value)[source]#
Constants use to represent different algorithms that can be used to compute budget allocations maximising the additive utilitarian welfare.
Valid values are as follows:
- ILP_SOLVER = <MaxAddUtilWelfareAlgo.ILP_SOLVER: 1>#
Converts the instance into a integer linear program (ILP) and uses an ILP solver to compute the outcome.
- PRIMAL_DUAL = <MaxAddUtilWelfareAlgo.PRIMAL_DUAL: 2>#
Uses state-of-the-art primal/dual solvers for knapsack problems to compute the outcome.
- max_additive_utilitarian_welfare(instance: Instance, profile: AbstractProfile, sat_class: type[SatisfactionMeasure] | None = None, sat_profile: GroupSatisfactionMeasure | None = None, resoluteness: bool = True, initial_budget_allocation: Collection[Project] | None = None, inner_algo: MaxAddUtilWelfareAlgo | None = None) BudgetAllocation | list[BudgetAllocation] [source]#
Rule returning the budget allocation(s) maximizing the utilitarian social welfare. The utilitarian social welfare is defined as the sum of the satisfactin of the voters, where the satisfaction is computed using the satisfaction measure given as a parameter. The satisfaction measure is assumed to be additive.
The outcome can be computed either via a integer linear program solver or with a primal/dual approach. Note that depending on the selected algorithm, not all functionalities are supported (with the ILP solver ties cannot be handled while the primal/dual approach does not support irresolute outcomes).
- Parameters:
instance (
Instance
) – The instance.profile (
AbstractProfile
) – The profile.sat_class (type[
SatisfactionMeasure
]) – The class defining the satisfaction function used to measure the social welfare. It should be a class inhereting from pabutools.election.satisfaction.satisfactionmeasure.SatisfactionMeasure. If no satisfaction is provided, a satisfaction profile needs to be provided. If a satisfation profile is provided, the satisfaction argument is disregarded.sat_profile (
GroupSatisfactionMeasure
) – The satisfaction profile corresponding to the instance and the profile. If no satisfaction profile is provided, but a satisfaction function is, the former is computed from the latter.initial_budget_allocation (Iterable[
Project
]) – An initial budget allocation, typically empty.resoluteness (bool, optional) – Set to False to obtain an irresolute outcome, where all tied budget allocations are returned. Defaults to True.
inner_algo (
MaxAddUtilWelfareAlgo
, optional) – The inner algorithm used. SeeMaxAddUtilWelfareAlgo
for the available choices. Defaults toMaxAddUtilWelfareAlgo.PRIMAL_DUAL
ifresoluteness == True
, otherwise defaults toMaxAddUtilWelfareAlgo.ILP_SOLVER
.
- Returns:
The selected projects if resolute (
resoluteness == True
), or the set of selected projects if irresolute (resoluteness == False
).- Return type:
BudgetAllocation
| list[BudgetAllocation
]
Sequential Phragmén’s Rule#
- sequential_phragmen(instance: Instance, profile: AbstractApprovalProfile, initial_loads: list[int | float | mpq] | None = None, initial_budget_allocation: Collection[Project] | None = None, tie_breaking: TieBreakingRule | None = None, resoluteness: bool = True) BudgetAllocation | list[BudgetAllocation] [source]#
Phragmén’s sequential rule. It works as follows. Voters receive money in a virtual currency. They all start with a budget of 0 and that budget continuously increases. As soon asa group of supporters have enough virtual currency to buy a project they all approve, the project is bought. The rule stops as soon as there is a project that could be bought but only by violating the budget constraint.
Note that this rule can only be applied to profile of approval ballots.
- Parameters:
instance (
Instance
) – The instance.profile (
AbstractApprovalProfile
) – The profile.initial_loads (list[Numeric], optional) – A list of initial load, one per ballot in profile. By defaults, the initial load is 0.
initial_budget_allocation (Iterable[
Project
]) – An initial budget allocation, typically empty.tie_breaking (
TieBreakingRule
, optional) – The tie-breaking rule used. Defaults to the lexicographic tie-breaking.resoluteness (bool, optional) – Set to False to obtain an irresolute outcome, where all tied budget allocations are returned. Defaults to True.
- Returns:
The selected projects if resolute (
resoluteness == True
), or the set of selected projects if irresolute (resoluteness == False
).- Return type:
BudgetAllocation
| list[BudgetAllocation
]
Cumulative Support Transfer Voting Rule#
- cstv(instance: Instance, profile: AbstractCumulativeProfile, combination: CSTV_Combination = None, select_project_to_fund_func: Callable = None, eligible_projects_func: Callable = None, no_eligible_project_func: Callable = None, exhaustiveness_postprocess_func: Callable = None, initial_budget_allocation: Iterable[Project] | None = None, tie_breaking: TieBreakingRule | None = None, resoluteness: bool = True, verbose: bool = False) BudgetAllocation | list[BudgetAllocation] [source]#
The CSTV (Cumulative Support Transfer Voting) budgeting algorithm determines project funding based on cumulative support from donor ballots. This function evaluates a list of projects and donor profiles, selecting projects for funding according to the CSTV methodology. It employs various procedures for project selection, eligibility determination, and handling of scenarios where no eligible projects exist or to ensure inclusive maximality. You can read more about the algorithm in sections 4 and 5 in the paper here: https://arxiv.org/pdf/2009.02690 in sections 4 and 5.
- Parameters:
instance (
Instance
) – The list of projects.profile (
AbstractCumulativeProfile
) – The list of donor ballots.combination (
CSTV_Combination
) – Shortcut to use pre-defined sets of parameters (all the different procedures).select_project_to_fund_func (Callable) – The procedure to select a project for funding.
eligible_projects_func (Callable) – The function to determine eligible projects.
no_eligible_project_func (Callable) – The procedure when there are no eligible projects.
exhaustiveness_postprocess_func (Callable) – The post procedure to handle inclusive maximality.
initial_budget_allocation (Iterable[
Project
]) – An initial budget allocation, typically empty.tie_breaking (
TieBreakingRule
, optional) – The tie-breaking rule to use, defaults to lexico_tie_breaking.resoluteness (bool, optional) – Set to False to obtain an irresolute outcome, where all tied budget allocations are returned. Defaults to True.
verbose (bool, optional) – (De)Activate the display of additional information. Defaults to False.
- Returns:
The list of selected projects.
- Return type:
- class CSTV_Combination(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]#
- EWT = 1#
Project selection via greedy-by-excess; eligible projects selected via greedy-by-excess; elimination with transfer used if no eligible projects; and reverse elimination as post-processing method.
- EWTC = 2#
Project selection via greedy-by-support-over-cost; eligible projects selected via greedy-by-support-over-cost; elimination with transfer used if no eligible projects; and reverse elimination as post-processing method.
- MT = 3#
Project selection via greedy-by-excess; eligible projects selected via greedy-by-excess; minimal transfer used if no eligible projects; and acceptance of under-supported projects as post-processing method.
- MTC = 4#
Project selection via greedy-by-support-over-cost; eligible projects selected via greedy-by-support-over-cost minimal transfer used if no eligible projects; and acceptance of under-supported projects as post-processing method.
Exhaustion Methods#
- completion_by_rule_combination(instance: Instance, profile: AbstractProfile, rule_sequence: Collection[Callable], rule_params: Collection[dict] | None = None, initial_budget_allocation: Iterable[Project] | None = None, resoluteness: bool = True) BudgetAllocation | list[BudgetAllocation] [source]#
Runs the given rules on the given instance and profile in sequence until an exhaustive budget allocation has been reached (or all rules have been applied). This is useful if the first rules are non-exhaustive. In the irresolute version, all outcomes are completed separately.
- Parameters:
instance (
Instance
) – The instance.profile (
AbstractProfile
) – The profile.rule_sequence (Iterable[Callable]) – Iterable of the rule functions.
rule_params (Iterable[dict], optional) – Iterable of dictionaries of additional parameters that are passed as keyword arguments to the rule functions. Defaults to {}.
initial_budget_allocation (Iterable[
Project
], optional) – An initial budget allocation, typically empty. Defaults to [].resoluteness (bool, optional) – Set to False to obtain an irresolute outcome, where all tied budget allocations are returned. Defaults to True.
- Returns:
The selected projects.
- Return type:
BudgetAllocation
| list[BudgetAllocation
]
- exhaustion_by_budget_increase(instance: Instance, profile: AbstractProfile, rule: Callable, rule_params: dict | None = None, initial_budget_allocation: Iterable[Project] | None = None, resoluteness: bool = True, exhaustive_stop: bool = True, budget_step: int | float | mpq | None = None, budget_bound: int | float | mpq | None = None) BudgetAllocation | list[BudgetAllocation] [source]#
Runs the given rule iteratively with increasing budget, until an exhaustive allocation is retrieved or the budget limit is exceeded by the rule with increased budget. In the irresolute version, as soon as one outcome is exhaustive or infeasible, the procedure stops.
If you are interested to only stop when the returned budget allocation is not feasible (and thus not when it is exhaustive), set
exhaustive_stop=False
.- Parameters:
instance (
Instance
) – The instance.profile (
AbstractProfile
) – The profile.rule – The rule function
rule_params (dict, optional) – Dictionary of additional parameters that are passed as keyword arguments to the rule function. Defaults to {}.
initial_budget_allocation (Collection[Project], optional) – An initial budget allocation, typically empty. Defaults to []. Overrides the parameter in rule_params.
resoluteness (bool, optional) – Set to False to obtain an irresolute outcome, where all tied budget allocations are returned. Defaults to True.
exhaustive_stop (bool, optional) – Set to False to disable the exhaustive allocation stop condition, leaving only the non-feasibility as the stop condition of this rule. Defaults to True.
budget_step (Numeric) – The step at which the budget is increased. Defaults to 1% of the budget limit.
budget_bound (Numeric) – An upper bound on the budget limit. The method stops if this bound is exceeded. Defaults to the budget limit multiplied by the number of agents plus 1.
- Returns:
The selected budget allocation if resolute (
resoluteness == True
), or the set of budget allocations if irresolute (resoluteness == False
).- Return type:
BudgetAllocation | Iterable[BudgetAllocation]
Rule Composition#
- popularity_comparison(instance: Instance, profile: Profile, sat_class: type[SatisfactionMeasure], rule_sequence: Collection[Callable], rule_params: Collection[dict] | None = None, initial_budget_allocation: Iterable[Project] | None = None) list[BudgetAllocation] [source]#
Compute the outcome of several rules and returns the ones that are the most preferred by the largest set of voters, according to a given satisfaction measure. Should only be applied to resolute rules.
- Parameters:
instance (
Instance
) – The instance.profile (
AbstractProfile
) – The profile.sat_class (type[
SatisfactionMeasure
]) – The satisfaction measure used to do the comparison.rule_sequence (Collection[Callable]) – Iterable of the rule functions.
rule_params (Collection[dict], optional) – Iterable of dictionaries of additional parameters that are passed as keyword arguments to the rule functions. Defaults to {}.
initial_budget_allocation (Iterable[Project], optional) – An initial budget allocation, typically empty. Defaults to [].
- Returns:
All the budget allocations yielding the maximum total satisfaction for the outcomes of the rules.
- Return type:
list[
BudgetAllocation
]
- social_welfare_comparison(instance: Instance, profile: Profile, sat_class: type[SatisfactionMeasure], rule_sequence: Collection[Callable], rule_params: Collection[dict] | None = None, initial_budget_allocation: Iterable[Project] | None = None) list[BudgetAllocation] [source]#
Compute the outcome of several rules and returns the one that is the most preferred by the voters according to a given satisfaction measure. Should only be applied to resolute rules.
- Parameters:
instance (
Instance
) – The instance.profile (
AbstractProfile
) – The profile.sat_class (type[
SatisfactionMeasure
]) – The satisfaction measure used to do the comparison.rule_sequence (Collection[Callable]) – Iterable of the rule functions.
rule_params (Collection[dict], optional) – Iterable of dictionaries of additional parameters that are passed as keyword arguments to the rule functions. Defaults to {}.
initial_budget_allocation (Iterable[Project], optional) – An initial budget allocation, typically empty. Defaults to [].
- Returns:
All the budget allocations yielding the maximum total satisfaction for the outcomes of the rules.
- Return type:
list[
BudgetAllocation
]