Skip to content

Commit c96d930

Browse files
committed
Docs and refactoring
1 parent f14ae7d commit c96d930

40 files changed

+332
-177
lines changed

docs-source/source/reference/analysis/index.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ Analysis module
1414

1515
.. automodule:: pabutools.analysis.category
1616
:members:
17+
18+
.. automodule:: pabutools.analysis.projectloss
19+
:members:

docs-source/source/reference/rules/index.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,47 @@ Rules module
33

44
.. automodule:: pabutools.rules
55

6+
Budget Allocation
7+
-----------------
8+
69
.. autoclass:: pabutools.rules.budgetallocation.BudgetAllocation
710

11+
.. autoclass:: pabutools.rules.budgetallocation.AllocationDetails
12+
13+
Greedy Utilitarian Rule
14+
-----------------------
15+
816
.. autofunction:: pabutools.rules.greedywelfare.greedy_utilitarian_welfare
917

18+
Additive Utilitarian Welfare Maximiser
19+
--------------------------------------
20+
1021
.. autofunction:: pabutools.rules.maxwelfare.max_additive_utilitarian_welfare
1122

23+
Sequential Phragmén's Rule
24+
--------------------------
25+
1226
.. autofunction:: pabutools.rules.phragmen.sequential_phragmen
1327

28+
Method of Equal Shares (MES)
29+
----------------------------
30+
1431
.. autofunction:: pabutools.rules.mes.method_of_equal_shares
1532

33+
.. autoclass:: pabutools.rules.mes.MESAllocationDetails
34+
35+
.. autoclass:: pabutools.rules.mes.MESIteration
36+
37+
Exhaustion Methods
38+
------------------
39+
1640
.. autofunction:: pabutools.rules.exhaustion.completion_by_rule_combination
1741

1842
.. autofunction:: pabutools.rules.exhaustion.exhaustion_by_budget_increase
1943

44+
Rule Composition
45+
----------------
46+
2047
.. autofunction:: pabutools.rules.composition.popularity_comparison
2148

2249
.. autofunction:: pabutools.rules.composition.social_welfare_comparison

docs-source/source/usage.rst

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,8 @@ outcome (for visualisation/explanation purposes).
527527
Additive Utilitarian Welfare Maximiser
528528
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
529529

530+
:py:func:`~pabutools.rules.maxwelfare.max_additive_utilitarian_welfare`
531+
530532
The first rule provided is the Additive Utilitarian Welfare Maximiser. It aims to return
531533
budget allocations that maximize the utilitarian social welfare when the satisfaction
532534
measure is additive.
@@ -584,6 +586,8 @@ for non-additive satisfaction measures.
584586
Greedy Approximation of the Welfare Maximiser
585587
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
586588

589+
:py:func:`~pabutools.rules.greedywelfare.greedy_utilitarian_welfare`
590+
587591
The library also implements standard greedy rules. The primary rule used in this
588592
context is the Greedy Utilitarian Welfare. It behaves similarly to the
589593
Utilitarian Welfare Maximiser but offers additional functionalities: it is not limited
@@ -653,6 +657,8 @@ to additive satisfaction measures (and runs faster).
653657
Sequential Phragmén's Rule
654658
^^^^^^^^^^^^^^^^^^^^^^^^^^
655659

660+
:py:func:`~pabutools.rules.phragmen.sequential_phragmen`
661+
656662
Another rule provided is the Sequential Phragmén's Rule, which is different from the
657663
previous two as it does not rely on a satisfaction measure.
658664

@@ -700,6 +706,8 @@ previous two as it does not rely on a satisfaction measure.
700706
Method of Equal Shares (MES)
701707
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
702708

709+
:py:func:`~pabutools.rules.mes.method_of_equal_shares`
710+
703711
The Method of Equal Shares is another rule that returns budget allocations based on the satisfaction
704712
measure provided. For more details, see the `equalshares.net <https://equalshares.net/>`_ website.
705713

@@ -773,6 +781,10 @@ performances, one should use the following:
773781
Exhaustion Methods
774782
^^^^^^^^^^^^^^^^^^
775783

784+
:py:func:`~pabutools.rules.exhaustion.completion_by_rule_combination`
785+
786+
:py:func:`~pabutools.rules.exhaustion.exhaustion_by_budget_increase`
787+
776788
Since not all rules return exhaustive budget allocations, the library offers standard
777789
methods to render their outcome exhaustive.
778790

@@ -856,6 +868,10 @@ parameter directly to obtain the iterated version.
856868
Rule Composition
857869
^^^^^^^^^^^^^^^^
858870

