diff --git a/docs/source/mods/bipartite-matching.rst b/docs/source/mods/bipartite-matching.rst index 9ea10526..60b9e162 100644 --- a/docs/source/mods/bipartite-matching.rst +++ b/docs/source/mods/bipartite-matching.rst @@ -182,10 +182,12 @@ Solution .. doctest:: bipartite_matching_sp :options: +NORMALIZE_WHITESPACE - >>> print(sp.triu(matching)) - (0, 7) 1.0 - (1, 6) 1.0 - (3, 5) 1.0 + >>> upper = sp.triu(matching) + >>> for edge, value in zip(zip(*upper.coords), upper.data): + ... print(f"{edge}: {value}") + (0, 7): 1.0 + (1, 6): 1.0 + (3, 5): 1.0 .. group-tab:: networkx diff --git a/docs/source/mods/max-flow-min-cut.rst b/docs/source/mods/max-flow-min-cut.rst index aa90e80a..b1478261 100644 --- a/docs/source/mods/max-flow-min-cut.rst +++ b/docs/source/mods/max-flow-min-cut.rst @@ -126,17 +126,15 @@ An example of these inputs with their respective requirements is shown below. >>> from gurobi_optimods import datasets >>> G, capacities, _, _ = datasets.simple_graph_scipy() >>> G.data = capacities.data # Copy capacity data - >>> G - <5x6 sparse array of type '' - with 7 stored elements in COOrdinate format> - >>> print(G) - (0, 1) 2 - (0, 2) 2 - (1, 3) 1 - (2, 3) 1 - (2, 4) 2 - (3, 5) 2 - (4, 5) 2 + >>> for edge, value in zip(zip(*G.coords), G.data): + ... print(f"{edge}: {value}") + (0, 1): 2 + (0, 2): 2 + (1, 3): 1 + (2, 3): 1 + (2, 4): 2 + (3, 5): 2 + (4, 5): 2 We only need the adjacency matrix for the graph (as a sparse array) where each each entry contains the capacity of the edge. @@ -204,16 +202,14 @@ Let us use the data to solve the maximum flow problem. >>> obj, sol = max_flow(G, 0, 5, verbose=False) >>> obj 3.0 - >>> sol - <5x6 sparse array of type '' - with 6 stored elements in COOrdinate format> - >>> print(sol) - (0, 1) 1.0 - (0, 2) 2.0 - (1, 3) 1.0 - (2, 4) 2.0 - (3, 5) 1.0 - (4, 5) 2.0 + >>> for edge, value in zip(zip(*sol.coords), sol.data): + ... print(f"{edge}: {value}") + (0, 1): 1.0 + (0, 2): 2.0 + (1, 3): 1.0 + (2, 4): 2.0 + (3, 5): 1.0 + (4, 5): 2.0 The ``max_flow`` function returns the value of the maximum flow as well a sparse array with the amount of non-zero flow in each edge in the diff --git a/docs/source/mods/min-cost-flow.rst b/docs/source/mods/min-cost-flow.rst index e7a0c639..fbecd625 100644 --- a/docs/source/mods/min-cost-flow.rst +++ b/docs/source/mods/min-cost-flow.rst @@ -88,33 +88,33 @@ An example of these inputs with their respective requirements is shown below. >>> from gurobi_optimods import datasets >>> G, capacities, cost, demands = datasets.simple_graph_scipy() - >>> G - <5x6 sparse array of type '' - with 7 stored elements in COOrdinate format> - >>> print(G) - (0, 1) 1 - (0, 2) 1 - (1, 3) 1 - (2, 3) 1 - (2, 4) 1 - (3, 5) 1 - (4, 5) 1 - >>> print(capacities) - (0, 1) 2 - (0, 2) 2 - (1, 3) 1 - (2, 3) 1 - (2, 4) 2 - (3, 5) 2 - (4, 5) 2 - >>> print(cost) - (0, 1) 9 - (0, 2) 7 - (1, 3) 1 - (2, 3) 10 - (2, 4) 6 - (3, 5) 1 - (4, 5) 1 + >>> for edge, value in zip(zip(*G.coords), G.data): + ... print(f"{edge}: {value}") + (0, 1): 1 + (0, 2): 1 + (1, 3): 1 + (2, 3): 1 + (2, 4): 1 + (3, 5): 1 + (4, 5): 1 + >>> for edge, value in zip(zip(*capacities.coords), capacities.data): + ... print(f"{edge}: {value}") + (0, 1): 2 + (0, 2): 2 + (1, 3): 1 + (2, 3): 1 + (2, 4): 2 + (3, 5): 2 + (4, 5): 2 + >>> for edge, value in zip(zip(*cost.coords), cost.data): + ... print(f"{edge}: {value}") + (0, 1): 9 + (0, 2): 7 + (1, 3): 1 + (2, 3): 10 + (2, 4): 6 + (3, 5): 1 + (4, 5): 1 >>> print(demands) [-2 0 -1 1 0 2] @@ -206,15 +206,13 @@ formats. >>> obj, sol = min_cost_flow_scipy(G, capacities, cost, demands, verbose=False) >>> obj 31.0 - >>> sol - <5x6 sparse array of type '' - with 5 stored elements in COOrdinate format> - >>> print(sol) - (0, 1) 1.0 - (0, 2) 1.0 - (1, 3) 1.0 - (2, 4) 2.0 - (4, 5) 2.0 + >>> for edge, value in zip(zip(*sol.coords), sol.data): + ... print(f"{edge}: {value}") + (0, 1): 1.0 + (0, 2): 1.0 + (1, 3): 1.0 + (2, 4): 2.0 + (4, 5): 2.0 The ``min_cost_flow_scipy`` function returns the cost of the solution as well as a ``sp.sparray`` that provides the amount of flow for each diff --git a/src/gurobi_optimods/min_cut.py b/src/gurobi_optimods/min_cut.py index 640aae4f..b1a3e7a7 100644 --- a/src/gurobi_optimods/min_cut.py +++ b/src/gurobi_optimods/min_cut.py @@ -205,10 +205,11 @@ def _min_cut_scipy(G, source, sink, create_env): return MinCutResult(0.0, (set(), set()), set()) queue = [source] + G = G.tocsr() while len(queue) > 0: node = queue.pop() p1.add(node) - row = G.getrow(node) + row = G[[node]] # Add successors of `node` that are not in the cutset queue.extend( [ diff --git a/tests/test_bipartite_matching.py b/tests/test_bipartite_matching.py index 057f7f9e..5606eca9 100644 --- a/tests/test_bipartite_matching.py +++ b/tests/test_bipartite_matching.py @@ -34,7 +34,7 @@ def assert_is_unweighted_matching(self, matching): assert_allclose(matching.data, np.ones(matching.data.shape)) adj = matching.todense() assert_allclose(adj, adj.T) - self.assertTrue(np.alltrue(adj.sum(axis=0) <= 1)) + self.assertTrue(np.all(adj.sum(axis=0) <= 1)) def test_empty(self): # Matching of an empty graph is empty