Source code for apem.order_book_based_model.euphemia.cutting_strategies.no_good
from typing import TYPE_CHECKING
from gurobipy import GRB
import gurobipy as gp
if TYPE_CHECKING:
from apem.order_book_based_model.euphemia.master_problem.master_problem import MasterProblem
def _log(self: "MasterProblem", message: str) -> None:
if hasattr(self, "run_logger"):
self.run_logger.info(message)
elif hasattr(self, "_emit"):
self._emit(message)
[docs]
def add_no_good_cut(self: "MasterProblem", callback_model: gp.Model) -> None:
"""Post a generic no-good cut for the current master-problem incumbent.
The cut inspects all binary master variables in the callback model and
constructs an exclusion constraint requiring at least one of them to flip
value in future incumbents.
:param self: Active Euphemia master-problem instance.
:param callback_model: Gurobi callback model used to post the lazy cut.
:return: ``None``.
"""
terms = []
# match variable from current solution with Gurobi variable from model
for gurobi_acceptance_var in callback_model.getVars():
if gurobi_acceptance_var.VType == GRB.BINARY:
solution_value = self.current_alloc_solution.get(gurobi_acceptance_var.VarName)
if solution_value is None:
_log(self, f"{gurobi_acceptance_var.VarName} not found in solution dict")
continue
if solution_value[0] > 0.5:
terms.append(1 - gurobi_acceptance_var)
else:
terms.append(gurobi_acceptance_var)
if terms:
expr = gp.quicksum(terms)
callback_model.cbLazy(expr >= 1)
_log(self, f"Added no good cut: {expr} >= 1")