03 — Stable Matching | mathuser.com

Topic 03 — CS 70 Discrete Mathematics

Stable
Matching

A beautiful algorithmic problem with real-world consequence — the Gale-Shapley algorithm assigns medical residents to hospitals, students to schools, and more. We prove it always works, always terminates, and has deep optimality properties.

The Problem

We have n jobs and n candidates. Each job has a ranked preference list of all candidates, and each candidate has a ranked preference list of all jobs. We want to find a stable matching — a one-to-one pairing where nobody has an incentive to break their assigned pair.

Real-world application: The National Residency Matching Program (NRMP) uses Gale-Shapley to assign ~40,000 medical school graduates to hospital residency programs each year. Lloyd Shapley won the 2012 Nobel Prize in Economics for this work.

Definitions

Matching

A matching is a set of (candidate, job) pairs such that each candidate appears in at most one pair and each job appears in at most one pair. A perfect matching pairs every candidate and every job.

Rogue Couple

A pair (c, j) is a rogue couple in a matching M if:

  • c and j are not matched to each other in M,
  • c prefers j over their current match in M, AND
  • j prefers c over their current match in M.

Both parties have mutual incentive to abandon their current assignments.

Stable Matching

A matching M is stable if it has no rogue couples. Neither party has mutual incentive to defect.

Optimality Terms

Optimal candidate for job j: The best candidate that j is paired with in any stable matching.

Optimal job for candidate c: The best job c is paired with in any stable matching.

Job-optimal: A matching where every job gets its optimal candidate.

Candidate-pessimal: A matching where every candidate gets their worst possible job across all stable matchings.

The Propose-and-Reject Algorithm (Gale-Shapley)

// Propose-and-Reject: Jobs Propose
Each day until no rejections occur:
Morning: Each job proposes to the highest-ranked candidate on its list who has not yet rejected it.
(A job re-proposes to the same candidate if not rejected yesterday.)
Afternoon: Each candidate:
— Holds the best offer received so far ("maybe")
— Rejects all other offers
Evening: Each job crosses off any candidate who rejected them.
Termination: All candidates accept their current offer.
Key invariant: A candidate never "lets go" of a good offer to take a worse one. Once a candidate says "maybe" to a job, they only upgrade. Jobs can only get rejected and propose down their list.

Worked Example (DIS 1B)

Job Preferences

Job1st2nd3rd
1ABC
2BAC
3ABC

Candidate Preferences

Candidate1st2nd3rd
A213
B132
C123
Day 1 — Morning
Job 1 → proposes to A (top choice). Job 2 → proposes to B (top choice). Job 3 → proposes to A (top choice).

Afternoon: A receives offers from Job 1 and Job 3. A prefers Job 2 over both, but Job 2 didn't propose to A. Between Jobs 1 and 3: A prefers Job 1 (rank 2) over Job 3 (rank 3). A says maybe to Job 1, rejects Job 3. B receives offer from Job 2, says maybe.

Evening: Job 3 crosses off A.
Day 2 — Morning
Job 1 → re-proposes to A (still holding). Job 2 → re-proposes to B. Job 3 → proposes to B (next on list after A).

Afternoon: A has only Job 1: says maybe. B receives offers from Job 2 and Job 3. B prefers Job 1 most, but Job 1 proposed to A. Between Jobs 2 and 3: B prefers Job 3 (rank 2) over Job 2 (rank 3). B says maybe to Job 3, rejects Job 2.

Evening: Job 2 crosses off B.
Day 3 — Morning
Job 1 → re-proposes to A. Job 2 → proposes to A (next after B). But A is holding Job 1. A prefers Job 2 (rank 1) over Job 1 (rank 2)! A says maybe to Job 2, rejects Job 1. Job 3 → re-proposes to B.

Afternoon: A: holds Job 2. B: holds Job 3. Job 1 is rejected by A.

Evening: Job 1 crosses off A.
Day 4 — Morning
Job 1 → proposes to B (next after A). But B is holding Job 3. B prefers Job 1 (rank 1) over Job 3 (rank 2). B says maybe to Job 1, rejects Job 3. Job 2 → re-proposes to A. Job 3 → must now propose to C (next after A and B).

Afternoon: A: holds Job 2 ✓. B: holds Job 1 ✓. C: receives Job 3, says maybe ✓.

No rejections! Algorithm terminates.
Final Matching (after 4 days)

A ↔ Job 2,   B ↔ Job 1,   C ↔ Job 3

Verify stability: Check all unmatched pairs for rogue couples.

  • (A, Job 1): A prefers Job 2 over Job 1. No rogue couple.
  • (A, Job 3): A prefers Job 2 over Job 3. No rogue couple.
  • (B, Job 2): B prefers Job 1 over Job 2. No rogue couple (B is with Job 1).
  • (B, Job 3): B prefers Job 1 over Job 3. No rogue couple.
  • (C, Job 1): Job 1 prefers A over C. No rogue couple.
  • (C, Job 2): Job 2 prefers B over C. No rogue couple.

