#matching #gale-shapley #stable-marriage

stable_matching

Implementation of the Gale-Shapley stable matching algorithm

1 unstable release

0.1.0 Jan 12, 2023

#76 in #matching

MIT/Apache

9KB
66 lines

stable_matching

Implementation of the Gale-Shapley algorithm, as described on page 6 of Algorithm Design by Kleinberg and Tardos.

Client supplies two slices representing each of the two groups seeking a match, and distance functions indicating preferences. A Vec of pairs of slice indices is returned to indicate the stable matches.

License

Licensed under either of

at your option.

Contributions

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.


lib.rs:

The stable_matching_distance() function implements the Gale-Shapley algorithm, as described on page 6 of Algorithm Design by Kleinberg and Tardos.

The client supplies a distance function. Preferences are ranked in terms of distance function values, with lower values indicating higher preferences. When calculating preferences, the member of the proposing group is the first argument, and the member of the proposal-receiving group is the second argument.

The value function will be called at most twice for each proposer-receiver pair.

The function returns a Vec containing pairs of indices of elements of the groups. The first element in the pair is an index into the proposing group slice, and the second element is an index into the proposal-receiving group slice.

The groups may be of different sizes. In those cases, everyone in the smaller group will have a match with someone in the larger group, but there will be unmatched leftovers in the larger group.

In the event of a tie between two proposers competing for the same receiver, the receiver will maintain their current match.

Proposers are placed in a queue in order of appearance in the input slice. Each maintains a queue of proposal-receivers, with ties broken by maintaining the order of the input slice. When a proposed match is broken, the proposer is sent to the back of the queue.

use stable_matching::stable_matching_distance;

let group1: Vec<i64> = vec![1, 2, 3, 4, 5];
let group2: Vec<i64> = vec![8, 9, 10, 11];

let pairs = stable_matching_distance(&group1, &group2, |p1, p2| (p1 - p2).abs());
assert_eq!(pairs, vec![(4, 0), (3, 1), (2, 2), (1, 3)]);

let pairs = stable_matching_distance(&group2, &group1, |p1, p2| (p1 - p2).abs());
assert_eq!(pairs, vec![(3, 1), (2, 2), (1, 3), (0, 4)]);

If the members of different groups have different preference functions, the stable_matching_asymmetric() function may be used to supply these distinct preference functions.

In the example below, the receiving group preference is for even numbers to match even, and odd numbers to match odd. Because this implementation will not break a match in the event of a tie in preferences, once a receiver has received a proposal from a proposer with the same evenness/oddness, it will always stick with that proposer.

use stable_matching::stable_matching_asymmetric;

let group1: Vec<i64> = vec![1, 2, 3, 4, 5];
let group2: Vec<i64> = vec![8, 9, 10, 11];

let pairs = stable_matching_asymmetric(&group1, |p1, p2| (p1 - p2).abs(), &group2, |p1, p2| if p1 % 2 == p2 % 2 {0} else {1});
assert_eq!(pairs, vec![(1, 0), (0, 1), (3, 2), (2, 3)]);

let group1: Vec<i64> = vec![5, 4, 3, 2, 1];
let pairs = stable_matching_asymmetric(&group1, |p1, p2| (p1 - p2).abs(), &group2, |p1, p2| if p1 % 2 == p2 % 2 {0} else {1});
assert_eq!(pairs, vec![(1, 0), (0, 1), (3, 2), (2, 3)]);

No runtime deps