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_example_in_issue(): """ Verify that the matching found is consistent with the example in #67. """ group_prefs = { "Group 1": ["Intellectual property", "Privacy"], "Group 2": ["Privacy", "Fairness in AI"], "Group 3": ["Privacy", "Social media"], } topic_hospital_prefs = { "Fairness in AI": ["Group 2"], "Intellectual property": ["Group 1"], "Privacy": ["Group 3", "Group 2", "Group 1"], "Social media": ["Group 3"], } capacities = {t: 2 for t in topic_hospital_prefs} game = HospitalResident.create_from_dictionaries( group_prefs, topic_hospital_prefs, capacities ) (G1, G2, G3), (F, I, P, S) = game.residents, game.hospitals matching = game.solve() assert matching == {I: [G1], P: [G3, G2], F: [], S: []}
def test_readme_example(): """ Verify the example used in the repo README. """ resident_prefs = { "A": ["C"], "S": ["C", "M"], "D": ["C", "M", "G"], "J": ["C", "G", "M"], "L": ["M", "C", "G"], } hospital_prefs = { "M": ["D", "L", "S", "J"], "C": ["D", "A", "S", "L", "J"], "G": ["D", "J", "L"], } capacities = {hosp: 2 for hosp in hospital_prefs} game = HospitalResident.create_from_dictionaries( resident_prefs, hospital_prefs, capacities ) (A, S, D, J, L), (M, C, G) = game.residents, game.hospitals matching = game.solve() assert matching == {M: [L, S], C: [D, A], G: [J]}
def fuzzy_matching(identifier: Tuple, pdf: pd.DataFrame): # Default recusion limit of 1000 causes the deepcopy in # HospitalResident.create_from_dictionaries to fail for particularly # large inputs. (identifier,) = identifier identifier = str(identifier) # instead of np.str sys.setrecursionlimit(10000) audio_preferences = defaultdict(list) text_preferences = defaultdict(list) for row in pdf.itertuples(): audio_preferences[row.audio_document_id].append( (row.levenshtein, row.text_document_id) ) text_preferences[row.text_document_id].append( (row.levenshtein, row.audio_document_id) ) # tuples are sorted lexicographically, so by levenshtein distance first for k, v in audio_preferences.items(): audio_preferences[k] = [text_id for _score, text_id in sorted(v)] for k, v in text_preferences.items(): text_preferences[k] = [audio_id for _score, audio_id in sorted(v)] # problem = StableMarriage.create_from_dictionaries(audio_preferences, text_preferences) more_audio_files = len(audio_preferences) > len(text_preferences) if more_audio_files: resident_preferences = audio_preferences hospital_preferences = text_preferences else: resident_preferences = text_preferences hospital_preferences = audio_preferences hospital_capacities = {k: 1 for k in hospital_preferences.keys()} try: problem = HospitalResident.create_from_dictionaries( resident_preferences, hospital_preferences, hospital_capacities ) except RecursionError: print("GALVEZ:problem=", identifier[0]) pprint.pprint("GALVEZ:residents:") pprint.pprint(resident_preferences) pprint.pprint("GALVEZ:hospitals:") pprint.pprint(hospital_preferences) raise pairs = problem.solve(optimal="hospital") pdf_dict = {"identifier": [], "audio_document_id": [], "text_document_id": []} for hospital_id, (resident_id,) in pairs.items(): if more_audio_files: audio_id = resident_id text_id = hospital_id else: audio_id = hospital_id text_id = resident_id pdf_dict["identifier"].append(identifier) pdf_dict["audio_document_id"].append(audio_id.name) pdf_dict["text_document_id"].append(text_id.name) return pd.DataFrame(pdf_dict)
def make_game(resident_names, hospital_names, capacities, seed, clean): """ Make all of the residents and hospitals, and the match itself. """ np.random.seed(seed) residents, hospitals = make_players(resident_names, hospital_names, capacities) game = HospitalResident(residents, hospitals, clean) return residents, hospitals, game
def test_resident_loses_all_preferences(): """ An example that forces a resident to be removed from the game as all of their preferences have been forgotten. """ resident_prefs = {"A": ["X"], "B": ["X", "Y"]} hospital_prefs = {"X": ["B", "A"], "Y": ["B"]} capacities = {"X": 1, "Y": 1} game = HospitalResident.create_from_dictionaries( resident_prefs, hospital_prefs, capacities ) (A, B), (X, Y) = game.residents, game.hospitals matching = game.solve() assert matching == {X: [B], Y: []}
def combinate_users_with_respect_interests_and_history(users, clear_history, userdata_this_time): user_prefs = {} user_for_interests = {} for user in users: user_prefs[user] = userdata_this_time[user]['interests'] for interest in userdata_this_time[user]['interests']: if interest not in user_for_interests.keys(): user_for_interests[interest] = [] user_for_interests[interest].append(user) capacities = {hosp: 2 for hosp in user_for_interests} game = HospitalResident.create_from_dictionaries(user_prefs, user_for_interests, capacities) pairs_by_interests = [ tuple(x) for x in game.solve(optimal="hospital").values() if len(tuple(x)) == 2 ] combinations_without_history = set(pairs_by_interests) - set(clear_history) return combinations_without_history
def test_init(players, clean): """Test that an instance of HospitalResident is created correctly when passed a set of players.""" residents, hospitals = players game = HospitalResident(residents, hospitals, clean) for resident, game_resident in zip(residents, game.residents): assert resident.name == game_resident.name assert resident._pref_names == game_resident._pref_names for hospital, game_hospital in zip(hospitals, game.hospitals): assert hospital.name == game_hospital.name assert hospital._pref_names == game_hospital._pref_names assert hospital.capacity == game_hospital.capacity assert all([resident.matching is None for resident in game.residents]) assert all([hospital.matching == [] for hospital in game.hospitals]) assert game.matching is None
def test_create_from_dictionaries(connections, clean): """Test that HospitalResident is created correctly when passed a set of dictionaries for each party.""" resident_prefs, hospital_prefs, capacities = connections game = HospitalResident.create_from_dictionaries(resident_prefs, hospital_prefs, capacities, clean) for resident in game.residents: assert resident._pref_names == resident_prefs[resident.name] assert resident.matching is None for hospital in game.hospitals: assert hospital._pref_names == hospital_prefs[hospital.name] assert hospital.capacity == capacities[hospital.name] assert hospital.matching == [] assert game.matching is None assert game.clean is clean
def random_experience(num_residents, num_hospitals): np.random.seed() uniform_capacity = int(num_residents / num_hospitals) + 1 resident_prefs = { r: np.argsort(np.random.random(size=num_hospitals)) for r in range(num_residents) } hospital_prefs = { h: np.argsort(np.random.random(size=num_residents)) for h in range(num_hospitals) } capacities = {h: num_hospitals for h in hospital_prefs} capacities = {h: uniform_capacity for h in hospital_prefs} game = HospitalResident.create_from_dictionaries(resident_prefs, hospital_prefs, capacities) _ = game.solve() return game, resident_prefs
def test_create_from_dictionaries(resident_names, hospital_names, capacities, seed): """ Test that HospitalResident is created correctly when passed a set of dictionaries for each party. """ resident_prefs, hospital_prefs = make_prefs(resident_names, hospital_names, seed) capacities_ = dict(zip(hospital_names, capacities)) game = HospitalResident.create_from_dictionaries(resident_prefs, hospital_prefs, capacities_) for resident in game.residents: assert resident.pref_names == resident_prefs[resident.name] assert resident.matching is None for hospital in game.hospitals: assert hospital.pref_names == hospital_prefs[hospital.name] assert hospital.capacity == capacities_[hospital.name] assert hospital.matching == [] assert game.matching is None
df_sorted = df_wiki_2.sort_values(by=['entity_wiki2_id', 'dist'], ascending=True) df_sorted = df_sorted.reset_index(drop=True) df_sorted = df_sorted[['entity_wiki2_id', 'entity_wiki1_id']] #results = df_sorted.groupby(['entity_wiki2_id'])['entity_wiki1_id'].apply(list) #df_results = pd.DataFrame(results) #dict_of_women = df_results.to_dict()['entity_wiki1_id'] dict_of_women = df_sorted.groupby( ['entity_wiki2_id'])['entity_wiki1_id'].apply(list).to_dict() print('*********Preparing Dictionary for Women Done**********') print('Data Preparation Done, running algo . . . . ') capacities = {women: 1 for women in dict_of_women} #capacities = {women: 1 for women in dict_of_women} game = HospitalResident.create_from_dictionaries(dict_of_men, dict_of_women, capacities) result = game.solve() def get_name(x): return entities[x.name] #entities[x.name] #print(entities[437]) #print(entities[292]) with open(COR_FOLDER + '/' + MODEL + '/' + file + '.csv', 'w+', encoding='utf-8') as stable_marriage_op: stable_marriage_op.write("entity_id_wiki_2,entity_id_wiki_1\n") for key in result:
def run_pairing(mentors, learners, requested_pairings_learners, requested_pairings_mentors): learners_left = list(learners.keys()) #mentors_left = list(mentors.keys()) once_more = True pairings = [] while once_more: if len(learners) < len(mentors): once_more = False learner_prefs = {} # check for if no matches after contraints satisfied, then soften constraint (allow more mentors?) for learner_id, learner in learners.items(): #if learner.get_id() == "*****@*****.**": is_requested = False if learner_id in requested_pairings_learners: is_requested = True #print("jlund requested " + requested_pairings_mentors[requested_pairings_learners.index(learner_id)]) learner.set_preferences( mentors, requested_pairings_mentors[ requested_pairings_learners.index(learner_id)]) else: learner.set_preferences(mentors) lprefs = learner.get_preferences() if len(lprefs) == 0: #rerun with softened contraints pairings.append( Pair(learner=learner, is_requested=is_requested)) learners_left.remove(learner_id) print("learner " + learner_id + " has no matching preferences.") continue # put learner prefs into dictionary for matching learner_prefs[learner_id] = learner.get_ranked_mentors() mentor_prefs = {} for mentor_id, mentor in mentors.items(): #if learner.get_id() == "*****@*****.**": # get all learners in learner_prefs that have mentor in their values list subscribed_learner_ids = [ k for k, v in learner_prefs.items() if mentor_id in v ] subscribed_learners = { id: learners[id] for id in subscribed_learner_ids } is_requested = False if mentor_id in requested_pairings_mentors: is_requested = True mentor.set_preferences_subscribed( subscribed_learners, requested_pairings_learners[ requested_pairings_mentors.index(mentor_id)]) else: mentor.set_preferences_subscribed(subscribed_learners) mprefs = mentor.get_preferences() if len(mprefs) == 0: #rerun with softened contraints #pairings.append(Pair(mentor=mentor)) print("mentor " + mentor.get_id() + " has no matching preferences.") continue # put learner prefs into dictionary for matching mentor_prefs[mentor.get_id()] = mentor.get_ranked_learners() capacities = {m: 1 for m in mentor_prefs} game = HospitalResident.create_from_dictionaries( learner_prefs, mentor_prefs, capacities) matching = game.solve() for k, v in matching.items(): if len(v) > 0: if k.name in requested_pairings_learners or v[ 0].name in requested_pairings_learners: pairings.append( Pair(mentor=mentors[k.name], learner=learners[v[0].name], is_requested=True)) else: pairings.append( Pair(mentor=mentors[k.name], learner=learners[ v[0].name])) # assumes capacity is 1 learners_left.remove(v[0].name) #else: # pairings.append(Pair(mentor=mentors[k.name])) # list unpaired learners learners = {k: learners[k] for k in learners_left} return pairings
def generate(self): # create the specialties list_of_specialties = [] for i in range(0, self.n_specialties): list_of_specialties.append(Specialty(i)) # create the programs list_of_programs = [] for i in range(0, self.n_specialties): specialty = list_of_specialties[i] for j in range(0, self.n_programs_per_specialty): list_of_programs.append(Program(i*self.n_programs_per_specialty + j, specialty, self.n_interviews_per_spot)) # create the probability distribution applicant specialty selection list_specialty_spots_distribution = [] for specialty in list_of_specialties: n_spots = 0 for program in list_of_programs: if program._specialty == specialty: n_spots += program._spots list_specialty_spots_distribution.append(n_spots) total_spots = int(np.sum(list_specialty_spots_distribution)) list_specialty_spots_distribution = np.array(list_specialty_spots_distribution) list_specialty_spots_distribution = [x + np.abs(np.random.normal(0, x*self.specialty_choice_stddev_multiplier)) for x in list_specialty_spots_distribution] list_specialty_spots_distribution = [np.max(x, 0) for x in list_specialty_spots_distribution] list_specialty_spots_distribution = list_specialty_spots_distribution / np.sum(list_specialty_spots_distribution) # create the applicants list_of_applicants = [] n_applicants = total_spots for i in range(0, n_applicants): list_of_applicants.append(Applicant(i, list_specialty_spots_distribution, self.n_specialties, self.n_spec_per_applicant, self.n_programs_per_specialty)) # assign the programs to which the applicants applied for i in range(0, n_applicants): applicant = list_of_applicants[i] list_of_specialties_to_which_applicant_applied = applicant._specialties_id programs_applied = [] for specialty in list_of_specialties_to_which_applicant_applied: programs_applied += find_all_programs_for_specialty(list_of_programs, specialty) applicant._programs_to_which_applied = programs_applied for program_index in programs_applied: program = list_of_programs[program_index] program._list_of_applicants.append(applicant._id) # assign the applicants who received interviews for i in range(0, self.n_programs): program = list_of_programs[i] applicants_to_program = program._list_of_applicants interview_spots = program._spots * self.n_interviews_per_spot if len(applicants_to_program) < interview_spots: interviewed_applicants = applicants_to_program else: interviewed_applicants = np.random.choice(applicants_to_program, size=(interview_spots), replace=False) program._list_of_interviewees = interviewed_applicants for applicant_index in interviewed_applicants: try: applicant = list_of_applicants[applicant_index] applicant._programs_at_which_interviewed.append(program._id) except TypeError: pdb.set_trace() # create the applicants' rank lists for applicant in list_of_applicants: rank_list = deepcopy(applicant._programs_at_which_interviewed) np.random.shuffle(rank_list) applicant._applicant_rank_list = rank_list # create the programs' rank lists for program in list_of_programs: rank_list = deepcopy(program._list_of_interviewees) np.random.shuffle(rank_list) program._rank_of_applicants_list = rank_list applicant_prefs = {applicant._id: applicant._applicant_rank_list for applicant in list_of_applicants} applicants_without_interviews = [] for key in applicant_prefs.keys(): applicant_pref = applicant_prefs[key] if len(applicant_pref) == 0: applicants_without_interviews.append(key) for applicant in applicants_without_interviews: del applicant_prefs[applicant] applicant_prefs_keys = list(applicant_prefs.keys()) for key in applicant_prefs_keys: applicant_prefs['applicant'+str(key)] = ['program'+str(x) for x in applicant_prefs[key]] del applicant_prefs[key] program_prefs = {program._id: program._rank_of_applicants_list for program in list_of_programs} program_prefs_keys = list(program_prefs.keys()) for key in program_prefs_keys: program_prefs['program'+str(key)] = ['applicant'+str(x) for x in program_prefs[key]] del program_prefs[key] capacities = {'program'+str(program._id): program._spots for program in list_of_programs} game = HospitalResident.create_from_dictionaries(applicant_prefs, program_prefs, capacities) result = game.solve() num_applicants = len(list_of_applicants) number_matched = sum_all_matched_applicants(result) number_unmatched = len(list_of_applicants) - number_matched match_rate = number_matched/len(list_of_applicants) unfilled_spots = find_all_unfilled_spots(result, list_of_programs) n_applicants_no_interviews = len(applicants_without_interviews) return {'num_applicants': num_applicants, 'fraction_applicants_no_interviews':n_applicants_no_interviews/num_applicants, 'match_rate':match_rate}
from reader import Reader operation = sys.argv[1] # insert path of doctors excel below r = Reader("Projektprioritäten für Challengezuteilung(1-60).xlsx") DOCTORS = None HOSPITAL_PREFS = None if operation == "candidates": """ reads doctors excel and writes new excel with candidates per hospital """ r.read_doctors() elif operation == "matching": DOCTORS = r.read_doctors() HOSPITAL_PREFS = r.read_hospital_prefs() capacities = r.read_hospital_capacities() game = HospitalResident.create_from_dictionaries( DOCTORS, HOSPITAL_PREFS, capacities ) result = game.solve() turned = r.turn_dict(result) df_result = pd.DataFrame(turned, index=[0]).T df_result.to_excel("matching_result.xlsx")
def games(draw, clean=booleans(), **kwargs): """ A custom strategy for making a game instance. """ residents, hospitals = draw(players(**kwargs)) return HospitalResident(residents, hospitals, clean)