I'm using PySCIPOpt (SCIP version 6.0.2, PySCIPOpt version 2.2.3) to solve a mixed integer problem. A constraint handler should be checking and enforcing some of the requirements that are not modeled directly into the problem (lazy constraints).
Problem: the presolving is simplifying the original problem so much (deleting variables) such that constraints that are inserted by the constraint handler (after the presolving) lead to infeasibility.
In the example below are only two binary variables and a set partitioning constraint present. Presolving is able to remove all variables and constraints. The constraint handler restricts the x_0
variable to 0 and the problem gets infeasible. If presolving is turned off, the "correct" solution x_1 = 1
is found.
from pyscipopt import Model, quicksum, Conshdlr, SCIP_RESULT, SCIP_PRESOLTIMING, SCIP_PROPTIMING, SCIP_PARAMSETTING
class ConshdlrNotZero(Conshdlr):
def __init__(self):
pass
def conscheck(self, constraints, solution, checkintegrality, checklprows, printreason, completely):
x = self.data
if self.model.getSolVal(solution, x[0]) > 0.5:
return {"result": SCIP_RESULT.INFEASIBLE}
return {"result": SCIP_RESULT.FEASIBLE}
def consenfolp(self, constraints, nusefulconss, solinfeasible):
x = self.data
if self.model.getSolVal(None, x[0]) > 0.5:
self.model.addCons(x[0] <= 0, name='fix_x0')
return {"result": SCIP_RESULT.CONSADDED}
return {"result": SCIP_RESULT.FEASIBLE}
def conslock(self, constraint, locktype, nlockspos, nlocksneg):
pass
m = Model('test_presolve')
x = dict()
x[0] = m.addVar(vtype='BINARY', obj=0, name="x_%d" % 0)
x[1] = m.addVar(vtype='BINARY', obj=1, name="x_%d" % 1)
m.addCons(quicksum(x_var for x_var in x.values()) == 1, name="set_partitioning")
conshdlr = ConshdlrNotZero()
conshdlr.data = x
m.includeConshdlr(conshdlr, "n0", "please not the x_0 variable",
sepapriority=-1, enfopriority=-1, chckpriority=-1, sepafreq=-1, propfreq=-1,
eagerfreq=-1, maxprerounds=0, delaysepa=False, delayprop=False, needscons=False,
presoltiming=SCIP_PRESOLTIMING.FAST, proptiming=SCIP_PROPTIMING.BEFORELP)
# m.setPresolve(SCIP_PARAMSETTING.OFF)
m.setMinimize()
m.optimize()
m.printSol()
Is there a way to ensure considering the constraint handler in the presolving (except disabling presolving)?
Edit: Disabling dual reductions (set misc/allowdualreds to 0) within presolving works. I'm still wondering why this solves the problem and if there is a better solution.