From b3991452489888c73e68167c6ffcc962da238b4f Mon Sep 17 00:00:00 2001 From: torressa <23246013+torressa@users.noreply.github.com> Date: Thu, 28 Sep 2023 14:19:09 +0100 Subject: [PATCH 1/4] Change csc/csc_matrix to array --- src/gurobi_optimods/bipartite_matching.py | 2 +- src/gurobi_optimods/min_cost_flow.py | 2 +- tests/test_bipartite_matching.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gurobi_optimods/bipartite_matching.py b/src/gurobi_optimods/bipartite_matching.py index 07c0c56d6..c0e77a9be 100644 --- a/src/gurobi_optimods/bipartite_matching.py +++ b/src/gurobi_optimods/bipartite_matching.py @@ -194,7 +194,7 @@ def _maximum_bipartite_matching_scipy(adjacency, nodes1, nodes2, create_env): indptr = np.arange(0, 2 * from_arc.shape[0] + 2, 2) ones = np.ones(from_arc.shape) data = np.column_stack((ones * -1.0, ones)).reshape(-1, order="C") - A = sp.csc_matrix((data, indices, indptr)) + A = sp.csc_array((data, indices, indptr)) # Solve model with gurobi, return cost and flows x = model.addMVar(A.shape[1], lb=0, ub=capacity) diff --git a/src/gurobi_optimods/min_cost_flow.py b/src/gurobi_optimods/min_cost_flow.py index 5520f0cba..4e83437ed 100644 --- a/src/gurobi_optimods/min_cost_flow.py +++ b/src/gurobi_optimods/min_cost_flow.py @@ -132,7 +132,7 @@ def min_cost_flow_scipy( ones = np.ones(edge_source.shape) data = np.column_stack((ones * -1.0, ones)).reshape(-1, order="C") - A = sp.csc_matrix((data, indices, indptr)) + A = sp.csc_array((data, indices, indptr)) logger.info("Solving min-cost flow with {0} nodes and {1} edges".format(*A.shape)) diff --git a/tests/test_bipartite_matching.py b/tests/test_bipartite_matching.py index 6492b9f51..9d0491c38 100644 --- a/tests/test_bipartite_matching.py +++ b/tests/test_bipartite_matching.py @@ -126,11 +126,11 @@ def test_random(self): self.assertEqual(matching.shape, adjacency.shape) self.assert_is_unweighted_matching(matching) - def test_random_csr_matrix(self): + def test_random_csr_array(self): # Property test for matchings on random graphs adjacency, nodes1, nodes2 = random_bipartite(n1=8, n2=7, p=0.5, seed=98634) - matching = maximum_bipartite_matching(sp.csr_matrix(adjacency), nodes1, nodes2) + matching = maximum_bipartite_matching(sp.csr_array(adjacency), nodes1, nodes2) self.assertIsInstance(matching, sp.spmatrix) self.assertIsNot(matching, adjacency) From ece87f7cf70c511ef6fce495a06c4f730d5c2a8f Mon Sep 17 00:00:00 2001 From: torressa <23246013+torressa@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:57:58 +0100 Subject: [PATCH 2/4] Bump gurobipy version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a2ce77b82..bbcda5d39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ classifiers = [ "Operating System :: OS Independent", ] dependencies = [ - "gurobipy>=10.0.1", + "gurobipy>=10.0.3", "gurobipy-pandas>=1.0.0", "numpy", "pandas", From 9ed1faa607b866131869f0e77610e030a4c94df2 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Thu, 19 Oct 2023 08:38:48 +1100 Subject: [PATCH 3/4] Update more sparse arrays --- docs/source/mods/min-cost-flow.rst | 4 ++-- docs/source/mods/qubo.rst | 2 +- src/gurobi_optimods/bipartite_matching.py | 2 +- src/gurobi_optimods/datasets.py | 8 ++++---- src/gurobi_optimods/min_cost_flow.py | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/mods/min-cost-flow.rst b/docs/source/mods/min-cost-flow.rst index 1775fc4d5..e7a0c639e 100644 --- a/docs/source/mods/min-cost-flow.rst +++ b/docs/source/mods/min-cost-flow.rst @@ -89,7 +89,7 @@ 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 matrix of type '' + <5x6 sparse array of type '' with 7 stored elements in COOrdinate format> >>> print(G) (0, 1) 1 @@ -207,7 +207,7 @@ formats. >>> obj 31.0 >>> sol - <5x6 sparse matrix of type '' + <5x6 sparse array of type '' with 5 stored elements in COOrdinate format> >>> print(sol) (0, 1) 1.0 diff --git a/docs/source/mods/qubo.rst b/docs/source/mods/qubo.rst index 1052cbbc4..8d278c32f 100644 --- a/docs/source/mods/qubo.rst +++ b/docs/source/mods/qubo.rst @@ -109,7 +109,7 @@ definition as a SciPy sparse matrix in a comment). # weights = [-3, 2, -1, -2, 3] # row = [1, 2, 0, 0, 1] # col = [1, 2, 1, 2, 2] - # Q = sp.coo_matrix((weights, (row, col)), shape=(3, 3)) + # Q = sp.coo_array((weights, (row, col)), shape=(3, 3)) result = solve_qubo(Q) diff --git a/src/gurobi_optimods/bipartite_matching.py b/src/gurobi_optimods/bipartite_matching.py index c0e77a9be..9c3c9afdc 100644 --- a/src/gurobi_optimods/bipartite_matching.py +++ b/src/gurobi_optimods/bipartite_matching.py @@ -215,5 +215,5 @@ def _maximum_bipartite_matching_scipy(adjacency, nodes1, nodes2, create_env): # Return undirected, unweighted adjacency matrix arg = (np.ones(from_arc_result.shape), (from_arc_result, to_arc_result)) - matching = sp.coo_matrix(arg, dtype=float, shape=G.shape) + matching = sp.coo_array(arg, dtype=float, shape=G.shape) return matching + matching.T diff --git a/src/gurobi_optimods/datasets.py b/src/gurobi_optimods/datasets.py index cc19f2eea..8e3a01f72 100644 --- a/src/gurobi_optimods/datasets.py +++ b/src/gurobi_optimods/datasets.py @@ -106,7 +106,7 @@ def _convert_pandas_to_scipy( edge_data, node_data, capacity=True, cost=True, demand=True ): """ - Convert from a pandas DataFrame to several scipy.sparse.coo_matrix contain + Convert from a pandas DataFrame to several scipy.sparse.coo_array contain the graph structure, the capacity and cost values per edge, and the demand values per node. """ @@ -116,17 +116,17 @@ def _convert_pandas_to_scipy( a1 = np.array([c[1] for c in coords]) data = np.ones(len(coords), dtype=np.int64) - G = sp.coo_matrix((data, (a0, a1))) + G = sp.coo_array((data, (a0, a1))) costs = None if cost: data = edge_data["cost"].values - costs = sp.coo_matrix((data, (a0, a1))) + costs = sp.coo_array((data, (a0, a1))) cap = None if capacity: data = edge_data["capacity"].values - cap = sp.coo_matrix((data, (a0, a1))) + cap = sp.coo_array((data, (a0, a1))) dem = None if demand: diff --git a/src/gurobi_optimods/min_cost_flow.py b/src/gurobi_optimods/min_cost_flow.py index 4e83437ed..d8efe4c9d 100644 --- a/src/gurobi_optimods/min_cost_flow.py +++ b/src/gurobi_optimods/min_cost_flow.py @@ -149,7 +149,7 @@ def min_cost_flow_scipy( edge_source_result = edge_source[select] edge_target_result = edge_target[select] arg = (x.X[select], (edge_source_result, edge_target_result)) - return model.ObjVal, sp.coo_matrix(arg, dtype=float, shape=G.shape) + return model.ObjVal, sp.coo_array(arg, dtype=float, shape=G.shape) @optimod() From f8bf2588d4d7d2df67062e38ade73feccabbf77c Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Thu, 19 Oct 2023 08:43:30 +1100 Subject: [PATCH 4/4] Add test --- tests/test_bipartite_matching.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_bipartite_matching.py b/tests/test_bipartite_matching.py index 9d0491c38..e4b25d51f 100644 --- a/tests/test_bipartite_matching.py +++ b/tests/test_bipartite_matching.py @@ -126,6 +126,17 @@ def test_random(self): self.assertEqual(matching.shape, adjacency.shape) self.assert_is_unweighted_matching(matching) + def test_random_csr_matrix(self): + # Property test for matchings on random graphs + adjacency, nodes1, nodes2 = random_bipartite(n1=8, n2=7, p=0.5, seed=98634) + + matching = maximum_bipartite_matching(sp.csr_matrix(adjacency), nodes1, nodes2) + + self.assertIsInstance(matching, sp.spmatrix) + self.assertIsNot(matching, adjacency) + self.assertEqual(matching.shape, adjacency.shape) + self.assert_is_unweighted_matching(matching) + def test_random_csr_array(self): # Property test for matchings on random graphs adjacency, nodes1, nodes2 = random_bipartite(n1=8, n2=7, p=0.5, seed=98634)