Skip to content
Merged
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Unreleased
### Added
- Added getLinearConsIndicator
- Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam for lpi
- Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam, isOptimal, getObjVal, getRedcost for lpi
- Added isFeasPositive
### Fixed
### Changed
Expand Down
49 changes: 47 additions & 2 deletions src/pyscipopt/lp.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,31 @@ cdef class LP:

return objval

def isOptimal(self):
"""
returns true iff LP was solved to optimality.

Returns
-------
bool

"""
return SCIPlpiIsOptimal(self.lpi)

def getObjVal(self):
"""Returns the objective value of the last LP solve."""
assert self.isOptimal(), "LP is not optimal"

cdef SCIP_Real objval

PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, &objval, NULL, NULL, NULL, NULL))

return objval

def getPrimal(self):
"""Returns the primal solution of the last LP solve."""
assert self.isOptimal(), "LP is not optimal"

cdef int ncols = self.ncols()
cdef SCIP_Real* c_primalsol = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
cdef int i
Expand All @@ -381,6 +404,8 @@ cdef class LP:

def getDual(self):
"""Returns the dual solution of the last LP solve."""
assert self.isOptimal(), "LP is not optimal"

cdef int nrows = self.nrows()
cdef SCIP_Real* c_dualsol = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
cdef int i
Expand Down Expand Up @@ -445,17 +470,37 @@ cdef class LP:

return niters

def getActivity(self):
"""Returns the row activity vector of the last LP solve."""
assert self.isOptimal(), "LP is not optimal"

cdef int nrows = self.nrows()
cdef SCIP_Real* c_activity = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
cdef int i

PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, NULL, NULL, NULL, c_activity, NULL))

activity = [0.0] * nrows
for i in range(nrows):
activity[i] = c_activity[i]

free(c_activity)

return activity

def getRedcost(self):
"""Returns the reduced cost vector of the last LP solve."""
assert self.isOptimal(), "LP is not optimal"

cdef int ncols = self.ncols()
cdef SCIP_Real* c_redcost = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
cdef int i

PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, NULL, NULL, NULL, NULL, c_redcost))

redcost = []
redcost = [0.0] * ncols
for i in range(ncols):
redcost[i].append(c_redcost[i])
redcost[i] = c_redcost[i]

free(c_redcost)

Expand Down
1 change: 1 addition & 0 deletions src/pyscipopt/scip.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,7 @@ cdef extern from "scip/scip.h":
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI* lpi, int* ncols)
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI* lpi)
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI* lpi)
SCIP_RETCODE SCIPlpiIsOptimal(SCIP_LPI* lpi)
SCIP_RETCODE SCIPlpiGetObjval(SCIP_LPI* lpi, SCIP_Real* objval)
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI* lpi, SCIP_Real* objval, SCIP_Real* primsol, SCIP_Real* dualsol, SCIP_Real* activity, SCIP_Real* redcost)
SCIP_RETCODE SCIPlpiGetIterations(SCIP_LPI* lpi, int* iterations)
Expand Down
15 changes: 15 additions & 0 deletions tests/test_lp.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,19 @@ def test_lp():

solval = myLP.solve()

assert(myLP.isOptimal())
assert(myLP.getPrimal() is not None)
assert(myLP.getDual() is not None)

redcost = myLP.getRedcost()
assert(redcost is not None)
for i in redcost:
assert(i is not None)

activity = myLP.getActivity()
assert(activity is not None)
for i in activity:
assert(i is not None)

assert round(myLP.getObjVal() == solval)
assert round(5.0 == solval)
Loading