- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 359
 
Open
Labels
ProblemThis is a problem in the archive or an implementation.This is a problem in the archive or an implementation.
Description
Bug Report
Description
The Python implementation in the stable marriage chapter is worst case ϴ(n³), but should be O(n²).
I have attached an alternative implementation that runs in worst-case quadratic time. I can make a PR if you want to replace the current algorithm.
Steps to Reproduce
Run the code with N = 3000.
Expected behavior
Terminate within seconds.
Screenshots
| N | current | new | 
|---|---|---|
| 0 | 0:00.11 | 0:00.08 | 
| 100 | 0:00.10 | 0:00.07 | 
| 200 | 0:00.14 | 0:00.09 | 
| 300 | 0:00.18 | 0:00.13 | 
| 400 | 0:00.28 | 0:00.16 | 
| 500 | 0:00.24 | 0:00.20 | 
| 600 | 0:00.90 | 0:00.27 | 
| 700 | 0:00.71 | 0:00.35 | 
| 800 | 0:01.38 | 0:00.43 | 
| 900 | 0:01.95 | 0:00.55 | 
| 1000 | 0:01.37 | 0:00.65 | 
| 1100 | 0:04.69 | 0:00.80 | 
| 1200 | 0:02.42 | 0:00.95 | 
| 1300 | 0:04.20 | 0:01.15 | 
| 1400 | 0:05.49 | 0:01.29 | 
| 1500 | 0:09.23 | 0:01.55 | 
| 1600 | 0:15.27 | 0:01.76 | 
| 1700 | 0:09.13 | 0:01.93 | 
| 1800 | 0:10.11 | 0:02.19 | 
| 1900 | 0:11.64 | 0:02.27 | 
| 2000 | 0:18.57 | 0:02.49 | 
| 2100 | 0:22.63 | 0:02.89 | 
| 2200 | 0:19.52 | 0:03.13 | 
| 2300 | 0:26.70 | 0:03.43 | 
| 2400 | 0:54.32 | 0:03.72 | 
| 2500 | 1:07.84 | 0:04.16 | 
Additional context
from random import sample as shuffle
def stable_matching(hospital_preferences, student_preferences):
    students = [s for s in student_preferences]
    hospitals = [h for h in hospital_preferences]
    proposals = {h: 0 for h in hospitals}
    unmatched_hospitals = [h for h in hospitals]
    student = {h: None for h in hospitals}
    hospital = {s: None for s in students}
    inrank = {
        s: {} for s in students
    }  # maps s to each hospital's s-ranking
    for s in students:
        for idx, h in enumerate(student_preferences[s]):
            inrank[s][h] = idx
    while unmatched_hospitals:
        h = unmatched_hospitals.pop()
        nxt = proposals[h]
        s = hospital_preferences[h][nxt]
        proposals[h] += 1
        # h proposes to its best student not yet proposed to
        if not hospital[s]:
            # s is available
            hospital[s] = h
            student[h] = s
        else:
            sh = hospital[s]
            rank_sh = inrank[s][sh]
            rank_h = inrank[s][h]
            if rank_h < rank_sh:
                # s dumps sh for h
                hospital[s] = h
                student[sh] = None
                student[h] = s
                unmatched_hospitals.append(sh)
            else:
                # s is taken
                unmatched_hospitals.append(h)
    return student
def _generate_instance(N):
    HOSPITALS = [f"h{i}" for i in range(N)]
    STUDENTS = [f"s{i}" for i in range(N)]
    hospital_preferences = {h: STUDENTS[:N] for h in HOSPITALS[:N]}
    student_preferences = {s: HOSPITALS[:N] for s in STUDENTS[:N]}
    for h in HOSPITALS[:N]:
        hospital_preferences[h] = shuffle(hospital_preferences[h], N)
    for s in STUDENTS[:N]:
        student_preferences[s] = shuffle(student_preferences[s], N)
    return hospital_preferences, student_preferences
if __name__ == "__main__":
    import sys
    hospital_preferences, student_preferences = _generate_instance(int(sys.argv[1]))
    #print(hospital_preferences)
    #print(student_preferences)
    M = stable_matching(hospital_preferences, student_preferences)
    for h in M:
        print(f"Hospital {h} + Student {M[h]}")For Algorithm Archive Developers
- The bug can be reproduced
 - The bug can be fixed (if not, please explain why not in a comment below)
 - There is a timeline to fix the bug
 - The bug has been fixed (Please link the PR)
 
Liikt
Metadata
Metadata
Assignees
Labels
ProblemThis is a problem in the archive or an implementation.This is a problem in the archive or an implementation.