From 25d9d819a296301b90b84766167ceb476391db2e Mon Sep 17 00:00:00 2001 From: Akash Shroff <63399889+akashvshroff@users.noreply.github.com> Date: Sun, 5 Jul 2020 14:51:32 +0530 Subject: [PATCH] Gale Shapley Algorithm (#2100) * Gale Shapley Algorithm Implementation of a Nobel prize-winning algorithm that determines a stable matching in a bipartite graph. * Update graphs/gale_shapley_bigraph.py Co-authored-by: Christian Clauss * Fixed some flake8 issues. * Updated it to donors and recipients * description changes Co-authored-by: Christian Clauss * description changes Co-authored-by: Christian Clauss * description changes Co-authored-by: Christian Clauss * Edited the line lengths * Update gale_shapley_bigraph.py * Update gale_shapley_bigraph.py Co-authored-by: Christian Clauss --- graphs/gale_shapley_bigraph.py | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 graphs/gale_shapley_bigraph.py diff --git a/graphs/gale_shapley_bigraph.py b/graphs/gale_shapley_bigraph.py new file mode 100644 index 000000000000..07a3922f86ec --- /dev/null +++ b/graphs/gale_shapley_bigraph.py @@ -0,0 +1,44 @@ +from typing import List + + +def stable_matching(donor_pref: List[int], recipient_pref: List[int]) -> List[int]: + """ + Finds the stable match in any bipartite graph, i.e a pairing where no 2 objects + prefer each other over their partner. The function accepts the preferences of + oegan donors and recipients (where both are assigned numbers from 0 to n-1) and + returns a list where the index position corresponds to the donor and value at the + index is the organ recipient. + + To better understand the algorithm, see also: + https://github.com/akashvshroff/Gale_Shapley_Stable_Matching (README). + https://www.youtube.com/watch?v=Qcv1IqHWAzg&t=13s (Numberphile YouTube). + + >>> donor_pref = [[0, 1, 3, 2], [0, 2, 3, 1], [1, 0, 2, 3], [0, 3, 1, 2]] + >>> recipient_pref = [[3, 1, 2, 0], [3, 1, 0, 2], [0, 3, 1, 2], [1, 0, 3, 2]] + >>> print(stable_matching(donor_pref, recipient_pref)) + [1, 2, 3, 0] + """ + assert len(donor_pref) == len(recipient_pref) + n = len(donor_pref) + unmatched_donors = list(range(n)) + donor_record = [-1] * n # who the donor has donated to + rec_record = [-1] * n # who the recipient has received from + num_donations = [0] * n + while unmatched_donors: + donor = unmatched_donors[0] + donor_preference = donor_pref[donor] + recipient = donor_preference[num_donations[donor]] + num_donations[donor] += 1 + rec_preference = recipient_pref[recipient] + prev_donor = rec_record[recipient] + if prev_donor != -1: + if rec_preference.index(prev_donor) > rec_preference.index(donor): + rec_record[recipient] = donor + donor_record[donor] = recipient + unmatched_donors.append(prev_donor) + unmatched_donors.remove(donor) + else: + rec_record[recipient] = donor + donor_record[donor] = recipient + unmatched_donors.remove(donor) + return donor_record