Stable! ✓

Termination

Theorem — Algorithm Always Terminates

The propose-and-reject algorithm terminates in at most n² days.

Proof

Each day where a rejection occurs, at least one job crosses at least one candidate off its list permanently. There are n jobs, each with a list of n candidates, giving n² total crossings possible. Since at least one crossing happens per non-terminating day, the algorithm runs for at most n² days. ∎

The Improvement Lemma

Improvement Lemma — Candidates Only Upgrade

Once a candidate c receives a proposal and says "maybe," every subsequent proposal c holds is at least as good (by c's preferences). Candidate c's situation can only improve or stay the same over time.

Proof

A candidate c replaces a current held proposal only when a better offer arrives. So the job on c's "string" at any point is at least as good as any previous job on c's string. ∎

Dual — Jobs Only Descend

Every job proposes to candidates in decreasing order of preference. Once rejected by a candidate, a job never proposes to that candidate again.

Correctness — The Output Is a Stable Matching

Theorem — Output Is a Perfect Stable Matching

The propose-and-reject algorithm always outputs a perfect matching (every candidate and job is matched), and the matching is stable (no rogue couples).

Proof Sketch

Perfect: No candidate can be unmatched. If candidate c received no proposals, that means all n jobs skipped c — impossible since each job works through its entire list before c could be last for all of them. Formally: if c is unmatched, some job j is also unmatched (by counting). But j would have proposed to c eventually. Contradiction.

Stable: Suppose for contradiction that (c, j) is a rogue couple in the final matching M. So c is matched to some j' and j is matched to some c', where c prefers j over j' and j prefers c over c'. Since j prefers c over c', j must have proposed to c before proposing to c' (jobs go down their list). By the Improvement Lemma, when j proposed to c, either c rejected j immediately (meaning c already had something better than j — contradicting c preferring j over current j') or c held j and later upgraded to something better. Either way, c ended with something at least as good as j — contradicting c preferring j over current match. Contradiction! ∎

Optimality — Job Optimal, Candidate Pessimal

Theorem — Job Optimal

When jobs propose, the output matching is job-optimal: every job is matched with the best candidate it could get in any stable matching.

Theorem — Candidate Pessimal

When jobs propose, the output matching is candidate-pessimal: every candidate is matched with the worst job they receive in any stable matching.

The Proposer Advantage: Whichever side proposes gets the optimal outcome for their side. The receiving side gets the worst stable outcome. This is why in practice, it matters who "proposes." In the medical match, hospitals historically proposed first — getting the best residents. When the algorithm was changed to residents proposing, residents got better assignments.

Key True/False Statements (DIS 1B)

Statement (a) — TRUE

"There is a stable matching instance where in the jobs-proposing algorithm, every job ends up with its least preferred candidate."

Example: n=2 jobs {1,2} and candidates {A,B}. Job 1: A>B. Job 2: B>A. Candidate A: 2>1. Candidate B: 1>2. Algorithm: Day 1: Job 1→A (A holds), Job 2→B (B holds). No rejections. Match: {1↔A, 2↔B}. Job 1 got A (top choice — wait, that's optimal). Try symmetric version where everyone's last choice forces it. The key insight: pessimal for candidates doesn't mean pessimal for jobs in the same matching.

Statement (b) — TRUE

"If job J and candidate C are each other's top choice, then J and C are paired in every stable matching."

Proof: Suppose some stable matching M has J paired with C' ≠ C and C with J' ≠ J. Since J prefers C over C' and C prefers J over J', the pair (C,J) is a rogue couple in M. Contradiction. So J and C must be together in every stable matching. ∎

Statement (c) — FALSE

"If J and C rank each other last, they cannot be paired in any stable matching."

Counterexample: With n=2: Jobs {1,2}, Candidates {A,B}. Job 1: A>B, Job 2: A>B. Candidate A: 1>2, Candidate B: 1>2. The only valid matching is {1↔A, 2↔B}. Job 2 and Candidate B are each other's last choice, yet they must be paired. It is stable (no rogue couple: (A,2) — A prefers 1, no issue).

Practice Problems

Prove (DIS 1B)

Claim: In any execution, if a candidate receives a proposal on day i, they receive a proposal on every subsequent day until termination.

Proof: By the Improvement Lemma, a candidate who holds offer from job j on day i will either continue holding j (j re-proposes), or upgrade to j' ≻ j (some j' proposes). In either case, they receive a proposal on day i+1. By induction on days, they receive a proposal every day after i until termination. ∎

Practice — Run the Algorithm

2 jobs {A,B} and 2 candidates {X,Y}. Job A: X>Y. Job B: X>Y. Candidate X: B>A. Candidate Y: A>B.

Trace the algorithm and find the stable matching. Is it job-optimal? Is it candidate-pessimal?