Skip to content

Commit

Permalink
Merge pull request #743 from Joao-Dionisio/getPrimalRay
Browse files Browse the repository at this point in the history
Add hasPrimalRay, getPrimalRay, getPrimalRayVal
  • Loading branch information
mmghannam authored Nov 3, 2023
2 parents f95846e + 5e8774f commit 63db0c8
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
- Add SCIP functions SCIPchgCoefLinear, SCIPaddCoefLinear and SCIPdelCoefLinear
- Add SCIP function SCIPgetSolTime and wrapper getSolTime
- Add convenience methods relax and getVarDict
- Add SCIP functions hasPrimalRay, getPrimalRay, getPrimalRayVal
### Fixed
- Fixed typo in documentation of chgRhs
- Pricer plugin fundamental callbacks now raise an error if not implemented
- Brachrule plugin fundamental callbacks now raise an error if not implemented
- Fixed segmentation fault when accessing the Solution class directly
Expand Down
2 changes: 2 additions & 0 deletions src/pyscipopt/scip.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,8 @@ cdef extern from "scip/scip.h":
SCIP_Real SCIPgetPrimalbound(SCIP* scip)
SCIP_Real SCIPgetGap(SCIP* scip)
int SCIPgetDepth(SCIP* scip)
SCIP_Bool SCIPhasPrimalRay(SCIP * scip)
SCIP_Real SCIPgetPrimalRayVal(SCIP * scip, SCIP_VAR * var)
SCIP_RETCODE SCIPaddSolFree(SCIP* scip, SCIP_SOL** sol, SCIP_Bool* stored)
SCIP_RETCODE SCIPaddSol(SCIP* scip, SCIP_SOL* sol, SCIP_Bool* stored)
SCIP_RETCODE SCIPreadSol(SCIP* scip, const char* filename)
Expand Down
31 changes: 30 additions & 1 deletion src/pyscipopt/scip.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -2883,7 +2883,7 @@ cdef class Model:
"""Change right hand side value of a constraint.
:param Constraint cons: linear or quadratic constraint
:param rhs: new ride hand side (set to None for +infinity)
:param rhs: new right hand side (set to None for +infinity)
"""

Expand Down Expand Up @@ -4621,6 +4621,35 @@ cdef class Model:
if not self.getStage() >= SCIP_STAGE_SOLVING:
raise Warning("method cannot be called before problem is solved")
return self.getSolVal(self._bestSol, expr)

def hasPrimalRay(self):
"""
Returns whether a primal ray is stored that proves unboundedness of the LP relaxation
"""
return SCIPhasPrimalRay(self._scip)

def getPrimalRayVal(self, Variable var):
"""
Gets value of given variable in primal ray causing unboundedness of the LP relaxation
"""
assert SCIPhasPrimalRay(self._scip), "The problem does not have a primal ray."

return SCIPgetPrimalRayVal(self._scip, var.scip_var)

def getPrimalRay(self):
"""
Gets primal ray causing unboundedness of the LP relaxation
"""
assert SCIPhasPrimalRay(self._scip), "The problem does not have a primal ray."

cdef int _nvars = SCIPgetNVars(self._scip)
cdef SCIP_VAR ** _vars = SCIPgetVars(self._scip)

ray = []
for i in range(_nvars):
ray.append(float(SCIPgetPrimalRayVal(self._scip, _vars[i])))

return ray

def getPrimalbound(self):
"""Retrieve the best primal bound."""
Expand Down
46 changes: 43 additions & 3 deletions tests/test_solution.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pyscipopt import Model, scip
from pyscipopt import Model, scip, SCIP_PARAMSETTING
import pytest

def test_solution_getbest():
Expand Down Expand Up @@ -62,6 +62,47 @@ def test_solution_evaluation():
assert sol[expr] == m.getVal(expr)
assert sol[expr2] == m.getVal(expr2)

def test_hasPrimalRay():
m = Model()
x = m.addVar()
m.setObjective(x, "maximize")
m.setPresolve(SCIP_PARAMSETTING.OFF)

m.optimize()

assert m.hasPrimalRay()

m = Model()
x = m.addVar(lb = 0) # for readability
m.setPresolve(SCIP_PARAMSETTING.OFF)

m.optimize()

assert not m.hasPrimalRay()

def test_getPrimalRayVal():
m = Model()
x = m.addVar()
m.setObjective(x, "maximize")
m.setPresolve(SCIP_PARAMSETTING.OFF)

m.hideOutput()
m.optimize()

assert m.getPrimalRayVal(x) == 1

def test_getPrimalRay():
m = Model()
x = m.addVar()
y = m.addVar()
m.setObjective(x, "maximize")
m.setPresolve(SCIP_PARAMSETTING.OFF)

m.hideOutput()
m.optimize()

assert m.getPrimalRay() == [1,0]


def test_create_solution():
with pytest.raises(ValueError):
Expand All @@ -86,5 +127,4 @@ def test_getSols():
assert any(sol[x] == 0.0 for sol in m.getSols())

if __name__ == "__main__":
test_solution_getbest()
test_solution_create()
test_getPrimalRayVal()

0 comments on commit 63db0c8

Please sign in to comment.