Skip to content

Commit 75d6ea6

Browse files
lidingxulidingxuJoao-Dionisio
authored
More LPI functions and optimality check (#967)
* add parameter set and get functions for lpi * remove some unavailbale set and get functions * add comments and assertation for lp test * change function order * remove parameter tests and add isFeasPositive * optimality check before getsol for lpi, fix memory issue * Update src/pyscipopt/lp.pxi Co-authored-by: João Dionísio <[email protected]> * Update src/pyscipopt/lp.pxi Co-authored-by: João Dionísio <[email protected]> * Update src/pyscipopt/lp.pxi Co-authored-by: João Dionísio <[email protected]> * Update src/pyscipopt/lp.pxi Co-authored-by: João Dionísio <[email protected]> * fix conflict * style change * Update test_lp.py * typo --------- Co-authored-by: lidingxu <[email protected]> Co-authored-by: João Dionísio <[email protected]>
1 parent ccc3798 commit 75d6ea6

File tree

4 files changed

+64
-3
lines changed

4 files changed

+64
-3
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
## Unreleased
44
### Added
55
- Added getLinearConsIndicator
6-
- Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam for lpi
6+
- Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam, isOptimal, getObjVal, getRedcost for lpi
77
- Added isFeasPositive
88
### Fixed
99
### Changed

src/pyscipopt/lp.pxi

+47-2
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,31 @@ cdef class LP:
361361

362362
return objval
363363

364+
def isOptimal(self):
365+
"""
366+
returns true iff LP was solved to optimality.
367+
368+
Returns
369+
-------
370+
bool
371+
372+
"""
373+
return SCIPlpiIsOptimal(self.lpi)
374+
375+
def getObjVal(self):
376+
"""Returns the objective value of the last LP solve."""
377+
assert self.isOptimal(), "LP is not optimal"
378+
379+
cdef SCIP_Real objval
380+
381+
PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, &objval, NULL, NULL, NULL, NULL))
382+
383+
return objval
384+
364385
def getPrimal(self):
365386
"""Returns the primal solution of the last LP solve."""
387+
assert self.isOptimal(), "LP is not optimal"
388+
366389
cdef int ncols = self.ncols()
367390
cdef SCIP_Real* c_primalsol = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
368391
cdef int i
@@ -381,6 +404,8 @@ cdef class LP:
381404

382405
def getDual(self):
383406
"""Returns the dual solution of the last LP solve."""
407+
assert self.isOptimal(), "LP is not optimal"
408+
384409
cdef int nrows = self.nrows()
385410
cdef SCIP_Real* c_dualsol = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
386411
cdef int i
@@ -445,17 +470,37 @@ cdef class LP:
445470

446471
return niters
447472

473+
def getActivity(self):
474+
"""Returns the row activity vector of the last LP solve."""
475+
assert self.isOptimal(), "LP is not optimal"
476+
477+
cdef int nrows = self.nrows()
478+
cdef SCIP_Real* c_activity = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
479+
cdef int i
480+
481+
PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, NULL, NULL, NULL, c_activity, NULL))
482+
483+
activity = [0.0] * nrows
484+
for i in range(nrows):
485+
activity[i] = c_activity[i]
486+
487+
free(c_activity)
488+
489+
return activity
490+
448491
def getRedcost(self):
449492
"""Returns the reduced cost vector of the last LP solve."""
493+
assert self.isOptimal(), "LP is not optimal"
494+
450495
cdef int ncols = self.ncols()
451496
cdef SCIP_Real* c_redcost = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
452497
cdef int i
453498

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

456-
redcost = []
501+
redcost = [0.0] * ncols
457502
for i in range(ncols):
458-
redcost[i].append(c_redcost[i])
503+
redcost[i] = c_redcost[i]
459504

460505
free(c_redcost)
461506

src/pyscipopt/scip.pxd

+1
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,7 @@ cdef extern from "scip/scip.h":
13931393
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI* lpi, int* ncols)
13941394
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI* lpi)
13951395
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI* lpi)
1396+
SCIP_RETCODE SCIPlpiIsOptimal(SCIP_LPI* lpi)
13961397
SCIP_RETCODE SCIPlpiGetObjval(SCIP_LPI* lpi, SCIP_Real* objval)
13971398
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI* lpi, SCIP_Real* objval, SCIP_Real* primsol, SCIP_Real* dualsol, SCIP_Real* activity, SCIP_Real* redcost)
13981399
SCIP_RETCODE SCIPlpiGetIterations(SCIP_LPI* lpi, int* iterations)

tests/test_lp.py

+15
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,19 @@ def test_lp():
7373

7474
solval = myLP.solve()
7575

76+
assert(myLP.isOptimal())
77+
assert(myLP.getPrimal() is not None)
78+
assert(myLP.getDual() is not None)
79+
80+
redcost = myLP.getRedcost()
81+
assert(redcost is not None)
82+
for i in redcost:
83+
assert(i is not None)
84+
85+
activity = myLP.getActivity()
86+
assert(activity is not None)
87+
for i in activity:
88+
assert(i is not None)
89+
90+
assert round(myLP.getObjVal() == solval)
7691
assert round(5.0 == solval)

0 commit comments

Comments
 (0)