diff --git a/miplearn/solvers.py b/miplearn/solvers.py index e6298fe..fd44ba9 100644 --- a/miplearn/solvers.py +++ b/miplearn/solvers.py @@ -4,6 +4,7 @@ from . import WarmStartComponent, BranchPriorityComponent import pyomo.environ as pe +from pyomo.core import Var from copy import deepcopy import pickle from scipy.stats import randint @@ -76,7 +77,7 @@ class LearningSolver: if self.threads is not None: self.internal_solver.options["Threads"] = self.threads if self.time_limit is not None: - self.internal_solver.options["TimeLimit"] = self.time_limit + self.internal_solver.options["timelimit"] = self.time_limit if self.gap_limit is not None: self.internal_solver.options["MIPGap"] = self.gap_limit @@ -100,6 +101,14 @@ class LearningSolver: else: solve_results = self.internal_solver.solve(model, tee=tee, warmstart=is_warm_start_available) + instance.solution = {} + instance.lower_bound = solve_results["Problem"][0]["Lower bound"] + instance.upper_bound = solve_results["Problem"][0]["Upper bound"] + for var in model.component_objects(Var): + instance.solution[str(var)] = {} + for index in var: + instance.solution[str(var)][index] = var[index].value + if self.internal_solver.name == "gurobi_persistent": solve_results["Solver"][0]["Nodes"] = self.internal_solver._solver_model.getAttr("NodeCount") else: @@ -124,11 +133,22 @@ class LearningSolver: solver.internal_solver = None if not collect_training_data: solver.components = {} - return solver, results + return { + "solver": solver, + "results": results, + "solution": instance.solution, + "upper bound": instance.upper_bound, + "lower bound": instance.lower_bound, + } - solver_result_pairs = p_map(_process, instances, num_cpus=n_jobs, desc=label) - subsolvers = [p[0] for p in solver_result_pairs] - results = [p[1] for p in solver_result_pairs] + p_map_results = p_map(_process, instances, num_cpus=n_jobs, desc=label) + subsolvers = [p["solver"] for p in p_map_results] + results = [p["results"] for p in p_map_results] + + for (idx, r) in enumerate(p_map_results): + instances[idx].solution = r["solution"] + instances[idx].lower_bound = r["lower bound"] + instances[idx].upper_bound = r["upper bound"] for (name, component) in self.components.items(): subcomponents = [subsolver.components[name] diff --git a/miplearn/tests/test_solver.py b/miplearn/tests/test_solver.py index 6a9db3f..df66f7b 100644 --- a/miplearn/tests/test_solver.py +++ b/miplearn/tests/test_solver.py @@ -18,6 +18,13 @@ def test_solver(): instance = _get_instance() solver = LearningSolver() solver.solve(instance) + assert instance.solution["x"][0] == 1.0 + assert instance.solution["x"][1] == 0.0 + assert instance.solution["x"][2] == 1.0 + assert instance.solution["x"][3] == 1.0 + assert instance.lower_bound == 1183.0 + assert instance.upper_bound == 1183.0 + solver.fit() solver.solve(instance) @@ -52,3 +59,6 @@ def test_parallel_solve(): assert len(solver.components["warm-start"].x_train["default"]) == 40 assert len(solver.components["warm-start"].y_train["default"]) == 40 + for instance in instances: + assert len(instance.solution["x"].keys()) == 4 +