0

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.

M. Kruber
  • 11
  • 3

1 Answers1

0

Dual reductions in presolving mean that they possibly cut off optimal solutions, but leave at least one optimal solution.

Your reasoning seems to exploit knowledge of the original feasible region, so it makes sense that you have to disable dual presolving reductions.

Leon
  • 1,588
  • 1
  • 7
  • 16