mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 09:28:51 -06:00
Use np.array for Variables.names
This commit is contained in:
2
Makefile
2
Makefile
@@ -2,7 +2,7 @@ PYTHON := python3
|
|||||||
PYTEST := pytest
|
PYTEST := pytest
|
||||||
PIP := $(PYTHON) -m pip
|
PIP := $(PYTHON) -m pip
|
||||||
MYPY := $(PYTHON) -m mypy
|
MYPY := $(PYTHON) -m mypy
|
||||||
PYTEST_ARGS := -W ignore::DeprecationWarning -vv -x --log-level=DEBUG
|
PYTEST_ARGS := -W ignore::DeprecationWarning -vv --log-level=DEBUG
|
||||||
VERSION := 0.2
|
VERSION := 0.2
|
||||||
|
|
||||||
all: docs test
|
all: docs test
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class PrimalSolutionComponent(Component):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def sample_predict(self, sample: Sample) -> Solution:
|
def sample_predict(self, sample: Sample) -> Solution:
|
||||||
var_names = sample.get_vector("static_var_names")
|
var_names = sample.get_array("static_var_names")
|
||||||
var_categories = sample.get_vector("static_var_categories")
|
var_categories = sample.get_vector("static_var_categories")
|
||||||
assert var_names is not None
|
assert var_names is not None
|
||||||
assert var_categories is not None
|
assert var_categories is not None
|
||||||
@@ -145,7 +145,7 @@ class PrimalSolutionComponent(Component):
|
|||||||
instance_features = sample.get_vector("static_instance_features")
|
instance_features = sample.get_vector("static_instance_features")
|
||||||
mip_var_values = sample.get_vector("mip_var_values")
|
mip_var_values = sample.get_vector("mip_var_values")
|
||||||
var_features = sample.get_vector_list("lp_var_features")
|
var_features = sample.get_vector_list("lp_var_features")
|
||||||
var_names = sample.get_vector("static_var_names")
|
var_names = sample.get_array("static_var_names")
|
||||||
var_categories = sample.get_vector("static_var_categories")
|
var_categories = sample.get_vector("static_var_categories")
|
||||||
if var_features is None:
|
if var_features is None:
|
||||||
var_features = sample.get_vector_list("static_var_features")
|
var_features = sample.get_vector_list("static_var_features")
|
||||||
@@ -187,8 +187,8 @@ class PrimalSolutionComponent(Component):
|
|||||||
_: Optional[Instance],
|
_: Optional[Instance],
|
||||||
sample: Sample,
|
sample: Sample,
|
||||||
) -> Dict[str, Dict[str, float]]:
|
) -> Dict[str, Dict[str, float]]:
|
||||||
mip_var_values = sample.get_vector("mip_var_values")
|
mip_var_values = sample.get_array("mip_var_values")
|
||||||
var_names = sample.get_vector("static_var_names")
|
var_names = sample.get_array("static_var_names")
|
||||||
assert mip_var_values is not None
|
assert mip_var_values is not None
|
||||||
assert var_names is not None
|
assert var_names is not None
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
import collections
|
import collections
|
||||||
import numbers
|
import numbers
|
||||||
from math import log, isfinite
|
from math import log, isfinite
|
||||||
from typing import TYPE_CHECKING, Dict, Optional, List, Any, Tuple
|
from typing import TYPE_CHECKING, Dict, Optional, List, Any, Tuple, KeysView, cast
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ class FeaturesExtractor:
|
|||||||
variables = solver.get_variables(with_static=True)
|
variables = solver.get_variables(with_static=True)
|
||||||
constraints = solver.get_constraints(with_static=True, with_lhs=self.with_lhs)
|
constraints = solver.get_constraints(with_static=True, with_lhs=self.with_lhs)
|
||||||
sample.put_array("static_var_lower_bounds", variables.lower_bounds)
|
sample.put_array("static_var_lower_bounds", variables.lower_bounds)
|
||||||
sample.put_vector("static_var_names", variables.names)
|
sample.put_array("static_var_names", variables.names)
|
||||||
sample.put_array("static_var_obj_coeffs", variables.obj_coeffs)
|
sample.put_array("static_var_obj_coeffs", variables.obj_coeffs)
|
||||||
sample.put_vector("static_var_types", variables.types)
|
sample.put_vector("static_var_types", variables.types)
|
||||||
sample.put_array("static_var_upper_bounds", variables.upper_bounds)
|
sample.put_array("static_var_upper_bounds", variables.upper_bounds)
|
||||||
@@ -139,12 +139,29 @@ class FeaturesExtractor:
|
|||||||
instance: "Instance",
|
instance: "Instance",
|
||||||
sample: Sample,
|
sample: Sample,
|
||||||
) -> Tuple[List, List]:
|
) -> Tuple[List, List]:
|
||||||
categories: List[Optional[str]] = []
|
# Query variable names
|
||||||
user_features: List[Optional[List[float]]] = []
|
var_names = sample.get_array("static_var_names")
|
||||||
var_features_dict = instance.get_variable_features()
|
|
||||||
var_categories_dict = instance.get_variable_categories()
|
|
||||||
var_names = sample.get_vector("static_var_names")
|
|
||||||
assert var_names is not None
|
assert var_names is not None
|
||||||
|
|
||||||
|
# Query variable features and categories
|
||||||
|
var_features_dict = {
|
||||||
|
v.encode(): f for (v, f) in instance.get_variable_features().items()
|
||||||
|
}
|
||||||
|
var_categories_dict = {
|
||||||
|
v.encode(): f for (v, f) in instance.get_variable_categories().items()
|
||||||
|
}
|
||||||
|
|
||||||
|
# Assert that variables in user-provided dicts actually exist
|
||||||
|
var_names_set = set(var_names)
|
||||||
|
for keys in [var_features_dict.keys(), var_categories_dict.keys()]:
|
||||||
|
for vn in cast(KeysView, keys):
|
||||||
|
assert (
|
||||||
|
vn in var_names_set
|
||||||
|
), f"Variable {vn!r} not found in the problem; {var_names_set}"
|
||||||
|
|
||||||
|
# Assemble into compact lists
|
||||||
|
user_features: List[Optional[List[float]]] = []
|
||||||
|
categories: List[Optional[str]] = []
|
||||||
for (i, var_name) in enumerate(var_names):
|
for (i, var_name) in enumerate(var_names):
|
||||||
if var_name not in var_categories_dict:
|
if var_name not in var_categories_dict:
|
||||||
user_features.append(None)
|
user_features.append(None)
|
||||||
|
|||||||
@@ -73,11 +73,11 @@ class GurobiSolver(InternalSolver):
|
|||||||
self._has_lp_solution = False
|
self._has_lp_solution = False
|
||||||
self._has_mip_solution = False
|
self._has_mip_solution = False
|
||||||
|
|
||||||
self._varname_to_var: Dict[str, "gurobipy.Var"] = {}
|
self._varname_to_var: Dict[bytes, "gurobipy.Var"] = {}
|
||||||
self._cname_to_constr: Dict[str, "gurobipy.Constr"] = {}
|
self._cname_to_constr: Dict[str, "gurobipy.Constr"] = {}
|
||||||
self._gp_vars: List["gurobipy.Var"] = []
|
self._gp_vars: List["gurobipy.Var"] = []
|
||||||
self._gp_constrs: List["gurobipy.Constr"] = []
|
self._gp_constrs: List["gurobipy.Constr"] = []
|
||||||
self._var_names: List[str] = []
|
self._var_names: np.ndarray = np.empty(0)
|
||||||
self._constr_names: List[str] = []
|
self._constr_names: List[str] = []
|
||||||
self._var_types: List[str] = []
|
self._var_types: List[str] = []
|
||||||
self._var_lbs: np.ndarray = np.empty(0)
|
self._var_lbs: np.ndarray = np.empty(0)
|
||||||
@@ -263,11 +263,13 @@ class GurobiSolver(InternalSolver):
|
|||||||
if self.cb_where is not None:
|
if self.cb_where is not None:
|
||||||
if self.cb_where == self.gp.GRB.Callback.MIPNODE:
|
if self.cb_where == self.gp.GRB.Callback.MIPNODE:
|
||||||
return {
|
return {
|
||||||
v.varName: self.model.cbGetNodeRel(v) for v in self.model.getVars()
|
v.varName.encode(): self.model.cbGetNodeRel(v)
|
||||||
|
for v in self.model.getVars()
|
||||||
}
|
}
|
||||||
elif self.cb_where == self.gp.GRB.Callback.MIPSOL:
|
elif self.cb_where == self.gp.GRB.Callback.MIPSOL:
|
||||||
return {
|
return {
|
||||||
v.varName: self.model.cbGetSolution(v) for v in self.model.getVars()
|
v.varName.encode(): self.model.cbGetSolution(v)
|
||||||
|
for v in self.model.getVars()
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
@@ -276,7 +278,7 @@ class GurobiSolver(InternalSolver):
|
|||||||
)
|
)
|
||||||
if self.model.solCount == 0:
|
if self.model.solCount == 0:
|
||||||
return None
|
return None
|
||||||
return {v.varName: v.x for v in self.model.getVars()}
|
return {v.varName.encode(): v.x for v in self.model.getVars()}
|
||||||
|
|
||||||
@overrides
|
@overrides
|
||||||
def get_variable_attrs(self) -> List[str]:
|
def get_variable_attrs(self) -> List[str]:
|
||||||
@@ -584,7 +586,10 @@ class GurobiSolver(InternalSolver):
|
|||||||
assert self.model is not None
|
assert self.model is not None
|
||||||
gp_vars: List["gurobipy.Var"] = self.model.getVars()
|
gp_vars: List["gurobipy.Var"] = self.model.getVars()
|
||||||
gp_constrs: List["gurobipy.Constr"] = self.model.getConstrs()
|
gp_constrs: List["gurobipy.Constr"] = self.model.getConstrs()
|
||||||
var_names: List[str] = self.model.getAttr("varName", gp_vars)
|
var_names: np.ndarray = np.array(
|
||||||
|
self.model.getAttr("varName", gp_vars),
|
||||||
|
dtype="S",
|
||||||
|
)
|
||||||
var_types: List[str] = self.model.getAttr("vtype", gp_vars)
|
var_types: List[str] = self.model.getAttr("vtype", gp_vars)
|
||||||
var_ubs: np.ndarray = np.array(
|
var_ubs: np.ndarray = np.array(
|
||||||
self.model.getAttr("ub", gp_vars),
|
self.model.getAttr("ub", gp_vars),
|
||||||
@@ -599,7 +604,7 @@ class GurobiSolver(InternalSolver):
|
|||||||
dtype=float,
|
dtype=float,
|
||||||
)
|
)
|
||||||
constr_names: List[str] = self.model.getAttr("constrName", gp_constrs)
|
constr_names: List[str] = self.model.getAttr("constrName", gp_constrs)
|
||||||
varname_to_var: Dict = {}
|
varname_to_var: Dict[bytes, "gurobipy.Var"] = {}
|
||||||
cname_to_constr: Dict = {}
|
cname_to_constr: Dict = {}
|
||||||
for (i, gp_var) in enumerate(gp_vars):
|
for (i, gp_var) in enumerate(gp_vars):
|
||||||
assert var_names[i] not in varname_to_var, (
|
assert var_names[i] not in varname_to_var, (
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class MIPSolveStats:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Variables:
|
class Variables:
|
||||||
names: Optional[List[str]] = None
|
names: Optional[np.ndarray] = None
|
||||||
basis_status: Optional[List[str]] = None
|
basis_status: Optional[List[str]] = None
|
||||||
lower_bounds: Optional[np.ndarray] = None
|
lower_bounds: Optional[np.ndarray] = None
|
||||||
obj_coeffs: Optional[np.ndarray] = None
|
obj_coeffs: Optional[np.ndarray] = None
|
||||||
@@ -71,7 +71,7 @@ class Constraints:
|
|||||||
basis_status: Optional[List[str]] = None
|
basis_status: Optional[List[str]] = None
|
||||||
dual_values: Optional[np.ndarray] = None
|
dual_values: Optional[np.ndarray] = None
|
||||||
lazy: Optional[List[bool]] = None
|
lazy: Optional[List[bool]] = None
|
||||||
lhs: Optional[List[List[Tuple[str, float]]]] = None
|
lhs: Optional[List[List[Tuple[bytes, float]]]] = None
|
||||||
names: Optional[List[str]] = None
|
names: Optional[List[str]] = None
|
||||||
rhs: Optional[np.ndarray] = None
|
rhs: Optional[np.ndarray] = None
|
||||||
sa_rhs_down: Optional[np.ndarray] = None
|
sa_rhs_down: Optional[np.ndarray] = None
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ from miplearn.types import (
|
|||||||
SolverParams,
|
SolverParams,
|
||||||
UserCutCallback,
|
UserCutCallback,
|
||||||
Solution,
|
Solution,
|
||||||
VariableName,
|
|
||||||
Category,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -59,7 +57,7 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
self._is_warm_start_available: bool = False
|
self._is_warm_start_available: bool = False
|
||||||
self._pyomo_solver: SolverFactory = solver_factory
|
self._pyomo_solver: SolverFactory = solver_factory
|
||||||
self._obj_sense: str = "min"
|
self._obj_sense: str = "min"
|
||||||
self._varname_to_var: Dict[str, pe.Var] = {}
|
self._varname_to_var: Dict[bytes, pe.Var] = {}
|
||||||
self._cname_to_constr: Dict[str, pe.Constraint] = {}
|
self._cname_to_constr: Dict[str, pe.Constraint] = {}
|
||||||
self._termination_condition: str = ""
|
self._termination_condition: str = ""
|
||||||
self._has_lp_solution = False
|
self._has_lp_solution = False
|
||||||
@@ -166,7 +164,7 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
|
|
||||||
names: List[str] = []
|
names: List[str] = []
|
||||||
rhs: List[float] = []
|
rhs: List[float] = []
|
||||||
lhs: List[List[Tuple[str, float]]] = []
|
lhs: List[List[Tuple[bytes, float]]] = []
|
||||||
senses: List[str] = []
|
senses: List[str] = []
|
||||||
dual_values: List[float] = []
|
dual_values: List[float] = []
|
||||||
slacks: List[float] = []
|
slacks: List[float] = []
|
||||||
@@ -199,18 +197,18 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
if isinstance(term, MonomialTermExpression):
|
if isinstance(term, MonomialTermExpression):
|
||||||
lhsc.append(
|
lhsc.append(
|
||||||
(
|
(
|
||||||
term._args_[1].name,
|
term._args_[1].name.encode(),
|
||||||
float(term._args_[0]),
|
float(term._args_[0]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif isinstance(term, _GeneralVarData):
|
elif isinstance(term, _GeneralVarData):
|
||||||
lhsc.append((term.name, 1.0))
|
lhsc.append((term.name.encode(), 1.0))
|
||||||
else:
|
else:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"Unknown term type: {term.__class__.__name__}"
|
f"Unknown term type: {term.__class__.__name__}"
|
||||||
)
|
)
|
||||||
elif isinstance(expr, _GeneralVarData):
|
elif isinstance(expr, _GeneralVarData):
|
||||||
lhsc.append((expr.name, 1.0))
|
lhsc.append((expr.name.encode(), 1.0))
|
||||||
else:
|
else:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"Unknown expression type: {expr.__class__.__name__}"
|
f"Unknown expression type: {expr.__class__.__name__}"
|
||||||
@@ -264,7 +262,7 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
for index in var:
|
for index in var:
|
||||||
if var[index].fixed:
|
if var[index].fixed:
|
||||||
continue
|
continue
|
||||||
solution[f"{var}[{index}]"] = var[index].value
|
solution[f"{var}[{index}]".encode()] = var[index].value
|
||||||
return solution
|
return solution
|
||||||
|
|
||||||
@overrides
|
@overrides
|
||||||
@@ -328,7 +326,7 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
values.append(v.value)
|
values.append(v.value)
|
||||||
|
|
||||||
return Variables(
|
return Variables(
|
||||||
names=_none_if_empty(names),
|
names=_none_if_empty(np.array(names, dtype="S")),
|
||||||
types=_none_if_empty(types),
|
types=_none_if_empty(types),
|
||||||
upper_bounds=_none_if_empty(np.array(upper_bounds, dtype=float)),
|
upper_bounds=_none_if_empty(np.array(upper_bounds, dtype=float)),
|
||||||
lower_bounds=_none_if_empty(np.array(lower_bounds, dtype=float)),
|
lower_bounds=_none_if_empty(np.array(lower_bounds, dtype=float)),
|
||||||
@@ -558,9 +556,9 @@ class BasePyomoSolver(InternalSolver):
|
|||||||
self._varname_to_var = {}
|
self._varname_to_var = {}
|
||||||
for var in self.model.component_objects(Var):
|
for var in self.model.component_objects(Var):
|
||||||
for idx in var:
|
for idx in var:
|
||||||
varname = f"{var.name}[{idx}]"
|
varname = f"{var.name}[{idx}]".encode()
|
||||||
if idx is None:
|
if idx is None:
|
||||||
varname = var.name
|
varname = var.name.encode()
|
||||||
self._varname_to_var[varname] = var[idx]
|
self._varname_to_var[varname] = var[idx]
|
||||||
self._all_vars += [var[idx]]
|
self._all_vars += [var[idx]]
|
||||||
if var[idx].domain == pyomo.core.base.set_types.Binary:
|
if var[idx].domain == pyomo.core.base.set_types.Binary:
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from miplearn.solvers.internal import InternalSolver, Variables, Constraints
|
|||||||
|
|
||||||
inf = float("inf")
|
inf = float("inf")
|
||||||
|
|
||||||
|
|
||||||
# NOTE:
|
# NOTE:
|
||||||
# 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.
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ def run_basic_usage_tests(solver: InternalSolver) -> None:
|
|||||||
assert_equals(
|
assert_equals(
|
||||||
solver.get_variables(),
|
solver.get_variables(),
|
||||||
Variables(
|
Variables(
|
||||||
names=["x[0]", "x[1]", "x[2]", "x[3]", "z"],
|
names=np.array(["x[0]", "x[1]", "x[2]", "x[3]", "z"], dtype="S"),
|
||||||
lower_bounds=np.array([0.0, 0.0, 0.0, 0.0, 0.0]),
|
lower_bounds=np.array([0.0, 0.0, 0.0, 0.0, 0.0]),
|
||||||
upper_bounds=np.array([1.0, 1.0, 1.0, 1.0, 67.0]),
|
upper_bounds=np.array([1.0, 1.0, 1.0, 1.0, 67.0]),
|
||||||
types=["B", "B", "B", "B", "C"],
|
types=["B", "B", "B", "B", "C"],
|
||||||
@@ -56,11 +57,11 @@ def run_basic_usage_tests(solver: InternalSolver) -> None:
|
|||||||
rhs=np.array([0.0]),
|
rhs=np.array([0.0]),
|
||||||
lhs=[
|
lhs=[
|
||||||
[
|
[
|
||||||
("x[0]", 23.0),
|
(b"x[0]", 23.0),
|
||||||
("x[1]", 26.0),
|
(b"x[1]", 26.0),
|
||||||
("x[2]", 20.0),
|
(b"x[2]", 20.0),
|
||||||
("x[3]", 18.0),
|
(b"x[3]", 18.0),
|
||||||
("z", -1.0),
|
(b"z", -1.0),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
senses=["="],
|
senses=["="],
|
||||||
@@ -83,7 +84,7 @@ def run_basic_usage_tests(solver: InternalSolver) -> None:
|
|||||||
_filter_attrs(
|
_filter_attrs(
|
||||||
solver.get_variable_attrs(),
|
solver.get_variable_attrs(),
|
||||||
Variables(
|
Variables(
|
||||||
names=["x[0]", "x[1]", "x[2]", "x[3]", "z"],
|
names=np.array(["x[0]", "x[1]", "x[2]", "x[3]", "z"], dtype="S"),
|
||||||
basis_status=["U", "B", "U", "L", "U"],
|
basis_status=["U", "B", "U", "L", "U"],
|
||||||
reduced_costs=np.array(
|
reduced_costs=np.array(
|
||||||
[193.615385, 0.0, 187.230769, -23.692308, 13.538462]
|
[193.615385, 0.0, 187.230769, -23.692308, 13.538462]
|
||||||
@@ -140,7 +141,7 @@ def run_basic_usage_tests(solver: InternalSolver) -> None:
|
|||||||
_filter_attrs(
|
_filter_attrs(
|
||||||
solver.get_variable_attrs(),
|
solver.get_variable_attrs(),
|
||||||
Variables(
|
Variables(
|
||||||
names=["x[0]", "x[1]", "x[2]", "x[3]", "z"],
|
names=np.array(["x[0]", "x[1]", "x[2]", "x[3]", "z"], dtype="S"),
|
||||||
values=np.array([1.0, 0.0, 1.0, 1.0, 61.0]),
|
values=np.array([1.0, 0.0, 1.0, 1.0, 61.0]),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -161,7 +162,7 @@ def run_basic_usage_tests(solver: InternalSolver) -> None:
|
|||||||
# Build new constraint and verify that it is violated
|
# Build new constraint and verify that it is violated
|
||||||
cf = Constraints(
|
cf = Constraints(
|
||||||
names=["cut"],
|
names=["cut"],
|
||||||
lhs=[[("x[0]", 1.0)]],
|
lhs=[[(b"x[0]", 1.0)]],
|
||||||
rhs=np.array([0.0]),
|
rhs=np.array([0.0]),
|
||||||
senses=["<"],
|
senses=["<"],
|
||||||
)
|
)
|
||||||
@@ -178,14 +179,14 @@ def run_basic_usage_tests(solver: InternalSolver) -> None:
|
|||||||
rhs=np.array([0.0, 0.0]),
|
rhs=np.array([0.0, 0.0]),
|
||||||
lhs=[
|
lhs=[
|
||||||
[
|
[
|
||||||
("x[0]", 23.0),
|
(b"x[0]", 23.0),
|
||||||
("x[1]", 26.0),
|
(b"x[1]", 26.0),
|
||||||
("x[2]", 20.0),
|
(b"x[2]", 20.0),
|
||||||
("x[3]", 18.0),
|
(b"x[3]", 18.0),
|
||||||
("z", -1.0),
|
(b"z", -1.0),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
("x[0]", 1.0),
|
(b"x[0]", 1.0),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
senses=["=", "<"],
|
senses=["=", "<"],
|
||||||
@@ -208,16 +209,16 @@ def run_warm_start_tests(solver: InternalSolver) -> None:
|
|||||||
instance = solver.build_test_instance_knapsack()
|
instance = solver.build_test_instance_knapsack()
|
||||||
model = instance.to_model()
|
model = instance.to_model()
|
||||||
solver.set_instance(instance, model)
|
solver.set_instance(instance, model)
|
||||||
solver.set_warm_start({"x[0]": 1.0, "x[1]": 0.0, "x[2]": 0.0, "x[3]": 1.0})
|
solver.set_warm_start({b"x[0]": 1.0, b"x[1]": 0.0, b"x[2]": 0.0, b"x[3]": 1.0})
|
||||||
stats = solver.solve(tee=True)
|
stats = solver.solve(tee=True)
|
||||||
if stats.mip_warm_start_value is not None:
|
if stats.mip_warm_start_value is not None:
|
||||||
assert_equals(stats.mip_warm_start_value, 725.0)
|
assert_equals(stats.mip_warm_start_value, 725.0)
|
||||||
|
|
||||||
solver.set_warm_start({"x[0]": 1.0, "x[1]": 1.0, "x[2]": 1.0, "x[3]": 1.0})
|
solver.set_warm_start({b"x[0]": 1.0, b"x[1]": 1.0, b"x[2]": 1.0, b"x[3]": 1.0})
|
||||||
stats = solver.solve(tee=True)
|
stats = solver.solve(tee=True)
|
||||||
assert stats.mip_warm_start_value is None
|
assert stats.mip_warm_start_value is None
|
||||||
|
|
||||||
solver.fix({"x[0]": 1.0, "x[1]": 0.0, "x[2]": 0.0, "x[3]": 1.0})
|
solver.fix({b"x[0]": 1.0, b"x[1]": 0.0, b"x[2]": 0.0, b"x[3]": 1.0})
|
||||||
stats = solver.solve(tee=True)
|
stats = solver.solve(tee=True)
|
||||||
assert_equals(stats.mip_lower_bound, 725.0)
|
assert_equals(stats.mip_lower_bound, 725.0)
|
||||||
assert_equals(stats.mip_upper_bound, 725.0)
|
assert_equals(stats.mip_upper_bound, 725.0)
|
||||||
@@ -257,15 +258,15 @@ def run_lazy_cb_tests(solver: InternalSolver) -> None:
|
|||||||
def lazy_cb(cb_solver: InternalSolver, cb_model: Any) -> None:
|
def lazy_cb(cb_solver: InternalSolver, cb_model: Any) -> None:
|
||||||
relsol = cb_solver.get_solution()
|
relsol = cb_solver.get_solution()
|
||||||
assert relsol is not None
|
assert relsol is not None
|
||||||
assert relsol["x[0]"] is not None
|
assert relsol[b"x[0]"] is not None
|
||||||
if relsol["x[0]"] > 0:
|
if relsol[b"x[0]"] > 0:
|
||||||
instance.enforce_lazy_constraint(cb_solver, cb_model, "cut")
|
instance.enforce_lazy_constraint(cb_solver, cb_model, "cut")
|
||||||
|
|
||||||
solver.set_instance(instance, model)
|
solver.set_instance(instance, model)
|
||||||
solver.solve(lazy_cb=lazy_cb)
|
solver.solve(lazy_cb=lazy_cb)
|
||||||
solution = solver.get_solution()
|
solution = solver.get_solution()
|
||||||
assert solution is not None
|
assert solution is not None
|
||||||
assert_equals(solution["x[0]"], 0.0)
|
assert_equals(solution[b"x[0]"], 0.0)
|
||||||
|
|
||||||
|
|
||||||
def _equals_preprocess(obj: Any) -> Any:
|
def _equals_preprocess(obj: Any) -> Any:
|
||||||
@@ -274,7 +275,7 @@ def _equals_preprocess(obj: Any) -> Any:
|
|||||||
return np.round(obj, decimals=6).tolist()
|
return np.round(obj, decimals=6).tolist()
|
||||||
else:
|
else:
|
||||||
return obj.tolist()
|
return obj.tolist()
|
||||||
elif isinstance(obj, (int, str, bool, np.bool_)):
|
elif isinstance(obj, (int, str, bool, np.bool_, np.bytes_, bytes)):
|
||||||
return obj
|
return obj
|
||||||
elif isinstance(obj, float):
|
elif isinstance(obj, float):
|
||||||
return round(obj, 6)
|
return round(obj, 6)
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ IterationCallback = Callable[[], bool]
|
|||||||
LazyCallback = Callable[[Any, Any], None]
|
LazyCallback = Callable[[Any, Any], None]
|
||||||
SolverParams = Dict[str, Any]
|
SolverParams = Dict[str, Any]
|
||||||
UserCutCallback = Callable[["InternalSolver", Any], None]
|
UserCutCallback = Callable[["InternalSolver", Any], None]
|
||||||
VariableName = str
|
Solution = Dict[bytes, Optional[float]]
|
||||||
Solution = Dict[VariableName, Optional[float]]
|
|
||||||
|
|
||||||
LearningSolveStats = TypedDict(
|
LearningSolveStats = TypedDict(
|
||||||
"LearningSolveStats",
|
"LearningSolveStats",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from miplearn.solvers.tests import assert_equals
|
|||||||
def sample() -> Sample:
|
def sample() -> Sample:
|
||||||
sample = MemorySample(
|
sample = MemorySample(
|
||||||
{
|
{
|
||||||
"static_var_names": ["x[0]", "x[1]", "x[2]", "x[3]"],
|
"static_var_names": np.array(["x[0]", "x[1]", "x[2]", "x[3]"], dtype="S"),
|
||||||
"static_var_categories": ["default", None, "default", "default"],
|
"static_var_categories": ["default", None, "default", "default"],
|
||||||
"mip_var_values": np.array([0.0, 1.0, 1.0, 0.0]),
|
"mip_var_values": np.array([0.0, 1.0, 1.0, 0.0]),
|
||||||
"static_instance_features": [5.0],
|
"static_instance_features": [5.0],
|
||||||
@@ -112,10 +112,10 @@ def test_usage() -> None:
|
|||||||
def test_evaluate(sample: Sample) -> None:
|
def test_evaluate(sample: Sample) -> None:
|
||||||
comp = PrimalSolutionComponent()
|
comp = PrimalSolutionComponent()
|
||||||
comp.sample_predict = lambda _: { # type: ignore
|
comp.sample_predict = lambda _: { # type: ignore
|
||||||
"x[0]": 1.0,
|
b"x[0]": 1.0,
|
||||||
"x[1]": 1.0,
|
b"x[1]": 1.0,
|
||||||
"x[2]": 0.0,
|
b"x[2]": 0.0,
|
||||||
"x[3]": None,
|
b"x[3]": None,
|
||||||
}
|
}
|
||||||
ev = comp.sample_evaluate(None, sample)
|
ev = comp.sample_evaluate(None, sample)
|
||||||
assert_equals(
|
assert_equals(
|
||||||
@@ -150,8 +150,8 @@ def test_predict(sample: Sample) -> None:
|
|||||||
assert_array_equal(x["default"], clf.predict_proba.call_args[0][0])
|
assert_array_equal(x["default"], clf.predict_proba.call_args[0][0])
|
||||||
assert_array_equal(x["default"], thr.predict.call_args[0][0])
|
assert_array_equal(x["default"], thr.predict.call_args[0][0])
|
||||||
assert pred == {
|
assert pred == {
|
||||||
"x[0]": 0.0,
|
b"x[0]": 0.0,
|
||||||
"x[1]": None,
|
b"x[1]": None,
|
||||||
"x[2]": None,
|
b"x[2]": None,
|
||||||
"x[3]": 1.0,
|
b"x[3]": 1.0,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ def test_knapsack() -> None:
|
|||||||
extractor.extract_after_load_features(instance, solver, sample)
|
extractor.extract_after_load_features(instance, solver, sample)
|
||||||
assert_equals(
|
assert_equals(
|
||||||
sample.get_vector("static_var_names"),
|
sample.get_vector("static_var_names"),
|
||||||
["x[0]", "x[1]", "x[2]", "x[3]", "z"],
|
np.array(["x[0]", "x[1]", "x[2]", "x[3]", "z"], dtype="S"),
|
||||||
)
|
)
|
||||||
assert_equals(
|
assert_equals(
|
||||||
sample.get_vector("static_var_lower_bounds"), [0.0, 0.0, 0.0, 0.0, 0.0]
|
sample.get_vector("static_var_lower_bounds"), [0.0, 0.0, 0.0, 0.0, 0.0]
|
||||||
@@ -126,16 +126,16 @@ def test_constraint_getindex() -> None:
|
|||||||
senses=["=", "<", ">"],
|
senses=["=", "<", ">"],
|
||||||
lhs=[
|
lhs=[
|
||||||
[
|
[
|
||||||
("x1", 1.0),
|
(b"x1", 1.0),
|
||||||
("x2", 1.0),
|
(b"x2", 1.0),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
("x2", 2.0),
|
(b"x2", 2.0),
|
||||||
("x3", 2.0),
|
(b"x3", 2.0),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
("x3", 3.0),
|
(b"x3", 3.0),
|
||||||
("x4", 3.0),
|
(b"x4", 3.0),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -147,12 +147,12 @@ def test_constraint_getindex() -> None:
|
|||||||
senses=["=", ">"],
|
senses=["=", ">"],
|
||||||
lhs=[
|
lhs=[
|
||||||
[
|
[
|
||||||
("x1", 1.0),
|
(b"x1", 1.0),
|
||||||
("x2", 1.0),
|
(b"x2", 1.0),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
("x3", 3.0),
|
(b"x3", 3.0),
|
||||||
("x4", 3.0),
|
(b"x4", 3.0),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user