Repository: CharJon/GeCO

Issue:
mips.max_cut: Add tests if seeding works as intended.
There should be some testcases that ensure different seeds are creating different instances.

Discussion:

Patch:
diff --git a/geco/mips/facility_location.py b/geco/mips/facility_location.py
index 8675a33..f11fb20 100644
--- a/geco/mips/facility_location.py
+++ b/geco/mips/facility_location.py
@@ -93,7 +93,7 @@ def capacitated_facility_location(
     return model
 
 
-@py_random_state(3)
+@py_random_state(-1)
 def cornuejols_instance_params(n_customers, n_facilities, ratio, seed):
     # locations for customers
     c_x = np.array([seed.random() for _ in range(n_customers)])
@@ -103,11 +103,13 @@ def cornuejols_instance_params(n_customers, n_facilities, ratio, seed):
     f_x = np.array([seed.random() for _ in range(n_facilities)])
     f_y = np.array([seed.random() for _ in range(n_facilities)])
 
-    demands = np.array(seed.sample(range(5, 35 + 1), k=n_customers))
-    capacities = np.array(seed.sample(range(10, 160 + 1), k=n_facilities))
+    demands = np.array([seed.randint(5, 35 + 1) for _ in range(n_customers)])
+    capacities = np.array([seed.randint(10, 160 + 1) for _ in range(n_facilities)])
     fixed_costs = np.array(
-        seed.sample(range(100, 110 + 1), k=n_facilities) * np.sqrt(capacities)
-    ) + np.array(seed.sample(range(90 + 1), k=n_facilities))
+        [seed.randint(100, 110 + 1) for _ in range(n_facilities)]
+    ) * np.sqrt(capacities) + np.array(
+        [seed.randint(0, 90 + 1) for _ in range(n_facilities)]
+    )
     fixed_costs = fixed_costs.astype(int)
 
     # adjust capacities according to ratio