871+
:py:func:`~pabutools.rules.composition.popularity_comparison`
872+
873+
:py:func:`~pabutools.rules.composition.social_welfare_comparison`
874+
859875
The library also provides ways to compose rules, such as selecting the outcome that is
860876
preferred by the largest number of voters for a given satisfaction measure.
861877

@@ -929,13 +945,33 @@ the following:
929945
We also provide a similar comparison using utilitarian social welfare through the function
930946
:py:func:`~pabutools.rules.composition.social_welfare_comparison`.
931947

948+
Details for the Budget Allocation Rule
949+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
950+
951+
Some rules, for instance :py:func:`~pabutools.rules.mes.method_of_equal_shares`, accept a
952+
:code:`analytics` boolean argument to activate the storage of additional information
953+
regarding the budget allocations output by the rule. When :code:`analytics = True`,
954+
the rule populate the :code:`details` member of the
955+
:py:class:`~pabutools.rules.budgetallocation.BudgetAllocation` object it returns.
956+
The stored information can then be used for analytical purposes.
957+
958+
.. list-table::
959+
:widths: 50 50
960+
:header-rows: 1
961+
962+
* - Rule
963+
- Details class
964+
* - :py:func:`~pabutools.rules.mes.method_of_equal_shares`
965+
- :py:class:`~pabutools.rules.mes.MESAllocationDetails`
966+
967+
932968
Tie-Breaking
933969
------------
934970

935971
For reference, see the module :py:mod:`~pabutools.tiebreaking`.
936972

937973
We provide several ways to break ties between several projects. All tie-breaking rules are
938-
instantiations of the :py:class:`pabutools.tiebreaking.TieBreakingRule` class.
974+
instantiations of the :py:class:`~pabutools.tiebreaking.TieBreakingRule` class.
939975
This class defines two functions `untie` and `order` that respectively return a single project
940976
from a set of several or order a list of projects.
941977

docs/_sources/usage.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ Tie-Breaking
935935
For reference, see the module :py:mod:`~pabutools.tiebreaking`.
936936

937937
We provide several ways to break ties between several projects. All tie-breaking rules are
938-
instantiations of the :py:class:`pabutools.tiebreaking.TieBreakingRule` class.
938+
instantiations of the :py:class:`~pabutools.tiebreaking.TieBreakingRule` class.
939939
This class defines two functions `untie` and `order` that respectively return a single project
940940
from a set of several or order a list of projects.
941941

pabutools/analysis/justifiedrepresentation.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
Additive_Cardinal_Sat,
1414
AbstractCardinalProfile,
1515
ApprovalBallot,
16-
total_cost, AbstractProfile,
16+
total_cost,
17+
AbstractProfile,
1718
)
1819
from pabutools.utils import powerset
1920

