Repository: CharJon/GeCO

Issue:
Increase test coverage to 100%

Discussion:

Patch:
diff --git a/.travis.yml b/.travis.yml
index 88b2f86..1f0ab24 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ install:
   - conda update -q conda
   # Useful for debugging any issues with conda
   - conda info -a
-  - conda env create -n GeCO --file conda-env.yml
+  - conda env create -n GeCO --file conda-dev-env.yml
   - conda activate GeCO
 script:
   - black --check geco/
diff --git a/conda-dev-env.yml b/conda-dev-env.yml
index f5a772d..b320d2d 100644
--- a/conda-dev-env.yml
+++ b/conda-dev-env.yml
@@ -1,4 +1,4 @@
-# run: conda env create -n GeCO --file conda-env.yml
+# run: conda env create -n GeCO --file conda-dev-env.yml
 channels:
   - scipopt
   - conda-forge
@@ -14,7 +14,8 @@ dependencies:
   - pyscipopt
   - networkx
   - pytest
-  - coverage
+  - black
+  - codecov
   - pip:
       - git+https://github.com/rhgrant10/tsplib95.git
       - dwave_networkx
diff --git a/conda-env.yml b/conda-env.yml
deleted file mode 100644
index 598d83d..0000000
--- a/conda-env.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-# run: conda env create -n GeCO --file conda-env.yml
-channels:
-  - scipopt
-  - conda-forge
-  - default
-dependencies:
-  - python=3.8
-  - pip
-  - numpy
-  - scipy
-  - jupyter
-  - pytest
-  - pandas
-  - tqdm
-  - pyscipopt
-  - networkx
-  - codecov
-  - pip:
-      - black
-      - git+https://github.com/rhgrant10/tsplib95.git
-      - dwave_networkx
-      - git+https://github.com/CharJon/GeCO
diff --git a/geco/mips/max_cut.py b/geco/mips/max_cut.py
index 0c98d07..be52fbc 100644
--- a/geco/mips/max_cut.py
+++ b/geco/mips/max_cut.py
@@ -118,8 +118,4 @@ def triangle(graph: nx):
 
 def _get_edge_variable(u, v, edge_variables):
     edge_name = naming.undirected_edge_name(u, v)
-    alternative_edge_name = naming.undirected_edge_name(v, u)
-    if edge_name in edge_variables:
-        return edge_variables[edge_name]
-    else:
-        return edge_variables[alternative_edge_name]
+    return edge_variables[edge_name]
diff --git a/geco/mips/scheduling.py b/geco/mips/scheduling.py
index fa5167a..6bdf382 100644
--- a/geco/mips/scheduling.py
+++ b/geco/mips/scheduling.py
@@ -98,7 +98,7 @@ def generate_hookers_instances():
     for n, t, seed in itertools.product(number_of_tasks, time_steps, seeds):
         params = 3, n, t, seed
         yield params, hooker_late_tasks_formulation(
-            *params[:-1], *generate_params(*params[:-1])[:-1], seed=seed
+            *params[:-1], *generate_params(*params[:-1])[:-1]
         )
 
 
diff --git a/geco/mips/utilities/naming.py b/geco/mips/utilities/naming.py
index ebe3570..09463e3 100644
--- a/geco/mips/utilities/naming.py
+++ b/geco/mips/utilities/naming.py
@@ -6,10 +6,3 @@ def undirected_edge_name(u, v) -> str:
     if u_i > v_i:
         u_i, v_i = v_i, u_i
     return f"({u_i},{v_i})"
-
-
-def is_edge(var) -> bool:
-    """
-    checks variable name if it represents and edge or not
-    """
-    return "," in str(var)


Test patch:
diff --git a/geco/mips/tests/test_knapsack.py b/geco/mips/tests/test_knapsack.py
index 8b615ac..b251c12 100644
--- a/geco/mips/tests/test_knapsack.py
+++ b/geco/mips/tests/test_knapsack.py
@@ -15,8 +15,7 @@ Yang Generators Tests
     "n,seed", itertools.product([10, 100, 1000], [0, 1, 1337, 53115])
 )
 def test_yang_knapsack_creation(n, seed):
