def find_matchings(graph, n=5): best_matching = nx.max_weight_matching(graph, True) matchings = [best_matching] for u, v in best_matching.items(): if v <= u: continue smaller_graph = nx.Graph(graph) smaller_graph.remove_edge(u, v) matching = nx.max_weight_matching(smaller_graph, True) if len(matching) > 0: matchings.append(matching) matching_costs = [(matching_cost(graph, matching), matching) for matching in matchings] matching_costs.sort() final_matchings = [] last_cost = None for cost, matching in matching_costs: if cost == last_cost: continue last_cost = cost final_matchings.append((cost, matching)) return final_matchings
def find_matchings(graph, n=5): """ Find the n best matchings for a graph. The best matching is guaranteed to be the best, but the others are only estimates. """ best_matching = nx.max_weight_matching(graph, True) matchings = [best_matching] for u, v in best_matching.items(): if v <= u: continue # Remove the matching smaller_graph = nx.Graph(graph) smaller_graph.remove_edge(u, v) matching = nx.max_weight_matching(smaller_graph, True) matchings.append(matching) matching_costs = [(matching_cost(graph, matching), matching) for matching in matchings] matching_costs.sort() # HACK: The above code end up giving duplicates of the same path, even though the matching is different. To prevent # this, we remove matchings with the same cost. final_matchings = [] last_cost = None for cost, matching in matching_costs: if cost == last_cost: continue last_cost = cost final_matchings.append((cost, matching)) return final_matchings
def test_s_blossom(self): """Create S-blossom and use it for augmentation:""" G = nx.Graph() G.add_weighted_edges_from([(1, 2, 8), (1, 3, 9), (2, 3, 10), (3, 4, 7)]) assert_equal(nx.max_weight_matching(G), {1: 2, 2: 1, 3: 4, 4: 3}) G.add_weighted_edges_from([(1, 6, 5), (4, 5, 6)]) assert_equal(nx.max_weight_matching(G), {1: 6, 2: 3, 3: 2, 4: 5, 5: 4, 6: 1})
def test_trivial5(self): """Path""" G = nx.Graph() G.add_edge(1, 2, weight=5) G.add_edge(2, 3, weight=11) G.add_edge(3, 4, weight=5) assert_equal(nx.max_weight_matching(G), {2: 3, 3: 2}) assert_equal(nx.max_weight_matching(G, 1), {1: 2, 2: 1, 3: 4, 4: 3})
def test_negative_weights(self): """Negative weights""" G = nx.Graph() G.add_edge(1, 2, weight=2) G.add_edge(1, 3, weight=-2) G.add_edge(2, 3, weight=1) G.add_edge(2, 4, weight=-1) G.add_edge(3, 4, weight=-6) assert_equal(nx.max_weight_matching(G), {1: 2, 2: 1}) assert_equal(nx.max_weight_matching(G, 1), {1: 3, 2: 4, 3: 1, 4: 2})
def test_s_t_blossom(self): """Create S-blossom, relabel as T-blossom, use for augmentation:""" G = nx.Graph() G.add_weighted_edges_from([(1, 2, 9), (1, 3, 8), (2, 3, 10), (1, 4, 5), (4, 5, 4), (1, 6, 3)]) assert_equal(nx.max_weight_matching(G), {1: 6, 2: 3, 3: 2, 4: 5, 5: 4, 6: 1}) G.add_edge(4, 5, weight=3) G.add_edge(1, 6, weight=4) assert_equal(nx.max_weight_matching(G), {1: 6, 2: 3, 3: 2, 4: 5, 5: 4, 6: 1}) G.remove_edge(1, 6) G.add_edge(3, 6, weight=4) assert_equal(nx.max_weight_matching(G), {1: 2, 2: 1, 3: 6, 4: 5, 5: 4, 6: 3})
def test050_linear(self): """ Multiple edges, linear. """ g = nx.Graph() g.add_edges_from([(0,1),(1,2),(2,3),(3,4),(4,5),(5,6)]) mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) self.assertEqual( len(mate1), len(mate2) )
def test_nasty_blossom_augmenting(self): """Create nested blossom, relabel as T in more than one way""" # expand outer blossom such that inner blossom ends up on an # augmenting path: G = nx.Graph() G.add_weighted_edges_from( [ (1, 2, 45), (1, 7, 45), (2, 3, 50), (3, 4, 45), (4, 5, 95), (4, 6, 94), (5, 6, 94), (6, 7, 50), (1, 8, 30), (3, 11, 35), (5, 9, 36), (7, 10, 26), (11, 12, 5), ] ) assert_equal( nx.max_weight_matching(G), {1: 8, 2: 3, 3: 2, 4: 6, 5: 9, 6: 4, 7: 10, 8: 1, 9: 5, 10: 7, 11: 12, 12: 11} )
def test030_twoedges(self): """ Two edges. """ g = nx.Graph() g.add_edges_from([(0,1),(1,2)]) mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) self.assertEqual( len(mate1), len(mate2) )
def test020_singleedge(self): """ Single edge. """ g = nx.Graph() g.add_edge(0,1) mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) self.assertEqual( len(mate1), len(mate2) )
def test200_icosahedralgraph(self): """ Icosahedral graph. """ g = nx.icosahedral_graph() mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) #td.showGraph(g, mate1, "test200_icosahedralgraph") self.assertEqual( len(mate1), len(mate2) )
def test190_octahedralgraph(self): """ Octahedral graph. """ g = nx.octahedral_graph() mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) td.showGraph(g, mate1, "test190_octahedralgraph") self.assertEqual( len(mate1), len(mate2) )
def weightedBipartite(matches, source, target): """ Weighted Bipartite Matching Filter. Adapted from @WeiFoo's HDP codebase. See https://goo.gl/3AN2Qd. :param matches: Dictionary. Key is a pair (source, target). Value is p-value. Obtained from KSAnalyzer :return: Best bipartite pair from the matches. """ # Tags for source and target metrics. s_tag = "_s" t_tag = "_t" G = nx.Graph() for key, val in matches.iteritems(): G.add_edge(key[0] + s_tag, key[1] + t_tag, weight=val) # add suffix to make it unique result = nx.max_weight_matching(G) """ We only want matched pairs with (S->T) and (T<-S). Remove singletons; i.e., only (S->T) or only (T->S) """ pairs = [] for attr_1, attr_2 in result.iteritems(): if attr_1[:-2] in source and attr_2[:-2] in target: if (attr_1[:-2], attr_2[:-2]) not in pairs: pairs.append((attr_1[:-2], attr_2[:-2])) elif attr_1[:-2] in target and attr_2[:-2] in source: if (attr_2[:-2], attr_1[:-2]) not in pairs: pairs.append((attr_2[:-2], attr_1[:-2])) return pairs
def add_edges_for_euler(in_g, out_g): # optimize_dead_ends(in_g, out_g) temp_graph = graph_of_odd_nodes(in_g, out_g) print "DEBUG: Finished calculating shortest paths, now calculating matching..." matching = networkx.max_weight_matching(temp_graph, maxcardinality=True) print "DEBUG: Finished calculating matching, now adding new edges..." short_matching = {} for k in matching: if k not in short_matching and matching[k] not in short_matching: short_matching[k] = matching[k] for source in short_matching: add_artificial_edge(in_g, out_g, source, short_matching[source]) #assert(networkx.is_connected(out_g)) nodes = odd_nodes(out_g) num_odd_nodes = len(nodes) print "DEBUG: After all that we have %s odd-degree nodes." % num_odd_nodes # reachable_nodes = set(networkx.dfs_preorder_nodes(out_g, 105437194)) # unreachable_nodes = set(out_g.nodes()) - reachable_nodes # for n in unreachable_nodes: # print "%s (%s) is unreachable." % (n, out_g.node[n]['pretty_name']) # path = networkx.dijkstra_path(in_g, 105437194, n, weight='length') # print "Here is how we would get there on the original graph: %s" % [(pn, in_g.node[pn]['pretty_name']) for pn in path] # print "Here are the nodes we have purged from that path: %s" % [(pn, in_g.node[pn]['pretty_name']) for pn in path if pn not in out_g] if not networkx.is_connected(out_g): print "The graph is still not connected. Components: %s" % [[(n, in_g.node[n]['pretty_name']) for n in comp] for comp in networkx.connected_components(out_g)] return out_g
def _pairs_from_graph(graph): mate = nx.max_weight_matching(graph, maxcardinality=True) # Extract pairs matched_players = [] pairs = [] for k, v in mate: if (k, v) not in pairs: pairs.append((k, v)) # Sort pairs by wins for i, pair in enumerate(pairs): wins_zero = match_log.times_match_win(pair[0]) wins_one = match_log.times_match_win(pair[1]) if wins_zero < wins_one: pairs[i] = (pair[1], pair[0]) # Format as matchups matchups = Matchups() for e in pairs: cost = cost_map[e[0]][e[1]] if e[0] == bye_dummy(): assert(matchups.bye_player is None) matchups.bye_player = e[1] elif e[1] == bye_dummy(): assert(matchups.bye_player is None) matchups.bye_player = e[0] else: num_0 = tournament.player_number_of_player(e[0]) num_1 = tournament.player_number_of_player(e[1]) player_a = e[0] if num_0 < num_1 else e[1] player_b = e[1] if player_a == e[0] else e[0] matchups.pairs.append(Matchup(player_a, player_b, cost)) # Set bye player return matchups
def test070_circle(self): """ Multiple edges, circle of even length. """ g = nx.Graph() g.add_edges_from([(0,1),(1,2),(2,3),(3,4),(4,5),(5,0)]) mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) self.assertEqual( len(mate1), len(mate2) )
def test025_barbell_graph(self): """ Very small barbell graph. """ g = nx.barbell_graph(9, 2) mate2 = nx.max_weight_matching( g, True ) td.showGraph(g, mate2, "test025_barbell_graph_edmonds") mate1 = mv.max_cardinality_matching( g ) self.assertEqual( len(mate1), len(mate2) )
def test180_tutte_cage_graph(self): """ Tutte 12-cage graph. """ g = nx.LCF_graph(126, [17, 27, -13, -59, -35, 35, -11, 13, -53\ , 53, -27, 21, 57, 11, -21, -57, 59, -17], 7) mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) self.assertEqual( len(mate1), len(mate2) )
def test142_utility_graph(self): """ Larger utility graph from LCF notation. """ g = nx.LCF_graph(60, [3, -3], 3) mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) td.showGraph(g, mate1, "test142_utility_graph") self.assertEqual( len(mate1), len(mate2) )
def test_nested_s_blossom_relabel(self): """Create S-blossom, relabel as S, include in nested S-blossom:""" G = nx.Graph() G.add_weighted_edges_from( [(1, 2, 10), (1, 7, 10), (2, 3, 12), (3, 4, 20), (3, 5, 20), (4, 5, 25), (5, 6, 10), (6, 7, 10), (7, 8, 8)] ) assert_equal(nx.max_weight_matching(G), {1: 2, 2: 1, 3: 4, 4: 3, 5: 6, 6: 5, 7: 8, 8: 7})
def test090_singlebloom(self): """ Single bloom, two edge extensions, case 1. """ g = nx.Graph() g.add_edges_from([(0,1),(1,2),(2,3),(3,4),(4,5),(5,1),(3,6)]) mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) self.assertEqual( len(mate1), len(mate2) )
def match_candidates_and_characters(characters, candidates): matches = dict([(character, {}) for character in characters]) # generate a graph that connects candidates and characters that match G = nx.Graph() G.add_nodes_from(characters, bipartite=0) G.add_nodes_from(candidates, bipartite=1) for character in characters: names = [] for name in [character] + characters[character]: names.append(tuple(name.replace(',', ' ').replace('\'s ', ' \'s ').replace('s\'', 's \' ').split())) for cand in candidates: score = match_to_any_names(names, cand) if score > 0: G.add_edge(character, cand, weight=score) # if don't find any match, try the other direction # sparknote character name might be contained by some candidate names if len(matches[character]) == 0 and len(candidates) > 0: scores = [strict_fuzzy_match_reference(cand, names[0]) for cand in candidates] index, score = max(enumerate(scores), key=operator.itemgetter(1)) if score > 0: G.add_edge(character, candidates[index], weight=score) max_matching = nx.max_weight_matching(G, maxcardinality=True) return (max_matching, G)
def test160_petersengraph(self): """ Petersen graph. """ g = nx.petersen_graph() mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) td.showGraph(g, mate1, "test160_petersengraph") self.assertEqual( len(mate1), len(mate2) )
def test170_bullgraph(self): """ Bull graph. """ g = nx.bull_graph() mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) #td.showGraph(g, mate1, "test170_bullgraph") self.assertEqual( len(mate1), len(mate2) )
def maximumWeighted(match, target_lst, source_lst): """ using max_weighted_bipartite to select a group of matched metrics :param match : matched metrics with p values, key is the tuple of matched metrics :type match : dict :param target_lst : matched target metrics :type target_lst: list :param source_lst : matched source metcis :type source_lst: list :return : matched metrics as well as corresponding values :rtype: class o """ value = 0 attr_source, attr_target = [], [] G = nx.Graph() for key, val in match.iteritems(): G.add_edge(key[0] + "source", key[1] + "target", weight=val) # add suffix to make it unique result = nx.max_weight_matching(G) for key, val in result.iteritems(): # in Results, (A:B) and (B:A) both exist if key[:-6] in source_lst and val[:-6] in target_lst \ and (key[:-6], val[:-6]) in match : # get rid of (A:B) exists but (B:A) not if key[:-6] in attr_source and val[:-6] in attr_target and\ attr_source.index(key[:-6]) == attr_target.index(val[:-6]): continue # this is (A:B) already in attr_source and attr_target attr_target.append(val[:-6]) attr_source.append(key[:-6]) value += match[(key[:-6], val[:-6])] # pdb.set_trace() return o(score=value, attr_source=attr_source, attr_target=attr_target)
def test040_threeedges(self): """ Three edges, linear. """ g = nx.Graph() g.add_edges_from([(0,1),(1,2),(2,3)]) mate1 = mv.max_cardinality_matching( g ) mate2 = nx.max_weight_matching( g, True ) self.assertEqual( len(mate1), len(mate2) )
def test_nested_s_blossom_relabel_expand(self): """Create nested S-blossom, relabel as T, expand:""" G = nx.Graph() G.add_weighted_edges_from( [(1, 2, 19), (1, 3, 20), (1, 8, 8), (2, 3, 25), (2, 4, 18), (3, 5, 18), (4, 5, 13), (4, 7, 7), (5, 6, 7)] ) assert_equal(nx.max_weight_matching(G), {1: 8, 2: 3, 3: 2, 4: 7, 5: 6, 6: 5, 7: 4, 8: 1})
def test_s_blossom_relabel_expand(self): """Create S-blossom, relabel as T, expand:""" G = nx.Graph() G.add_weighted_edges_from( [(1, 2, 23), (1, 5, 22), (1, 6, 15), (2, 3, 25), (3, 4, 22), (4, 5, 25), (4, 8, 14), (5, 7, 13)] ) assert_equal(nx.max_weight_matching(G), {1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4})
def test_trivial4(self): """Small graph""" G = nx.Graph() G.add_edge('one', 'two', weight=10) G.add_edge('two', 'three', weight=11) assert_equal(nx.max_weight_matching(G), {'three': 'two', 'two': 'three'})
def test_trivial6(self): """Small graph with arbitrary weight attribute""" G = nx.Graph() G.add_edge('one', 'two', weight=10, abcd=11) G.add_edge('two', 'three', weight=11, abcd=10) assert_equal(nx.max_weight_matching(G, weight='abcd'), {'one': 'two', 'two': 'one'})
def Get_Min_Weight_Matching(G): "Get_Min_Weight_Matching takes as input a complete weighted undirected networkx graph G, and returns a dictionary called matching, such that matching[v] == w if and only if the node v of G is matched with node w." nodes = G.nodes() # Get negative of distance matrix NegDistMat = -nx.to_numpy_matrix(G, weight='length') # Form new graph to obtain the matching Gnew = nx.from_numpy_matrix(NegDistMat, create_using=None) # Get min-weight matching matching = nx.max_weight_matching(Gnew, maxcardinality=True) # Return the matching matching_with_correct_nodes = { nodes[i]: nodes[matching[i]] for i in matching.keys() } return matching_with_correct_nodes
def match(self): import networkx as nx G = nx.Graph() G.add_nodes_from(self.V) for e in self.E: e.match = False [v, w] = e.end G.add_edge(v, w) M = nx.max_weight_matching(G, maxcardinality=True) print(G) print(M) for (v, w) in M: e = self.get_edge(v, w) print("\nv:", v, "\nw:", w, "\ne:", e) if e is not None: e.match = True
def assignment_random(cands, pos, fitness, G): bi_edges, edge_weights, l = UW.update_weights_simple(pos, cands, fitness) bi_G = nx.Graph() bi_edges = [(u, v, w) for (u, v, w) in bi_edges if w != 0] bi_G.add_weighted_edges_from(bi_edges) final_matched = nx.max_weight_matching(bi_G) gender = nx.get_node_attributes(G, 'att') for (u, v) in final_matched: if u in pos: gender.update({u: cands[v]}) else: gender.update({v: cands[u]}) nx.set_node_attributes(G, gender, 'att') return G, final_matched
def get_UA_pairs(UA, AC): """ find the largest list of bonds in which all atom appears at most once :param UA: :param AC: :return: """ bonds = ACParser.get_bonds(UA, AC) if len(bonds) == 0: return [()] G = nx.Graph() G.add_edges_from(bonds) UA_pairs = [list(nx.max_weight_matching(G))] return UA_pairs
def _get_ua_pairs(ua, ac): bonds = [] for k, i in enumerate(ua): for j in ua[k + 1:]: if ac[i, j] == 1: bonds.append(tuple(sorted([i, j]))) if len(bonds) == 0: return [()] G = nx.Graph() G.add_edges_from(bonds) ua_pairs = [list(nx.max_weight_matching(G))] return ua_pairs
def get_max_weight_match(sim: np.ndarray) -> np.ndarray: if nx is None: raise ValueError("networkx must be installed to use match algorithm.") def permute(edge): if edge[0] < sim.shape[0]: return edge[0], edge[1] - sim.shape[0] else: return edge[1], edge[0] - sim.shape[0] G = from_biadjacency_matrix(csr_matrix(sim)) matching = nx.max_weight_matching(G, maxcardinality=True) matching = [permute(x) for x in matching] matching = sorted(matching, key=lambda x: x[0]) res_matrix = np.zeros_like(sim) for edge in matching: res_matrix[edge[0], edge[1]] = 1 return res_matrix
def matching(self, matching_graph, syndrome_key): """Return matches of minimum weight perfect matching (MWPM) on matching_graph. Args: matching_graph (nx.Graph): Graph to run MWPM. syndrome_key (char): Which X/Z syndrome subgraph these nodes are from. Returns: [(node, node),]: List of matchings found from MWPM """ matches = nx.max_weight_matching(matching_graph, maxcardinality=True) filtered_matches = [ (source, target) for (source, target) in matches if not (len(source) > 3 and len(target) > 3) ] # remove 0 weighted matched edges between virtual syndrome nodes return filtered_matches
def test_nested_s_blossom_relabel_expand(self): """Create nested S-blossom, relabel as T, expand:""" G = nx.Graph() G.add_weighted_edges_from([(1, 2, 19), (1, 3, 20), (1, 8, 8), (2, 3, 25), (2, 4, 18), (3, 5, 18), (4, 5, 13), (4, 7, 7), (5, 6, 7)]) assert_equal(nx.max_weight_matching(G), { 1: 8, 2: 3, 3: 2, 4: 7, 5: 6, 6: 5, 7: 4, 8: 1 })
def test_nested_s_blossom_relabel(self): """Create S-blossom, relabel as S, include in nested S-blossom:""" G = nx.Graph() G.add_weighted_edges_from([(1, 2, 10), (1, 7, 10), (2, 3, 12), (3, 4, 20), (3, 5, 20), (4, 5, 25), (5, 6, 10), (6, 7, 10), (7, 8, 8)]) assert_equal(nx.max_weight_matching(G), { 1: 2, 2: 1, 3: 4, 4: 3, 5: 6, 6: 5, 7: 8, 8: 7 })
def test_trivial6(self): """Small graph with arbitrary weight attribute""" G = nx.Graph() G.add_edge("one", "two", weight=10, abcd=11) G.add_edge("two", "three", weight=11, abcd=10) assert edges_equal( nx.max_weight_matching(G, weight="abcd"), matching_dict_to_set({ "one": "two", "two": "one" }), ) assert edges_equal( nx.min_weight_matching(G, weight="abcd"), matching_dict_to_set({"three": "two"}), )
def test_s_blossom_relabel_expand(self): """Create S-blossom, relabel as T, expand:""" G = nx.Graph() G.add_weighted_edges_from([(1, 2, 23), (1, 5, 22), (1, 6, 15), (2, 3, 25), (3, 4, 22), (4, 5, 25), (4, 8, 14), (5, 7, 13)]) assert_equal(nx.max_weight_matching(G), { 1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4 })
def test_nested_s_blossom(self): """Create nested S-blossom, use for augmentation:""" G = nx.Graph() G.add_weighted_edges_from([(1, 2, 9), (1, 3, 9), (2, 3, 10), (2, 4, 8), (3, 5, 8), (4, 5, 10), (5, 6, 6)]) assert_equal( nx.max_weight_matching(G), matching_dict_to_set({ 1: 3, 2: 4, 3: 1, 4: 2, 5: 6, 6: 5 }))
def maximal_matching(assembly_points_by_sources, acyclic=True, min_cw=0.0): assembly_points_by_sources = [ ap for ap_list in assembly_points_by_sources.values() for ap in ap_list ] scaffold_edges = get_scaffold_edges( assembly_points=assembly_points_by_sources) unoriented_assembly_points = get_un_oriented_assembly_points( assembly_points=assembly_points_by_sources) assembly_edges_graph = MergedScaffoldAssemblyGraph() for ap in assembly_points_by_sources: for (u, v, weight) in ap.get_edges(sort=True, weight=True): assembly_edges_graph.add_edge(u, v, weight=weight) assembly_edges_graph.remove_edges_with_low_cw(cw_threshold=min_cw) matching = networkx.max_weight_matching(G=assembly_edges_graph.graph) cover_graph = networkx.Graph() cover_graph.add_edges_from(scaffold_edges) edges = matching for u, v in edges: cover_graph.add_edge(u, v, weight=assembly_edges_graph.graph[u][v]['weight']) # sanity check for vertex in cover_graph.nodes(): assert cover_graph.degree[vertex] <= 2 # checking for any issues with unoriented assembly points for assembly_point in unoriented_assembly_points: participating_edges = [] for (u, v) in assembly_point.get_edges(): if cover_graph.has_edge(u=u, v=v): participating_edges.append((u, v)) assert len(participating_edges) <= 2 # this is just a sanity check if len(participating_edges) == 2: cover_graph.remove_edge(participating_edges[0][0], participating_edges[0][1]) if acyclic: edges_to_delete = [] for cc in networkx.connected_component_subgraphs(G=cover_graph, copy=True): if networkx.number_of_nodes(cc) == networkx.number_of_edges(cc): assembly_edges = filter(lambda entry: "weight" in entry[2], cc.edges(data=True)) edges_to_delete.append( min(assembly_edges, key=lambda entry: entry[2]["weight"])) for u, v, data in edges_to_delete: cover_graph.remove_edge(u, v) return cover_graph
def swissPairings(tournament): """Returns a list of pairs of players for the next round of a match. Each player appears exactly once in the pairings. Each player is paired with another player with and equal or nearly-equal points record, that is, a player adjacent to him or her in the standings. For matching resuls Blossom algorithm is used and it is provided by "networkx" library (http://networkx.github.io/). Args: tournament: the id number of the tournament Returns: A list of tuples, each of which contains (id1, name1, id2, name2) id1: the first player's unique id name1: the first player's name id2: the second player's unique id name2: the second player's name """ pairs = [] players = playerTournamentStandings(tournament) players_number = countTournamentPlayers(tournament) if players_number % 2 != 0: players.append((None, None, 'Bye', 0, 0, 0, 0)) # use Blossom algorighm to generrate best matches graph = nx.complete_graph(len(players)) player_to_node = {players[key][1]: key for key, row in enumerate(players)} # exclude already played games for pair in playedMatches(tournament): for opponent in pair[1]: if graph.has_edge(player_to_node[pair[0]], player_to_node[opponent]): graph.remove_edge(player_to_node[pair[0]], player_to_node[opponent]) #add weight to each pair (edge) for n1, n2, data in graph.edges(data=True): weight = 1 + min(players[n1][6], players[n2][6]) if players[n1][6] != players[n2][6]: weight += 1 data['weight'] = weight # generate pairs for n1, n2 in nx.max_weight_matching(graph).iteritems(): if n1 < n2: continue pairs.append( (players[n1][1], players[n1][2], players[n2][1], players[n2][2])) return pairs
def matching(self,weights={}): if not weights: for pair in self.links: weights[pair] = random.random() G=nx.Graph() for pair in self.links: G.add_edge(self.links[pair][0],self.links[pair][1],weight=weights[pair]) raw_pairs = nx.max_weight_matching(G, maxcardinality=True) pairs = [] for pair in raw_pairs: pairs.append(list(pair)) return pairs
def test_gnp_random_against_networkx_with_negative_weight(self): for i in range(1024): with self.subTest(i=i): random.seed(i) rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) for edge in rx_graph.edge_list(): rx_graph.update_edge(*edge, random.randint(-5000, 5000)) nx_graph = networkx.Graph([(x[0], x[1], { "weight": x[2] }) for x in rx_graph.weighted_edge_list()]) nx_matches = networkx.max_weight_matching(nx_graph) rx_matches = retworkx.max_weight_matching( rx_graph, weight_fn=lambda x: x, verify_optimum=True) self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph)
def align_columns(A, B): k = A.shape[1] G = nx.Graph() G.add_nodes_from(range(0, k), bipartite=0) G.add_nodes_from(range(k, k * 2), bipartite=1) elist = [] for i in range(0, k): for j in range(0, k): # elist.append((i,k+j,wasserstein_distance(L2[h,:,i],L2R3[h,:,j]))) elist.append((i, k + j, np.abs(A[:, i] - B[:, j]).sum())) maximum = max(elist, key=lambda t: t[2])[2] elist = list(map(lambda x: (x[0], x[1], maximum - x[2]), elist)) G.add_weighted_edges_from(elist) matching = nx.max_weight_matching(G) sorted_matching = sorted([sorted(pair) for pair in matching]) indexes = np.array(list(map(lambda x: x[1] - k, sorted_matching))) return indexes
def get_maximum_weighted_matching(self): graph = nx.Graph() matching_graph = nx.Graph() for idx, node in enumerate(self.nodes1): graph.add_node(node.index, pos=(0, idx)) matching_graph.add_node(node.index, pos=(0, idx)) for idx, node in enumerate(self.nodes2): graph.add_node(node.index, pos=(20, idx)) matching_graph.add_node(node.index, pos=(20, idx)) for edge in self.edges: graph.add_edge(edge.node1_index, edge.node2_index, weight=edge.weight) matching_edges_set = nx.max_weight_matching(graph, maxcardinality=True) for node1, node2 in matching_edges_set: matching_graph.add_edge(node1, node2) return matching_graph
def find_matches(self): searching = self.filter(state=self.model.SEARCHING) G = nx.Graph() for search in searching: G.add_node(search) for other in searching: G.add_node(other) can_match, score = search.matching_score(other) if can_match: # 1 / score because there is only max_weight_matching and no min version G.add_edge(search, other, weight=1 / score) matches = nx.max_weight_matching(G) for search, other in matches: self.suggest_match(search, other)
def test_nested_s_blossom(self): """Create nested S-blossom, use for augmentation:""" G = nx.Graph() G.add_weighted_edges_from([ (1, 2, 9), (1, 3, 9), (2, 3, 10), (2, 4, 8), (3, 5, 8), (4, 5, 10), (5, 6, 6), ]) dict_format = {1: 3, 2: 4, 3: 1, 4: 2, 5: 6, 6: 5} expected = {frozenset(e) for e in matching_dict_to_set(dict_format)} answer = {frozenset(e) for e in nx.max_weight_matching(G)} assert answer == expected
def test_nested_s_blossom_expand(self): """Create nested S-blossom, augment, expand recursively:""" G = nx.Graph() G.add_weighted_edges_from([(1, 2, 8), (1, 3, 8), (2, 3, 10), (2, 4, 12), (3, 5, 12), (4, 5, 14), (4, 6, 12), (5, 7, 12), (6, 7, 14), (7, 8, 12)]) assert_equal(nx.max_weight_matching(G), { 1: 2, 2: 1, 3: 5, 4: 6, 5: 3, 6: 4, 7: 8, 8: 7 })
def update(self, boxes): redetected_boxes = [0] * len(boxes) redetected_objects = [0] * len(self.tracked_objects) if len(boxes) > 0 and len(self.tracked_objects) > 0: # create complete bipartite graph G of boxes to tracked objects, # where edge weight is (maxint - euclidian_distance), # such that max-matching can be performed to find closest matches G = nx.Graph() for i in range(len(boxes)): for j in range(len(self.tracked_objects)): tracked_box = self.tracked_objects[j].box euclid_dist = vector_euclidian_distance( box_centre_point(boxes[i]), box_centre_point(tracked_box)) weight = sys.maxint - euclid_dist # set weight = 0 if box is more than one box away (discard) box_dist = vector_euclidian_distance( (tracked_box[0], tracked_box[1]), (tracked_box[2], tracked_box[3])) if euclid_dist > box_dist: weight = 0 G.add_edge(('b', i), ('t', j), weight=weight) # max-match using Blossom algorithm max_match = nx.max_weight_matching(G) for match in max_match: if not G[('b', match[0][1])][('t', match[1][1])]['weight'] == 0: self.tracked_objects[match[1][1]].box = boxes[match[0][1]] redetected_boxes[match[0][1]] = 1 redetected_objects[match[1][1]] = 1 # delete dropped objects self.tracked_objects = [ self.tracked_objects[i] for i in range(len(redetected_objects)) if redetected_objects[i] ] # add new detections for i in range(len(redetected_boxes)): if redetected_boxes[i] == 0: self.tracked_objects.append( TrackedObject(self.id, boxes[i], rospy.Time.now())) self.id += 1
def experiment(length, ones_range_min, ones_range_max, reps, numStrings): strings = [] ones = [] maxmatch_avg = [] maxmatch_std_dev = [] greedymatch_avg = [] greedymatch_std_dev = [] for numOnes in range(ones_range_min, ones_range_max + 1): ones.append(numOnes) freed_pages_maxmatching = [] freed_pages_greedymatching = [] for iterations in range(reps): for i in range(numStrings): strings.append(createRandomString(length, numOnes)) graph = makeGraph(strings) frdpgs_maxmatching = len(nx.max_weight_matching(graph)) / 2 perc = (frdpgs_maxmatching / numStrings) * 100 freed_pages_maxmatching.append(perc) # graph_c = nx.complement(graph) # frdpgs_greedymatching = numStrings - color_counter(graph_c) # perc = (frdpgs_greedymatching/numStrings)*100 # freed_pages_greedymatching.append(perc) b, unmatched = greedyMesher(strings) frdpgs_greedymatching = (numStrings - len(unmatched)) / 2 perc = (frdpgs_greedymatching / numStrings) * 100 freed_pages_greedymatching.append(perc) strings = [] m = np.asarray(freed_pages_maxmatching) m_a = np.mean(m) maxmatch_avg.append(m_a) m_s = np.std(m) maxmatch_std_dev.append(m_s) c = np.asarray(freed_pages_greedymatching) c_a = np.mean(c) greedymatch_avg.append(c_a) c_s = np.std(c) greedymatch_std_dev.append(c_s) return ones, maxmatch_avg, maxmatch_std_dev, greedymatch_avg, greedymatch_std_dev
def get_benchmark_set(self): # return bm_list: List[Tuple[int, int]] list of tuples [(node1, node2)] # convert multigraph to simplified graph with weighted edges node_degree_dict = dict(nx.degree(self.graph)) tmp_graph = nx.Graph() tmp_graph.add_nodes_from(self.graph.nodes) edges_list = [] for e in self.graph.edges: edges_list.append(e[0:2]) edges_set = set(edges_list) edges_to_add = [] # calculate weight based on degree of each node (n1.degree * n2.degree) for e in edges_set: c = 1 / (node_degree_dict[e[0]] * node_degree_dict[e[1]]) t = (e[0], e[1], c) edges_to_add.append(t) tmp_graph.add_weighted_edges_from(edges_to_add) print("NODES:") print(tmp_graph.nodes) print("EDGES:") print(tmp_graph.edges) for e in tmp_graph.edges: print(tmp_graph.edges[e]) node_list = self.graph.nodes # for i in node_list: # node_list[i]['evenlevel'] = math.inf # node_list[i]['oddlevel'] = math.inf # node_list[i]['blossom'] = None # node_list[i]['predecessors'] = [] # node_list[i]['anomalies'] = [] # node_list[i]['visited'] = False # for e in self.graph.edges: # self.graph.edges[e]['visited'] = False # self.graph.edges[e]['used'] = False return nx.max_weight_matching(tmp_graph, maxcardinality=True, weight='weight')
def max_weight_matching(Mrkt, Agents, verbose=False, maxcardinality=True): """ Computes max-weight matching of graph of inputted agents based on the “blossom” method for finding augmenting paths and the “primal-dual” method for finding a matching of maximum weight, both methods invented by Jack Edmonds Implemented by NetworkX Runtime: O(n^3) for n nodes Arguments --------- Mrkt: mm.Market object The market in which the matches are made Agents: list list of agents initiating matches maxcardinality: bool if True, compute the maximum-cardinality matching with maximum weight among all maximum-cardinality matchings. verbose: bool Whether algorithm prints information on action Returns ------- dict { agent.name : agent.name } of matches Reference: “Efficient Algorithms for Finding Maximum Matching in Graphs”, Zvi Galil, ACM Computing Surveys, 1986. """ if verbose: print("\nMax Weight Match Algorithm\n") print("Agents to match ", [a.name for a in Agents], "\n") # If Agents not whole market, get subgraph if len(Mrkt.Graph.nodes()) != len(Agents): to_match = deepcopy(Mrkt.Graph.subgraph(Agents)) else: to_match = Mrkt.Graph # Workaround of assertionerror in Nx verifyOptimum() function # Breaks around integer weights for u, v, d in to_match.edges(data=True): d['weight'] = float(d['weight']) mate = nx.max_weight_matching(to_match, maxcardinality=maxcardinality) result = {a.name: mate[a].name for a in mate} return result
def test_gnp_random_against_networkx_with_weight(self): for i in range(1024): # TODO: add back subTest usage on new testtools release random.seed(i) rx_graph = retworkx.undirected_gnp_random_graph(10, .75, seed=42 + i) for edge in rx_graph.edge_list(): rx_graph.update_edge(*edge, random.randint(0, 5000)) nx_graph = networkx.Graph([(x[0], x[1], { 'weight': x[2] }) for x in rx_graph.weighted_edge_list()]) nx_matches = networkx.max_weight_matching(nx_graph) rx_matches = retworkx.max_weight_matching(rx_graph, weight_fn=lambda x: x, verify_optimum=True) self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph)
def single_chinese_postman_path(graph): """ Given a graph, return a list of node id's forming the shortest chinese postman path. If we assume V' (number of nodes with odd degree) is at least some constant fraction of V (total number of nodes), say 10%, the overall complexity is O(V^3). """ # Build a fully-connected graph containing only the odd edges. Complexity: O(V'*(E + V log(V)) ) odd = odd_graph(graph) # Find the best matching of pairs of odd nodes. Complexity: O(V'^3) matching = nx.max_weight_matching(odd, True) # Complexity of the remainder is less approximately O(E) eulerian_graph = build_eulerian_graph(graph, odd, matching) nodes = eulerian_circuit(eulerian_graph) return eulerian_graph, nodes
def getMaxWeightMatching(G): """Returns the maximum weighted matching of G as dict""" # initialize matching as dict matching = {} # iterate over each connected component C of G (for better runtime performance) for C in nx.connected_component_subgraphs(G) : # TODO get maximum cardinality!!! # compute maximum weight matching for connected component C m = nx.max_weight_matching(C, maxcardinality=True) # append it to the matching of the entire graph G matching.update(m) return matching
def _min_weight_matching(graph): """ Finds a perfect matching with minimum weight """ for v1, v2 in graph.edges_iter(): graph[v1][v2]["weight"] = -graph[v1][v2]["weight"] #want minimum weght MIN_LOG_SIZE = 20 if len(graph) > MIN_LOG_SIZE: logger.debug("Finding perfect matching for a component of " "size {0}".format(len(graph))) edges = nx.max_weight_matching(graph, maxcardinality=True) unique_edges = set() for v1, v2 in edges.items(): if not (v2, v1) in unique_edges: unique_edges.add((v1, v2)) return list(unique_edges)
def getMergedRides(self, combinedRideWithDist): mergeableTripGraph = nx.Graph() mergeableTripGraph.add_weighted_edges_from(combinedRideWithDist) matching_dictionary = nx.max_weight_matching(mergeableTripGraph, maxcardinality=True) #print(matching_dictionary) return matching_dictionary #g = GraphMatching::Graph::WeightedGraph[ # [1, 2, 10], # [1, 3, 11] #] #m = g.maximum_weighted_matching #print(m.edges) ##=> [[3, 1]] #print(m.weight(g)) ##=> 11