Skip to content

Commit

Permalink
add some examples
Browse files Browse the repository at this point in the history
  • Loading branch information
erelsgl committed Oct 18, 2023
1 parent 7d39d37 commit 1192f59
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 2 deletions.
82 changes: 81 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,85 @@
![PyTest result](https://github.com/ariel-research/fairpyx/workflows/pytest/badge.svg)
[![PyPI version](https://badge.fury.io/py/fairpyx.svg)](https://badge.fury.io/py/fairpyx)

`fairpyx` is a Python library containing various algorithms for fair allocation, with an emphasis on [Course-seat allocation](https://en.wikipedia.org/wiki/Course_allocation).
`fairpyx` is a Python library containing various algorithms for fair allocation, with an emphasis on [Course allocation](https://en.wikipedia.org/wiki/Course_allocation). It is designed for three target audiences:

* Laypeople, who want to use existing fair division algorithms for real-life problems.
* Researchers, who develop new fair division algorithms and want to quickly implement them and compare to existing algorithms.
* Students, who want to trace the execution of algorithms to understand how they work.

## Installation

For the stable version:

pip install fairpyx

For the latest version:

pip install git+https://github.com/ariel-research/fairpyx.git

To verify that everything was installed correctly, run one of the example programs, e.g.

python examples/items.py
python examples/cake.py

or run the tests:

pytest

## Usage

The function `fairpyx.divide` can be used to activate all fair division algorithms. For example:

import fairpyx

valuations = {"Alice": {"w":11,"x":22,"y":44,"z":0}, "George": {"w":22,"x":11,"y":66,"z":33}}

### Allocating indivisible items using the Iterated Maximum Matching algorithm:
fairpy.divide(algorithm=fairpy.items.iterated_maximum_matching, input=valuations)

### Allocating divisible goods using the leximin algorithm:
fairpy.divide(fairpy.items.leximin, valuations)

### Dividing a cake using cut-and-choose:
from fairpy import PiecewiseConstantAgent
Alice = PiecewiseConstantAgent([33,33], "Alice")
George = PiecewiseConstantAgent([11,55], "George")
fairpy.divide(algorithm=fairpy.cake.cut_and_choose.asymmetric_protocol, input=[George, Alice])


## Features and Examples

1. [Item allocation algorithms](examples/items.md), for both divisible and indivisible items;

1. [Cake-cutting algorithms](examples/cake.md);

1. [Various input formats](examples/input_formats.md), to easily use by both researchers and end-users;

1. [Various output formats](examples/output_formats.md);

1. [Optional logging](examples/loggers.md), to learn and understand how the algorithms work.


## Adding new algorithms

To add a new algorithm for item allocation, write a function that accepts one of the following parameters:

* [AgentList](fairpy/agentlist.py) - a list of [Agent](fairpy/agents.py) objects. See e.g. [the implementation of Round Robin](fairpy/items/round_robin.py) for usage example.
* [ValuationMatrix](fairpy/valuations.py) - a matrix v where v[i,j] is the value of agent i to item j. See e.g. [the implementation of Leximin](fairpy/items/leximin.py) for usage example.

Your function may accept any other custom parameters.


## See also

* [other open-source projects related to fairness](related.md).


## Installation for development

clone https://github.com/ariel-research/fairpyx.git
cd fairpyx
pip install -r requirements.txt
pip install -e .


26 changes: 26 additions & 0 deletions examples/_pweave.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
Run all the example files and convert them to markdown files containing the output.
Uses `pweave`.
"""

import pweave, datetime, glob, os


def publish_to_markdown(python_file: str, output_file: str):
doc = pweave.Pweb(python_file, kernel="python3", doctype="markdown", output=output_file)

doc.theme = "skeleton" # The default option is skeleton , other options are pweave (the old theme), bootstrap , cerulean and journal. All look the same to me.

doc.read()
doc.run()
doc.format()
doc.formatted += f"\n---\nMarkdown generated automatically from [{python_file}]({python_file}) using [Pweave](http://mpastell.com/pweave) {pweave.__version__} on {datetime.date.today()}.\n"
doc.write()


if __name__ == "__main__":
for python_file in glob.glob("*.py"):
print(python_file)
if python_file != os.path.basename(__file__):
output_file = python_file.replace(".py", ".md")
publish_to_markdown(python_file, output_file)
67 changes: 67 additions & 0 deletions examples/input_formats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Input formats


```python
import fairpyx
divide = fairpyx.divide
```



`fairpyx` allows various input formats, so that you can easily use it on your own data,
whether for applications or for research.
For example, suppose you want to divide candies among your children.
It is convenient to collect their preferences in a dict of dicts:


```python
valuations = {
"Ami": {"green": 8, "red":7, "blue": 6, "yellow": 5},
"Tami": {"green": 12, "red":8, "blue": 4, "yellow": 2} }
allocation = divide(fairpyx.algorithms.round_robin, valuations=valuations)
```



You can then see the resulting allocation with the agents' real names:


```python
print(allocation)
```

```
{'Ami': ['blue', 'green'], 'Tami': ['red', 'yellow']}
```



For research, passing a dict of dicts as a parameter may be too verbose.
You can call the same algorithm with only the values, or only the value matrix:


```python
print(divide(fairpyx.algorithms.round_robin, valuations={"Ami": [8,7,6,5], "Tami": [12,8,4,2]}))
print(divide(fairpyx.algorithms.round_robin, valuations=[[8,7,6,5], [12,8,4,2]]))


# #' For experiments, you can use a numpy random matrix:

import numpy as np
valuations = np.random.randint(1,100,[2,4])
print(valuations)
allocation = divide(fairpyx.algorithms.round_robin, valuations=valuations)
print(allocation)
```

```
{'Ami': [0, 2], 'Tami': [1, 3]}
{0: [0, 2], 1: [1, 3]}
[[70 26 35 78]
[47 8 51 38]]
{0: [0, 3], 1: [1, 2]}
```


---
Markdown generated automatically from [input_formats.py](input_formats.py) using [Pweave](http://mpastell.com/pweave) 0.30.3 on 2023-10-18.
33 changes: 33 additions & 0 deletions examples/input_formats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#' # Input formats

import fairpyx
divide = fairpyx.divide

#' `fairpyx` allows various input formats, so that you can easily use it on your own data,
#' whether for applications or for research.
#' For example, suppose you want to divide candies among your children.
#' It is convenient to collect their preferences in a dict of dicts:

valuations = {
"Ami": {"green": 8, "red":7, "blue": 6, "yellow": 5},
"Tami": {"green": 12, "red":8, "blue": 4, "yellow": 2} }
allocation = divide(fairpyx.algorithms.round_robin, valuations=valuations)

#' You can then see the resulting allocation with the agents' real names:

print(allocation)

#' For research, passing a dict of dicts as a parameter may be too verbose.
#' You can call the same algorithm with only the values, or only the value matrix:

print(divide(fairpyx.algorithms.round_robin, valuations={"Ami": [8,7,6,5], "Tami": [12,8,4,2]}))
print(divide(fairpyx.algorithms.round_robin, valuations=[[8,7,6,5], [12,8,4,2]]))


# #' For experiments, you can use a numpy random matrix:

import numpy as np
valuations = np.random.randint(1,100,[2,4])
print(valuations)
allocation = divide(fairpyx.algorithms.round_robin, valuations=valuations)
print(allocation)
5 changes: 4 additions & 1 deletion fairpyx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
from fairpyx.explanations import ExplanationLogger, ConsoleExplanationLogger, StringsExplanationLogger, FilesExplanationLogger
from fairpyx.adaptors import divide

import fairpyx.algorithms as algorithms

# # Algorithms:
# from fairpyx.iterated_maximum_matching import iterated_maximum_matching, iterated_maximum_matching_adjusted, iterated_maximum_matching_unadjusted
# from fairpyx.utilitarian_matching import utilitarian_matching
# from fairpyx.picking_sequence import picking_sequence, serial_dictatorship, round_robin, bidirectional_round_robin
# from fairpyx.algorithms.picking_sequence import picking_sequence, serial_dictatorship, round_robin, bidirectional_round_robin
# from fairpyx.almost_egalitarian import almost_egalitarian_allocation, almost_egalitarian_with_donation, almost_egalitarian_without_donation

1 change: 1 addition & 0 deletions fairpyx/algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from fairpyx.algorithms.picking_sequence import round_robin, bidirectional_round_robin, serial_dictatorship

0 comments on commit 1192f59

Please sign in to comment.