-    params = yang_parameter(n, seed=seed)
-    model = knapsack(*params)
+    model = yang_instance(n, seed=seed)
     assert model.getNVars() == n
     assert model.getNConss() == 1
     assert model.getObjectiveSense() == "maximize"
diff --git a/geco/mips/tests/test_max_cut.py b/geco/mips/tests/test_max_cut.py
index 32dede0..59b69df 100644
--- a/geco/mips/tests/test_max_cut.py
+++ b/geco/mips/tests/test_max_cut.py
@@ -21,17 +21,19 @@ def test_empty_edge():
 
 
 def test_triangle():
-    graph = nx.generators.complete_graph(3)
+    graph = nx.generators.cycle_graph(4)
     for _, _, data in graph.edges(data=True):
         data["weight"] = 1
     _, model = triangle(graph)
-    m = len(graph.edges)
-    assert model.getNVars() == m
-    assert model.getNConss() == 2
+    n = len(graph.nodes)
+    assert model.getNVars() == n * (n - 1) / 2
+    assert (
+        model.getNConss() == n * (n - 1) * (n - 2) / 3
+    )  # 2 constraints for each triple of nodes
     model.hideOutput()
     model.optimize()
     assert model.getStatus() == "optimal"
-    assert model.getObjVal() == 2
+    assert model.getObjVal() == 4
 
 
 def test_naive_negative():
diff --git a/geco/mips/tests/test_scheduling.py b/geco/mips/tests/test_scheduling.py
index c6c34e6..1f69060 100644
--- a/geco/mips/tests/test_scheduling.py
+++ b/geco/mips/tests/test_scheduling.py
@@ -8,23 +8,12 @@ def test_late_tasks_formulation():
     params = p, C, c, R, d = generate_params(*main_params[:-1], seed=0)[:-1]
 
     model = hooker_late_tasks_formulation(*main_params, *params)
-    assert (
-        model.getNVars()
-        == number_of_facilities * number_of_tasks * time_steps + number_of_tasks
-    )
-    constraints_lowerbound = (
-        number_of_tasks * time_steps
-        + number_of_tasks
-        + number_of_facilities * time_steps
-    )
-    constraints_upperbound = (
-        number_of_tasks * time_steps
-        + number_of_tasks
-        + number_of_facilities * time_steps
-        + number_of_facilities * number_of_tasks * time_steps
-    )
-    assert constraints_lowerbound <= model.getNConss() <= constraints_upperbound
-    assert model.getObjectiveSense() == "minimize"
+    check_hookers_instance(model, number_of_facilities, number_of_tasks, time_steps)
+
+
+def test_hooker_generation():
+    for params, model in generate_hookers_instances():
+        check_hookers_instance(model, *params[:-1])
 
 
 @pytest.mark.xfail
@@ -115,22 +104,6 @@ def test_heinz_simple_instance():
     assert heinz_model.getObjVal() == 1
 
 
-def get_keys(iterable):
-    """
-    Given a list or a dict returns keys(indices)
-
-    Returns
-    -------
-    an iterable of keys
-    """
-    if isinstance(iterable, list):
-        return range(len(iterable))
-    elif isinstance(iterable, dict):
-        return iterable.keys()
-    else:
-        raise ValueError("iterable given should be of type list or dict")
-
-
 def simple_instance_params():
     n_resources = 1
     n_tasks = 1
@@ -154,3 +127,23 @@ def simple_instance_params():
         deadlines,
         resource_requirements,
     )
+
+
+def check_hookers_instance(model, number_of_facilities, number_of_tasks, time_steps):
+    assert (
+        model.getNVars()
+        == number_of_facilities * number_of_tasks * time_steps + number_of_tasks
+    )
+    constraints_lowerbound = (
+        number_of_tasks * time_steps
+        + number_of_tasks
+        + number_of_facilities * time_steps
+    )
+    constraints_upperbound = (
+        number_of_tasks * time_steps
+        + number_of_tasks
+        + number_of_facilities * time_steps
+        + number_of_facilities * number_of_tasks * time_steps
+    )
+    assert constraints_lowerbound <= model.getNConss() <= constraints_upperbound
+    assert model.getObjectiveSense() == "minimize"