mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 01:18:52 -06:00
Use compact variable features everywhere
This commit is contained in:
@@ -6,11 +6,11 @@ import re
|
||||
import sys
|
||||
from io import StringIO
|
||||
from random import randint
|
||||
from typing import List, Any, Dict, Optional, Hashable, Tuple, cast, TYPE_CHECKING
|
||||
from typing import List, Any, Dict, Optional, Hashable, Tuple, TYPE_CHECKING
|
||||
|
||||
from overrides import overrides
|
||||
|
||||
from miplearn.features import Constraint, Variable, VariableFeatures
|
||||
from miplearn.features import Constraint, VariableFeatures
|
||||
from miplearn.instance.base import Instance
|
||||
from miplearn.solvers import _RedirectOutput
|
||||
from miplearn.solvers.internal import (
|
||||
@@ -289,89 +289,6 @@ class GurobiSolver(InternalSolver):
|
||||
"values",
|
||||
]
|
||||
|
||||
@overrides
|
||||
def get_variables_old(
|
||||
self,
|
||||
with_static: bool = True,
|
||||
with_sa: bool = True,
|
||||
) -> Dict[str, Variable]:
|
||||
assert self.model is not None
|
||||
|
||||
names = self._var_names
|
||||
ub = self._var_ubs
|
||||
lb = self._var_lbs
|
||||
obj_coeff = self._var_obj_coeffs
|
||||
|
||||
values = None
|
||||
rc = None
|
||||
sa_obj_up = None
|
||||
sa_obj_down = None
|
||||
sa_ub_up = None
|
||||
sa_ub_down = None
|
||||
sa_lb_up = None
|
||||
sa_lb_down = None
|
||||
vbasis = None
|
||||
|
||||
if self.model.solCount > 0:
|
||||
values = self.model.getAttr("x", self._gp_vars)
|
||||
|
||||
if self._has_lp_solution:
|
||||
rc = self.model.getAttr("rc", self._gp_vars)
|
||||
vbasis = self.model.getAttr("vbasis", self._gp_vars)
|
||||
if with_sa:
|
||||
sa_obj_up = self.model.getAttr("saobjUp", self._gp_vars)
|
||||
sa_obj_down = self.model.getAttr("saobjLow", self._gp_vars)
|
||||
sa_ub_up = self.model.getAttr("saubUp", self._gp_vars)
|
||||
sa_ub_down = self.model.getAttr("saubLow", self._gp_vars)
|
||||
sa_lb_up = self.model.getAttr("salbUp", self._gp_vars)
|
||||
sa_lb_down = self.model.getAttr("salbLow", self._gp_vars)
|
||||
|
||||
variables = {}
|
||||
for (i, gp_var) in enumerate(self._gp_vars):
|
||||
assert len(names[i]) > 0, "Empty variable name detected."
|
||||
assert (
|
||||
names[i] not in variables
|
||||
), f"Duplicated variable name detected: {names[i]}"
|
||||
var = Variable()
|
||||
if with_static:
|
||||
assert lb is not None
|
||||
assert ub is not None
|
||||
assert obj_coeff is not None
|
||||
var.lower_bound = lb[i]
|
||||
var.upper_bound = ub[i]
|
||||
var.obj_coeff = obj_coeff[i]
|
||||
var.type = self._var_types[i]
|
||||
if values is not None:
|
||||
var.value = values[i]
|
||||
if rc is not None:
|
||||
assert vbasis is not None
|
||||
var.reduced_cost = rc[i]
|
||||
if vbasis[i] == 0:
|
||||
var.basis_status = "B"
|
||||
elif vbasis[i] == -1:
|
||||
var.basis_status = "L"
|
||||
elif vbasis[i] == -2:
|
||||
var.basis_status = "U"
|
||||
elif vbasis[i] == -3:
|
||||
var.basis_status = "S"
|
||||
else:
|
||||
raise Exception(f"unknown vbasis: {vbasis}")
|
||||
if with_sa:
|
||||
assert sa_obj_up is not None
|
||||
assert sa_obj_down is not None
|
||||
assert sa_ub_up is not None
|
||||
assert sa_ub_down is not None
|
||||
assert sa_lb_up is not None
|
||||
assert sa_lb_down is not None
|
||||
var.sa_obj_up = sa_obj_up[i]
|
||||
var.sa_obj_down = sa_obj_down[i]
|
||||
var.sa_ub_up = sa_ub_up[i]
|
||||
var.sa_ub_down = sa_ub_down[i]
|
||||
var.sa_lb_up = sa_lb_up[i]
|
||||
var.sa_lb_down = sa_lb_down[i]
|
||||
variables[names[i]] = var
|
||||
return variables
|
||||
|
||||
@overrides
|
||||
def get_variables(
|
||||
self,
|
||||
@@ -651,27 +568,6 @@ class GurobiSolver(InternalSolver):
|
||||
"get_value cannot be called from cb_where=%s" % self.cb_where
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _parse_gurobi_var_lp(gp_var: Any, var: Variable) -> None:
|
||||
var.reduced_cost = gp_var.rc
|
||||
var.sa_obj_up = gp_var.saobjUp
|
||||
var.sa_obj_down = gp_var.saobjLow
|
||||
var.sa_ub_up = gp_var.saubUp
|
||||
var.sa_ub_down = gp_var.saubLow
|
||||
var.sa_lb_up = gp_var.salbUp
|
||||
var.sa_lb_down = gp_var.salbLow
|
||||
vbasis = gp_var.vbasis
|
||||
if vbasis == 0:
|
||||
var.basis_status = "B"
|
||||
elif vbasis == -1:
|
||||
var.basis_status = "L"
|
||||
elif vbasis == -2:
|
||||
var.basis_status = "U"
|
||||
elif vbasis == -3:
|
||||
var.basis_status = "S"
|
||||
else:
|
||||
raise Exception(f"unknown vbasis: {vbasis}")
|
||||
|
||||
def _raise_if_callback(self) -> None:
|
||||
if self.cb_where is not None:
|
||||
raise Exception("method cannot be called from a callback")
|
||||
|
||||
@@ -9,7 +9,7 @@ from typing import Any, Dict, List, Optional
|
||||
|
||||
from overrides import EnforceOverrides
|
||||
|
||||
from miplearn.features import Constraint, Variable, VariableFeatures
|
||||
from miplearn.features import Constraint, VariableFeatures
|
||||
from miplearn.instance.base import Instance
|
||||
from miplearn.types import (
|
||||
IterationCallback,
|
||||
@@ -17,7 +17,6 @@ from miplearn.types import (
|
||||
BranchPriorities,
|
||||
UserCutCallback,
|
||||
Solution,
|
||||
VariableName,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -236,10 +235,6 @@ class InternalSolver(ABC, EnforceOverrides):
|
||||
"""
|
||||
return False
|
||||
|
||||
@abstractmethod
|
||||
def get_variables_old(self, with_static: bool = True) -> Dict[str, Variable]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_variables(
|
||||
self,
|
||||
|
||||
@@ -19,7 +19,7 @@ from pyomo.core.expr.numeric_expr import SumExpression, MonomialTermExpression
|
||||
from pyomo.opt import TerminationCondition
|
||||
from pyomo.opt.base.solvers import SolverFactory
|
||||
|
||||
from miplearn.features import Variable, VariableFeatures
|
||||
from miplearn.features import VariableFeatures
|
||||
from miplearn.instance.base import Instance
|
||||
from miplearn.solvers import _RedirectOutput
|
||||
from miplearn.solvers.internal import (
|
||||
@@ -175,21 +175,6 @@ class BasePyomoSolver(InternalSolver):
|
||||
solution[f"{var}[{index}]"] = var[index].value
|
||||
return solution
|
||||
|
||||
@overrides
|
||||
def get_variables_old(self, with_static: bool = True) -> Dict[str, Variable]:
|
||||
assert self.model is not None
|
||||
variables = {}
|
||||
for var in self.model.component_objects(pyomo.core.Var):
|
||||
for idx in var:
|
||||
varname = f"{var}[{idx}]"
|
||||
if idx is None:
|
||||
varname = str(var)
|
||||
variables[varname] = self._parse_pyomo_variable(
|
||||
var[idx],
|
||||
with_static=with_static,
|
||||
)
|
||||
return variables
|
||||
|
||||
@overrides
|
||||
def get_variables(
|
||||
self,
|
||||
@@ -495,49 +480,6 @@ class BasePyomoSolver(InternalSolver):
|
||||
def _get_warm_start_regexp(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
def _parse_pyomo_variable(
|
||||
self,
|
||||
pyomo_var: pyomo.core.Var,
|
||||
with_static: bool = True,
|
||||
) -> Variable:
|
||||
assert self.model is not None
|
||||
variable = Variable()
|
||||
|
||||
if with_static:
|
||||
# Variable type
|
||||
vtype: Optional[str] = None
|
||||
if pyomo_var.domain == pyomo.core.Binary:
|
||||
vtype = "B"
|
||||
elif pyomo_var.domain in [
|
||||
pyomo.core.Reals,
|
||||
pyomo.core.NonNegativeReals,
|
||||
pyomo.core.NonPositiveReals,
|
||||
pyomo.core.NegativeReals,
|
||||
pyomo.core.PositiveReals,
|
||||
]:
|
||||
vtype = "C"
|
||||
if vtype is None:
|
||||
raise Exception(f"unknown variable domain: {pyomo_var.domain}")
|
||||
variable.type = vtype
|
||||
|
||||
# Bounds
|
||||
lb, ub = pyomo_var.bounds
|
||||
variable.upper_bound = float(ub)
|
||||
variable.lower_bound = float(lb)
|
||||
|
||||
# Objective coefficient
|
||||
obj_coeff = 0.0
|
||||
if pyomo_var.name in self._obj:
|
||||
obj_coeff = self._obj[pyomo_var.name]
|
||||
variable.obj_coeff = obj_coeff
|
||||
|
||||
# Reduced costs
|
||||
if pyomo_var in self.model.rc:
|
||||
variable.reduced_cost = self.model.rc[pyomo_var]
|
||||
|
||||
variable.value = pyomo_var.value
|
||||
return variable
|
||||
|
||||
def _parse_pyomo_constraint(
|
||||
self,
|
||||
pyomo_constr: pyomo.core.Constraint,
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
import logging
|
||||
from typing import Optional, List, Dict
|
||||
from typing import Optional
|
||||
|
||||
from overrides import overrides
|
||||
from pyomo import environ as pe
|
||||
from scipy.stats import randint
|
||||
|
||||
from miplearn.features import Variable
|
||||
from miplearn.solvers.gurobi import GurobiSolver
|
||||
from miplearn.solvers.pyomo.base import BasePyomoSolver
|
||||
from miplearn.types import SolverParams, BranchPriorities
|
||||
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
from typing import Any, Dict, List
|
||||
import numpy as np
|
||||
|
||||
from miplearn.features import Constraint, Variable, VariableFeatures
|
||||
from miplearn.features import Constraint, VariableFeatures
|
||||
from miplearn.solvers.internal import InternalSolver
|
||||
|
||||
inf = float("inf")
|
||||
@@ -22,33 +21,15 @@ def _round_constraints(constraints: Dict[str, Constraint]) -> Dict[str, Constrai
|
||||
return constraints
|
||||
|
||||
|
||||
def _round_variables(vars: Dict[str, Variable]) -> Dict[str, Variable]:
|
||||
for (cname, c) in vars.items():
|
||||
for attr in [
|
||||
"upper_bound",
|
||||
"lower_bound",
|
||||
"obj_coeff",
|
||||
"value",
|
||||
"reduced_cost",
|
||||
"sa_obj_up",
|
||||
"sa_obj_down",
|
||||
"sa_ub_up",
|
||||
"sa_ub_down",
|
||||
"sa_lb_up",
|
||||
"sa_lb_down",
|
||||
]:
|
||||
if getattr(c, attr) is not None:
|
||||
setattr(c, attr, round(getattr(c, attr), 6))
|
||||
if c.alvarez_2017 is not None:
|
||||
c.alvarez_2017 = list(np.round(c.alvarez_2017, 6))
|
||||
return vars
|
||||
|
||||
|
||||
def _round(obj: Any) -> Any:
|
||||
if obj is None:
|
||||
return None
|
||||
if isinstance(obj, float):
|
||||
return round(obj, 6)
|
||||
if isinstance(obj, tuple):
|
||||
if obj is None:
|
||||
return None
|
||||
return tuple([round(v, 6) for v in obj])
|
||||
return tuple([_round(v) for v in obj])
|
||||
if isinstance(obj, list):
|
||||
return [_round(v) for v in obj]
|
||||
if isinstance(obj, VariableFeatures):
|
||||
obj.reduced_costs = _round(obj.reduced_costs)
|
||||
obj.sa_obj_up = _round(obj.sa_obj_up)
|
||||
@@ -58,6 +39,7 @@ def _round(obj: Any) -> Any:
|
||||
obj.sa_ub_up = _round(obj.sa_ub_up)
|
||||
obj.sa_ub_down = _round(obj.sa_ub_down)
|
||||
obj.values = _round(obj.values)
|
||||
obj.alvarez_2017 = _round(obj.alvarez_2017)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user