diff --git a/geco/mips/max_cut.py b/geco/mips/max_cut.py
index 876226b..0c98d07 100644
--- a/geco/mips/max_cut.py
+++ b/geco/mips/max_cut.py
@@ -19,12 +19,21 @@ def tang_instance(n, m, seed=0):
     """
 
     graph = nx.generators.gnm_random_graph(n, m, seed=seed)
-    for _, _, data in graph.edges(data=True):
-        data["weight"] = seed.randint(0, 10)
+    weights = tang_weights(graph, seed=0)
+    for (_, _, data), weight in zip(graph.edges(data=True), weights):
+        data["weight"] = weight
     _, model = naive(graph)
     return model
 
 
+@py_random_state(1)
+def tang_weights(graph, seed=0):
+    weights = []
+    for _ in graph.edges:
+        weights.append(seed.randint(0, 10))
+    return weights
+
+
 def empty_edge(graph: nx):
     model = scip.Model("Odd-Cycle MaxCut")
 


Test patch:
diff --git a/geco/mips/tests/test_facility_location.py b/geco/mips/tests/test_facility_location.py
index 2a71fda..1d7bc28 100644
--- a/geco/mips/tests/test_facility_location.py
+++ b/geco/mips/tests/test_facility_location.py
@@ -1,3 +1,5 @@
+import pytest
+
 from geco.mips.facility_location import *
 
 
@@ -12,5 +14,23 @@ def test_capacitated_facility_location():
         model.getNConss() == n_customers + n_facilities + 1 + n_customers * n_facilities
     )
     assert model.getObjectiveSense() == "minimize"
+    model.hideOutput()
     model.optimize()
-    assert 5856 <= model.getObjVal() <= 5857
+    assert 5403 <= model.getObjVal() <= 5404
+
+
+@pytest.mark.parametrize(
+    "n_customers,n_facilities,ratio,seed1,seed2",
+    itertools.product(
+        [3, 10, 15], [3, 10, 15], [1, 2], [0, 1, 1337, 53115], [0, 1, 1337, 53115]
+    ),
+)
+def test_seeding(n_customers, n_facilities, ratio, seed1, seed2):
+    params1 = cornuejols_instance_params(n_customers, n_facilities, ratio, seed=seed1)
+    params2 = cornuejols_instance_params(n_customers, n_facilities, ratio, seed=seed2)
+    something_different = False
+    for param1, param2 in zip(params1, params2):
+        if (param1 != param2).any():
+            something_different = True
+            break
+    assert seed1 == seed2 or something_different
diff --git a/geco/mips/tests/test_knapsack.py b/geco/mips/tests/test_knapsack.py
index 257187c..3e96c9b 100644
--- a/geco/mips/tests/test_knapsack.py
+++ b/geco/mips/tests/test_knapsack.py
@@ -1,6 +1,7 @@
-import pytest
 import itertools
 
+import pytest
+
 from geco.mips.knapsack import *
 
 
@@ -27,3 +28,13 @@ def test_yang_knapsack_solution_2():
     model.optimize()
     assert model.getStatus() == "optimal"
     assert model.getObjVal() == 3
+
+
+@pytest.mark.parametrize(
+    "n,seed1,seed2",
+    itertools.product([3, 10, 15], [0, 1, 1337, 53115], [0, 1, 1337, 53115]),
+)
+def test_seeding(n, seed1, seed2):
+    params1 = yang_parameter(n, seed=seed1)
+    params2 = yang_parameter(n, seed=seed2)
+    assert seed1 == seed2 or params1 != params2
diff --git a/geco/mips/tests/test_max_cut.py b/geco/mips/tests/test_max_cut.py
index e57a80a..b7a30ca 100644
--- a/geco/mips/tests/test_max_cut.py
+++ b/geco/mips/tests/test_max_cut.py
@@ -1,3 +1,5 @@
+import pytest
+
 from geco.mips.max_cut import *
 
 
@@ -58,3 +60,14 @@ def test_naive_non_negative():
     model.optimize()
     assert model.getStatus() == "optimal"
     assert model.getObjVal() == 2
+
+
+@pytest.mark.parametrize(
+    "n,seed1,seed2",
+    itertools.product([3, 10, 100], [0, 1, 1337, 53115], [0, 1, 1337, 53115]),
+)
+def test_seeding(n, seed1, seed2):
+    graph = nx.generators.complete_graph(n)
+    weights1 = tang_weights(graph, seed=seed1)
+    weights2 = tang_weights(graph, seed=seed2)
+    assert seed1 == seed2 or weights1 != weights2
diff --git a/geco/mips/tests/test_scheduling.py b/geco/mips/tests/test_scheduling.py
index ec6ce1a..3da7551 100644
--- a/geco/mips/tests/test_scheduling.py
+++ b/geco/mips/tests/test_scheduling.py
@@ -1,3 +1,5 @@
+import pytest
+
 from geco.mips.scheduling import *
 
 
@@ -60,12 +62,15 @@ def test_heinz_formulation():
     model.optimize()
 
 
-def test_param_generation_seeding():
-    n_resources, n_tasks = 10, 10
-    params1 = generate_params(n_resources, n_tasks, seed=1)
-    params2 = generate_params(n_resources, n_tasks, seed=2)
+@pytest.mark.parametrize(
+    "n_resources,n_tasks,seed1,seed2",
+    itertools.product([1, 2, 3], [5, 10, 15], [0, 1, 1337, 53115], [0, 1, 1337, 53115]),
+)
+def test_param_generation_seeding(n_resources, n_tasks, seed1, seed2):
+    params1 = generate_params(n_resources, n_tasks, seed=seed1)
+    params2 = generate_params(n_resources, n_tasks, seed=seed2)
 
-    assert params1 != params2
+    assert seed1 == seed2 or params1 != params2
 
 
 def test_hooker_simple_instance():