def test_check_stability(): """ Test that StableMarriage can recognise whether a matching is stable. """ from matching import Player suitors = [Player("A"), Player("B")] reviewers = [Player("X"), Player("Y")] (a, b), (x, y) = suitors, reviewers a.set_prefs(reviewers) b.set_prefs(reviewers[::-1]) x.set_prefs(suitors) y.set_prefs(suitors[::-1]) game = StableMarriage(suitors, reviewers) matching = game.solve() assert game.check_stability() (a, b), (x, y) = game.suitors, game.reviewers matching[a] = y matching[b] = x assert not game.check_stability()
def test_check_validity(player_names, seed): """ Test that StableMarriage finds no errors when the game is solved. """ suitors, reviewers = make_players(player_names, seed) game = StableMarriage(suitors, reviewers) game.solve() assert game.check_validity()
def test_solve(player_names, seed): """ Test that StableMarriage can solve games correctly when passed players. """ for optimal in ["suitor", "reviewer"]: suitors, reviewers = make_players(player_names, seed) game = StableMarriage(suitors, reviewers) matching = game.solve(optimal) assert isinstance(matching, Matching) assert set(matching.keys()) == set(suitors) assert set(matching.values()) == set(reviewers)
def test_all_matched(player_names, seed): """ Test that StableMarriage recognises a valid matching requires all players to be matched as players and as part of the game. """ suitors, reviewers = make_players(player_names, seed) game = StableMarriage(suitors, reviewers) matching = game.solve() matching[game.suitors[0]].matching = None game.matching[game.suitors[0]] = None with pytest.raises(Exception): game._check_all_matched()
def test_inputs_num_players(player_names, seed): """ Test StableMarriage raises a ValueError when a different number of suitors and reviewers are passed. """ suitors, reviewers = make_players(player_names, seed) game = StableMarriage(suitors, reviewers) assert game._check_num_players() suitors = suitors[:-1] with pytest.raises(ValueError): StableMarriage(suitors, reviewers)
def test_inputs_player_ranks(player_names, seed): """ Test StableMarriage raises a ValueError when a player has not ranked all members of the opposing party. """ suitors, reviewers = make_players(player_names, seed) game = StableMarriage(suitors, reviewers) for player in game.suitors + game.reviewers: assert game._check_player_ranks(player) suitors[0].prefs = suitors[0].prefs[:-1] with pytest.raises(ValueError): StableMarriage(suitors, reviewers)
def test_check_for_players_not_in_matching(player_names, seed): """Test that StableMarriage recognises a valid matching requires all players to be matched in the matching.""" suitors, reviewers = make_players(player_names, seed) game = StableMarriage(suitors, reviewers) matching = game.solve() player = game.suitors[0] matching[player] = None with pytest.raises(MatchingError) as e: game.check_validity() error = e.players[0] assert error.startswith(player.name)
def solve(inputs): cur = 0 (N, index) = parse.parse("{:d} {:d}", inputs[cur]) cur += 1 college_preferences = {} student_preferences = {} names = [] for i in range(N): xs = list(map(int, inputs[cur].split(" "))) cur += 1 college_preferences[i] = xs for i in range(N): xs = list(map(int, inputs[cur].split(" "))) cur += 1 student_preferences[i] = xs for i in range(N): names.append(inputs[cur]) cur += 1 game = StableMarriage.create_from_dictionaries( student_preferences, college_preferences ) t = game.solve() ks = list(t.keys()) vs = list(t.values()) pairs = {} for i in range(N): pairs[vs[i].name] = ks[i].name return names[pairs[index]]
def test_init(player_names, seed): """ Test that the StableMarriage solver takes two sets of preformed players correctly. """ suitors, reviewers = make_players(player_names, seed) game = StableMarriage(suitors, reviewers) assert game.suitors == suitors assert game.reviewers == reviewers assert all( [player.matching is None for player in game.suitors + game.reviewers]) assert game.matching is None
def test_solve(player_names, seed): """Test that StableMarriage can solve games correctly when passed players.""" for optimal in ["suitor", "reviewer"]: suitors, reviewers = make_players(player_names, seed) game = StableMarriage(suitors, reviewers) matching = game.solve(optimal) assert isinstance(matching, Matching) suitors = sorted(suitors, key=lambda s: s.name) reviewers = sorted(reviewers, key=lambda r: r.name) matching_keys = sorted(matching.keys(), key=lambda k: k.name) matching_values = sorted(matching.values(), key=lambda v: v.name) for game_suitor, suitor in zip(matching_keys, suitors): assert game_suitor.name == suitor.name assert game_suitor.pref_names == suitor.pref_names for game_reviewer, reviewer in zip(matching_values, reviewers): assert game_reviewer.name == reviewer.name assert game_reviewer.pref_names == reviewer.pref_names
def test_check_stability(): """ Test that StableMarriage can recognise whether a matching is stable. """ from matching import Player suitors = [Player("A"), Player("B")] reviewers = [Player(1), Player(2)] suitors[0].set_prefs(reviewers) suitors[1].set_prefs(reviewers[::-1]) reviewers[0].set_prefs(suitors) reviewers[1].set_prefs(suitors[::-1]) game = StableMarriage(suitors, reviewers) matching = game.solve() assert game.check_stability() (s_a, s_b), (r_1, r_2) = game.suitors, game.reviewers matching[s_a] = r_2 matching[s_b] = r_1 assert not game.check_stability()
def test_create_from_dictionaries(player_names, seed): """Test that the StableMarriage solver can take two preference dictionaries correctly.""" suitor_prefs, reviewer_prefs = make_prefs(player_names, seed) game = StableMarriage.create_from_dictionaries(suitor_prefs, reviewer_prefs) for suitor in game.suitors: assert suitor_prefs[suitor.name] == suitor.pref_names assert suitor.matching is None for reviewer in game.reviewers: assert reviewer_prefs[reviewer.name] == reviewer.pref_names assert reviewer.matching is None assert game.matching is None
def test_matching_consistent(player_names, seed): """ Test that StableMarriage recognises a valid matching requires there to be consistency between the game's matching and its players'. """ suitors, reviewers = make_players(player_names, seed) game = StableMarriage(suitors, reviewers) game.solve() game.suitors[0].matching = None game.reviewers[0].matching = None with pytest.raises(Exception): game._check_matching_consistent()
def solveProblem(member_list1, member_list2, coeff_list): """Solve the matching problem""" # randomize lists in order to avoid unwanted effects print('Randomize lists...') random.shuffle(member_list1) random.shuffle(member_list2) # creating the dicts print('Creating the dicts for solving...') N = len(member_list1) firstYear_prefs = {} secondYear_prefs = {} for i in range(N): firstYear_prefs[i] = sorted( range(N), key=lambda n: loveScore(member_list2[n]['answers'], member_list1[i] ['answers'], coeff_list)) secondYear_prefs[i] = sorted( range(N), key=lambda n: loveScore(member_list2[i]['answers'], member_list1[n] ['answers'], coeff_list)) # make the marriage and solve the problem! Les 1A sont privilégiés dans leurs préférences print('Solving...') game = StableMarriage.create_from_dictionaries(firstYear_prefs, secondYear_prefs) dict_solved = game.solve() # get the family for each 1A print('Add families to 1A members') for player_1A, player_2A in dict_solved.items(): id_1A = player_1A.name id_2A = player_2A.name member_list1[id_1A]['family'] = member_list2[id_2A]['family'] return member_list1
firstYear_prefs[i] = sorted( range(N), key=lambda n: loveScore(students_secondYear[n].answers, students_firstYear[i].answers)) secondYear_prefs[i] = sorted( range(N), key=lambda n: loveScore(students_secondYear[i].answers, students_firstYear[n].answers)) # -- -- # -- Solve the problem -- from matching.games import StableMarriage game = StableMarriage.create_from_dictionaries(firstYear_prefs, secondYear_prefs) dict_solved = game.solve() # -- -- families_solved = {} orphans = {} f = open('out.log', 'w') for fillot_id, parrain_id in dict_solved.items(): fillot = students_firstYear[fillot_id.name] parrain = students_secondYear[parrain_id.name] fillot.parrain = parrain parrain.fillot = fillot
def Match(atom_ID,ss_freqs,RefFile,ShiftFile): warnings.filterwarnings("ignore") #All Atom Info natoms = sum(atom_ID) dim = natoms * 3 ss_freqs = np.reshape(ss_freqs,(-1,dim)) Ref_UCParams = data.ReadYaml(RefFile) [ref_freqs, ref_vecs] = Ref_UCParams.get_UC() ref_vecs = np.reshape(ref_vecs,(-1,dim)) ref_freqs[0] = 0 ref_freqs[1] = 0 ref_freqs[2] = 0 Shift_UCParams = data.ReadYaml(ShiftFile) [shift_freqs, shift_vecs] = Shift_UCParams.get_UC() shift_vecs = np.reshape(shift_vecs,(-1,dim)) #Get initial dotprod matrix dots = get_dots(dim,shift_vecs,ref_vecs) dft_ranks = [] #Ranking DFT matches with FIXED DFTB modes for i in range(dim): sort_dots = np.sort(dots[i,:])[::-1] seen = set() available_matches = list(range(0,dim)) for j in range(dim): val = sort_dots[j] arr = dots[i,:] tmp = (np.where(arr == val)[0][0]) if tmp not in seen: available_matches.remove(tmp) seen.add(tmp) else: availdots = [] for k in available_matches: availdots.append(dots[i,k]) tmp = available_matches[availdots.index(max(availdots))] available_matches.remove(tmp) dft_ranks = np.append(dft_ranks,tmp) dftb_ranks = [] #Ranking DFTB matches with FIXED DFT modes for i in range(dim): sort_dots = np.sort(dots[:,i])[::-1] seen = set() available_matches = list(range(0,dim)) for j in range(dim): val = sort_dots[j] arr = dots[:,i] tmp = (np.where(arr == val)[0][0]) if tmp not in seen: available_matches.remove(tmp) seen.add(tmp) else: availdots = [] for k in available_matches: availdots.append(dots[k,i]) tmp = available_matches[availdots.index(max(availdots))] available_matches.remove(tmp) dftb_ranks = np.append(dftb_ranks,tmp) dft_ranks = dft_ranks.reshape([-1,dim]) dftb_ranks = dftb_ranks.reshape([-1,dim]) dftRankDict = dict(((i), dft_ranks[i][:]) for i in range(dim)) #Favored DFT pairing to a DFTB mode -- "Suitor" dftbRankDict = dict(((i), dftb_ranks[i][:]) for i in range(dim)) #Favored DFTB pairing to a DFT mode -- "Reviewer" matching = StableMarriage.create_from_dictionaries(dftRankDict, dftbRankDict) AllMatches = matching.solve() AllMatches = list(str(AllMatches).replace('{','').replace('}','').split(',')) matches = [] for i in AllMatches: line = (i.split(':')) DFTmode = int(line[0]) DFTBmode = int(line[1]) matches.append(DFTmode) matches.append(DFTBmode) matches = np.array(matches).reshape([dim,2]) ##In matches array, the first column is the DFT modes, and the second is DFTB. Need to re-sort in order to get the ##DFTB modes in ascending order for the shift match_array = matches[np.argsort(matches[:,1])] match_array = match_array[:,0] #Set new order according to match shift_freqs = shift_freqs[match_array] #Apply shifts to dftb freqs shifts = [ref_freqs - shift_freqs] shifts = np.array(shifts).reshape(dim,-1) ss_freqs = ss_freqs.transpose() shifted_freqs = ss_freqs[match_array] + shifts shifted_freqs = shifted_freqs.flatten() return shifted_freqs
#except KeyError: # row_str = row_str + ", " + str(0) print(row_str) # future strategy # GS algo fine for small enough dataset & guarantees stable solution that optimizes max allocations # but since it's iterative & evaluates entire solution space, grows exponential # so use these pairings & scores & feedback to develop an ML soluted # also use ML to develop more sophisticated ranking & explore different scoring (objective) functions # pseudo-global matching based on ranked preferences suitors = [Player(name="A"), Player(name="B"), Player(name="C")] reviewers = [Player(name="D"), Player(name="E"), Player(name="F")] (A, B, C), (D, E, F) = suitors, reviewers #print(type(suitors)) A.set_prefs([D, E, F]) B.set_prefs([D, F, E]) C.set_prefs([F, D, E]) D.set_prefs([B, C, A]) E.set_prefs([A, C, B]) F.set_prefs([C, B, A]) from matching.games import StableMarriage game = StableMarriage(suitors, reviewers) print(game.solve()) # {A: E, B: D, C: F}
from matching.games import StableMarriage malePreferences = {1: [2, 3, 1], 2: [2, 3, 1], 3: [1, 3, 2]} femalePreferences = {1: [2, 3, 1], 2: [3, 2, 1], 3: [1, 3, 2]} # females review males preferences game = StableMarriage.create_from_dictionaries(malePreferences, femalePreferences) print("{Male: Female} pairs\n", game.solve())
def makeQuintuplets(quads: list, aloneStudents: dict, singles: dict, matchBefore: dict): #Each quad needs to match with one alone Student #make an empty list to avoid changing quads and aloneStudents extraStudentsQuads = [] extraStudentsAlone = [] for quad in quads: extraStudentsQuads.append(quad) for key in aloneStudents: extraStudentsAlone.append(aloneStudents[key]) quintuplets = [] finished = False if len(extraStudentsAlone) != len(extraStudentsQuads): print("Error: size mismatch in makeQuintuplets") if len(extraStudentsAlone) == 0: finished = True i = 0 while (not finished) and i < 5: preferenceListOnes = preferenceAsymmetricalSort(extraStudentsAlone, extraStudentsQuads, "GroupByOne", matchBefore) preferenceListQuads = preferenceAsymmetricalSort(extraStudentsQuads, extraStudentsAlone, "OneByGroup", matchBefore) game = StableMarriage.create_from_dictionaries(preferenceListOnes, preferenceListQuads) ans = game.solve() removeImpossibleQuin(ans, matchBefore, singles, aloneStudents, extraStudentsAlone, extraStudentsQuads) moveStudentsGroups(quintuplets, ans, singles, aloneStudents, quads) if len(extraStudentsAlone) == 0: finished = True i = i+ 1 if len(extraStudentsAlone) != len(extraStudentsQuads): print("Errror: size mismatch in makeQuintuplets") listUsedIndexesAlone = list() listUsedIndexesQuads = list() groupsToMake = list() for index1 in range(len(extraStudentsAlone)): for index2 in range(len(extraStudentsQuads)): if index1 not in listUsedIndexesAlone and index2 not in listUsedIndexesQuads: tempList = [(extraStudentsAlone[index1])] tempList.extend(extraStudentsQuads[index2]) if isValidGroup(matchBefore, tempList) == 0: listUsedIndexesAlone.append(index1) listUsedIndexesQuads.append(index2) groupsToMake.append([index1, index2]) usedAlone = list() usedQuads = list() for groupToMake in groupsToMake: tempList = [extraStudentsAlone[groupToMake[0]]] tempList.extend(extraStudentsQuads[groupToMake[1]]) quintuplets.append(tempList) usedAlone.append(extraStudentsAlone[groupToMake[0]]) usedQuads.append(extraStudentsQuads[groupToMake[1]]) for student in usedAlone: extraStudentsAlone.remove(student) for student in usedQuads: extraStudentsQuads.remove(student) for index in range(0, len(extraStudentsAlone)): tempList = extraStudentsQuads[index] tempList.append(extraStudentsAlone[index]) quintuplets.append(tempList) extraStudentsAlone.clear() extraStudentsQuads.clear() return quintuplets