mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 09:28:51 -06:00
Move collected data to instance.training_data
This commit is contained in:
@@ -78,7 +78,15 @@ class ObjectiveValueComponent(Component):
|
|||||||
|
|
||||||
def evaluate(self, instances):
|
def evaluate(self, instances):
|
||||||
y_pred = self.predict(instances)
|
y_pred = self.predict(instances)
|
||||||
y_true = np.array([[inst.lower_bound, inst.upper_bound] for inst in instances])
|
y_true = np.array(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
inst.training_data[0]["Lower bound"],
|
||||||
|
inst.training_data[0]["Upper bound"],
|
||||||
|
]
|
||||||
|
for inst in instances
|
||||||
|
]
|
||||||
|
)
|
||||||
y_true_lb, y_true_ub = y_true[:, 0], y_true[:, 1]
|
y_true_lb, y_true_ub = y_true[:, 0], y_true[:, 1]
|
||||||
y_pred_lb, y_pred_ub = y_pred[:, 1], y_pred[:, 1]
|
y_pred_lb, y_pred_ub = y_pred[:, 1], y_pred[:, 1]
|
||||||
ev = {
|
ev = {
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ class PrimalSolutionComponent(Component):
|
|||||||
for label in [0, 1]:
|
for label in [0, 1]:
|
||||||
y_train = solutions[category][:, label].astype(int)
|
y_train = solutions[category][:, label].astype(int)
|
||||||
|
|
||||||
# If all samples are either positive or negative, make constant predictions
|
# If all samples are either positive or negative, make constant
|
||||||
|
# predictions
|
||||||
y_avg = np.average(y_train)
|
y_avg = np.average(y_train)
|
||||||
if y_avg < 0.001 or y_avg >= 0.999:
|
if y_avg < 0.001 or y_avg >= 0.999:
|
||||||
self.classifiers[category, label] = round(y_avg)
|
self.classifiers[category, label] = round(y_avg)
|
||||||
@@ -130,7 +131,7 @@ class PrimalSolutionComponent(Component):
|
|||||||
desc="Evaluate (primal)",
|
desc="Evaluate (primal)",
|
||||||
):
|
):
|
||||||
instance = instances[instance_idx]
|
instance = instances[instance_idx]
|
||||||
solution_actual = instance.solution
|
solution_actual = instance.training_data[0]["Solution"]
|
||||||
solution_pred = self.predict(instance)
|
solution_pred = self.predict(instance)
|
||||||
|
|
||||||
vars_all, vars_one, vars_zero = set(), set(), set()
|
vars_all, vars_one, vars_zero = set(), set(), set()
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ def test_convert_tight_usage():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Solve original problem
|
# Solve original problem
|
||||||
solver.solve(instance)
|
stats = solver.solve(instance)
|
||||||
original_upper_bound = instance.upper_bound
|
original_upper_bound = stats["Upper bound"]
|
||||||
|
|
||||||
# Should collect training data
|
# Should collect training data
|
||||||
assert instance.training_data[0]["slacks"]["eq_capacity"] == 0.0
|
assert instance.training_data[0]["slacks"]["eq_capacity"] == 0.0
|
||||||
@@ -35,12 +35,12 @@ def test_convert_tight_usage():
|
|||||||
stats = solver.solve(instance)
|
stats = solver.solve(instance)
|
||||||
|
|
||||||
# Objective value should be the same
|
# Objective value should be the same
|
||||||
assert instance.upper_bound == original_upper_bound
|
assert stats["Upper bound"] == original_upper_bound
|
||||||
assert stats["ConvertTight: Inf iterations"] == 0
|
assert stats["ConvertTight: Inf iterations"] == 0
|
||||||
assert stats["ConvertTight: Subopt iterations"] == 0
|
assert stats["ConvertTight: Subopt iterations"] == 0
|
||||||
|
|
||||||
|
|
||||||
class TestInstance(Instance):
|
class SampleInstance(Instance):
|
||||||
def to_model(self):
|
def to_model(self):
|
||||||
import gurobipy as grb
|
import gurobipy as grb
|
||||||
|
|
||||||
@@ -70,9 +70,9 @@ def test_convert_tight_infeasibility():
|
|||||||
components=[comp],
|
components=[comp],
|
||||||
solve_lp_first=False,
|
solve_lp_first=False,
|
||||||
)
|
)
|
||||||
instance = TestInstance()
|
instance = SampleInstance()
|
||||||
stats = solver.solve(instance)
|
stats = solver.solve(instance)
|
||||||
assert instance.lower_bound == 5.0
|
assert stats["Upper bound"] == 5.0
|
||||||
assert stats["ConvertTight: Inf iterations"] == 1
|
assert stats["ConvertTight: Inf iterations"] == 1
|
||||||
assert stats["ConvertTight: Subopt iterations"] == 0
|
assert stats["ConvertTight: Subopt iterations"] == 0
|
||||||
|
|
||||||
@@ -93,9 +93,9 @@ def test_convert_tight_suboptimality():
|
|||||||
components=[comp],
|
components=[comp],
|
||||||
solve_lp_first=False,
|
solve_lp_first=False,
|
||||||
)
|
)
|
||||||
instance = TestInstance()
|
instance = SampleInstance()
|
||||||
stats = solver.solve(instance)
|
stats = solver.solve(instance)
|
||||||
assert instance.lower_bound == 5.0
|
assert stats["Upper bound"] == 5.0
|
||||||
assert stats["ConvertTight: Inf iterations"] == 0
|
assert stats["ConvertTight: Inf iterations"] == 0
|
||||||
assert stats["ConvertTight: Subopt iterations"] == 1
|
assert stats["ConvertTight: Subopt iterations"] == 1
|
||||||
|
|
||||||
@@ -116,8 +116,8 @@ def test_convert_tight_optimal():
|
|||||||
components=[comp],
|
components=[comp],
|
||||||
solve_lp_first=False,
|
solve_lp_first=False,
|
||||||
)
|
)
|
||||||
instance = TestInstance()
|
instance = SampleInstance()
|
||||||
stats = solver.solve(instance)
|
stats = solver.solve(instance)
|
||||||
assert instance.lower_bound == 5.0
|
assert stats["Upper bound"] == 5.0
|
||||||
assert stats["ConvertTight: Inf iterations"] == 0
|
assert stats["ConvertTight: Inf iterations"] == 0
|
||||||
assert stats["ConvertTight: Subopt iterations"] == 0
|
assert stats["ConvertTight: Subopt iterations"] == 0
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ def test_usage():
|
|||||||
instances, models = get_test_pyomo_instances()
|
instances, models = get_test_pyomo_instances()
|
||||||
comp = ObjectiveValueComponent()
|
comp = ObjectiveValueComponent()
|
||||||
comp.fit(instances)
|
comp.fit(instances)
|
||||||
assert instances[0].lower_bound == 1183.0
|
assert instances[0].training_data[0]["Lower bound"] == 1183.0
|
||||||
assert instances[0].upper_bound == 1183.0
|
assert instances[0].training_data[0]["Upper bound"] == 1183.0
|
||||||
assert np.round(comp.predict(instances), 2).tolist() == [
|
assert np.round(comp.predict(instances), 2).tolist() == [
|
||||||
[1183.0, 1183.0],
|
[1183.0, 1183.0],
|
||||||
[1070.0, 1070.0],
|
[1070.0, 1070.0],
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ def test_evaluate():
|
|||||||
comp = PrimalSolutionComponent(classifier=[clf_zero, clf_one], threshold=0.50)
|
comp = PrimalSolutionComponent(classifier=[clf_zero, clf_one], threshold=0.50)
|
||||||
comp.fit(instances[:1])
|
comp.fit(instances[:1])
|
||||||
assert comp.predict(instances[0]) == {"x": {0: 0, 1: 0, 2: 1, 3: None}}
|
assert comp.predict(instances[0]) == {"x": {0: 0, 1: 0, 2: 1, 3: None}}
|
||||||
assert instances[0].solution == {"x": {0: 1, 1: 0, 2: 1, 3: 1}}
|
assert instances[0].training_data[0]["Solution"] == {"x": {0: 1, 1: 0, 2: 1, 3: 1}}
|
||||||
ev = comp.evaluate(instances[:1])
|
ev = comp.evaluate(instances[:1])
|
||||||
assert ev == {
|
assert ev == {
|
||||||
"Fix one": {
|
"Fix one": {
|
||||||
|
|||||||
@@ -2,14 +2,13 @@
|
|||||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
# Copyright (C) 2020, 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.
|
||||||
|
|
||||||
|
import gzip
|
||||||
import logging
|
import logging
|
||||||
import pickle
|
import pickle
|
||||||
import gzip
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from tqdm.auto import tqdm
|
from tqdm.auto import tqdm
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -48,10 +47,10 @@ class Extractor(ABC):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def split_variables(instance):
|
def split_variables(instance):
|
||||||
assert hasattr(instance, "lp_solution")
|
|
||||||
result = {}
|
result = {}
|
||||||
for var_name in instance.lp_solution:
|
lp_solution = instance.training_data[0]["LP solution"]
|
||||||
for index in instance.lp_solution[var_name]:
|
for var_name in lp_solution:
|
||||||
|
for index in lp_solution[var_name]:
|
||||||
category = instance.get_variable_category(var_name, index)
|
category = instance.get_variable_category(var_name, index)
|
||||||
if category is None:
|
if category is None:
|
||||||
continue
|
continue
|
||||||
@@ -71,6 +70,7 @@ class VariableFeaturesExtractor(Extractor):
|
|||||||
):
|
):
|
||||||
instance_features = instance.get_instance_features()
|
instance_features = instance.get_instance_features()
|
||||||
var_split = self.split_variables(instance)
|
var_split = self.split_variables(instance)
|
||||||
|
lp_solution = instance.training_data[0]["LP solution"]
|
||||||
for (category, var_index_pairs) in var_split.items():
|
for (category, var_index_pairs) in var_split.items():
|
||||||
if category not in result:
|
if category not in result:
|
||||||
result[category] = []
|
result[category] = []
|
||||||
@@ -78,7 +78,7 @@ class VariableFeaturesExtractor(Extractor):
|
|||||||
result[category] += [
|
result[category] += [
|
||||||
instance_features.tolist()
|
instance_features.tolist()
|
||||||
+ instance.get_variable_features(var_name, index).tolist()
|
+ instance.get_variable_features(var_name, index).tolist()
|
||||||
+ [instance.lp_solution[var_name][index]]
|
+ [lp_solution[var_name][index]]
|
||||||
]
|
]
|
||||||
for category in result:
|
for category in result:
|
||||||
result[category] = np.array(result[category])
|
result[category] = np.array(result[category])
|
||||||
@@ -97,14 +97,15 @@ class SolutionExtractor(Extractor):
|
|||||||
disable=len(instances) < 5,
|
disable=len(instances) < 5,
|
||||||
):
|
):
|
||||||
var_split = self.split_variables(instance)
|
var_split = self.split_variables(instance)
|
||||||
|
if self.relaxation:
|
||||||
|
solution = instance.training_data[0]["LP solution"]
|
||||||
|
else:
|
||||||
|
solution = instance.training_data[0]["Solution"]
|
||||||
for (category, var_index_pairs) in var_split.items():
|
for (category, var_index_pairs) in var_split.items():
|
||||||
if category not in result:
|
if category not in result:
|
||||||
result[category] = []
|
result[category] = []
|
||||||
for (var_name, index) in var_index_pairs:
|
for (var_name, index) in var_index_pairs:
|
||||||
if self.relaxation:
|
v = solution[var_name][index]
|
||||||
v = instance.lp_solution[var_name][index]
|
|
||||||
else:
|
|
||||||
v = instance.solution[var_name][index]
|
|
||||||
if v is None:
|
if v is None:
|
||||||
result[category] += [[0, 0]]
|
result[category] += [[0, 0]]
|
||||||
else:
|
else:
|
||||||
@@ -121,7 +122,7 @@ class InstanceFeaturesExtractor(Extractor):
|
|||||||
np.hstack(
|
np.hstack(
|
||||||
[
|
[
|
||||||
instance.get_instance_features(),
|
instance.get_instance_features(),
|
||||||
instance.lp_value,
|
instance.training_data[0]["LP value"],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
for instance in InstanceIterator(instances)
|
for instance in InstanceIterator(instances)
|
||||||
@@ -137,13 +138,22 @@ class ObjectiveValueExtractor(Extractor):
|
|||||||
def extract(self, instances):
|
def extract(self, instances):
|
||||||
if self.kind == "lower bound":
|
if self.kind == "lower bound":
|
||||||
return np.array(
|
return np.array(
|
||||||
[[instance.lower_bound] for instance in InstanceIterator(instances)]
|
[
|
||||||
|
[instance.training_data[0]["Lower bound"]]
|
||||||
|
for instance in InstanceIterator(instances)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
if self.kind == "upper bound":
|
if self.kind == "upper bound":
|
||||||
return np.array(
|
return np.array(
|
||||||
[[instance.upper_bound] for instance in InstanceIterator(instances)]
|
[
|
||||||
|
[instance.training_data[0]["Upper bound"]]
|
||||||
|
for instance in InstanceIterator(instances)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
if self.kind == "lp":
|
if self.kind == "lp":
|
||||||
return np.array(
|
return np.array(
|
||||||
[[instance.lp_value] for instance in InstanceIterator(instances)]
|
[
|
||||||
|
[instance.training_data[0]["LP value"]]
|
||||||
|
for instance in InstanceIterator(instances)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ def test_stab():
|
|||||||
weights = [1.0, 1.0, 1.0, 1.0, 1.0]
|
weights = [1.0, 1.0, 1.0, 1.0, 1.0]
|
||||||
instance = MaxWeightStableSetInstance(graph, weights)
|
instance = MaxWeightStableSetInstance(graph, weights)
|
||||||
solver = LearningSolver()
|
solver = LearningSolver()
|
||||||
solver.solve(instance)
|
stats = solver.solve(instance)
|
||||||
assert instance.lower_bound == 2.0
|
assert stats["Lower bound"] == 2.0
|
||||||
|
|
||||||
|
|
||||||
def test_stab_generator_fixed_graph():
|
def test_stab_generator_fixed_graph():
|
||||||
|
|||||||
@@ -38,16 +38,16 @@ def test_instance():
|
|||||||
)
|
)
|
||||||
instance = TravelingSalesmanInstance(n_cities, distances)
|
instance = TravelingSalesmanInstance(n_cities, distances)
|
||||||
solver = LearningSolver()
|
solver = LearningSolver()
|
||||||
solver.solve(instance)
|
stats = solver.solve(instance)
|
||||||
x = instance.solution["x"]
|
x = instance.training_data[0]["Solution"]["x"]
|
||||||
assert x[0, 1] == 1.0
|
assert x[0, 1] == 1.0
|
||||||
assert x[0, 2] == 0.0
|
assert x[0, 2] == 0.0
|
||||||
assert x[0, 3] == 1.0
|
assert x[0, 3] == 1.0
|
||||||
assert x[1, 2] == 1.0
|
assert x[1, 2] == 1.0
|
||||||
assert x[1, 3] == 0.0
|
assert x[1, 3] == 0.0
|
||||||
assert x[2, 3] == 1.0
|
assert x[2, 3] == 1.0
|
||||||
assert instance.lower_bound == 4.0
|
assert stats["Lower bound"] == 4.0
|
||||||
assert instance.upper_bound == 4.0
|
assert stats["Upper bound"] == 4.0
|
||||||
|
|
||||||
|
|
||||||
def test_subtour():
|
def test_subtour():
|
||||||
@@ -68,7 +68,7 @@ def test_subtour():
|
|||||||
solver.solve(instance)
|
solver.solve(instance)
|
||||||
assert hasattr(instance, "found_violated_lazy_constraints")
|
assert hasattr(instance, "found_violated_lazy_constraints")
|
||||||
assert hasattr(instance, "found_violated_user_cuts")
|
assert hasattr(instance, "found_violated_user_cuts")
|
||||||
x = instance.solution["x"]
|
x = instance.training_data[0]["Solution"]["x"]
|
||||||
assert x[0, 1] == 1.0
|
assert x[0, 1] == 1.0
|
||||||
assert x[0, 4] == 1.0
|
assert x[0, 4] == 1.0
|
||||||
assert x[1, 2] == 1.0
|
assert x[1, 2] == 1.0
|
||||||
|
|||||||
@@ -115,11 +115,11 @@ class LearningSolver:
|
|||||||
|
|
||||||
def solve(
|
def solve(
|
||||||
self,
|
self,
|
||||||
instance,
|
instance: Union[Instance, str],
|
||||||
model=None,
|
model: Any = None,
|
||||||
output="",
|
output: str = "",
|
||||||
tee=False,
|
tee: bool = False,
|
||||||
):
|
) -> MIPSolveStats:
|
||||||
"""
|
"""
|
||||||
Solves the given instance. If trained machine-learning models are
|
Solves the given instance. If trained machine-learning models are
|
||||||
available, they will be used to accelerate the solution process.
|
available, they will be used to accelerate the solution process.
|
||||||
@@ -127,20 +127,9 @@ class LearningSolver:
|
|||||||
The argument `instance` may be either an Instance object or a
|
The argument `instance` may be either an Instance object or a
|
||||||
filename pointing to a pickled Instance object.
|
filename pointing to a pickled Instance object.
|
||||||
|
|
||||||
This method modifies the instance object. Specifically, the following
|
This method adds a new training sample to `instance.training_sample`.
|
||||||
properties are set:
|
If a filename is provided, then the file is modified in-place. That is,
|
||||||
|
the original file is overwritten.
|
||||||
- instance.lp_solution
|
|
||||||
- instance.lp_value
|
|
||||||
- instance.lower_bound
|
|
||||||
- instance.upper_bound
|
|
||||||
- instance.solution
|
|
||||||
- instance.solver_log
|
|
||||||
|
|
||||||
Additional solver components may set additional properties. Please
|
|
||||||
see their documentation for more details. If a filename is provided,
|
|
||||||
then the file is modified in-place. That is, the original file is
|
|
||||||
overwritten.
|
|
||||||
|
|
||||||
If `solver.solve_lp_first` is False, the properties lp_solution and
|
If `solver.solve_lp_first` is False, the properties lp_solution and
|
||||||
lp_value will be set to dummy values.
|
lp_value will be set to dummy values.
|
||||||
@@ -190,7 +179,7 @@ class LearningSolver:
|
|||||||
|
|
||||||
def _solve(
|
def _solve(
|
||||||
self,
|
self,
|
||||||
instance: Instance,
|
instance: Union[Instance, str],
|
||||||
model: Any = None,
|
model: Any = None,
|
||||||
output: str = "",
|
output: str = "",
|
||||||
tee: bool = False,
|
tee: bool = False,
|
||||||
@@ -211,14 +200,18 @@ class LearningSolver:
|
|||||||
fileformat = "pickle"
|
fileformat = "pickle"
|
||||||
with open(filename, "rb") as file:
|
with open(filename, "rb") as file:
|
||||||
instance = pickle.load(cast(IO[bytes], file))
|
instance = pickle.load(cast(IO[bytes], file))
|
||||||
|
assert isinstance(instance, Instance)
|
||||||
|
|
||||||
# Generate model
|
# Generate model
|
||||||
if model is None:
|
if model is None:
|
||||||
with RedirectOutput([]):
|
with RedirectOutput([]):
|
||||||
model = instance.to_model()
|
model = instance.to_model()
|
||||||
|
|
||||||
# Initialize training data
|
# Initialize training sample
|
||||||
training_sample: TrainingSample = {}
|
training_sample: TrainingSample = {}
|
||||||
|
if not hasattr(instance, "training_data"):
|
||||||
|
instance.training_data = []
|
||||||
|
instance.training_data += [training_sample]
|
||||||
|
|
||||||
# Initialize internal solver
|
# Initialize internal solver
|
||||||
self.tee = tee
|
self.tee = tee
|
||||||
@@ -275,11 +268,6 @@ class LearningSolver:
|
|||||||
for component in self.components.values():
|
for component in self.components.values():
|
||||||
component.after_solve(self, instance, model, stats, training_sample)
|
component.after_solve(self, instance, model, stats, training_sample)
|
||||||
|
|
||||||
# Append training data
|
|
||||||
if not hasattr(instance, "training_data"):
|
|
||||||
instance.training_data = []
|
|
||||||
instance.training_data += [training_sample]
|
|
||||||
|
|
||||||
# Write to file, if necessary
|
# Write to file, if necessary
|
||||||
if filename is not None and output is not None:
|
if filename is not None and output is not None:
|
||||||
output_filename = output
|
output_filename = output
|
||||||
@@ -350,7 +338,7 @@ class LearningSolver:
|
|||||||
self._restore_miplearn_logger()
|
self._restore_miplearn_logger()
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
def fit(self, training_instances):
|
def fit(self, training_instances: Union[List[str], List[Instance]]) -> None:
|
||||||
if len(training_instances) == 0:
|
if len(training_instances) == 0:
|
||||||
return
|
return
|
||||||
for component in self.components.values():
|
for component in self.components.values():
|
||||||
|
|||||||
@@ -25,20 +25,19 @@ def test_learning_solver():
|
|||||||
)
|
)
|
||||||
|
|
||||||
solver.solve(instance)
|
solver.solve(instance)
|
||||||
assert instance.solution["x"][0] == 1.0
|
data = instance.training_data[0]
|
||||||
assert instance.solution["x"][1] == 0.0
|
assert data["Solution"]["x"][0] == 1.0
|
||||||
assert instance.solution["x"][2] == 1.0
|
assert data["Solution"]["x"][1] == 0.0
|
||||||
assert instance.solution["x"][3] == 1.0
|
assert data["Solution"]["x"][2] == 1.0
|
||||||
assert instance.lower_bound == 1183.0
|
assert data["Solution"]["x"][3] == 1.0
|
||||||
assert instance.upper_bound == 1183.0
|
assert data["Lower bound"] == 1183.0
|
||||||
assert round(instance.lp_solution["x"][0], 3) == 1.000
|
assert data["Upper bound"] == 1183.0
|
||||||
assert round(instance.lp_solution["x"][1], 3) == 0.923
|
assert round(data["LP solution"]["x"][0], 3) == 1.000
|
||||||
assert round(instance.lp_solution["x"][2], 3) == 1.000
|
assert round(data["LP solution"]["x"][1], 3) == 0.923
|
||||||
assert round(instance.lp_solution["x"][3], 3) == 0.000
|
assert round(data["LP solution"]["x"][2], 3) == 1.000
|
||||||
assert round(instance.lp_value, 3) == 1287.923
|
assert round(data["LP solution"]["x"][3], 3) == 0.000
|
||||||
assert instance.found_violated_lazy_constraints == []
|
assert round(data["LP value"], 3) == 1287.923
|
||||||
assert instance.found_violated_user_cuts == []
|
assert len(data["MIP log"]) > 100
|
||||||
assert len(instance.solver_log) > 100
|
|
||||||
|
|
||||||
solver.fit([instance])
|
solver.fit([instance])
|
||||||
solver.solve(instance)
|
solver.solve(instance)
|
||||||
@@ -55,7 +54,8 @@ def test_parallel_solve():
|
|||||||
results = solver.parallel_solve(instances, n_jobs=3)
|
results = solver.parallel_solve(instances, n_jobs=3)
|
||||||
assert len(results) == 10
|
assert len(results) == 10
|
||||||
for instance in instances:
|
for instance in instances:
|
||||||
assert len(instance.solution["x"].keys()) == 4
|
data = instance.training_data[0]
|
||||||
|
assert len(data["Solution"]["x"].keys()) == 4
|
||||||
|
|
||||||
|
|
||||||
def test_solve_fit_from_disk():
|
def test_solve_fit_from_disk():
|
||||||
@@ -73,14 +73,14 @@ def test_solve_fit_from_disk():
|
|||||||
solver.solve(filenames[0])
|
solver.solve(filenames[0])
|
||||||
with open(filenames[0], "rb") as file:
|
with open(filenames[0], "rb") as file:
|
||||||
instance = pickle.load(file)
|
instance = pickle.load(file)
|
||||||
assert hasattr(instance, "solution")
|
assert len(instance.training_data) > 0
|
||||||
|
|
||||||
# Test: parallel_solve
|
# Test: parallel_solve
|
||||||
solver.parallel_solve(filenames)
|
solver.parallel_solve(filenames)
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
with open(filename, "rb") as file:
|
with open(filename, "rb") as file:
|
||||||
instance = pickle.load(file)
|
instance = pickle.load(file)
|
||||||
assert hasattr(instance, "solution")
|
assert len(instance.training_data) > 0
|
||||||
|
|
||||||
# Test: solve (with specified output)
|
# Test: solve (with specified output)
|
||||||
output = [f + ".out" for f in filenames]
|
output = [f + ".out" for f in filenames]
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ from typing import TypedDict, Optional, Dict, Callable, Any
|
|||||||
TrainingSample = TypedDict(
|
TrainingSample = TypedDict(
|
||||||
"TrainingSample",
|
"TrainingSample",
|
||||||
{
|
{
|
||||||
"LP log": Optional[str],
|
"LP log": str,
|
||||||
"LP solution": Optional[Dict],
|
"LP solution": Dict,
|
||||||
"LP value": Optional[float],
|
"LP value": float,
|
||||||
"Lower bound": Optional[float],
|
"Lower bound": float,
|
||||||
"MIP log": Optional[str],
|
"MIP log": str,
|
||||||
"Solution": Optional[Dict],
|
"Solution": Dict,
|
||||||
"Upper bound": Optional[float],
|
"Upper bound": float,
|
||||||
|
"slacks": Dict,
|
||||||
},
|
},
|
||||||
total=False,
|
total=False,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user