Move instance fixtures into the main source; remove duplication

This commit is contained in:
2021-04-09 18:45:06 -05:00
parent f3fd1e0cda
commit a8224b5a38
15 changed files with 188 additions and 225 deletions

View File

@@ -289,35 +289,3 @@ class KnapsackInstance(Instance):
self.weights[item],
self.prices[item],
]
class GurobiKnapsackInstance(KnapsackInstance):
"""
Simpler (one-dimensional) knapsack instance, implemented directly in Gurobi
instead of Pyomo, used for testing.
"""
def __init__(
self,
weights: List[float],
prices: List[float],
capacity: float,
) -> None:
super().__init__(weights, prices, capacity)
@overrides
def to_model(self) -> Any:
import gurobipy as gp
from gurobipy import GRB
model = gp.Model("Knapsack")
n = len(self.weights)
x = model.addVars(n, vtype=GRB.BINARY, name="x")
model.addConstr(
gp.quicksum(x[i] * self.weights[i] for i in range(n)) <= self.capacity,
"eq_capacity",
)
model.setObjective(
gp.quicksum(x[i] * self.prices[i] for i in range(n)), GRB.MAXIMIZE
)
return model

View File

@@ -19,6 +19,7 @@ from miplearn.solvers.internal import (
LazyCallback,
MIPSolveStats,
)
from miplearn.solvers.pyomo.base import PyomoTestInstanceKnapsack
from miplearn.types import (
SolverParams,
UserCutCallback,
@@ -442,3 +443,77 @@ class GurobiSolver(InternalSolver):
params=self.params,
lazy_cb_frequency=self.lazy_cb_frequency,
)
@overrides
def build_test_instance_infeasible(self) -> Instance:
return GurobiTestInstanceInfeasible()
@overrides
def build_test_instance_redundancy(self) -> Instance:
return GurobiTestInstanceRedundancy()
@overrides
def build_test_instance_knapsack(self) -> Instance:
return GurobiTestInstanceKnapsack(
weights=[23.0, 26.0, 20.0, 18.0],
prices=[505.0, 352.0, 458.0, 220.0],
capacity=67.0,
)
class GurobiTestInstanceInfeasible(Instance):
@overrides
def to_model(self) -> Any:
import gurobipy as gp
from gurobipy import GRB
model = gp.Model()
x = model.addVars(1, vtype=GRB.BINARY, name="x")
model.addConstr(x[0] >= 2)
model.setObjective(x[0])
return model
class GurobiTestInstanceRedundancy(Instance):
def to_model(self) -> Any:
import gurobipy as gp
from gurobipy import GRB
model = gp.Model()
x = model.addVars(2, vtype=GRB.BINARY, name="x")
model.addConstr(x[0] + x[1] <= 1)
model.addConstr(x[0] + x[1] <= 2)
model.setObjective(x[0] + x[1], GRB.MAXIMIZE)
return model
class GurobiTestInstanceKnapsack(PyomoTestInstanceKnapsack):
"""
Simpler (one-dimensional) knapsack instance, implemented directly in Gurobi
instead of Pyomo, used for testing.
"""
def __init__(
self,
weights: List[float],
prices: List[float],
capacity: float,
) -> None:
super().__init__(weights, prices, capacity)
@overrides
def to_model(self) -> Any:
import gurobipy as gp
from gurobipy import GRB
model = gp.Model("Knapsack")
n = len(self.weights)
x = model.addVars(n, vtype=GRB.BINARY, name="x")
model.addConstr(
gp.quicksum(x[i] * self.weights[i] for i in range(n)) <= self.capacity,
"eq_capacity",
)
model.setObjective(
gp.quicksum(x[i] * self.prices[i] for i in range(n)), GRB.MAXIMIZE
)
return model

View File

@@ -292,3 +292,15 @@ class InternalSolver(ABC):
completely unitialized.
"""
pass
@abstractmethod
def build_test_instance_infeasible(self) -> Instance:
pass
@abstractmethod
def build_test_instance_redundancy(self) -> Instance:
pass
@abstractmethod
def build_test_instance_knapsack(self) -> Instance:
pass

View File

@@ -29,7 +29,9 @@ from miplearn.types import (
UserCutCallback,
Solution,
VariableName,
Category,
)
import numpy as np
logger = logging.getLogger(__name__)
@@ -338,3 +340,88 @@ class BasePyomoSolver(InternalSolver):
@overrides
def get_sense(self) -> str:
return self._obj_sense
@overrides
def build_test_instance_infeasible(self) -> Instance:
return PyomoTestInstanceInfeasible()
@overrides
def build_test_instance_redundancy(self) -> Instance:
return PyomoTestInstanceRedundancy()
@overrides
def build_test_instance_knapsack(self) -> Instance:
return PyomoTestInstanceKnapsack(
weights=[23.0, 26.0, 20.0, 18.0],
prices=[505.0, 352.0, 458.0, 220.0],
capacity=67.0,
)
class PyomoTestInstanceInfeasible(Instance):
@overrides
def to_model(self) -> pe.ConcreteModel:
model = pe.ConcreteModel()
model.x = pe.Var([0], domain=pe.Binary)
model.OBJ = pe.Objective(expr=model.x[0], sense=pe.maximize)
model.eq = pe.Constraint(expr=model.x[0] >= 2)
return model
class PyomoTestInstanceRedundancy(Instance):
def to_model(self) -> pe.ConcreteModel:
model = pe.ConcreteModel()
model.x = pe.Var([0, 1], domain=pe.Binary)
model.OBJ = pe.Objective(expr=model.x[0] + model.x[1], sense=pe.maximize)
model.eq1 = pe.Constraint(expr=model.x[0] + model.x[1] <= 1)
model.eq2 = pe.Constraint(expr=model.x[0] + model.x[1] <= 2)
return model
class PyomoTestInstanceKnapsack(Instance):
"""
Simpler (one-dimensional) Knapsack Problem, used for testing.
"""
def __init__(
self,
weights: List[float],
prices: List[float],
capacity: float,
) -> None:
super().__init__()
self.weights = weights
self.prices = prices
self.capacity = capacity
self.varname_to_item: Dict[VariableName, int] = {
f"x[{i}]": i for i in range(len(self.weights))
}
@overrides
def to_model(self) -> pe.ConcreteModel:
model = pe.ConcreteModel()
items = range(len(self.weights))
model.x = pe.Var(items, domain=pe.Binary)
model.OBJ = pe.Objective(
expr=sum(model.x[v] * self.prices[v] for v in items),
sense=pe.maximize,
)
model.eq_capacity = pe.Constraint(
expr=sum(model.x[v] * self.weights[v] for v in items) <= self.capacity
)
return model
@overrides
def get_instance_features(self) -> List[float]:
return [
self.capacity,
np.average(self.weights),
]
@overrides
def get_variable_features(self, var_name: VariableName) -> List[Category]:
item = self.varname_to_item[var_name]
return [
self.weights[item],
self.prices[item],
]