Skip to content

oedokumaci/gale-shapley-algorithm

Repository files navigation

gale-shapley-algorithm

A Python implementation of the celebrated Gale-Shapley (a.k.a. the Deferred Acceptance) Algorithm.

Time complexity is O(n^2), space complexity is O(n).

CI Docs Docker PyPI Python Ruff uv License: MIT

GUI with Docker

The easiest way to try the algorithm is with the interactive web GUI:

docker pull oedokumaci/gale-shapley-algorithm
docker run --rm -p 8000:8000 oedokumaci/gale-shapley-algorithm

Then open http://localhost:8000 in your browser.

Or build locally for development:

docker build -t gale-shapley-algorithm .
docker run --rm -p 8000:8000 gale-shapley-algorithm

The GUI lets you:

  • Add and remove people on each side (proposers and responders)
  • Set preferences by drag-and-drop reordering
  • Randomize all preferences with one click
  • Run the matching and see results in a table with stability info
  • Animate step-by-step to watch proposals, rejections, and tentative matches unfold round by round in an SVG visualization
  • Upload images for each person to personalize the visualization
  • Toggle dark/light mode

Installation

pip install gale-shapley-algorithm

With CLI support:

pip install "gale-shapley-algorithm[cli]"

With numpy-backed primitives for large-scale / numerical work (adds numpy >= 2.0):

pip install "gale-shapley-algorithm[numeric]"

Quick Start

As a Library

import gale_shapley_algorithm as gsa

result = gsa.create_matching(
    proposer_preferences={
        "alice": ["bob", "charlie"],
        "dave": ["charlie", "bob"],
    },
    responder_preferences={
        "bob": ["alice", "dave"],
        "charlie": ["dave", "alice"],
    },
)
print(result.matches)  # {'alice': 'bob', 'dave': 'charlie'}

Numerical / large-scale usage

For high-throughput work (many random instances, enumerating the stable-matching lattice, using the output as input to downstream ML/RL pipelines), the numeric subpackage provides numpy-array APIs:

import numpy as np
from gale_shapley_algorithm.numeric import (
    gale_shapley, men_optimal_gs, women_optimal_gs,
    is_stable, find_blocking_pairs, enumerate_stable_matchings,
    exposed_rotations, apply_rotation,
)

# Rank matrices: men_rank[i, j] is woman j's 1-indexed position on man i's list.
men_rank   = np.array([[1, 2, 3], [3, 1, 2], [2, 3, 1]], dtype=np.int16)
women_rank = np.array([[3, 1, 2], [1, 3, 2], [2, 1, 3]], dtype=np.int16)

mo = men_optimal_gs(men_rank, women_rank)    # match[m] = w
wo = women_optimal_gs(men_rank, women_rank)
lattice = enumerate_stable_matchings(men_rank, women_rank)  # (|L|, n) int16 array

# Step through the lattice manually:
for rotation in exposed_rotations(men_rank, women_rank, mo):
    next_matching = apply_rotation(mo, rotation)
    assert is_stable(men_rank, women_rank, next_matching)

See examples/numeric_usage.py for a more complete walk-through. enumerate_stable_matchings defaults to the Gusfield-Irving rotation algorithm and scales past n=50; the brute-force method remains available via method="brute" as a correctness oracle for small instances.

As a CLI

The CLI uses interactive prompts -- no config files needed:

# Interactive mode: enter names and rank preferences
uvx --from "gale-shapley-algorithm[cli]" python -m gale_shapley_algorithm

# Random mode: auto-generate names and preferences
uvx --from "gale-shapley-algorithm[cli]" python -m gale_shapley_algorithm --random

# Swap proposers and responders
uvx --from "gale-shapley-algorithm[cli]" python -m gale_shapley_algorithm --swap-sides

Interactive mode example:

$ python -m gale_shapley_algorithm

  Gale-Shapley Algorithm

Enter proposer side name [Proposers]: Men
Enter responder side name [Responders]: Women

Enter names for Men (comma-separated): Will, Hampton
Enter names for Women (comma-separated): April, Summer

Ranking preferences for Men...

  Available for Will:
  1. April
  2. Summer
  Enter ranking for Will (e.g. 1,2): 1,2
  -> Will: April > Summer

  Available for Hampton:
  1. April
  2. Summer
  Enter ranking for Hampton (e.g. 1,2): 2,1
  -> Hampton: Summer > April

Ranking preferences for Women...
  ...

┌──────── Matching Result ────────┐
│ Men     │ Women                 │
├─────────┼───────────────────────┤
│ Will    │ April                 │
│ Hampton │ Summer                │
└─────────┴───────────────────────┘
Completed in 1 round. Stable: Yes

Random mode example:

$ python -m gale_shapley_algorithm --random

  Gale-Shapley Algorithm

Enter proposer side name [Proposers]: Cats
Enter responder side name [Responders]: Dogs
Number of Cats [3]: 3
Number of Dogs [3]: 3

  ... (random preferences generated and displayed) ...

Completed in 2 rounds. Stable: Yes

Development

This project is managed with uv and uses taskipy for task running.

git clone https://github.com/oedokumaci/gale-shapley-algorithm
cd gale-shapley-algorithm
uvx --from taskipy task setup   # Install dependencies
uvx --from taskipy task run     # Run the application
uvx --from taskipy task fix     # Auto-format + lint fix
uvx --from taskipy task ci      # Run all CI checks
uvx --from taskipy task test    # Run tests
uvx --from taskipy task docs    # Serve docs locally

Install pre-commit hooks:

uv run pre-commit install

Documentation

Full documentation is available at oedokumaci.github.io/gale-shapley-algorithm.

License

MIT