Remove unused classes and methods

master
Alinson S. Xavier 4 years ago
parent 91c8db2225
commit 4bf4d09cb5
No known key found for this signature in database
GPG Key ID: DCA0DAD4D2F58624

@ -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,
) )

Loading…
Cancel
Save