def yosupo_bi_match() -> None: # https://judge.yosupo.jp/problem/bipartitematching import scipy major, minor, _ = map(int, scipy.version.full_version.split('.')) if major < 1 or (major == 1 and minor < 4): raise RuntimeError L, R, M = map(int, input().split()) sink, source = L + R, L + R + 1 in_, out = [], [] edges = [] for _ in range(M): a, b = map(int, input().split()) in_.append(a) out.append(b + L) edges.append((a, b + L)) for i in range(L): in_.append(source) out.append(i) edges.append((i, source)) for i in range(R): in_.append(i + L) out.append(sink) edges.append((i + L, sink)) edges.sort() graph = csr_matrix((np.ones(L + R + M, dtype=int), (in_, out)), shape=(L + R + M, L + R + M)) flow = maximum_flow(graph, source, sink) ans = [] for (fr, to), val in zip(edges, flow.residual.data): if 0 <= fr < L and L <= to < L + R and val == 1: ans.append((fr, to - L)) print(flow.flow_value) print("\n".join(f"{v1} {v2}" for v1, v2 in ans))
def test_ford_fulkerson(): """ 最大ノード数 M, 最大重み M, 最大辺数ノード数 * 2 で重み付き逆平行有向グラフをランダム作成することを Iteration 回行う。 それぞれに対し、ソースとシンクを選んでフローを流すことをノード数だけ行い、scipy.sparse.csgraph.maximum_flow と結果を照合するストレステストを行う。 """ Iteration = 20 M = 20 for _ in range(Iteration): n = randint(2, M) # ---- ndarray, csr_matrix, エッジを張った FordFulkerson インスタンス生成 ---- mat = np.full((n, n), 0) for _ in range(2 * n): # 最大で 2 * n 個辺を張る a, b = randint(0, n - 1), randint(0, n - 1) if a == b: # 自己ループはだめ continue if mat[b, a] == 0: # 逆平行有向グラフにしたいので mat[a, b] = randint(1, M) # 上書きすることも多々あるだろう G = csr_matrix(mat) FF = FordFulkerson(n) for i in range(n): for j in range(n): if mat[i, j] != 0: assert i != j assert mat[j, i] == 0 FF.add_edge(i, j, mat[i, j]) # ---- source, sink を決定しフローを流して比較 ---- for i in range(n): while True: source, sink = randint(0, n - 1), randint(0, n - 1) if source != sink: break # ford_fulkerson をチェック if i % 2 == 0: expected_max_flow = cs.maximum_flow(G, source, sink).flow_value state = FF.reserve_state() got_max_flow = FF.ford_fulkerson(source, sink) assert got_max_flow == expected_max_flow FF.restore_state(state) # edmonds_karp をチェック else: expected_max_flow = cs.maximum_flow(G, source, sink).flow_value state = FF.reserve_state() got_max_flow = FF.edmonds_karp(source, sink) assert got_max_flow == expected_max_flow FF.restore_state(state)
def find_flow_and_split(top_level_indices, graph_rep_array, n_1, n_2, classifier_probs): sink_idx = n_1 + n_2 + 1 top_level_indices_1 = None top_level_indices_2 = None #Create subgraph from index array provided graph_rep_curr = graph_rep_array[top_level_indices] graph_rep_curr = graph_rep_curr[:, top_level_indices] graph_rep_curr, n_1_curr, n_2_curr = graph_rescale(graph_rep_curr, top_level_indices, n_1, n_2) graph_curr = csr_matrix(graph_rep_curr) flow_curr = maximum_flow(graph_curr, 0, len(top_level_indices) - 1) # Checking if full flow occurred, so no need to split if flow_curr.flow_value == n_1_curr * n_2_curr: set_classifier_prob_full_flow(top_level_indices, n_1_curr, n_2_curr, sink_idx, classifier_probs) return top_level_indices_1, top_level_indices_2, flow_curr elif flow_curr.flow_value == 0: set_classifier_prob_no_flow(top_level_indices, sink_idx, n_1, classifier_probs) return top_level_indices_1, top_level_indices_2, flow_curr # Finding remaining capacity edges remainder_array = graph_curr - flow_curr.residual rev_edge_ptr, tails = _make_edge_pointers(remainder_array) edge_ptr = remainder_array.indptr capacities = remainder_array.data heads = remainder_array.indices edge_list_curr = find_remaining_cap_edges(edge_ptr, capacities, heads, tails, 0, len(top_level_indices) - 1) # print(edge_list_curr) gz_idx = [] for item in edge_list_curr: gz_idx.append(item[0]) gz_idx.append(item[1]) if len(gz_idx) > 0: gz_idx = np.array(gz_idx) gz_idx_unique = np.unique(gz_idx) top_level_gz_idx = top_level_indices[gz_idx_unique] top_level_gz_idx = np.insert(top_level_gz_idx, len(top_level_gz_idx), sink_idx) top_level_indices_1 = top_level_gz_idx else: top_level_gz_idx = np.array([0, sink_idx]) # Indices without flow top_level_z_idx = np.setdiff1d(top_level_indices, top_level_gz_idx) if len(top_level_z_idx) > 0: # Add source and sink back to zero flow idx array top_level_z_idx = np.insert(top_level_z_idx, 0, 0) top_level_z_idx = np.insert(top_level_z_idx, len(top_level_z_idx), sink_idx) top_level_indices_2 = top_level_z_idx return top_level_indices_1, top_level_indices_2, flow_curr
def test_simple_graph(method): # This graph looks as follows: # (0) --5--> (1) graph = csr_matrix([[0, 5], [0, 0]]) res = maximum_flow(graph, 0, 1, method=method) assert res.flow_value == 5 expected_flow = np.array([[0, 5], [-5, 0]]) assert_array_equal(res.flow.toarray(), expected_flow)
def test_simple_graph(dfs): # This graph looks as follows: # (0) --5--> (1) graph = csr_matrix([[0, 5], [0, 0]]) res = maximum_flow(graph, 0, 1, dfs=dfs) assert res.flow_value == 5 expected_residual = np.array([[0, 5], [-5, 0]]) assert_array_equal(res.residual.toarray(), expected_residual)
def test_bottle_neck_graph(method): # This graph cannot use the full capacity between 0 and 1: # (0) --5--> (1) --3--> (2) graph = csr_matrix([[0, 5, 0], [0, 0, 3], [0, 0, 0]]) res = maximum_flow(graph, 0, 2, method=method) assert res.flow_value == 3 expected_flow = np.array([[0, 3, 0], [-3, 0, 3], [0, -3, 0]]) assert_array_equal(res.flow.toarray(), expected_flow)
def _part_two(data): """ Once again solve a matching problem with maxflow """ c = _parse_allergens(data) allergens = sorted(c.keys()) ingredients = set() for r in c.values(): ingredients.update(r) ingredients = list(ingredients) print(allergens) print(ingredients) assert len(ingredients) == len(allergens) N = 1 + len(ingredients) + len(allergens) + 1 def a_index(a): return 1 + a def i_index(i): return 1 + len(allergens) + i C = np.zeros([N, N], dtype=int) src = 0 snk = N - 1 for a, alg in enumerate(allergens): C[src, a_index(a)] = 1 # src to left side print(a, alg, c[alg]) for ing in c[alg]: i = ingredients.index(ing) C[a_index(a), i_index(i)] = 1 for i in range(len(ingredients)): C[i_index(i), snk] = 1 # rhs to sink print(C) result = maximum_flow(csr_matrix(C), src, snk) assert result.flow_value == len(ingredients), result print(f"flow_value: {result.flow_value}") answer = [] for a, alg in enumerate(allergens): for ing in c[alg]: i = ingredients.index(ing) if result.residual[a_index(a), i_index(i)] == 1: answer.append(ing) break return ','.join(answer)
def test_disconnected_graph(method): # This tests the following disconnected graph: # (0) --5--> (1) (2) --3--> (3) graph = csr_matrix([[0, 5, 0, 0], [0, 0, 0, 0], [0, 0, 9, 3], [0, 0, 0, 0]]) res = maximum_flow(graph, 0, 3, method=method) assert res.flow_value == 0 expected_flow = np.zeros((4, 4), dtype=np.int32) assert_array_equal(res.flow.toarray(), expected_flow)
def test_add_reverse_edges_large_graph(method): # Regression test for https://github.com/scipy/scipy/issues/14385 n = 100_000 indices = np.arange(1, n) indptr = np.array(list(range(n)) + [n - 1]) data = np.ones(n - 1, dtype=np.int32) graph = csr_matrix((data, indices, indptr), shape=(n, n)) res = maximum_flow(graph, 0, n - 1, method=method) assert res.flow_value == 1 expected_flow = graph - graph.transpose() assert_array_equal(res.flow.data, expected_flow.data) assert_array_equal(res.flow.indices, expected_flow.indices) assert_array_equal(res.flow.indptr, expected_flow.indptr)
def test_example_from_clrs_chapter_26_1(method): # See page 659 in CLRS second edition, but note that the maximum flow # we find is slightly different than the one in CLRS; we push a flow of # 12 to v_1 instead of v_2. graph = csr_matrix([[0, 16, 13, 0, 0, 0], [0, 0, 10, 12, 0, 0], [0, 4, 0, 0, 14, 0], [0, 0, 9, 0, 0, 20], [0, 0, 0, 7, 0, 4], [0, 0, 0, 0, 0, 0]]) res = maximum_flow(graph, 0, 5, method=method) assert res.flow_value == 23 expected_flow = np.array([[0, 12, 11, 0, 0, 0], [-12, 0, 0, 12, 0, 0], [-11, 0, 0, 0, 11, 0], [0, -12, 0, 0, -7, 19], [0, 0, -11, 7, 0, 4], [0, 0, 0, -19, -4, 0]]) assert_array_equal(res.flow.toarray(), expected_flow)
def solve_for_row_and_column_sums(row_sums, col_sums): """ applies the max flow algorithm for matrix rounding """ m = len(row_sums) n = len(col_sums) # produce a sparse matrix object and solve graph = csr_matrix(prod_target_matrix(row_sums, col_sums)) solution = maximum_flow(graph, 0, m+n+1).residual.toarray()[1:(m+1), (m+1):(m+n+1)] return solution
def scipy_maxflow(G: nx.DiGraph, s, t, capacity='capacity', **kwargs): cap = nx.get_edge_attributes(G, capacity) edges = G.edges cap = [cap[e] for e in edges] edges = np.array(edges) sparse_G = csr_matrix((cap, (edges[:, 0], edges[:, 1])), shape=(edges.max() + 1, ) * 2) res = csgraph.maximum_flow(sparse_G, s, t) R = nx.algorithms.flow.utils.build_residual_network(G, 'capacity') R.graph['flow_value'] = res.flow_value residual = res.residual for i, j in R.edges: R[i][j]['flow'] = residual[i, j] return R
def test_backwards_flow(method): # This example causes backwards flow between vertices 3 and 4, # and so this test ensures that we handle that accordingly. See # https://stackoverflow.com/q/38843963/5085211 # for more information. graph = csr_matrix([[0, 10, 0, 0, 10, 0, 0, 0], [0, 0, 10, 0, 0, 0, 0, 0], [0, 0, 0, 10, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 10], [0, 0, 0, 10, 0, 10, 0, 0], [0, 0, 0, 0, 0, 0, 10, 0], [0, 0, 0, 0, 0, 0, 0, 10], [0, 0, 0, 0, 0, 0, 0, 0]]) res = maximum_flow(graph, 0, 7, method=method) assert res.flow_value == 20 expected_flow = np.array([[0, 10, 0, 0, 10, 0, 0, 0], [-10, 0, 10, 0, 0, 0, 0, 0], [0, -10, 0, 10, 0, 0, 0, 0], [0, 0, -10, 0, 0, 0, 0, 10], [-10, 0, 0, 0, 0, 10, 0, 0], [0, 0, 0, 0, -10, 0, 10, 0], [0, 0, 0, 0, 0, -10, 0, 10], [0, 0, 0, -10, 0, 0, -10, 0]]) assert_array_equal(res.flow.toarray(), expected_flow)
def reduction_implication_network(self, rounding_parameter): """ Use an implication network to reduce the current problem instance. :param rounding_parameter: the projection data will be truncated to [rounding_parameter], in order to be able to use integer capacities in the implication network. """ current_N = self.A.shape[1] A_csc = self.A.tocsc() B = 10**rounding_parameter * A_csc.transpose() * A_csc int_y = (10**rounding_parameter * self.y + 0.1 * np.ones_like(self.y)).astype(int) diagonal = B.diagonal() B -= csr_matrix(np.diag(diagonal)) A_y = self.A.transpose() @ int_y outeredges = csr_matrix(2 * A_y - diagonal) Adjacency_matrix = 2 * sparse.bmat( [[None, 2 * B, None, None], [None, None, None, outeredges.transpose()], [outeredges, None, None, None], [None, None, 0, None]], format='csr') max_flow_output = csgraph.maximum_flow(Adjacency_matrix, 2 * current_N, 2 * current_N + 1) flow = max_flow_output.residual symmetric_central_flow = flow[:current_N, current_N:2 * current_N] + flow[:current_N, current_N:2 * current_N].transpose() symmetric_central_flow.data //= 2 flow[:current_N, current_N:2 * current_N] = symmetric_central_flow flow[current_N:2 * current_N, :current_N] = -symmetric_central_flow symmetric_outer_flow = \ flow[2*current_N, :current_N] + flow[current_N: 2 * current_N, 2*current_N + 1].transpose() symmetric_outer_flow.data //= 2 flow[2 * current_N, :current_N] = symmetric_outer_flow flow[current_N:2 * current_N, 2 * current_N + 1] = symmetric_outer_flow.transpose() residual = Adjacency_matrix - flow residual.eliminate_zeros() n_components, labels = csgraph.connected_components( residual, connection='strong') component_type = np.zeros(n_components, dtype=int) # Type 14: u and 1 - u are both contained in the component # Type 15: u is contained in the component, 1 - u is not, no path from u to u - 1 # Type 16: u is contained in the component, 1 - u is not, there exists a path from u to u - 1 indices = [] vals = [] for i in range(current_N): component = labels[i] if component_type[component] == 0: if component == labels[i + current_N]: component_type[component] = 14 else: reachable = csgraph.breadth_first_order( residual, i, return_predecessors=False) if i + current_N in reachable: component_type[component] = 16 else: component_type[component] = 15 if component_type[component] == 15: indices.append(i) vals.append(1) elif component_type[component] == 16: indices.append(i) vals.append(0) no_reductions = len(indices) order = np.array(indices).argsort() for j in range(no_reductions): i = order[no_reductions - j - 1] self.problem_reduction_single(indices[i], vals[i]) return 0
def test_raises_when_sink_is_out_of_bounds(sink, method): with pytest.raises(ValueError): graph = csr_matrix([[0, 1], [0, 0]]) maximum_flow(graph, 0, sink, method=method)
def test_raises_when_source_is_sink(): with pytest.raises(ValueError): graph = csr_matrix([[0, 1], [0, 0]]) maximum_flow(graph, 0, 0) maximum_flow(graph, 0, 0, method='edmonds_karp')
def test_raises_on_non_square_input(): with pytest.raises(ValueError): graph = csr_matrix([[0, 1, 2], [2, 1, 0]]) maximum_flow(graph, 0, 1)
def test_raises_on_floating_point_input(): with pytest.raises(ValueError): graph = csr_matrix([[0, 1.5], [0, 0]], dtype=np.float64) maximum_flow(graph, 0, 1) maximum_flow(graph, 0, 1, method='edmonds_karp')
def test_raises_on_csc_input(): with pytest.raises(TypeError): graph = csc_matrix([[0, 1], [0, 0]]) maximum_flow(graph, 0, 1) maximum_flow(graph, 0, 1, method='edmonds_karp')
def test_residual_raises_deprecation_warning(): graph = csr_matrix([[0, 5, 0], [0, 0, 3], [0, 0, 0]]) res = maximum_flow(graph, 0, 2) with pytest.deprecated_call(): res.residual
from scipy.sparse import csr_matrix from scipy.sparse.csgraph import maximum_flow import numpy as np inf = 100000000 n = int(input()) l = list(map(int , input().split())) # plus one is the index e = int(input()) m = [[0 for i in range(n+1)] for i in range(n+1)] for i in range(e): q1 , q2 , c = tuple(map(int ,input().split())) m[q1][q2] = c for i in range(n): if l[i]==1: m[0][i+1]=inf graph = csr_matrix(m) print(maximum_flow(graph, 0, l.index(2)+1).flow_value) ##connect all source with one source before them with edge capacity of infinte #index zero is the base source #source : 1 , node : 0 , sink : 2
def _get_valid_rules(rules, tickets) -> Dict[str, int]: # Let's try this using maxflow R = len(rules) T = len(tickets) # F is just number of rules F = R N = 1 + R + F + 1 C = np.zeros((N, N), dtype=int) # Initialize arcs from source to tickets src = 0 snk = N - 1 def rule_index(r): return 1 + r def field_index(f): return 1 + R + f # source to rule for r in range(R): C[src, rule_index(r)] = 1 # fields to snk for f in range(F): C[field_index(f), snk] = 1 # rules for r in range(R): for f in range(F): valid = all(rules[r].is_valid(t[f]) for t in tickets) if not valid: continue C[rule_index(r), field_index(f)] = 1 print(f"dims: T: {T}, F: {F}, R: {R}, N: {N}") print(C) print("Converting to CSR...") C = csr_matrix(C) print(f"Solving max flow for matrix shape {C.shape}...") result = maximum_flow(C, src, snk) print(f"result: {result.flow_value}") if (result.flow_value != R): print(f"Uh oh, not enough flow!") residual = result.residual matches = dict() for r in range(R): for f in range(F): try: if residual[rule_index(r), field_index(f)] == 1: rule = rules[r] if rule.name in matches: raise ValueError() matches[rule.name] = f except KeyError: continue if not set(range(F)) == set(matches.values()): print("Error: Invalid matching!") return matches
def test_raises_when_source_is_out_of_bounds(source): with pytest.raises(ValueError): graph = csr_matrix([[0, 1], [0, 0]]) maximum_flow(graph, source, 1)
def time_maximum_flow(self, n, density): maximum_flow(self.data, 0, n - 1)
def test_raises_on_dense_input(): with pytest.raises(TypeError): graph = np.array([[0, 1], [0, 0]]) maximum_flow(graph, 0, 1) maximum_flow(graph, 0, 1, method='edmonds_karp')
def min_cut(self): self.graph = csr_matrix((self.weight, (self.from_node, self.to_node)), shape=(self.N+2, self.N+2)) max_flow = maximum_flow(self.graph, self.bgd_src, self.fgd_sink) return max_flow
from scipy.sparse import csr_matrix from scipy.sparse.csgraph import shortest_path, floyd_warshall, dijkstra, bellman_ford, johnson, NegativeCycleError, maximum_bipartite_matching, maximum_flow, minimum_spanning_tree import numpy as np n, m = map(int, input().split()) edges = [list(map(int, input().split())) for i in range(m)] def graph_csr(edges, n, directed=True, indexed_1=True): # 隣接リストから粗行列を作成 arr = np.array(edges, dtype=np.int64).T arr = arr.astype(np.int64) index = int(indexed_1) if not directed: return csr_matrix((np.concatenate([arr[2], arr[2]]), (np.concatenate([arr[0]-index, arr[1]-index]), np.concatenate([arr[1]-index, arr[0]-index]))), shape=(n, n)) else: return csr_matrix((arr[2], (arr[0]-index, arr[1]-index)), shape=(n, n)) csr = graph_csr(edges, n) try: print(floyd_warshall(csr)) except NegativeCycleError: print('-1') dijkstra(csr, indices=0) bellman_ford(csr, indices=0) maximum_bipartite_matching(csr, perm_type='column') maximum_flow(csr, source=0, sink=1).flow_value maximum_flow(csr, source=0, sink=1).residual int(sum(minimum_spanning_tree(csr).data))