You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MIPLearn/miplearn/solvers.py

79 lines
2.6 KiB

# MIPLearn: A Machine-Learning Framework for Mixed-Integer Optimization
# Copyright (C) 2019-2020 Argonne National Laboratory. All rights reserved.
# Written by Alinson S. Xavier <axavier@anl.gov>
from .warmstart import *
import pyomo.environ as pe
import numpy as np
from math import isfinite
class LearningSolver:
"""
Mixed-Integer Linear Programming (MIP) solver that extracts information from previous runs,
using Machine Learning methods, to accelerate the solution of new (yet unseen) instances.
"""
def __init__(self,
threads = 4,
ws_predictor = None):
self.parent_solver = pe.SolverFactory('cplex_persistent')
self.parent_solver.options["threads"] = threads
self.train_x = None
self.train_y = None
self.ws_predictor = ws_predictor
def solve(self,
instance,
tee=False,
learn=True):
model = instance.to_model()
self.parent_solver.set_instance(model)
self.cplex = self.parent_solver._solver_model
x = self._get_features(instance)
if self.ws_predictor is not None:
self.cplex.MIP_starts.delete()
ws = self.ws_predictor.predict(x)
if ws is not None:
_add_warm_start(self.cplex, ws)
self.parent_solver.solve(tee=tee)
solution = np.array(self.cplex.solution.get_values())
y = np.transpose(np.vstack((solution, 1 - solution)))
self._update_training_set(x, y)
return y
def transform(self, instance):
model = instance.to_model()
self.parent_solver.set_instance(model)
self.cplex = self.parent_solver._solver_model
return self._get_features(instance)
def predict(self, instance):
pass
def _update_training_set(self, x, y):
if self.train_x is None:
self.train_x = x
self.train_y = y
else:
self.train_x = np.vstack((self.train_x, x))
self.train_y = np.vstack((self.train_y, y))
def fit(self):
if self.ws_predictor is not None:
self.ws_predictor.fit(self.train_x, self.train_y)
def _add_warm_start(cplex, ws):
assert isinstance(ws, np.ndarray)
assert ws.shape == (cplex.variables.get_num(),)
indices, values = [], []
for k in range(len(ws)):
if isfinite(ws[k]):
indices += [k]
values += [ws[k]]
print("Adding warm start with %d values" % len(indices))
cplex.MIP_starts.add([indices, values], cplex.MIP_starts.effort_level.solve_MIP)