mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 09:28:51 -06:00
Remove sample.after_lp
This commit is contained in:
@@ -77,20 +77,15 @@ class ObjectiveValueComponent(Component):
|
|||||||
_: Optional[Instance],
|
_: Optional[Instance],
|
||||||
sample: Sample,
|
sample: Sample,
|
||||||
) -> Tuple[Dict[Hashable, List[List[float]]], Dict[Hashable, List[List[float]]]]:
|
) -> Tuple[Dict[Hashable, List[List[float]]], Dict[Hashable, List[List[float]]]]:
|
||||||
# Instance features
|
lp_instance_features = sample.get("lp_instance_features")
|
||||||
assert sample.after_load is not None
|
if lp_instance_features is None:
|
||||||
assert sample.after_load.instance is not None
|
lp_instance_features = sample.get("instance_features_user")
|
||||||
f = sample.after_load.instance.to_list()
|
assert lp_instance_features is not None
|
||||||
|
|
||||||
# LP solve features
|
|
||||||
if sample.after_lp is not None:
|
|
||||||
assert sample.after_lp.lp_solve is not None
|
|
||||||
f.extend(sample.after_lp.lp_solve.to_list())
|
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
x: Dict[Hashable, List[List[float]]] = {
|
x: Dict[Hashable, List[List[float]]] = {
|
||||||
"Upper bound": [f],
|
"Upper bound": [lp_instance_features],
|
||||||
"Lower bound": [f],
|
"Lower bound": [lp_instance_features],
|
||||||
}
|
}
|
||||||
|
|
||||||
# Labels
|
# Labels
|
||||||
|
|||||||
@@ -155,7 +155,15 @@ class PrimalSolutionComponent(Component):
|
|||||||
assert sample.after_load.variables is not None
|
assert sample.after_load.variables is not None
|
||||||
assert sample.after_load.variables.names is not None
|
assert sample.after_load.variables.names is not None
|
||||||
assert sample.after_load.variables.categories is not None
|
assert sample.after_load.variables.categories is not None
|
||||||
|
|
||||||
|
instance_features = sample.get("instance_features_user")
|
||||||
mip_var_values = sample.get("mip_var_values")
|
mip_var_values = sample.get("mip_var_values")
|
||||||
|
var_features = sample.get("lp_var_features")
|
||||||
|
if var_features is None:
|
||||||
|
var_features = sample.get("var_features")
|
||||||
|
|
||||||
|
assert instance_features is not None
|
||||||
|
assert var_features is not None
|
||||||
|
|
||||||
for (i, var_name) in enumerate(sample.after_load.variables.names):
|
for (i, var_name) in enumerate(sample.after_load.variables.names):
|
||||||
# Initialize categories
|
# Initialize categories
|
||||||
@@ -167,11 +175,8 @@ class PrimalSolutionComponent(Component):
|
|||||||
y[category] = []
|
y[category] = []
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
features = list(sample.after_load.instance.to_list())
|
features = list(instance_features)
|
||||||
features.extend(sample.after_load.variables.to_list(i))
|
features.extend(var_features[i])
|
||||||
if sample.after_lp is not None:
|
|
||||||
assert sample.after_lp.variables is not None
|
|
||||||
features.extend(sample.after_lp.variables.to_list(i))
|
|
||||||
x[category].append(features)
|
x[category].append(features)
|
||||||
|
|
||||||
# Labels
|
# Labels
|
||||||
|
|||||||
@@ -204,17 +204,26 @@ class StaticLazyConstraintsComponent(Component):
|
|||||||
x: Dict[Hashable, List[List[float]]] = {}
|
x: Dict[Hashable, List[List[float]]] = {}
|
||||||
y: Dict[Hashable, List[List[float]]] = {}
|
y: Dict[Hashable, List[List[float]]] = {}
|
||||||
cids: Dict[Hashable, List[str]] = {}
|
cids: Dict[Hashable, List[str]] = {}
|
||||||
assert sample.after_load is not None
|
instance_features = sample.get("instance_features_user")
|
||||||
constraints = sample.after_load.constraints
|
constr_features = sample.get("lp_constr_features")
|
||||||
assert constraints is not None
|
constr_names = sample.get("constr_names")
|
||||||
assert constraints.names is not None
|
constr_categories = sample.get("constr_categories")
|
||||||
assert constraints.lazy is not None
|
constr_lazy = sample.get("constr_lazy")
|
||||||
assert constraints.categories is not None
|
lazy_enforced = sample.get("lazy_enforced")
|
||||||
for (cidx, cname) in enumerate(constraints.names):
|
if constr_features is None:
|
||||||
|
constr_features = sample.get("constr_features_user")
|
||||||
|
|
||||||
|
assert instance_features is not None
|
||||||
|
assert constr_features is not None
|
||||||
|
assert constr_names is not None
|
||||||
|
assert constr_categories is not None
|
||||||
|
assert constr_lazy is not None
|
||||||
|
|
||||||
|
for (cidx, cname) in enumerate(constr_names):
|
||||||
# Initialize categories
|
# Initialize categories
|
||||||
if not constraints.lazy[cidx]:
|
if not constr_lazy[cidx]:
|
||||||
continue
|
continue
|
||||||
category = constraints.categories[cidx]
|
category = constr_categories[cidx]
|
||||||
if category is None:
|
if category is None:
|
||||||
continue
|
continue
|
||||||
if category not in x:
|
if category not in x:
|
||||||
@@ -223,18 +232,12 @@ class StaticLazyConstraintsComponent(Component):
|
|||||||
cids[category] = []
|
cids[category] = []
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
sf = sample.after_load
|
features = list(instance_features)
|
||||||
if sample.after_lp is not None:
|
features.extend(constr_features[cidx])
|
||||||
sf = sample.after_lp
|
|
||||||
assert sf.instance is not None
|
|
||||||
assert sf.constraints is not None
|
|
||||||
features = list(sf.instance.to_list())
|
|
||||||
features.extend(sf.constraints.to_list(cidx))
|
|
||||||
x[category].append(features)
|
x[category].append(features)
|
||||||
cids[category].append(cname)
|
cids[category].append(cname)
|
||||||
|
|
||||||
# Labels
|
# Labels
|
||||||
lazy_enforced = sample.get("lazy_enforced")
|
|
||||||
if lazy_enforced is not None:
|
if lazy_enforced is not None:
|
||||||
if cname in lazy_enforced:
|
if cname in lazy_enforced:
|
||||||
y[category] += [[False, True]]
|
y[category] += [[False, True]]
|
||||||
|
|||||||
@@ -147,14 +147,12 @@ class Sample:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
after_load: Optional[Features] = None,
|
after_load: Optional[Features] = None,
|
||||||
after_lp: Optional[Features] = None,
|
|
||||||
data: Optional[Dict[str, Any]] = None,
|
data: Optional[Dict[str, Any]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
self._data: Dict[str, Any] = data
|
self._data: Dict[str, Any] = data
|
||||||
self.after_load = after_load
|
self.after_load = after_load
|
||||||
self.after_lp = after_lp
|
|
||||||
|
|
||||||
def get(self, key: str) -> Optional[Any]:
|
def get(self, key: str) -> Optional[Any]:
|
||||||
if key in self._data:
|
if key in self._data:
|
||||||
@@ -253,6 +251,29 @@ class FeaturesExtractor:
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
sample.put(
|
||||||
|
"lp_constr_features",
|
||||||
|
self._combine(
|
||||||
|
sample,
|
||||||
|
[
|
||||||
|
"constr_features_user",
|
||||||
|
"lp_constr_dual_values",
|
||||||
|
"lp_constr_sa_rhs_down",
|
||||||
|
"lp_constr_sa_rhs_up",
|
||||||
|
"lp_constr_slacks",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
instance_features_user = sample.get("instance_features_user")
|
||||||
|
assert instance_features_user is not None
|
||||||
|
sample.put(
|
||||||
|
"lp_instance_features",
|
||||||
|
instance_features_user
|
||||||
|
+ [
|
||||||
|
sample.get("lp_value"),
|
||||||
|
sample.get("lp_wallclock_time"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def extract_after_mip_features(
|
def extract_after_mip_features(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -210,20 +210,13 @@ class LearningSolver:
|
|||||||
# -------------------------------------------------------
|
# -------------------------------------------------------
|
||||||
logger.info("Extracting features (after-lp)...")
|
logger.info("Extracting features (after-lp)...")
|
||||||
initial_time = time.time()
|
initial_time = time.time()
|
||||||
|
for (k, v) in lp_stats.__dict__.items():
|
||||||
|
sample.put(k, v)
|
||||||
self.extractor.extract_after_lp_features(self.internal_solver, sample)
|
self.extractor.extract_after_lp_features(self.internal_solver, sample)
|
||||||
features = self.extractor.extract(
|
|
||||||
instance,
|
|
||||||
self.internal_solver,
|
|
||||||
with_static=False,
|
|
||||||
)
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"Features (after-lp) extracted in %.2f seconds"
|
"Features (after-lp) extracted in %.2f seconds"
|
||||||
% (time.time() - initial_time)
|
% (time.time() - initial_time)
|
||||||
)
|
)
|
||||||
for (k, v) in lp_stats.__dict__.items():
|
|
||||||
sample.put(k, v)
|
|
||||||
features.lp_solve = lp_stats
|
|
||||||
sample.after_lp = features
|
|
||||||
|
|
||||||
# Callback wrappers
|
# Callback wrappers
|
||||||
# -------------------------------------------------------
|
# -------------------------------------------------------
|
||||||
@@ -285,9 +278,9 @@ class LearningSolver:
|
|||||||
# -------------------------------------------------------
|
# -------------------------------------------------------
|
||||||
logger.info("Extracting features (after-mip)...")
|
logger.info("Extracting features (after-mip)...")
|
||||||
initial_time = time.time()
|
initial_time = time.time()
|
||||||
self.extractor.extract_after_mip_features(self.internal_solver, sample)
|
|
||||||
for (k, v) in mip_stats.__dict__.items():
|
for (k, v) in mip_stats.__dict__.items():
|
||||||
sample.put(k, v)
|
sample.put(k, v)
|
||||||
|
self.extractor.extract_after_mip_features(self.internal_solver, sample)
|
||||||
logger.info(
|
logger.info(
|
||||||
"Features (after-mip) extracted in %.2f seconds"
|
"Features (after-mip) extracted in %.2f seconds"
|
||||||
% (time.time() - initial_time)
|
% (time.time() - initial_time)
|
||||||
|
|||||||
@@ -19,19 +19,12 @@ from miplearn.solvers.pyomo.gurobi import GurobiPyomoSolver
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def sample() -> Sample:
|
def sample() -> Sample:
|
||||||
sample = Sample(
|
sample = Sample(
|
||||||
after_load=Features(
|
|
||||||
instance=InstanceFeatures(),
|
|
||||||
),
|
|
||||||
after_lp=Features(
|
|
||||||
lp_solve=LPSolveStats(),
|
|
||||||
),
|
|
||||||
data={
|
data={
|
||||||
"mip_lower_bound": 1.0,
|
"mip_lower_bound": 1.0,
|
||||||
"mip_upper_bound": 2.0,
|
"mip_upper_bound": 2.0,
|
||||||
|
"lp_instance_features": [1.0, 2.0, 3.0],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
sample.after_load.instance.to_list = Mock(return_value=[1.0, 2.0]) # type: ignore
|
|
||||||
sample.after_lp.lp_solve.to_list = Mock(return_value=[3.0]) # type: ignore
|
|
||||||
return sample
|
return sample
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,23 @@ def sample() -> Sample:
|
|||||||
categories=["default", None, "default", "default"],
|
categories=["default", None, "default", "default"],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
after_lp=Features(
|
|
||||||
variables=VariableFeatures(),
|
|
||||||
),
|
|
||||||
data={
|
data={
|
||||||
"var_names": ["x[0]", "x[1]", "x[2]", "x[3]"],
|
"var_names": ["x[0]", "x[1]", "x[2]", "x[3]"],
|
||||||
|
"var_categories": ["default", None, "default", "default"],
|
||||||
"mip_var_values": [0.0, 1.0, 1.0, 0.0],
|
"mip_var_values": [0.0, 1.0, 1.0, 0.0],
|
||||||
|
"instance_features_user": [5.0],
|
||||||
|
"var_features": [
|
||||||
|
[0.0, 0.0],
|
||||||
|
None,
|
||||||
|
[1.0, 0.0],
|
||||||
|
[1.0, 1.0],
|
||||||
|
],
|
||||||
|
"lp_var_features": [
|
||||||
|
[0.0, 0.0, 2.0, 2.0],
|
||||||
|
None,
|
||||||
|
[1.0, 0.0, 3.0, 2.0],
|
||||||
|
[1.0, 1.0, 3.0, 3.0],
|
||||||
|
],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
sample.after_load.instance.to_list = Mock(return_value=[5.0]) # type: ignore
|
sample.after_load.instance.to_list = Mock(return_value=[5.0]) # type: ignore
|
||||||
@@ -50,14 +61,6 @@ def sample() -> Sample:
|
|||||||
[1.0, 1.0],
|
[1.0, 1.0],
|
||||||
][i]
|
][i]
|
||||||
)
|
)
|
||||||
sample.after_lp.variables.to_list = Mock( # type:ignore
|
|
||||||
side_effect=lambda i: [
|
|
||||||
[2.0, 2.0],
|
|
||||||
None,
|
|
||||||
[3.0, 2.0],
|
|
||||||
[3.0, 3.0],
|
|
||||||
][i]
|
|
||||||
)
|
|
||||||
return sample
|
return sample
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,24 +44,28 @@ def sample() -> Sample:
|
|||||||
lazy=[True, True, True, True, False],
|
lazy=[True, True, True, True, False],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
after_lp=Features(
|
|
||||||
instance=InstanceFeatures(),
|
|
||||||
constraints=ConstraintFeatures(names=["c1", "c2", "c3", "c4", "c5"]),
|
|
||||||
),
|
|
||||||
data={
|
data={
|
||||||
|
"constr_categories": [
|
||||||
|
"type-a",
|
||||||
|
"type-a",
|
||||||
|
"type-a",
|
||||||
|
"type-b",
|
||||||
|
"type-b",
|
||||||
|
],
|
||||||
|
"constr_lazy": [True, True, True, True, False],
|
||||||
|
"constr_names": ["c1", "c2", "c3", "c4", "c5"],
|
||||||
|
"instance_features_user": [5.0],
|
||||||
"lazy_enforced": {"c1", "c2", "c4"},
|
"lazy_enforced": {"c1", "c2", "c4"},
|
||||||
|
"lp_constr_features": [
|
||||||
|
[1.0, 1.0],
|
||||||
|
[1.0, 2.0],
|
||||||
|
[1.0, 3.0],
|
||||||
|
[1.0, 4.0, 0.0],
|
||||||
|
None,
|
||||||
|
],
|
||||||
|
"static_lazy_count": 4,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
sample.after_lp.instance.to_list = Mock(return_value=[5.0]) # type: ignore
|
|
||||||
sample.after_lp.constraints.to_list = Mock( # type: ignore
|
|
||||||
side_effect=lambda idx: {
|
|
||||||
0: [1.0, 1.0],
|
|
||||||
1: [1.0, 2.0],
|
|
||||||
2: [1.0, 3.0],
|
|
||||||
3: [1.0, 4.0, 0.0],
|
|
||||||
4: None,
|
|
||||||
}[idx]
|
|
||||||
)
|
|
||||||
return sample
|
return sample
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user