diff --git a/README.md b/README.md index 915151a..4e876fc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ # Project Vania - A Fair Distributor -**Fair Distributor** is module that allows fair distribution of any number of **objects** through a group of **targets**. +**Fair Distributor** is a module which [fairly](#our-meaning-of-fairness) distributes a list of arbitrary **objects** through a set of **targets**. -Using linear programming, this module takes into consideration the **weights** of the **targets** relative to the **objects** and distributes them in the **fairest way possible**. +To be more explicit, this module considers 3 key components: +* **object**: some kind of entity that can be assigned to something. +* **target**: the entity that will have one (or more) **objects** assigned to it. +* **weight**: represents the cost of assigning a given **object** to a **target**. + +A collection of each of these components is given as input to the module. +Using linear programming, the **weights** of the **targets** relative to the **objects** are taken into consideration and used to build the constraints of an Integer Linear Programming (ILP) model. An ILP solver is then used, in order to distribute the **objects** through the **targets**, in the *fairest way possible*. For instance, this module can be used to fairly distribute: * A set of tasks (objects) among a group of people (targets) according to their preferences to do each task (weights). @@ -11,11 +17,11 @@ For instance, this module can be used to fairly distribute: ## Our Meaning of Fairness We define **Fairness** as: - * The total weight for the resulting attribution of objects to targets should be minimal. + * The total **weight** of distributing all **objects** through the **targets** should be minimal. This enforces that the least amount of shared effort is made. _Optionally_, the following rule can be applied (enabled by default): - * The difference between the total weight distributed between targets is minimal. + * The difference between the individual **weight** of each **target** is minimal. This enforces the least amount of individual effort. ## Documentation @@ -34,33 +40,75 @@ To work with the source code, clone this repository: $ git clone git://github.com/hackathonners/vania.git ## Usage - -A quick example for 3 abstract targets, 4 abstract objects and the following weight matrix. - +To start using the **Fair Distributor**, you need first to import it, by doing this: ```python from vania.fair_distributor import FairDistributor +``` +Now, just feed it with your problem variables, and ask for the solution. +To better explain how you can do it, lets consider a specific example. + +Suppose that you are managing a project, which contains **4** tasks: _Front-end Development_, _Back-end Development_, _Testing_, and _Documentation_. +There is a need to assign these **4** tasks through a set of **3** teams: _A_, _B_ and _C_. +You have the expected number of hours each team needs to finish each task: + +| |*Front-end Development*|*Back-end Development*|*Testing*|*Documentation*| +|--------|-----------------------|----------------------|---------|---------------| +|_Team A_| 1h | 2h | 3h | 2h | +|_Team B_| 3h | 1h | 4h | 2h | +|_Team C_| 3h | 4h | 1h | 1h | -targets = ['user1', 'user2'] -objects = ['task1', 'task2'] +Here, we consider tasks as **objects**, teams as **targets** and the hours expressed in each cell are the **weights**. + +It is necessary to create a data structure for each component. **Objects** and **targets** are lists, while **weights** is a collection, which contains for each target the cost of assigning every object to it, and is represented as a matrix. +The structures for this example would be as follow: + +```python +targets = ['Team A', 'Team B', 'Team C'] +objects = ['Front-end Development', 'Back-end Development', 'Testing', 'Documentation'] weights = [ - [1, 2], - [2, 1] + [1, 2, 3, 2], # hours for Team A to complete each task + [3, 1, 4, 2], # hours for Team B to complete each task + [3, 4, 1, 1] # hours for Team C to complete each task ] +``` +Now, just feed the **Fair Distributor** with all the components, and ask for the solution: +```python distributor = FairDistributor(targets, objects, weights) print(distributor.distribute()) +``` +And here is the solution! +```python # Output { - 'user1': ['task1'], # User 1 does the task1 - 'user2': ['task2'] # User 2 does the task2 + 'Team A': ['Front-end Development'], # Team A does the Front-end Development + 'Team C': ['Testing', 'Documentation'], # Team B does the Testing and Documentation + 'Team B': ['Front-end Development']} # Team C does the Front-end Development } ``` +Here is the final code of this example: +```python +from vania.fair_distributor import FairDistributor + +targets = ['Team A', 'Team B', 'Team C'] +objects = ['Front-end Development', 'Back-end Development', 'Testing', 'Documentation'] +weights = [ + [1, 2, 3, 2], # hours for Team A to complete each task + [3, 1, 4, 2], # hours for Team B to complete each task + [3, 4, 1, 1] # hours for Team C to complete each task +] + +distributor = FairDistributor(targets, objects, weights) +print(distributor.distribute()) +``` + ## Contributions and Bugs Found a bug and wish to report it? You can do so here: https://github.com/Hackathonners/vania/issues. If you'd rather contribute to this project with the bugfix, awesome! Simply Fork the project on Github and make a Pull Request. + Please tell us if you are unfamiliar with Git or Github and we'll definitely help you make your contribution. ## Authors