matchmaker 0.1.0

Rust library to fairly match students to categories.
Documentation
# Matchmaker

This library can be used to fairly match students to categories (or activities). Or students to schools. Or anything to anything else.

## Background

The matching problem this library solves is mathematically know as the residence problem and is a subset of the [stable marriage problem](https://en.wikipedia.org/wiki/Stable_marriage_problem).
There are sereval known algorithms that solve this problem, each with there own pros and cons. For more information about the subject see also [Matching algorithms for the secondary school admission problem in Amsterdam](https://staff.fnwi.uva.nl/b.bredeweg/pdf/BSc/20152016/Klijnsma.pdf).

## Algorithm

At this time this library only implements the `Deferred Acceptance - Single Tie Break` algorithm. The library has been designed to make the implementation of other algorithms possible (it just needs to be done ;).

## Usage

## Default matching

Students are distributed over multiple categories, but each student can only be placed once.

```rust
use matchmaker::da_stb::match_students;
use matchmaker::{Category, Student};
use rand::thread_rng;
use std::collections::VecDeque;

// Create categories
let cooking = Category::new("Cooking", 10);
let reading = Category::new("Reading", 10);
let walking = Category::new("Walking", 5);

// Create student Bert
// Bert wishes to be placed in category cooking or reading (in that order)
let bert = Student::new(
    "Bert",
    VecDeque::from(vec![cooking.clone(), reading.clone()]),
    Vec::new(),
);

// Create student Suze
// Suze wishes to be placed in category cooking or reading (in that order),
// but does not wish to be placed in category walking
let suze = Student::new(
    "Suze",
    VecDeque::from(vec![reading.clone(), cooking.clone()]),
    Vec::from([walking.clone()]),
);

let mut rng = thread_rng();
let categories = Vec::from([cooking, reading, walking]);

let match_result = match_students(Vec::from([bert, suze]), &categories, &mut rng);

println!("Students matched to categories:");
println!();
for category in &categories {
    println!("{}:", &category.name);
    for student in match_result
        .placed
        .get(&category.name)
        .unwrap_or(&Vec::new())
    {
        println!(" - {}", &student.name);
    }
}

if match_result.not_placable.is_empty() {
    println!();
    println!("All students could be placed.");
}
```

This should the following result:

```text
Students matched to categories:

Cooking:
 - Bert
Reading:
 - Suze
Walking:

All students could be placed.
```

## Place students in multiple categories

Students are distributed over multiple categories. A single student can be placed
in more than one category.

# Example

```rust
use matchmaker::{Category, Student};
use matchmaker::da_stb::match_students_to_multiple_categories;
use rand::thread_rng;
use std::collections::VecDeque;

// Create categories
let cooking = Category::new("Cooking", 10);
let reading = Category::new("Reading", 10);
let walking = Category::new("Walking", 5);

// Create student Bert
// Bert wishes to be placed in category cooking or reading (in that order)
let bert = Student::new(
    "Bert",
    VecDeque::from(vec![cooking.clone(), reading.clone()]),
    Vec::new(),
);

// Create student Suze
// Suze wishes to be placed in category cooking or reading (in that order),
// but does not wish to be placed in category walking
let suze = Student::new(
    "Suze",
    VecDeque::from(vec![cooking.clone(), reading.clone()]),
    Vec::from([walking.clone()]),
);

let mut rng = thread_rng();
let categories = Vec::from([cooking, reading, walking]);

let match_result = match_students_to_multiple_categories(
    Vec::from([bert, suze]),
    &categories,
    &mut rng);

println!("Students matched to categories:");
println!();
for category in &categories {
    println!("{}:", &category.name);
    for student in match_result
        .placed
        .get(&category.name)
        .unwrap_or(&Vec::new())
    {
        println!(" - {}", &student.name);
    }
}

if match_result.not_placable.is_empty() {
    println!();
    println!("All students could be placed.");
}
```

This should the following result:

```text
Students matched to categories:

Cooking:
 - Suze
 - Bert
Reading:
 - Bert
 - Suze
Walking:
 - Bert

All students could be placed.
```

---

// Copyright (c) 2020 Delirious Penguin
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.