def test_check_stability(): """Test that HospitalResident can recognise whether a matching is stable or not.""" residents = [Resident("A"), Resident("B"), Resident("C")] hospitals = [Hospital("X", 2), Hospital("Y", 2)] (a, b, c), (x, y) = residents, hospitals a.set_prefs([x, y]) b.set_prefs([y]) c.set_prefs([y, x]) x.set_prefs([c, a]) y.set_prefs([a, b, c]) game = HospitalResident(residents, hospitals) matching = game.solve() assert game.check_stability() (a, b, c), (x, y) = game.residents, game.hospitals matching[x] = [c] matching[y] = [a, b] assert not game.check_stability()
def test_check_for_unacceptable_matches_hospitals(resident_names, hospital_names, capacities, seed, clean): """Test that HospitalResident recognises a valid matching requires each hospital to have a preference of each of its matches, if any.""" _, _, game = make_game(resident_names, hospital_names, capacities, seed, clean) hospital = game.hospitals[0] resident = Resident(name="foo") hospital.matching.append(resident) issues = game._check_for_unacceptable_matches("hospitals") assert len(issues) == 1 issue = issues[0] assert issue.startswith(hospital.name) assert issue.endswith(f"{hospital.prefs}.") assert resident.name in issue with pytest.raises(MatchingError) as e: game.check_validity() error = e.unacceptable_matches[0] assert issue == error
def test_get_worst_match(name, capacity, pref_names): """ Check that a hospital can return its worst match. """ hospital = Hospital(name, capacity) others = [Resident(other) for other in pref_names] hospital.matching = [others[0]] assert hospital.get_worst_match() == others[0] hospital.matching = others assert hospital.get_worst_match() == others[-1]
def test_get_favourite(name, capacity, pref_names): """ Check the correct player is returned as the hospital's favourite. """ hospital = Hospital(name, capacity) others = [Resident(other) for other in pref_names] hospital.set_prefs(others) assert hospital.get_favourite() == others[0] hospital.matching = others assert hospital.get_favourite() is None
def test_hospital_matching(resident_names, hospital_names, capacities, seed): """ Test that HospitalResident recognises a valid matching requires a hospital to have a preference of each of its matches, if any. """ _, _, game = make_game(resident_names, hospital_names, capacities, seed) game.solve() game.hospitals[0].matching.append(Resident(name="foo")) with pytest.raises(Exception): game._check_hospital_matching()
def test_resident_matching(resident_names, hospital_names, capacities, seed): """ Test that HospitalResident recognises a valid matching requires a resident to have a preference of their match, if they have one. """ _, _, game = make_game(resident_names, hospital_names, capacities, seed) game.solve() game.residents[0].matching = Resident(name="foo") with pytest.raises(Exception): game._check_resident_matching()
def players(draw, **kwargs): """ A custom strategy for making a set of residents and hospitals. """ resident_prefs, hospital_prefs, capacities = draw(connections(**kwargs)) residents = [Resident(name) for name in resident_prefs] hospitals = [Hospital(name, cap) for name, cap in capacities.items()] residents = _get_preferences(residents, hospitals, resident_prefs) hospitals = _get_preferences(hospitals, residents, hospital_prefs) return residents, hospitals
def test_check_if_oversubscribed(name, capacity, pref_names): """ Check that a hospital can verify whether it is oversubscribed. """ hospital = Hospital(name, capacity) others = [Resident(other) for other in pref_names] assert hospital.check_if_oversubscribed() is False hospital.matching = others hospital.capacity = 0 message = hospital.oversubscribed_message() assert hospital.check_if_oversubscribed() == message
def test_check_if_match_is_unacceptable(name, capacity, pref_names): """ Check that a hospital can verify the acceptability of its matches. """ hospital = Hospital(name, capacity) others = [Resident(other) for other in pref_names] assert hospital.check_if_match_is_unacceptable() == [] hospital.set_prefs(others[:-1]) hospital.matching = [others[-1]] message = hospital.not_in_preferences_message(others[-1]) assert hospital.check_if_match_is_unacceptable() == [message]
def test_get_successors(name, capacity, pref_names): """Check that a hospital can get the successors to its worst current match.""" hospital = Hospital(name, capacity) others = [Resident(other) for other in pref_names] hospital.set_prefs(others) hospital.matching = [others[0]] assert hospital.get_successors() == others[1:] hospital.matching = others assert hospital.get_successors() == []
def test_unmatch(name, capacity, pref_names): """ Check that a hospital can unmatch from a player correctly. """ hospital = Hospital(name, capacity) others = [Resident(other) for other in pref_names] hospital.matching = others for i, other in enumerate(others[:-1]): hospital.unmatch(other) assert hospital.matching == others[i + 1:] hospital.unmatch(others[-1]) assert hospital.matching == []
def test_match(name, capacity, pref_names): """ Check that a hospital can match to a player correctly. """ hospital = Hospital(name, capacity) others = [Resident(other) for other in pref_names] hospital.set_prefs(others) for i, other in enumerate(others[:-1]): hospital.match(other) assert hospital.matching == others[:i + 1] hospital.match(others[-1]) assert hospital.matching == others
def test_inputs_resident_prefs(resident_names, hospital_names, capacities, seed): """ Test that each resident's preference list is a subset of the available hospitals, and check that an Exception is raised if not. """ _, _, game = make_game(resident_names, hospital_names, capacities, seed) assert game._check_resident_prefs() game.residents[0].prefs = [Resident("foo")] with pytest.raises(Exception): game._check_resident_prefs()
def _make_instances(resident_prefs, hospital_prefs, capacities): """ Create ``Player`` (resident) and ``Hospital`` instances for the names in each dictionary. """ resident_dict, hospital_dict = {}, {} for resident_name in resident_prefs: resident = Resident(name=resident_name) resident_dict[resident_name] = resident for hospital_name in hospital_prefs: capacity = capacities[hospital_name] hospital = Hospital(name=hospital_name, capacity=capacity) hospital_dict[hospital_name] = hospital return resident_dict, hospital_dict
def test_check_inputs_hospital_prefs_all_residents(game): """Test that every hospital has only residents in its preference list. If not, check that a warning is caught and the player's preferences are changed.""" hospital = game.hospitals[0] hospital.prefs = [Resident("foo")] with warnings.catch_warnings(record=True) as w: game._check_inputs_player_prefs_all_in_party("hospitals", "residents") message = w[-1].message assert isinstance(message, PreferencesChangedWarning) assert hospital.name in str(message) assert "foo" in str(message) if game.clean: assert hospital.prefs == []
def test_check_inputs_resident_prefs_all_hospitals(resident_names, hospital_names, capacities, seed, clean): """Test that every resident has only hospitals in its preference list. If not, check that a warning is caught and the player's preferences are changed.""" _, _, game = make_game(resident_names, hospital_names, capacities, seed, clean) resident = game.residents[0] resident.prefs = [Resident("foo")] with warnings.catch_warnings(record=True) as w: game._check_inputs_player_prefs_all_in_party("residents", "hospitals") message = w[-1].message assert isinstance(message, PreferencesChangedWarning) assert resident.name in str(message) assert "foo" in str(message) if clean: assert resident.prefs == []
def make_players(resident_names, hospital_names, capacities): """ Given some names and capacities, make a set of players for HR. """ residents = [Resident(name) for name in resident_names] hospitals = [ Hospital(name, capacity) for name, capacity in zip(hospital_names, capacities) ] possible_prefs = get_possible_prefs(hospitals) logged_prefs = {} for resident in residents: prefs = possible_prefs[np.random.randint(len(possible_prefs))] resident.set_prefs(prefs) for hospital in prefs: try: logged_prefs[hospital] += [resident] except KeyError: logged_prefs[hospital] = [resident] for hospital, resids in logged_prefs.items(): hospital.set_prefs(np.random.permutation(resids).tolist()) return residents, [hosp for hosp in hospitals if hosp.prefs is not None]