mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 01:18:52 -06:00
Remove unused classes and methods
This commit is contained in:
@@ -12,7 +12,7 @@ from miplearn.classifiers import Classifier
|
|||||||
from miplearn.classifiers.counting import CountingClassifier
|
from miplearn.classifiers.counting import CountingClassifier
|
||||||
from miplearn.classifiers.threshold import MinProbabilityThreshold, Threshold
|
from miplearn.classifiers.threshold import MinProbabilityThreshold, Threshold
|
||||||
from miplearn.components.component import Component
|
from miplearn.components.component import Component
|
||||||
from miplearn.features import Constraint, Sample, ConstraintFeatures
|
from miplearn.features import Sample, ConstraintFeatures
|
||||||
from miplearn.instance.base import Instance
|
from miplearn.instance.base import Instance
|
||||||
from miplearn.types import LearningSolveStats
|
from miplearn.types import LearningSolveStats
|
||||||
|
|
||||||
@@ -45,7 +45,6 @@ class StaticLazyConstraintsComponent(Component):
|
|||||||
self.threshold_prototype: Threshold = threshold
|
self.threshold_prototype: Threshold = threshold
|
||||||
self.classifiers: Dict[Hashable, Classifier] = {}
|
self.classifiers: Dict[Hashable, Classifier] = {}
|
||||||
self.thresholds: Dict[Hashable, Threshold] = {}
|
self.thresholds: Dict[Hashable, Threshold] = {}
|
||||||
self.pool_old: Dict[str, Constraint] = {}
|
|
||||||
self.pool: ConstraintFeatures = ConstraintFeatures()
|
self.pool: ConstraintFeatures = ConstraintFeatures()
|
||||||
self.violation_tolerance: float = violation_tolerance
|
self.violation_tolerance: float = violation_tolerance
|
||||||
self.enforced_cids: Set[Hashable] = set()
|
self.enforced_cids: Set[Hashable] = set()
|
||||||
|
|||||||
@@ -133,42 +133,6 @@ class ConstraintFeatures:
|
|||||||
return tuple(obj[i] for (i, selected_i) in enumerate(selected) if selected_i)
|
return tuple(obj[i] for (i, selected_i) in enumerate(selected) if selected_i)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Constraint:
|
|
||||||
basis_status: Optional[str] = None
|
|
||||||
category: Optional[Hashable] = None
|
|
||||||
dual_value: Optional[float] = None
|
|
||||||
lazy: bool = False
|
|
||||||
lhs: Optional[Dict[str, float]] = None
|
|
||||||
rhs: float = 0.0
|
|
||||||
sa_rhs_down: Optional[float] = None
|
|
||||||
sa_rhs_up: Optional[float] = None
|
|
||||||
sense: str = "<"
|
|
||||||
slack: Optional[float] = None
|
|
||||||
user_features: Optional[List[float]] = None
|
|
||||||
|
|
||||||
def to_list(self) -> List[float]:
|
|
||||||
features: List[float] = []
|
|
||||||
for attr in [
|
|
||||||
"dual value",
|
|
||||||
"rhs",
|
|
||||||
"sa_rhs_down",
|
|
||||||
"sa_rhs_up",
|
|
||||||
"slack",
|
|
||||||
]:
|
|
||||||
if getattr(self, attr) is not None:
|
|
||||||
features.append(getattr(self, attr))
|
|
||||||
for attr in ["user_features"]:
|
|
||||||
if getattr(self, attr) is not None:
|
|
||||||
features.extend(getattr(self, attr))
|
|
||||||
if self.lhs is not None and len(self.lhs) > 0:
|
|
||||||
features.append(np.max(self.lhs.values()))
|
|
||||||
features.append(np.average(self.lhs.values()))
|
|
||||||
features.append(np.min(self.lhs.values()))
|
|
||||||
_clip(features)
|
|
||||||
return features
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Features:
|
class Features:
|
||||||
instance: Optional[InstanceFeatures] = None
|
instance: Optional[InstanceFeatures] = None
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from typing import List, Any, Dict, Optional, Hashable, Tuple, TYPE_CHECKING
|
|||||||
|
|
||||||
from overrides import overrides
|
from overrides import overrides
|
||||||
|
|
||||||
from miplearn.features import Constraint, VariableFeatures, ConstraintFeatures
|
from miplearn.features import VariableFeatures, ConstraintFeatures
|
||||||
from miplearn.instance.base import Instance
|
from miplearn.instance.base import Instance
|
||||||
from miplearn.solvers import _RedirectOutput
|
from miplearn.solvers import _RedirectOutput
|
||||||
from miplearn.solvers.internal import (
|
from miplearn.solvers.internal import (
|
||||||
@@ -81,7 +81,6 @@ class GurobiSolver(InternalSolver):
|
|||||||
self._var_lbs: Tuple[float, ...] = tuple()
|
self._var_lbs: Tuple[float, ...] = tuple()
|
||||||
self._var_ubs: Tuple[float, ...] = tuple()
|
self._var_ubs: Tuple[float, ...] = tuple()
|
||||||
self._var_obj_coeffs: Tuple[float, ...] = tuple()
|
self._var_obj_coeffs: Tuple[float, ...] = tuple()
|
||||||
self._relaxed_constrs: Dict[str, Tuple["gurobipy.LinExpr", str, float]] = {}
|
|
||||||
|
|
||||||
if self.lazy_cb_frequency == 1:
|
if self.lazy_cb_frequency == 1:
|
||||||
self.lazy_cb_where = [self.gp.GRB.Callback.MIPSOL]
|
self.lazy_cb_where = [self.gp.GRB.Callback.MIPSOL]
|
||||||
@@ -156,10 +155,6 @@ class GurobiSolver(InternalSolver):
|
|||||||
capacity=67.0,
|
capacity=67.0,
|
||||||
)
|
)
|
||||||
|
|
||||||
@overrides
|
|
||||||
def build_test_instance_redundancy(self) -> Instance:
|
|
||||||
return GurobiTestInstanceRedundancy()
|
|
||||||
|
|
||||||
@overrides
|
@overrides
|
||||||
def clone(self) -> "GurobiSolver":
|
def clone(self) -> "GurobiSolver":
|
||||||
return GurobiSolver(
|
return GurobiSolver(
|
||||||
@@ -167,17 +162,6 @@ class GurobiSolver(InternalSolver):
|
|||||||
lazy_cb_frequency=self.lazy_cb_frequency,
|
lazy_cb_frequency=self.lazy_cb_frequency,
|
||||||
)
|
)
|
||||||
|
|
||||||
def enforce_constraints(self, names: List[str]) -> None:
|
|
||||||
assert self.model is not None
|
|
||||||
constr = [self._relaxed_constrs[n] for n in names]
|
|
||||||
for (i, (lhs, sense, rhs)) in enumerate(constr):
|
|
||||||
if sense == "=":
|
|
||||||
self.model.addConstr(lhs == rhs, name=names[i])
|
|
||||||
elif sense == "<":
|
|
||||||
self.model.addConstr(lhs <= rhs, name=names[i])
|
|
||||||
else:
|
|
||||||
self.model.addConstr(lhs >= rhs, name=names[i])
|
|
||||||
|
|
||||||
@overrides
|
@overrides
|
||||||
def fix(self, solution: Solution) -> None:
|
def fix(self, solution: Solution) -> None:
|
||||||
self._raise_if_callback()
|
self._raise_if_callback()
|
||||||
@@ -385,15 +369,6 @@ class GurobiSolver(InternalSolver):
|
|||||||
assert self.model is not None
|
assert self.model is not None
|
||||||
return self.model.status in [self.gp.GRB.INFEASIBLE, self.gp.GRB.INF_OR_UNBD]
|
return self.model.status in [self.gp.GRB.INFEASIBLE, self.gp.GRB.INF_OR_UNBD]
|
||||||
|
|
||||||
def relax_constraints(self, names: List[str]) -> None:
|
|
||||||
assert self.model is not None
|
|
||||||
constrs = [self._cname_to_constr[n] for n in names]
|
|
||||||
for (i, name) in enumerate(names):
|
|
||||||
c = constrs[i]
|
|
||||||
self._relaxed_constrs[name] = self.model.getRow(c), c.sense, c.rhs
|
|
||||||
self.model.remove(constrs)
|
|
||||||
self.model.update()
|
|
||||||
|
|
||||||
@overrides
|
@overrides
|
||||||
def remove_constraints(self, names: Tuple[str, ...]) -> None:
|
def remove_constraints(self, names: Tuple[str, ...]) -> None:
|
||||||
assert self.model is not None
|
assert self.model is not None
|
||||||
@@ -536,13 +511,6 @@ class GurobiSolver(InternalSolver):
|
|||||||
lp_wallclock_time=self.model.runtime,
|
lp_wallclock_time=self.model.runtime,
|
||||||
)
|
)
|
||||||
|
|
||||||
@overrides
|
|
||||||
def relax(self) -> None:
|
|
||||||
assert self.model is not None
|
|
||||||
self.model.update()
|
|
||||||
self.model = self.model.relax()
|
|
||||||
self._update()
|
|
||||||
|
|
||||||
def _apply_params(self, streams: List[Any]) -> None:
|
def _apply_params(self, streams: List[Any]) -> None:
|
||||||
assert self.model is not None
|
assert self.model is not None
|
||||||
with _RedirectOutput(streams):
|
with _RedirectOutput(streams):
|
||||||
@@ -666,20 +634,6 @@ class GurobiTestInstanceInfeasible(Instance):
|
|||||||
return model
|
return model
|
||||||
|
|
||||||
|
|
||||||
class GurobiTestInstanceRedundancy(Instance):
|
|
||||||
@overrides
|
|
||||||
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, name="c1")
|
|
||||||
model.addConstr(x[0] + x[1] <= 2, name="c2")
|
|
||||||
model.setObjective(x[0] + x[1], GRB.MAXIMIZE)
|
|
||||||
return model
|
|
||||||
|
|
||||||
|
|
||||||
class GurobiTestInstanceKnapsack(PyomoTestInstanceKnapsack):
|
class GurobiTestInstanceKnapsack(PyomoTestInstanceKnapsack):
|
||||||
"""
|
"""
|
||||||
Simpler (one-dimensional) knapsack instance, implemented directly in Gurobi
|
Simpler (one-dimensional) knapsack instance, implemented directly in Gurobi
|
||||||
|
|||||||
@@ -5,14 +5,13 @@
|
|||||||
import logging
|
import logging
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, List, Optional, Tuple
|
||||||
|
|
||||||
from miplearn.features import Constraint, VariableFeatures, ConstraintFeatures
|
from miplearn.features import VariableFeatures, ConstraintFeatures
|
||||||
from miplearn.instance.base import Instance
|
from miplearn.instance.base import Instance
|
||||||
from miplearn.types import (
|
from miplearn.types import (
|
||||||
IterationCallback,
|
IterationCallback,
|
||||||
LazyCallback,
|
LazyCallback,
|
||||||
BranchPriorities,
|
|
||||||
UserCutCallback,
|
UserCutCallback,
|
||||||
Solution,
|
Solution,
|
||||||
)
|
)
|
||||||
@@ -75,6 +74,9 @@ class InternalSolver(ABC):
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def build_test_instance_infeasible(self) -> Instance:
|
def build_test_instance_infeasible(self) -> Instance:
|
||||||
|
"""
|
||||||
|
Returns an infeasible instance, for testing purposes.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -89,10 +91,6 @@ class InternalSolver(ABC):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def build_test_instance_redundancy(self) -> Instance:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def clone(self) -> "InternalSolver":
|
def clone(self) -> "InternalSolver":
|
||||||
"""
|
"""
|
||||||
@@ -184,25 +182,6 @@ class InternalSolver(ABC):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def relax(self) -> None:
|
|
||||||
"""
|
|
||||||
Drops all integrality constraints from the model.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def set_branching_priorities(self, priorities: BranchPriorities) -> None:
|
|
||||||
"""
|
|
||||||
Sets the branching priorities for the given decision variables.
|
|
||||||
|
|
||||||
When the MIP solver needs to decide on which variable to branch, variables
|
|
||||||
with higher priority are picked first, given that they are fractional.
|
|
||||||
Ties are solved arbitrarily. By default, all variables have priority zero.
|
|
||||||
|
|
||||||
Missing values indicate variables whose priorities should not be modified.
|
|
||||||
"""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def set_instance(
|
def set_instance(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -136,10 +136,6 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
def build_test_instance_infeasible(self) -> Instance:
|
def build_test_instance_infeasible(self) -> Instance:
|
||||||
return PyomoTestInstanceInfeasible()
|
return PyomoTestInstanceInfeasible()
|
||||||
|
|
||||||
@overrides
|
|
||||||
def build_test_instance_redundancy(self) -> Instance:
|
|
||||||
return PyomoTestInstanceRedundancy()
|
|
||||||
|
|
||||||
@overrides
|
@overrides
|
||||||
def build_test_instance_knapsack(self) -> Instance:
|
def build_test_instance_knapsack(self) -> Instance:
|
||||||
return PyomoTestInstanceKnapsack(
|
return PyomoTestInstanceKnapsack(
|
||||||
@@ -490,7 +486,7 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
self,
|
self,
|
||||||
tee: bool = False,
|
tee: bool = False,
|
||||||
) -> LPSolveStats:
|
) -> LPSolveStats:
|
||||||
self.relax()
|
self._relax()
|
||||||
streams: List[Any] = [StringIO()]
|
streams: List[Any] = [StringIO()]
|
||||||
if tee:
|
if tee:
|
||||||
streams += [sys.stdout]
|
streams += [sys.stdout]
|
||||||
@@ -510,15 +506,6 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
lp_wallclock_time=results["Solver"][0]["Wallclock time"],
|
lp_wallclock_time=results["Solver"][0]["Wallclock time"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@overrides
|
|
||||||
def relax(self) -> None:
|
|
||||||
for var in self._bin_vars:
|
|
||||||
lb, ub = var.bounds
|
|
||||||
var.setlb(lb)
|
|
||||||
var.setub(ub)
|
|
||||||
var.domain = pyomo.core.base.set_types.Reals
|
|
||||||
self._pyomo_solver.update_var(var)
|
|
||||||
|
|
||||||
def _clear_warm_start(self) -> None:
|
def _clear_warm_start(self) -> None:
|
||||||
for var in self._all_vars:
|
for var in self._all_vars:
|
||||||
if not var.fixed:
|
if not var.fixed:
|
||||||
@@ -575,6 +562,14 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
raise Exception(f"Unknown expression type: {expr.__class__.__name__}")
|
raise Exception(f"Unknown expression type: {expr.__class__.__name__}")
|
||||||
return lhs
|
return lhs
|
||||||
|
|
||||||
|
def _relax(self) -> None:
|
||||||
|
for var in self._bin_vars:
|
||||||
|
lb, ub = var.bounds
|
||||||
|
var.setlb(lb)
|
||||||
|
var.setub(ub)
|
||||||
|
var.domain = pyomo.core.base.set_types.Reals
|
||||||
|
self._pyomo_solver.update_var(var)
|
||||||
|
|
||||||
def _restore_integrality(self) -> None:
|
def _restore_integrality(self) -> None:
|
||||||
for var in self._bin_vars:
|
for var in self._bin_vars:
|
||||||
var.domain = pyomo.core.base.set_types.Binary
|
var.domain = pyomo.core.base.set_types.Binary
|
||||||
@@ -624,17 +619,6 @@ class PyomoTestInstanceInfeasible(Instance):
|
|||||||
return model
|
return model
|
||||||
|
|
||||||
|
|
||||||
class PyomoTestInstanceRedundancy(Instance):
|
|
||||||
@overrides
|
|
||||||
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):
|
class PyomoTestInstanceKnapsack(Instance):
|
||||||
"""
|
"""
|
||||||
Simpler (one-dimensional) Knapsack Problem, used for testing.
|
Simpler (one-dimensional) Knapsack Problem, used for testing.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from pyomo import environ as pe
|
|||||||
from scipy.stats import randint
|
from scipy.stats import randint
|
||||||
|
|
||||||
from miplearn.solvers.pyomo.base import BasePyomoSolver
|
from miplearn.solvers.pyomo.base import BasePyomoSolver
|
||||||
from miplearn.types import SolverParams, BranchPriorities
|
from miplearn.types import SolverParams
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -42,17 +42,6 @@ class GurobiPyomoSolver(BasePyomoSolver):
|
|||||||
def clone(self) -> "GurobiPyomoSolver":
|
def clone(self) -> "GurobiPyomoSolver":
|
||||||
return GurobiPyomoSolver(params=self.params)
|
return GurobiPyomoSolver(params=self.params)
|
||||||
|
|
||||||
@overrides
|
|
||||||
def set_branching_priorities(self, priorities: BranchPriorities) -> None:
|
|
||||||
from gurobipy import GRB
|
|
||||||
|
|
||||||
for (varname, priority) in priorities.items():
|
|
||||||
if priority is None:
|
|
||||||
continue
|
|
||||||
var = self._varname_to_var[varname]
|
|
||||||
gvar = self._pyomo_solver._pyomo_var_to_solver_var_map[var]
|
|
||||||
gvar.setAttr(GRB.Attr.BranchPriority, int(round(priority)))
|
|
||||||
|
|
||||||
@overrides
|
@overrides
|
||||||
def _extract_node_count(self, log: str) -> int:
|
def _extract_node_count(self, log: str) -> int:
|
||||||
return max(1, int(self._pyomo_solver._solver_model.getAttr("NodeCount")))
|
return max(1, int(self._pyomo_solver._solver_model.getAttr("NodeCount")))
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
# Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved.
|
# Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved.
|
||||||
# Released under the modified BSD license. See COPYING.md for more details.
|
# Released under the modified BSD license. See COPYING.md for more details.
|
||||||
|
|
||||||
from typing import Any, Dict, List
|
from typing import Any, List
|
||||||
|
|
||||||
from miplearn.features import Constraint, VariableFeatures, ConstraintFeatures
|
from miplearn.features import VariableFeatures, ConstraintFeatures
|
||||||
from miplearn.solvers.internal import InternalSolver
|
from miplearn.solvers.internal import InternalSolver
|
||||||
|
|
||||||
inf = float("inf")
|
inf = float("inf")
|
||||||
@@ -13,14 +13,6 @@ inf = float("inf")
|
|||||||
# This file is in the main source folder, so that it can be called from Julia.
|
# This file is in the main source folder, so that it can be called from Julia.
|
||||||
|
|
||||||
|
|
||||||
def _round_constraints(constraints: Dict[str, Constraint]) -> Dict[str, Constraint]:
|
|
||||||
for (cname, c) in constraints.items():
|
|
||||||
for attr in ["slack", "dual_value"]:
|
|
||||||
if getattr(c, attr) is not None:
|
|
||||||
setattr(c, attr, round(getattr(c, attr), 6))
|
|
||||||
return constraints
|
|
||||||
|
|
||||||
|
|
||||||
def _round(obj: Any) -> Any:
|
def _round(obj: Any) -> Any:
|
||||||
if obj is None:
|
if obj is None:
|
||||||
return None
|
return None
|
||||||
@@ -46,20 +38,6 @@ def _filter_attrs(allowed_keys: List[str], obj: Any) -> Any:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
def _remove_unsupported_constr_attrs(
|
|
||||||
solver: InternalSolver,
|
|
||||||
constraints: Dict[str, Constraint],
|
|
||||||
) -> Dict[str, Constraint]:
|
|
||||||
for (cname, c) in constraints.items():
|
|
||||||
to_remove = []
|
|
||||||
for k in c.__dict__.keys():
|
|
||||||
if k not in solver.get_constraint_attrs():
|
|
||||||
to_remove.append(k)
|
|
||||||
for k in to_remove:
|
|
||||||
setattr(c, k, None)
|
|
||||||
return constraints
|
|
||||||
|
|
||||||
|
|
||||||
def run_internal_solver_tests(solver: InternalSolver) -> None:
|
def run_internal_solver_tests(solver: InternalSolver) -> None:
|
||||||
run_basic_usage_tests(solver.clone())
|
run_basic_usage_tests(solver.clone())
|
||||||
run_warm_start_tests(solver.clone())
|
run_warm_start_tests(solver.clone())
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ if TYPE_CHECKING:
|
|||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
from miplearn.solvers.learning import InternalSolver
|
from miplearn.solvers.learning import InternalSolver
|
||||||
|
|
||||||
BranchPriorities = Dict[str, Optional[float]]
|
|
||||||
Category = Hashable
|
Category = Hashable
|
||||||
IterationCallback = Callable[[], bool]
|
IterationCallback = Callable[[], bool]
|
||||||
LazyCallback = Callable[[Any, Any], None]
|
LazyCallback = Callable[[Any, Any], None]
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ from miplearn.components.static_lazy import StaticLazyConstraintsComponent
|
|||||||
from miplearn.features import (
|
from miplearn.features import (
|
||||||
InstanceFeatures,
|
InstanceFeatures,
|
||||||
Features,
|
Features,
|
||||||
Constraint,
|
|
||||||
Sample,
|
Sample,
|
||||||
ConstraintFeatures,
|
ConstraintFeatures,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,22 +35,3 @@ def test_gurobi_pyomo_solver() -> None:
|
|||||||
|
|
||||||
def test_gurobi_solver() -> None:
|
def test_gurobi_solver() -> None:
|
||||||
run_internal_solver_tests(GurobiSolver())
|
run_internal_solver_tests(GurobiSolver())
|
||||||
|
|
||||||
|
|
||||||
def test_redundancy() -> None:
|
|
||||||
solver = GurobiSolver()
|
|
||||||
instance = solver.build_test_instance_redundancy()
|
|
||||||
solver.set_instance(instance)
|
|
||||||
stats = solver.solve_lp()
|
|
||||||
assert stats.lp_value == 1.0
|
|
||||||
constraints = solver.get_constraints()
|
|
||||||
assert constraints.names[0] == "c1"
|
|
||||||
assert constraints.slacks[0] == 0.0
|
|
||||||
|
|
||||||
solver.relax_constraints(["c1"])
|
|
||||||
stats = solver.solve_lp()
|
|
||||||
assert stats.lp_value == 2.0
|
|
||||||
|
|
||||||
solver.enforce_constraints(["c1"])
|
|
||||||
stats = solver.solve_lp()
|
|
||||||
assert stats.lp_value == 1.0
|
|
||||||
|
|||||||
@@ -5,14 +5,12 @@
|
|||||||
from miplearn.features import (
|
from miplearn.features import (
|
||||||
FeaturesExtractor,
|
FeaturesExtractor,
|
||||||
InstanceFeatures,
|
InstanceFeatures,
|
||||||
Constraint,
|
|
||||||
VariableFeatures,
|
VariableFeatures,
|
||||||
ConstraintFeatures,
|
ConstraintFeatures,
|
||||||
)
|
)
|
||||||
from miplearn.solvers.gurobi import GurobiSolver
|
from miplearn.solvers.gurobi import GurobiSolver
|
||||||
from miplearn.solvers.tests import (
|
from miplearn.solvers.tests import (
|
||||||
assert_equals,
|
assert_equals,
|
||||||
_round_constraints,
|
|
||||||
_round,
|
_round,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user