|
|
@ -10,6 +10,7 @@ from typing import TYPE_CHECKING, Dict, Optional, List, Any, Tuple, KeysView, ca
|
|
|
|
import numpy as np
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
|
|
|
from miplearn.features.sample import Sample
|
|
|
|
from miplearn.features.sample import Sample
|
|
|
|
|
|
|
|
from miplearn.solvers.internal import LPSolveStats
|
|
|
|
|
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
from miplearn.solvers.internal import InternalSolver
|
|
|
|
from miplearn.solvers.internal import InternalSolver
|
|
|
@ -66,7 +67,10 @@ class FeaturesExtractor:
|
|
|
|
self,
|
|
|
|
self,
|
|
|
|
solver: "InternalSolver",
|
|
|
|
solver: "InternalSolver",
|
|
|
|
sample: Sample,
|
|
|
|
sample: Sample,
|
|
|
|
|
|
|
|
lp_stats: LPSolveStats,
|
|
|
|
) -> None:
|
|
|
|
) -> None:
|
|
|
|
|
|
|
|
for (k, v) in lp_stats.__dict__.items():
|
|
|
|
|
|
|
|
sample.put_scalar(k, v)
|
|
|
|
variables = solver.get_variables(with_static=False, with_sa=self.with_sa)
|
|
|
|
variables = solver.get_variables(with_static=False, with_sa=self.with_sa)
|
|
|
|
constraints = solver.get_constraints(with_static=False, with_sa=self.with_sa)
|
|
|
|
constraints = solver.get_constraints(with_static=False, with_sa=self.with_sa)
|
|
|
|
sample.put_array("lp_var_basis_status", variables.basis_status)
|
|
|
|
sample.put_array("lp_var_basis_status", variables.basis_status)
|
|
|
@ -113,15 +117,21 @@ class FeaturesExtractor:
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
static_instance_features = sample.get_vector("static_instance_features")
|
|
|
|
|
|
|
|
|
|
|
|
# Build lp_instance_features
|
|
|
|
|
|
|
|
static_instance_features = sample.get_array("static_instance_features")
|
|
|
|
assert static_instance_features is not None
|
|
|
|
assert static_instance_features is not None
|
|
|
|
sample.put_vector(
|
|
|
|
assert lp_stats.lp_value is not None
|
|
|
|
|
|
|
|
assert lp_stats.lp_wallclock_time is not None
|
|
|
|
|
|
|
|
sample.put_array(
|
|
|
|
"lp_instance_features",
|
|
|
|
"lp_instance_features",
|
|
|
|
static_instance_features
|
|
|
|
np.hstack(
|
|
|
|
+ [
|
|
|
|
[
|
|
|
|
sample.get_scalar("lp_value"),
|
|
|
|
static_instance_features,
|
|
|
|
sample.get_scalar("lp_wallclock_time"),
|
|
|
|
lp_stats.lp_value,
|
|
|
|
],
|
|
|
|
lp_stats.lp_wallclock_time,
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def extract_after_mip_features(
|
|
|
|
def extract_after_mip_features(
|
|
|
@ -241,30 +251,22 @@ class FeaturesExtractor:
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
lazy.append(False)
|
|
|
|
lazy.append(False)
|
|
|
|
sample.put_vector_list("static_constr_features", user_features)
|
|
|
|
sample.put_vector_list("static_constr_features", user_features)
|
|
|
|
sample.put_array("static_constr_lazy", np.array(lazy, dtype=bool))
|
|
|
|
|
|
|
|
sample.put_array("static_constr_categories", np.array(categories, dtype="S"))
|
|
|
|
sample.put_array("static_constr_categories", np.array(categories, dtype="S"))
|
|
|
|
|
|
|
|
constr_lazy = np.array(lazy, dtype=bool)
|
|
|
|
|
|
|
|
sample.put_array("static_constr_lazy", constr_lazy)
|
|
|
|
|
|
|
|
sample.put_scalar("static_constr_lazy_count", int(constr_lazy.sum()))
|
|
|
|
|
|
|
|
|
|
|
|
def _extract_user_features_instance(
|
|
|
|
def _extract_user_features_instance(
|
|
|
|
self,
|
|
|
|
self,
|
|
|
|
instance: "Instance",
|
|
|
|
instance: "Instance",
|
|
|
|
sample: Sample,
|
|
|
|
sample: Sample,
|
|
|
|
) -> None:
|
|
|
|
) -> None:
|
|
|
|
user_features = instance.get_instance_features()
|
|
|
|
features = cast(np.ndarray, instance.get_instance_features())
|
|
|
|
if isinstance(user_features, np.ndarray):
|
|
|
|
if isinstance(features, list):
|
|
|
|
user_features = user_features.tolist()
|
|
|
|
features = np.array(features, dtype=float)
|
|
|
|
assert isinstance(user_features, list), (
|
|
|
|
assert isinstance(features, np.ndarray)
|
|
|
|
f"Instance features must be a list. "
|
|
|
|
assert features.dtype.kind in ["f"], f"Unsupported dtype: {features.dtype}"
|
|
|
|
f"Found {type(user_features).__name__} instead."
|
|
|
|
sample.put_array("static_instance_features", features)
|
|
|
|
)
|
|
|
|
|
|
|
|
for v in user_features:
|
|
|
|
|
|
|
|
assert isinstance(v, numbers.Real), (
|
|
|
|
|
|
|
|
f"Instance features must be a list of numbers. "
|
|
|
|
|
|
|
|
f"Found {type(v).__name__} instead."
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
constr_lazy = sample.get_array("static_constr_lazy")
|
|
|
|
|
|
|
|
assert constr_lazy is not None
|
|
|
|
|
|
|
|
sample.put_vector("static_instance_features", user_features)
|
|
|
|
|
|
|
|
sample.put_scalar("static_constr_lazy_count", int(sum(constr_lazy)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Alvarez, A. M., Louveaux, Q., & Wehenkel, L. (2017). A machine learning-based
|
|
|
|
# Alvarez, A. M., Louveaux, Q., & Wehenkel, L. (2017). A machine learning-based
|
|
|
|
# approximation of strong branching. INFORMS Journal on Computing, 29(1), 185-195.
|
|
|
|
# approximation of strong branching. INFORMS Journal on Computing, 29(1), 185-195.
|
|
|
|