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 ae2a00d05..503fdfe21 100644 --- a/src/pyscipopt/scip.pyx +++ b/src/pyscipopt/scip.pyx @@ -2053,36 +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) - LPsol = SCIPvarGetLPSol(_vars[0]) - rhs = SCIPgetRhsLinear(self._scip, transcons.cons) - lhs = SCIPgetLhsLinear(self._scip, transcons.cons) - if (LPsol == rhs) or (LPsol == lhs): - dual = SCIPgetVarRedcost(self._scip, _vars[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.getObjectiveSense() == "maximize": - dual = -dual - except: - raise Warning("no dual solution available for constraint " + cons.name) - return dual + 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.