@@ -39,7 +40,10 @@ def is_in_core(
3940
sat = sat_class(instance, profile, ballot)
4041
surplus = 0
4142
if up_to_func is not None:
42-
surplus = up_to_func(sat.sat_project(p) for p in project_set if p not in budget_allocation
43+
surplus = up_to_func(
44+
sat.sat_project(p)
45+
for p in project_set
46+
if p not in budget_allocation
4347
)
4448
if sat.sat(budget_allocation) + surplus >= sat.sat(project_set):
4549
all_better_alone = False

pabutools/analysis/projectloss.py

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,23 @@
1010
class ProjectLoss(Project):
1111
"""
1212
Class used to represent the projects and how much budget they lost due to other projects being picked.
13+
This extends the :py:class:`~pabutools.election.instance.Project` and thus represents the project itself.
1314
1415
Parameters
1516
----------
16-
project: Project
17+
project: :py:class:`~pabutools.election.instance.Project`
1718
Project for which analytics is calculated.
18-
supporters_budget: Numeric
19+
supporters_budget: :py:class:`~pabutools.utils.Numeric`
1920
The collective budget of the project supporters when project was considered by a rule.
20-
budget_lost: dict[Project, Numeric]
21+
budget_lost: dict[:py:class:`~pabutools.election.instance.Project`, :py:class:`~pabutools.utils.Numeric`]
2122
Describes the amount of budget project supporters spent on other projects prior to this
2223
projects' consideration.
2324
2425
Attributes
2526
----------
26-
project: Project
27-
Project for which analytics is calculated.
28-
supporters_budget: Numeric
27+
supporters_budget: :py:class:`~pabutools.utils.Numeric`
2928
The collective budget of the project supporters when project was considered by rule.
30-
budget_lost: dict[Project, Numeric]
29+
budget_lost: dict[:py:class:`~pabutools.election.instance.Project`, :py:class:`~pabutools.utils.Numeric`]
3130
Describes the amount of budget project supporters spent on other projects prior to this
3231
projects' consideration.
3332
"""
@@ -50,7 +49,7 @@ def total_budget_lost(self) -> Numeric:
5049
5150
Returns
5251
-------
53-
Numeric
52+
:py:class:`~pabutools.utils.Numeric`
5453
The total budget spent.
5554
"""
5655
return sum(self.budget_lost.values())
@@ -65,12 +64,28 @@ def __repr__(self):
6564
def calculate_project_loss(
6665
allocation_details: AllocationDetails, verbose: bool = False
6766
) -> list[ProjectLoss]:
68-
if (
69-
allocation_details.iterations is None
70-
or allocation_details.initial_budget_per_voter is None
67+
"""Returns a list of :py:class:`~pabutools.analysis.projectloss.ProjectLoss` objects for the projects.
68+
69+
Parameters
70+
----------
71+
allocation_details: :py:class:`~pabutools.rules.budgetallocation.AllocationDetails`
72+
The details of the budget allocation considered.
73+
verbose: bool, optional
74+
(De)Activate the display of additional information.
75+
Defaults to `False`.
76+
77+
Returns
78+
-------
79+
list[:py:class:`~pabutools.analysis.projectloss.ProjectLoss`]
80+
List of :py:class:`~pabutools.analysis.projectloss.ProjectLoss` objects.
81+
82+
"""
83+
if not hasattr(allocation_details, "iterations") or not hasattr(
84+
allocation_details, "initial_budget_per_voter"
7185
):
7286
raise ValueError(
73-
"Provided allocation details do not support calculating project loss"
87+
"Provided budget allocation details do not support calculating project loss. The allocation_details "
88+
"should have an 'iterations' and an 'initial_budget_per_voter' attributes."
7489
)
7590
if len(allocation_details.iterations) == 0:
7691
if verbose:
@@ -87,31 +102,33 @@ def calculate_project_loss(
87102
allocation_details.initial_budget_per_voter for _ in range(voter_count)
88103
]
89104

90-
for iter in allocation_details.iterations:
105+
for iteration in allocation_details.iterations:
91106
if verbose:
92-
print(f"Considering: {iter.project.name}, status: {iter.was_picked}")
107+
print(
108+
f"Considering: {iteration.project.name}, status: {iteration.was_picked}"
109+
)
93110
budget_lost = {}
94-
for spending in [voter_spendings[i] for i in iter.supporter_indices]:
111+
for spending in [voter_spendings[i] for i in iteration.supporter_indices]:
95112
for project, spent in spending:
96113
if project not in budget_lost.keys():
97114
budget_lost[project] = 0
98115
budget_lost[project] = budget_lost[project] + spent
99116
project_losses.append(
100117
ProjectLoss(
101-
iter.project,
102-
sum(current_voters_budget[i] for i in iter.supporter_indices),
118+
iteration.project,
119+
sum(current_voters_budget[i] for i in iteration.supporter_indices),
103120
budget_lost,
104121
)
105122
)
106-
if iter.was_picked:
107-
for supporter_idx in iter.supporter_indices:
123+
if iteration.was_picked:
124+
for supporter_idx in iteration.supporter_indices:
108125
voter_spendings[supporter_idx].append(
109126
(
110-
iter.project,
127+
iteration.project,
111128
current_voters_budget[supporter_idx]
112-
- iter.voters_budget[supporter_idx],
129+
- iteration.voters_budget[supporter_idx],
113130
)
114131
)
115-
current_voters_budget = iter.voters_budget
132+
current_voters_budget = iteration.voters_budget
116133

117134
return project_losses

pabutools/election/ballot/approvalballot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Approval ballots, i.e., ballots in which the voters indicate which projects they approve of.
33
"""
4+
45
from __future__ import annotations
56

67
import random

pabutools/election/ballot/ballot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Ballots, that is, the information submitted by the voters during the election.
33
"""
4+
45
from __future__ import annotations
56

67
from abc import ABC, abstractmethod

pabutools/election/ballot/cardinalballot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Cardinal ballots, i.e., ballots in which the voters map projects to scores.
33
"""
4+
45
from __future__ import annotations
56

67
from abc import ABC

pabutools/election/ballot/cumulativeballot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Cumulative ballots, i.e., ballots in which the voters distribute a given amount of points to the projects.
33
"""
4+
45
from __future__ import annotations
56

67
from abc import ABC

0 commit comments

Comments
 (0)