From 8d94b96b85c5fec63262de5b7319aede9c8d1946 Mon Sep 17 00:00:00 2001 From: "Thomas (Tom) C. Gorordo" Date: Fri, 18 Apr 2025 02:06:33 -0700 Subject: [PATCH] format --- src/carousel/__init__.py | 40 ++++++++++++++++++++++++-------- test/galeshapley_test.py | 49 +++++++++++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/src/carousel/__init__.py b/src/carousel/__init__.py index 1c7ebb9..0800b78 100644 --- a/src/carousel/__init__.py +++ b/src/carousel/__init__.py @@ -5,6 +5,7 @@ import polars.selectors as pls import itertools as it + def rank_to_pref(R): """Converts a ranking to a preference.""" id_col_name = R.select(pls.by_index(0)).to_series().name @@ -66,53 +67,74 @@ def check_valid_rank(R): ).get_column("ties")[0] return not ties + def check_valid_match(match, applicants, reviewers): # TODO pass + def check_valid_assgn(assgn, applicants, reviewers): # TODO pass + def get_rank(ranking, ranker, rankee): idx = ranking.select(pl.arg_where(pl.col("") == rankee)).item() return ranking[ranker][idx] -def check_unstable(match, applicant_ranking, reviewer_ranking): - applicants = applicant_ranking.columns[1:] # assume unique applicants - for a, b in it.combinations(applicants, 2): - A = match.select(c for c in match.iter_columns() if a in c).to_series().name # the reviewer a is matched to - B = match.select(c for c in match.iter_columns() if b in c).to_series().name # the reviewer b is matched to - b_prefers_A = get_rank(applicant_ranking, b, A) < get_rank(applicant_ranking, b, B) - A_prefers_b = get_rank(reviewer_ranking, A, b) < get_rank(reviewer_ranking, A, a) +def check_unstable(match, applicant_ranking, reviewer_ranking): + applicants = applicant_ranking.columns[1:] # assume unique applicants + for a, b in it.combinations(applicants, 2): + A = ( + match.select(c for c in match.iter_columns() if a in c).to_series().name + ) # the reviewer a is matched to + B = ( + match.select(c for c in match.iter_columns() if b in c).to_series().name + ) # the reviewer b is matched to + + b_prefers_A = get_rank(applicant_ranking, b, A) < get_rank( + applicant_ranking, b, B + ) + A_prefers_b = get_rank(reviewer_ranking, A, b) < get_rank( + reviewer_ranking, A, a + ) if b_prefers_A and A_prefers_b: return True # or - a_prefers_B = get_rank(applicant_ranking, a, B) < get_rank(applicant_ranking, a, A) - B_prefers_a = get_rank(reviewer_ranking, B, a) < get_rank(reviewer_ranking, B, b) + a_prefers_B = get_rank(applicant_ranking, a, B) < get_rank( + applicant_ranking, a, A + ) + B_prefers_a = get_rank(reviewer_ranking, B, a) < get_rank( + reviewer_ranking, B, b + ) if a_prefers_B and B_prefers_a: return True # else return False + def check_stable(*args, **kwargs): return not check_unstable(*args, **kwargs) + def deferred_acceptance(A, R): """Find the Gale-Shapley deferred-acceptance stable matching for preferences A, R.""" # TODO - the core algorithm! pass + def assgn_to_match(assgn): # TODO pass + def match_to_assgn(match): # TODO pass + def main() -> None: rich.print("Hello from [italic red]carousel[/italic red]!") diff --git a/test/galeshapley_test.py b/test/galeshapley_test.py index 7c984f0..05e0abb 100644 --- a/test/galeshapley_test.py +++ b/test/galeshapley_test.py @@ -82,15 +82,48 @@ def test_prefs_tofrom_ranks(P): def test_eg3_unstable(): - applicant_rankings = pl.DataFrame({"": ["A", "B", "C", "D"], "a": [1, 2, 3, 4], "b": [1, 4, 3, 2], "c": [2, 1, 3, 4], "d": [4, 2, 3, 1]}) - reviewer_rankings = pl.DataFrame({"": ["a", "b", "c", "d"], "A": [3, 4, 2, 1], "B": [3, 1, 4, 2], "C": [2, 3, 4, 1], "D": [3, 2, 1, 4] }) - match = pl.DataFrame({"A" : ["a"], "B": ["b"], "C": ["c"], "D": ["d"]}) - + applicant_rankings = pl.DataFrame( + { + "": ["A", "B", "C", "D"], + "a": [1, 2, 3, 4], + "b": [1, 4, 3, 2], + "c": [2, 1, 3, 4], + "d": [4, 2, 3, 1], + } + ) + reviewer_rankings = pl.DataFrame( + { + "": ["a", "b", "c", "d"], + "A": [3, 4, 2, 1], + "B": [3, 1, 4, 2], + "C": [2, 3, 4, 1], + "D": [3, 2, 1, 4], + } + ) + match = pl.DataFrame({"A": ["a"], "B": ["b"], "C": ["c"], "D": ["d"]}) + assert crsl.check_unstable(match, applicant_rankings, reviewer_rankings) + def test_eg3_isstable(): - applicant_rankings = pl.DataFrame({"": ["A", "B", "C", "D"], "a": [1, 2, 3, 4], "b": [1, 4, 3, 2], "c": [2, 1, 3, 4], "d": [4, 2, 3, 1]}) - reviewer_rankings = pl.DataFrame({"": ["a", "b", "c", "d"], "A": [3, 4, 2, 1], "B": [3, 1, 4, 2], "C": [2, 3, 4, 1], "D": [3, 2, 1, 4] }) - match = pl.DataFrame({"A" : ["c"], "B": ["d"], "C": ["a"], "D": ["b"]}) - + applicant_rankings = pl.DataFrame( + { + "": ["A", "B", "C", "D"], + "a": [1, 2, 3, 4], + "b": [1, 4, 3, 2], + "c": [2, 1, 3, 4], + "d": [4, 2, 3, 1], + } + ) + reviewer_rankings = pl.DataFrame( + { + "": ["a", "b", "c", "d"], + "A": [3, 4, 2, 1], + "B": [3, 1, 4, 2], + "C": [2, 3, 4, 1], + "D": [3, 2, 1, 4], + } + ) + match = pl.DataFrame({"A": ["c"], "B": ["d"], "C": ["a"], "D": ["b"]}) + assert crsl.check_stable(match, applicant_rankings, reviewer_rankings)