Temporarily remove native solver callbacks; add iteration_cb

This commit is contained in:
2020-09-23 17:30:39 -05:00
parent e731f46b72
commit 425ea2b7cc
10 changed files with 201 additions and 189 deletions

View File

@@ -16,89 +16,23 @@ logger = logging.getLogger(__name__)
class GurobiPyomoSolver(BasePyomoSolver):
def __init__(self,
use_lazy_callbacks=True,
options=None):
"""
Creates a new Gurobi solver, accessed through Pyomo.
Parameters
----------
use_lazy_callbacks: bool
If true, lazy constraints will be enforced via lazy callbacks.
Otherwise, they will be enforced via a simple solve-check loop.
options: dict
Dictionary of options to pass to the Pyomo solver. For example,
{"Threads": 4} to set the number of threads.
"""
super().__init__()
self._use_lazy_callbacks = use_lazy_callbacks
self._pyomo_solver = pe.SolverFactory('gurobi_persistent')
self._pyomo_solver.options["Seed"] = randint(low=0, high=1000).rvs()
if options is not None:
for (key, value) in options.items():
self._pyomo_solver.options[key] = value
def solve(self, tee=False):
if self._use_lazy_callbacks:
return self._solve_with_callbacks(tee)
else:
return super().solve(tee)
def _solve_with_callbacks(self, tee):
from gurobipy import GRB
def cb(cb_model, cb_opt, cb_where):
try:
# User cuts
if cb_where == GRB.Callback.MIPNODE:
logger.debug("Finding violated cutting planes...")
cb_opt.cbGetNodeRel(self._all_vars)
violations = self.instance.find_violated_user_cuts(cb_model)
self.instance.found_violated_user_cuts += violations
logger.debug(" %d found" % len(violations))
for v in violations:
cut = self.instance.build_user_cut(cb_model, v)
cb_opt.cbCut(cut)
# Lazy constraints
if cb_where == GRB.Callback.MIPSOL:
cb_opt.cbGetSolution(self._all_vars)
logger.debug("Finding violated lazy constraints...")
violations = self.instance.find_violated_lazy_constraints(cb_model)
self.instance.found_violated_lazy_constraints += violations
logger.debug(" %d found" % len(violations))
for v in violations:
cut = self.instance.build_lazy_constraint(cb_model, v)
cb_opt.cbLazy(cut)
except Exception as e:
logger.error(e)
self._pyomo_solver.options["LazyConstraints"] = 1
self._pyomo_solver.options["PreCrush"] = 1
self._pyomo_solver.set_callback(cb)
self.instance.found_violated_lazy_constraints = []
self.instance.found_violated_user_cuts = []
streams = [StringIO()]
if tee:
streams += [sys.stdout]
with RedirectOutput(streams):
results = self._pyomo_solver.solve(tee=True,
warmstart=self._is_warm_start_available)
self._pyomo_solver.set_callback(None)
log = streams[0].getvalue()
return {
"Lower bound": results["Problem"][0]["Lower bound"],
"Upper bound": results["Problem"][0]["Upper bound"],
"Wallclock time": results["Solver"][0]["Wallclock time"],
"Nodes": self._extract_node_count(log),
"Sense": self._obj_sense,
"Log": log,
"Warm start value": self._extract_warm_start_value(log),
}
def _extract_node_count(self, log):
return max(1, int(self._pyomo_solver._solver_model.getAttr("NodeCount")))