From d844d3ad6d5932107c7fbbfba17bee68489f9d72 Mon Sep 17 00:00:00 2001 From: Matthias Miltenberger Date: Tue, 11 Sep 2018 12:53:09 +0200 Subject: [PATCH 1/2] compute activity before comparison with lhs/rhs for correct dualsols --- src/pyscipopt/scip.pyx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pyscipopt/scip.pyx b/src/pyscipopt/scip.pyx index ae2a00d05..fb4bc2eef 100644 --- a/src/pyscipopt/scip.pyx +++ b/src/pyscipopt/scip.pyx @@ -2056,6 +2056,7 @@ cdef class Model: # TODO this should ideally be handled on the SCIP side cdef int _nvars cdef SCIP_VAR** _vars + cdef SCIP_Real* _vals cdef SCIP_Bool _success dual = 0.0 @@ -2072,13 +2073,14 @@ cdef class Model: dual = SCIPgetDualsolLinear(self._scip, transcons.cons) if dual == 0.0 and _nvars == 1: _vars = SCIPgetVarsLinear(self._scip, transcons.cons) - LPsol = SCIPvarGetLPSol(_vars[0]) + _vals = SCIPgetValsLinear(self._scip, transcons.cons) + activity = SCIPvarGetLPSol(_vars[0]) * _vals[0] rhs = SCIPgetRhsLinear(self._scip, transcons.cons) lhs = SCIPgetLhsLinear(self._scip, transcons.cons) - if (LPsol == rhs) or (LPsol == lhs): + if (activity == rhs) or (activity == lhs): dual = SCIPgetVarRedcost(self._scip, _vars[0]) - if self.getObjectiveSense() == "maximize": + if self.getObjectiveSense() == "maximize" and not dual == 0.0: dual = -dual except: raise Warning("no dual solution available for constraint " + cons.name) From 1f1569128764f8180bbb9715788b692eca2c9c4d Mon Sep 17 00:00:00 2001 From: Matthias Miltenberger Date: Tue, 11 Sep 2018 15:40:28 +0200 Subject: [PATCH 2/2] use SCIP internal method for next release --- src/pyscipopt/scip.pxd | 1 + src/pyscipopt/scip.pyx | 58 +++++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index f1bd897e2..79dca3bf2 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -670,6 +670,7 @@ cdef extern from "scip/scip.h": SCIP_Real SCIPgetDualbound(SCIP* scip) SCIP_Real SCIPgetDualboundRoot(SCIP* scip) SCIP_Real SCIPgetVarRedcost(SCIP* scip, SCIP_VAR* var) + SCIP_RETCODE SCIPgetDualSolVal(SCIP* scip, SCIP_CONS* cons, SCIP_Real* dualsolval, SCIP_Bool* boundconstraint) # Reader plugin SCIP_RETCODE SCIPincludeReader(SCIP* scip, diff --git a/src/pyscipopt/scip.pyx b/src/pyscipopt/scip.pyx index fb4bc2eef..503fdfe21 100644 --- a/src/pyscipopt/scip.pyx +++ b/src/pyscipopt/scip.pyx @@ -2053,38 +2053,44 @@ cdef class Model: :param Constraint cons: linear constraint """ - # TODO this should ideally be handled on the SCIP side + cdef SCIP_Real dualsolval + cdef SCIP_Bool boundconstraint cdef int _nvars cdef SCIP_VAR** _vars cdef SCIP_Real* _vals cdef SCIP_Bool _success - dual = 0.0 - constype = bytes(SCIPconshdlrGetName(SCIPconsGetHdlr(cons.cons))).decode('UTF-8') - if not constype == 'linear': - raise Warning("dual solution values not available for constraints of type ", constype) + if self.version() > 6.0: + PY_SCIP_CALL( SCIPgetDualSolVal(self._scip, cons.cons, &dualsolval, &boundconstraint) ) + return dualsolval + else: + dual = 0.0 - try: - _nvars = SCIPgetNVarsLinear(self._scip, cons.cons) - if cons.isOriginal(): - transcons = self.getTransformedCons(cons) - else: - transcons = cons - dual = SCIPgetDualsolLinear(self._scip, transcons.cons) - if dual == 0.0 and _nvars == 1: - _vars = SCIPgetVarsLinear(self._scip, transcons.cons) - _vals = SCIPgetValsLinear(self._scip, transcons.cons) - activity = SCIPvarGetLPSol(_vars[0]) * _vals[0] - rhs = SCIPgetRhsLinear(self._scip, transcons.cons) - lhs = SCIPgetLhsLinear(self._scip, transcons.cons) - if (activity == rhs) or (activity == lhs): - dual = SCIPgetVarRedcost(self._scip, _vars[0]) - - if self.getObjectiveSense() == "maximize" and not dual == 0.0: - dual = -dual - except: - raise Warning("no dual solution available for constraint " + cons.name) - return dual + constype = bytes(SCIPconshdlrGetName(SCIPconsGetHdlr(cons.cons))).decode('UTF-8') + if not constype == 'linear': + raise Warning("dual solution values not available for constraints of type ", constype) + + try: + _nvars = SCIPgetNVarsLinear(self._scip, cons.cons) + if cons.isOriginal(): + transcons = self.getTransformedCons(cons) + else: + transcons = cons + dual = SCIPgetDualsolLinear(self._scip, transcons.cons) + if dual == 0.0 and _nvars == 1: + _vars = SCIPgetVarsLinear(self._scip, transcons.cons) + _vals = SCIPgetValsLinear(self._scip, transcons.cons) + activity = SCIPvarGetLPSol(_vars[0]) * _vals[0] + rhs = SCIPgetRhsLinear(self._scip, transcons.cons) + lhs = SCIPgetLhsLinear(self._scip, transcons.cons) + if (activity == rhs) or (activity == lhs): + dual = SCIPgetVarRedcost(self._scip, _vars[0]) + + if self.getObjectiveSense() == "maximize" and not dual == 0.0: + dual = -dual + except: + raise Warning("no dual solution available for constraint " + cons.name) + return dual def getDualfarkasLinear(self, Constraint cons): """Retrieve the dual farkas value to a linear constraint.