{"id":20071389,"url":"https://github.com/daffidwilde/matching","last_synced_at":"2025-05-16T00:06:45.593Z","repository":{"id":28877483,"uuid":"119597240","full_name":"daffidwilde/matching","owner":"daffidwilde","description":"A package for solving matching games","archived":false,"fork":false,"pushed_at":"2025-03-21T00:54:21.000Z","size":11805,"stargazers_count":158,"open_issues_count":10,"forks_count":43,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-03T05:02:13.776Z","etag":null,"topics":["gale-shapley","game-theory","hospital-residents","matching-game","matching-problems","stable-marriage"],"latest_commit_sha":null,"homepage":"https://daffidwilde.github.io/matching/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daffidwilde.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":"docs/contributing.qmd","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-01-30T21:34:24.000Z","updated_at":"2025-02-21T14:52:46.000Z","dependencies_parsed_at":"2022-09-13T22:00:29.060Z","dependency_job_id":"a18c3c11-068f-4fd8-bd2f-9af488c432a9","html_url":"https://github.com/daffidwilde/matching","commit_stats":{"total_commits":125,"total_committers":3,"mean_commits":"41.666666666666664","dds":0.02400000000000002,"last_synced_commit":"3baec44dd7e039fa82db24efc7646c38017c01b6"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daffidwilde%2Fmatching","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daffidwilde%2Fmatching/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daffidwilde%2Fmatching/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daffidwilde%2Fmatching/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daffidwilde","download_url":"https://codeload.github.com/daffidwilde/matching/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254059509,"owners_count":22007768,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gale-shapley","game-theory","hospital-residents","matching-game","matching-problems","stable-marriage"],"created_at":"2024-11-13T14:28:59.178Z","updated_at":"2025-05-16T00:06:40.555Z","avatar_url":"https://github.com/daffidwilde.png","language":"Python","readme":"![CI status](https://github.com/daffidwilde/matching/actions/workflows/ci.yml/badge.svg?branch=main)\n[![Code style](https://img.shields.io/badge/code%20style-black-black)](https://github.com/ambv/black)\n[![Zenodo archive](https://zenodo.org/badge/DOI/10.5281/zenodo.2553125.svg)](https://doi.org/10.5281/zenodo.2553125)\n[![JOSS paper](https://joss.theoj.org/papers/10.21105/joss.02169/status.svg)](https://doi.org/10.21105/joss.02169)\n\n\n# A package for solving matching games\n\nMatching games allow for the allocation of resources and partnerships in\na fair way. Typically, a matching game is defined by two sets of players\nthat each have preferences over at least some of the elements of the\nother set. The objective of the game is then to find a mapping between\nthe sets of players in which everyone is happy enough with their match.\n\nIn `matching`, we deal with four types of matching game:\n\n-   the stable marriage problem (SM);\n-   the hospital-resident assignment problem (HR);\n-   the student-allocation problem (SA);\n-   the stable roommates problem (SR).\n\n## Installation\n\nMatching requires Python 3.5 or above, and relies only on\n[NumPy](http://www.numpy.org/) for general use.\n\nThe library is most easily installed using `pip`:\n\n```bash\n    $ python -m pip install matching\n```\n\nHowever, if you would like to install it from source then go ahead and\nclone the GitHub repository:\n\n```bash\n    $ git clone https://github.com/daffidwilde/matching.git\n    $ cd matching\n    $ python -m pip install .\n```\n\n## Documentation\n\nFull documentation (including tutorials and discussion material) is\navailable here: \u003chttps://daffidwilde.github.io/matching/\u003e\n\nAn academic paper on this library has been included in the Journal of\nOpen Source Software (JOSS) and is available here:\n\u003chttps://joss.theoj.org/papers/10.21105/joss.02169\u003e\n\n## Playing a simple game\n\nWith all games, Matching uses a `Player` class to represent the members\nof the \"applying\" party, i.e. residents and students. For HR and SA,\nthere are specific classes to represent the roles of `Hospital`,\n`Project` and `Supervisor`.\n\nConsider the following instance of SM which is represented on a\nbipartite graph where the suitors and reviewers are along the left and\nright respectively.\n\n![image](./tex/stable_marriage.png){.align-center width=\"10cm\"}\n\nWe can construct these preferences using dictionaries:\n\n```python\n\u003e\u003e\u003e suitor_preferences = {\n...     \"A\": [\"D\", \"E\", \"F\"], \"B\": [\"D\", \"F\", \"E\"], \"C\": [\"F\", \"D\", \"E\"]\n... }\n\u003e\u003e\u003e reviewer_preferences = {\n...     \"D\": [\"B\", \"C\", \"A\"], \"E\": [\"A\", \"C\", \"B\"], \"F\": [\"C\", \"B\", \"A\"]\n... }\n\n```\n\nThen to solve this matching game, we make use of the `StableMarriage`\nclass, like so:\n\n\n```python\n\u003e\u003e\u003e from matching.games import StableMarriage\n\u003e\u003e\u003e game = StableMarriage.create_from_dictionaries(\n...     suitor_preferences, reviewer_preferences\n... )\n\u003e\u003e\u003e game.solve()\n{A: E, B: D, C: F}\n\n```\n\n## The `Matching` object\n\nThis matching is not a standard Python dictionary, though it does\nlargely look and behave like one. It is in fact an instance of the\n`SingleMatching` class:\n\n```python\n\u003e\u003e\u003e matching = game.matching\n\u003e\u003e\u003e type(matching)\n\u003cclass 'matching.matchings.SingleMatching'\u003e\n\n```\n\nThis dictionary-like object is primarily useful as a teaching device\nthat eases the process of manipulating a matching after a solution has\nbeen found.\n\n## `Player` classes\n\nDespite passing dictionaries of strings here, the matching displays\ninstances of `matching.player.Player`:\n\n```python\n\u003e\u003e\u003e matching = game.matching\n\u003e\u003e\u003e for suitor in matching:\n...     print(type(suitor))\n\u003cclass 'matching.players.player.Player'\u003e\n\u003cclass 'matching.players.player.Player'\u003e\n\u003cclass 'matching.players.player.Player'\u003e\n\n```\n\nThis is because `create_from_dictionaries` creates instances of the\nappropriate player classes first and passes them to the game class.\nUsing dictionaries like this can be an efficient way of creating large\ngames but it does require the names of the players in each party to be\nunique.\n\nWith all games, Matching uses a `Player` class to represent the members\nof the \"applying\" party, i.e. residents and students. For HR and SA,\nthere are specific classes to represent the roles of `Hospital`,\n`Project` and `Supervisor`.\n\n## A note on performance\n\nOne of the limitations of this library is the time complexities of the\nalgorithm implementations. In practical terms, the running time of any\nof the algorithms in Matching is negligible but the theoretic complexity\nof each has not yet been attained. For example, an instance of HR with\n400 applicants and 20 hospitals is solved in less than one tenth of a\nsecond:\n\n```python\n\u003e\u003e\u003e from matching.games import HospitalResident\n\u003e\u003e\u003e import numpy as np\n\u003e\u003e\u003e prng = np.random.default_rng(0)\n\u003e\u003e\u003e num_residents, num_hospitals = 400, 20\n\u003e\u003e\u003e resident_prefs = {\n...     r: np.argsort(prng.random(size=num_hospitals))\n...     for r in range(num_residents)\n... }\n\u003e\u003e\u003e hospital_prefs = {\n...     h: np.argsort(prng.random(size=num_residents))\n...     for h in range(num_hospitals)\n... }\n\u003e\u003e\u003e capacities = {h: num_hospitals for h in hospital_prefs}\n\u003e\u003e\u003e game = HospitalResident.create_from_dictionaries(\n...     resident_prefs, hospital_prefs, capacities\n... )\n\u003e\u003e\u003e _ = game.solve() # 48.6 ms ± 963 µs per loop\n\n```\n\n## Get in contact!\n\nI hope this package is useful, and feel free to contact me here with any\nissues or recommendations. Pull requests are always welcome!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaffidwilde%2Fmatching","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaffidwilde%2Fmatching","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaffidwilde%2Fmatching/lists"}