Repository: CharJon/GeCO

Issue:
Use packages for all generator types

Discussion:

Patch:
diff --git a/README.md b/README.md
index 8ff7d26..cb02f7a 100644
--- a/README.md
+++ b/README.md
@@ -29,16 +29,15 @@ That's it, now you are ready to generate some instances!
 Assume you want a knapsack instance like in the Yang et
 al. [paper](http://www.optimization-online.org/DB_HTML/2020/02/7626.html).
 
-You start by looking through the knapsack module/package, then searching for a function with the
-name `FIRSTAUTHOR_instance`. In this case we find a [`yang.py`](geco/mips/knapsack/yang.py) file in the `mips/knapsack`
-package.
+You start by looking through the knapsack package, then searching for a file with the name `FIRSTAUTHOR.py`. 
+In this case we find a [`yang.py`](geco/mips/knapsack/yang.py) file in the `mips/knapsack` package.
 
 To generate an instance with 5 items you would run
 
 ```python3
 from geco import knapsack
 
-knapsack.yang_instance(5, seed=1)
+knapsack.yang_instance(n=5, seed=1)
 ```
 
 This, as all generators inside the `mips` subpackage, return a `PySCIPOpt` model that makes use of the SCIP mixed
@@ -62,7 +61,7 @@ be
 from geco.generator import generate_n
 from geco.mips.knapsack import yang
 
-for model in generate_n(lambda seed: yang.yang_instance(5, seed), 10):
+for model in generate_n(lambda seed: yang.yang_instance(n=5, seed=seed), n=10):
     model.optimize()
 ```
 
diff --git a/geco/mips/packing/__init__.py b/geco/mips/packing/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/geco/mips/packing/generic.py b/geco/mips/packing/generic.py
new file mode 100644
index 0000000..15506fd
--- /dev/null
+++ b/geco/mips/packing/generic.py
@@ -0,0 +1,54 @@
+import pyscipopt as scip
+
+
+def packing(n, m, costs, constraint_coefficients, limits, binary, name="Packing"):
+    """Generates a packing instance as described in A.2 in [1].
+
+    Parameters:
+    ----------
+    n: int
+        Number of variables
+    m: int
+        Number of constraints
+    costs: list[number] of size n
+        Coefficients of objective function
+    constraint_coefficients: list[list[number]] of dimensions (m x n)
+        Coefficients of each variable for each constraint
+    limits: list[number] of size m
+        Limits of each constraint
+    name: str
+        Name of the model
+
+    Returns
+    -------
+    model: scip.Model
+        A pyscipopt model of the generated instance
+
+    References:
+    ----------
+    .. [1] Tang, Y., Agrawal, S., & Faenza, Y. (2019). Reinforcement learning for integer
+    programming: Learning to cut. arXiv preprint arXiv:1906.04859.
+    """
+    model = scip.Model(name)
+
+    # add variables and their cost
+    vars = []
+    for i in range(n):
+        cost = costs[i]
+        if binary:
+            var = model.addVar(lb=0, ub=1, obj=cost, name=f"v_{i}", vtype="B")
+        else:
+            var = model.addVar(lb=0, ub=None, obj=cost, name=f"v_{i}", vtype="I")
+        vars.append(var)
+
+    # add constraints
+    for i in range(m):
+        constraint_vars = (
+            constraint_coefficients[i][j] * var for j, var in enumerate(vars)
+        )
+        model.addCons(scip.quicksum(constraint_vars) <= limits[i])
+
+    # contrary to the paper (as of 05/11/2020) as a result of correspondence of with one of the authors
+    model.setMaximize()
+
+    return model
diff --git a/geco/mips/packing.py b/geco/mips/packing/tang.py
similarity index 58%
rename from geco/mips/packing.py
rename to geco/mips/packing/tang.py
index 209d777..1990135 100644
--- a/geco/mips/packing.py
+++ b/geco/mips/packing/tang.py
@@ -1,5 +1,6 @@
 import pyscipopt as scip
 from networkx.utils import py_random_state
+from geco.mips.packing.generic import *
 
 
 @py_random_state(-1)
@@ -71,56 +72,3 @@ def tang_params(n, m, binary, seed=0):
         limits = [seed.randint(9 * n, 10 * n) for _ in range(m)]
 
     return costs, constraint_coefficients, limits
-
-
-def packing(n, m, costs, constraint_coefficients, limits, binary, name="Packing"):
-    """Generates a packing instance as described in A.2 in [1].
-
-    Parameters:
-    ----------
-    n: int
-        Number of variables
-    m: int
-        Number of constraints
-    costs: list[number] of size n
-        Coefficients of objective function
-    constraint_coefficients: list[list[number]] of dimensions (m x n)
-        Coefficients of each variable for each constraint
-    limits: list[number] of size m
-        Limits of each constraint
-    name: str
-        Name of the model
-
-    Returns
-    -------
-    model: scip.Model
-        A pyscipopt model of the generated instance
-
-    References:
-    ----------
-    .. [1] Tang, Y., Agrawal, S., & Faenza, Y. (2019). Reinforcement learning for integer
-    programming: Learning to cut. arXiv preprint arXiv:1906.04859.
-    """
-    model = scip.Model(name)
-
-    # add variables and their cost
-    vars = []
-    for i in range(n):
-        cost = costs[i]
-        if binary:
-            var = model.addVar(lb=0, ub=1, obj=cost, name=f"v_{i}", vtype="B")
-        else:
-            var = model.addVar(lb=0, ub=None, obj=cost, name=f"v_{i}", vtype="I")
-        vars.append(var)
-
-    # add constraints
-    for i in range(m):
-        constraint_vars = (
-            constraint_coefficients[i][j] * var for j, var in enumerate(vars)
-        )
-        model.addCons(scip.quicksum(constraint_vars) <= limits[i])
-
-    # contrary to the paper (as of 05/11/2020) as a result of correspondence of with one of the authors
-    model.setMaximize()
-
-    return model
diff --git a/geco/mips/production_planning/__init__.py b/geco/mips/production_planning/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/geco/mips/production_planning/generic.py b/geco/mips/production_planning/generic.py
new file mode 100644
index 0000000..77d8a86
--- /dev/null
+++ b/geco/mips/production_planning/generic.py
@@ -0,0 +1,71 @@
+import pyscipopt as scip
+
+
+def uncapacitated_lot_sizing(
+    T, M, initial_storage, final_storage, p, h, q, d, name="Production Planning"
+):
+    """
+    Generates an uncapacitated lot-sizing MIP instance instance as in 2.1 of [1].
+
+    Parameters
+    ----------
+    T: int
+        Time horizon
+    M: int
+        Maximum lot size at any time step
+    initial_storage: int
+        Initial available storage
+    final_storage: int
+        Storage available at the last time step
+    p: list[int]
+        Unit production cost at each time step
+    h: list[int]
+        Unit inventory cost at each time step
+    q: list[int]
+        Fixed production cost at each time step
+    d: list[int]
+        Demand at each time step
+    name: str
+        Name to be given to the generated model
+
+    Returns
+    -------
+    model: scip.Model
+        A pyscipopt model of the generated instance
+
+    References
+    ----------
+    .. [1] Pochet, Y. and Wolsey, L. A. (2006). Production planning by
+    mixed integer programming. Springer Science & Business Media.
+    """
+    model = scip.Model(name)
+    # add variables and their cost
+    production_vars = []
+    produce_or_not_vars = []
+    storage_vars = []
+    for i in range(T + 1):
+        var = model.addVar(lb=0, ub=None, obj=p[i], name=f"x_{i}", vtype="I")
+        production_vars.append(var)
+
+        var = model.addVar(lb=0, ub=1, obj=h[i], name=f"y_{i}", vtype="B")
+        produce_or_not_vars.append(var)
+
+        var = model.addVar(lb=0, ub=None, obj=q[i], name=f"s_{i}", vtype="I")
+        storage_vars.append(var)
+
+    # remove unneeded var
+    model.delVar(production_vars[0])
+
+    # add constraints
+    for i in range(1, T + 1):
+        model.addCons(
+            storage_vars[i - 1] + production_vars[i] == d[i] + storage_vars[i]
+        )
+        model.addCons(production_vars[i] <= M * produce_or_not_vars[i])
+
+    model.addCons(storage_vars[0] == initial_storage)
+    model.addCons(storage_vars[T] == final_storage)
+
+    model.setMinimize()
+
+    return model
diff --git a/geco/mips/production_planning.py b/geco/mips/production_planning/tang.py
similarity index 50%
rename from geco/mips/production_planning.py
rename to geco/mips/production_planning/tang.py
index e3556da..db9e6dc 100644
--- a/geco/mips/production_planning.py
+++ b/geco/mips/production_planning/tang.py
@@ -1,5 +1,6 @@
 import pyscipopt as scip
 from networkx.utils import py_random_state
+from geco.mips.production_planning.generic import *
 
 
 @py_random_state(-1)
@@ -74,73 +75,3 @@ def tang_params(T, seed=0):
         q.append(seed.randint(1, 10))
         d.append(seed.randint(1, 10))
     return M, initial_storage, final_storage, p, h, q, d
-
-
-def uncapacitated_lot_sizing(
-    T, M, initial_storage, final_storage, p, h, q, d, name="Production Planning"
-):
-    """
-    Generates an uncapacitated lot-sizing MIP instance instance as in 2.1 of [1].
-
-    Parameters
-    ----------
-    T: int
-        Time horizon
-    M: int
-        Maximum lot size at any time step
-    initial_storage: int
-        Initial available storage
-    final_storage: int
-        Storage available at the last time step
-    p: list[int]
-        Unit production cost at each time step
-    h: list[int]
-        Unit inventory cost at each time step
-    q: list[int]
-        Fixed production cost at each time step
-    d: list[int]
-        Demand at each time step
-    name: str
-        Name to be given to the generated model
-
-    Returns
-    -------
-    model: scip.Model
-        A pyscipopt model of the generated instance
-
-    References
-    ----------
-    .. [1] Pochet, Y. and Wolsey, L. A. (2006). Production planning by
-    mixed integer programming. Springer Science & Business Media.
-    """
-    model = scip.Model(name)
-    # add variables and their cost
-    production_vars = []
-    produce_or_not_vars = []
-    storage_vars = []
-    for i in range(T + 1):
-        var = model.addVar(lb=0, ub=None, obj=p[i], name=f"x_{i}", vtype="I")
-        production_vars.append(var)
-
-        var = model.addVar(lb=0, ub=1, obj=h[i], name=f"y_{i}", vtype="B")
-        produce_or_not_vars.append(var)
-
-        var = model.addVar(lb=0, ub=None, obj=q[i], name=f"s_{i}", vtype="I")
-        storage_vars.append(var)
-
-    # remove unneeded var
-    model.delVar(production_vars[0])
-
-    # add constraints
-    for i in range(1, T + 1):
-        model.addCons(
-            storage_vars[i - 1] + production_vars[i] == d[i] + storage_vars[i]
-        )
-        model.addCons(production_vars[i] <= M * produce_or_not_vars[i])
-
-    model.addCons(storage_vars[0] == initial_storage)
-    model.addCons(storage_vars[T] == final_storage)
-
-    model.setMinimize()
-
-    return model
diff --git a/geco/mips/set_packing/__init__.py b/geco/mips/set_packing/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/geco/mips/set_packing/generic.py b/geco/mips/set_packing/generic.py
new file mode 100644
index 0000000..c043bfe
--- /dev/null
+++ b/geco/mips/set_packing/generic.py
@@ -0,0 +1,47 @@
+import pyscipopt as scip
+
+
+def set_packing(m, n, values, nonzero_vars_for_constraint, name="Set Packing"):
+    """
+    Generates a set packing formulation following [1].
+
+    Parameters
+    ----------
+    m: int
+        Number of constraints
+    n: int
+        Number of elements
+    values: list[int]
+        Value you get for packing each item
+    nonzero_vars_for_constraint: list[list[int]]
+        Nonzero variables list for each constraint
+    name: str
+        Name of the model
+
+    Returns
+    -------
+    model: scip.Model
+        A pyscipopt model of the generated instance
+
+    References
+    ----------
+    .. [1] Yu Yang, Natashia Boland, Bistra Dilkina, Martin Savelsbergh,
+    "Learning Generalized Strong Branching for Set Covering,
+    Set Packing, and 0-1 Knapsack Problems", 2020.
+    """
+    model = scip.Model(name)
+
+    # add variables and their cost
+    vars = []
+    for i in range(n):
+        var = model.addVar(lb=0, ub=1, obj=values[i], name=f"v_{i}", vtype="B")
+        vars.append(var)
+
+    # add constraints
+    for i in range(m):
+        nonzero_vars = (vars[j] for j in nonzero_vars_for_constraint[i])
+        model.addCons(scip.quicksum(nonzero_vars) <= 1)
+
+    model.setMaximize()
+
+    return model
diff --git a/geco/mips/set_packing.py b/geco/mips/set_packing/yang.py
similarity index 59%
rename from geco/mips/set_packing.py
rename to geco/mips/set_packing/yang.py
index ee38753..9a5ac02 100644
--- a/geco/mips/set_packing.py
+++ b/geco/mips/set_packing/yang.py
@@ -1,5 +1,6 @@
 import pyscipopt as scip
 from networkx.utils import py_random_state
+from geco.mips.set_packing.generic import *
 
 
 @py_random_state(-1)
@@ -64,49 +65,3 @@ def yang_parameters(m, seed=0):
         seed.sample(range(n), k=num) for num in num_nonzero_vars_for_constraint
     ]
     return n, values, nonzero_vars_for_constraint
-
-
-def set_packing(m, n, values, nonzero_vars_for_constraint, name="Set Packing"):
-    """
-    Generates a set packing formulation following [1].
-
-    Parameters
-    ----------
-    m: int
-        Number of constraints
-    n: int
-        Number of elements
-    values: list[int]
-        Value you get for packing each item
-    nonzero_vars_for_constraint: list[list[int]]
-        Nonzero variables list for each constraint
-    name: str
-        Name of the model
-
-    Returns
-    -------
-    model: scip.Model
-        A pyscipopt model of the generated instance
-
-    References
-    ----------
-    .. [1] Yu Yang, Natashia Boland, Bistra Dilkina, Martin Savelsbergh,
-    "Learning Generalized Strong Branching for Set Covering,
-    Set Packing, and 0-1 Knapsack Problems", 2020.
-    """
-    model = scip.Model(name)
-
-    # add variables and their cost
-    vars = []
-    for i in range(n):
-        var = model.addVar(lb=0, ub=1, obj=values[i], name=f"v_{i}", vtype="B")
-        vars.append(var)
-
-    # add constraints
-    for i in range(m):
-        nonzero_vars = (vars[j] for j in nonzero_vars_for_constraint[i])
-        model.addCons(scip.quicksum(nonzero_vars) <= 1)
-
-    model.setMaximize()
-
-    return model
diff --git a/setup.py b/setup.py
index 18a5892..1fa7f98 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding="utf-8") as f:
 
 setup(
     name="GeCO",
-    version="0.1.2",
+    version="1.0.0",
     description="Generators for Combinatorial Optimization",
     long_description=readme_text,
     long_description_content_type="text/markdown",


Test patch:
diff --git a/geco/mips/tests/test_packing.py b/geco/mips/tests/test_packing.py
index e21c55a..7595b16 100644
--- a/geco/mips/tests/test_packing.py
+++ b/geco/mips/tests/test_packing.py
@@ -2,7 +2,7 @@ import itertools
 
 import pytest
 
-from geco.mips.packing import *
+from geco.mips.packing.tang import *
 
 
 def test_tang_integral():
diff --git a/geco/mips/tests/test_production_planning.py b/geco/mips/tests/test_production_planning.py
index e137dac..8dd38d8 100644
--- a/geco/mips/tests/test_production_planning.py
+++ b/geco/mips/tests/test_production_planning.py
@@ -2,7 +2,7 @@ import itertools
 
 import pytest
 
-from geco.mips.production_planning import *
+from geco.mips.production_planning.tang import *
 
 
 def test_tang():
diff --git a/geco/mips/tests/test_set_packing.py b/geco/mips/tests/test_set_packing.py
index 89a671d..b220093 100644
--- a/geco/mips/tests/test_set_packing.py
+++ b/geco/mips/tests/test_set_packing.py
@@ -2,7 +2,7 @@ import itertools
 
 import pytest
 
-from geco.mips.set_packing import *
+from geco.mips.set_packing.yang import *
 
 
 def test_yang():