From 8a1dd62e2cc107e612d92c3631b304c88f5e122b Mon Sep 17 00:00:00 2001 From: lidingxu Date: Wed, 19 Mar 2025 13:44:11 +0100 Subject: [PATCH 01/14] add parameter set and get functions for lpi --- CHANGELOG.md | 1 + src/pyscipopt/__init__.py | 1 + src/pyscipopt/lp.pxi | 73 +++++++ src/pyscipopt/scip.pxd | 416 ++++++++++++++++++++------------------ src/pyscipopt/scip.pxi | 208 ++++++++++--------- tests/test_lp.py | 31 +++ 6 files changed, 443 insertions(+), 287 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f310be426..9b2a02324 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased ### Added - Added getLinearConsIndicator +- Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam ### Fixed ### Changed ### Removed diff --git a/src/pyscipopt/__init__.py b/src/pyscipopt/__init__.py index 713e125ec..3f18cb1bf 100644 --- a/src/pyscipopt/__init__.py +++ b/src/pyscipopt/__init__.py @@ -26,6 +26,7 @@ from pyscipopt.scip import Reader from pyscipopt.scip import Sepa from pyscipopt.scip import LP +from pyscipopt.scip import PY_SCIP_LPPARAM as SCIP_LPPARAM from pyscipopt.scip import readStatistics from pyscipopt.scip import Expr from pyscipopt.scip import MatrixExpr diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index c17c900ad..b768c9159 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -476,3 +476,76 @@ cdef class LP: free(c_binds) return binds + + # Parameter Methods + + def setIntParam(self, param, value): + """ + Set an int-valued parameter. + + Parameters + ---------- + param : SCIP_LPPARAM + name of parameter + value : int + value of parameter + + """ + PY_SCIP_CALL(SCIPlpiSetIntpar(self.lpi, param, value)) + + def setRealParam(self, param, value): + """ + Set a real-valued parameter. + + Parameters + ---------- + param : SCIP_LPPARAM + name of parameter + value : float + value of parameter + + """ + PY_SCIP_CALL(SCIPlpiSetRealpar(self.lpi, param, value)) + + + def getIntParam(self, param): + """ + Get the value of a parameter of type + float. + + Parameters + ---------- + param : SCIP_LPPARAM + name of parameter + + Returns + ------- + float + + """ + cdef SCIP_Real value + + PY_SCIP_CALL(SCIPlpiGetRealpar(self.lpi, param, &value)) + + return value + + def getIntParam(self, param): + """ + Get the value of a parameter of type + int. + + Parameters + ---------- + param : SCIP_LPPARAM + name of parameter + + Returns + ------- + int + + """ + cdef int value + + PY_SCIP_CALL(SCIPlpiGetIntpar(self.lpi, param, &value)) + + return value diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index b05ec4e8a..6f6a3d455 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -2,127 +2,127 @@ #@brief holding prototype of the SCIP public functions to use them in PySCIPOpt cdef extern from "scip/scip.h": # SCIP internal types - ctypedef int SCIP_RETCODE + ctypedef int SCIP_RETCODE cdef extern from "scip/type_retcode.h": - SCIP_RETCODE SCIP_OKAY - SCIP_RETCODE SCIP_ERROR - SCIP_RETCODE SCIP_NOMEMORY - SCIP_RETCODE SCIP_READERROR - SCIP_RETCODE SCIP_WRITEERROR - SCIP_RETCODE SCIP_NOFILE - SCIP_RETCODE SCIP_FILECREATEERROR - SCIP_RETCODE SCIP_LPERROR - SCIP_RETCODE SCIP_NOPROBLEM - SCIP_RETCODE SCIP_INVALIDCALL - SCIP_RETCODE SCIP_INVALIDDATA - SCIP_RETCODE SCIP_INVALIDRESULT - SCIP_RETCODE SCIP_PLUGINNOTFOUND - SCIP_RETCODE SCIP_PARAMETERUNKNOWN - SCIP_RETCODE SCIP_PARAMETERWRONGTYPE - SCIP_RETCODE SCIP_PARAMETERWRONGVAL - SCIP_RETCODE SCIP_KEYALREADYEXISTING - SCIP_RETCODE SCIP_MAXDEPTHLEVEL + SCIP_RETCODE SCIP_OKAY + SCIP_RETCODE SCIP_ERROR + SCIP_RETCODE SCIP_NOMEMORY + SCIP_RETCODE SCIP_READERROR + SCIP_RETCODE SCIP_WRITEERROR + SCIP_RETCODE SCIP_NOFILE + SCIP_RETCODE SCIP_FILECREATEERROR + SCIP_RETCODE SCIP_LPERROR + SCIP_RETCODE SCIP_NOPROBLEM + SCIP_RETCODE SCIP_INVALIDCALL + SCIP_RETCODE SCIP_INVALIDDATA + SCIP_RETCODE SCIP_INVALIDRESULT + SCIP_RETCODE SCIP_PLUGINNOTFOUND + SCIP_RETCODE SCIP_PARAMETERUNKNOWN + SCIP_RETCODE SCIP_PARAMETERWRONGTYPE + SCIP_RETCODE SCIP_PARAMETERWRONGVAL + SCIP_RETCODE SCIP_KEYALREADYEXISTING + SCIP_RETCODE SCIP_MAXDEPTHLEVEL ctypedef int SCIP_VARTYPE cdef extern from "scip/type_var.h": - SCIP_VARTYPE SCIP_VARTYPE_BINARY - SCIP_VARTYPE SCIP_VARTYPE_INTEGER - SCIP_VARTYPE SCIP_VARTYPE_IMPLINT - SCIP_VARTYPE SCIP_VARTYPE_CONTINUOUS + SCIP_VARTYPE SCIP_VARTYPE_BINARY + SCIP_VARTYPE SCIP_VARTYPE_INTEGER + SCIP_VARTYPE SCIP_VARTYPE_IMPLINT + SCIP_VARTYPE SCIP_VARTYPE_CONTINUOUS ctypedef int SCIP_OBJSENSE cdef extern from "scip/type_prob.h": - SCIP_OBJSENSE SCIP_OBJSENSE_MAXIMIZE - SCIP_OBJSENSE SCIP_OBJSENSE_MINIMIZE + SCIP_OBJSENSE SCIP_OBJSENSE_MAXIMIZE + SCIP_OBJSENSE SCIP_OBJSENSE_MINIMIZE # This version is used in LPI. - ctypedef int SCIP_OBJSEN + ctypedef int SCIP_OBJSEN cdef extern from "lpi/type_lpi.h": - SCIP_OBJSEN SCIP_OBJSEN_MAXIMIZE - SCIP_OBJSEN SCIP_OBJSEN_MINIMIZE + SCIP_OBJSEN SCIP_OBJSEN_MAXIMIZE + SCIP_OBJSEN SCIP_OBJSEN_MINIMIZE - ctypedef int SCIP_BOUNDTYPE + ctypedef int SCIP_BOUNDTYPE cdef extern from "scip/type_lp.h": - SCIP_BOUNDTYPE SCIP_BOUNDTYPE_LOWER - SCIP_BOUNDTYPE SCIP_BOUNDTYPE_UPPER + SCIP_BOUNDTYPE SCIP_BOUNDTYPE_LOWER + SCIP_BOUNDTYPE SCIP_BOUNDTYPE_UPPER - ctypedef int SCIP_RESULT + ctypedef int SCIP_RESULT cdef extern from "scip/type_result.h": - SCIP_RESULT SCIP_DIDNOTRUN - SCIP_RESULT SCIP_DELAYED - SCIP_RESULT SCIP_DIDNOTFIND - SCIP_RESULT SCIP_FEASIBLE - SCIP_RESULT SCIP_INFEASIBLE - SCIP_RESULT SCIP_UNBOUNDED - SCIP_RESULT SCIP_CUTOFF - SCIP_RESULT SCIP_SEPARATED - SCIP_RESULT SCIP_NEWROUND - SCIP_RESULT SCIP_REDUCEDDOM - SCIP_RESULT SCIP_CONSADDED - SCIP_RESULT SCIP_CONSCHANGED - SCIP_RESULT SCIP_BRANCHED - SCIP_RESULT SCIP_SOLVELP - SCIP_RESULT SCIP_FOUNDSOL - SCIP_RESULT SCIP_SUSPENDED - SCIP_RESULT SCIP_SUCCESS - - ctypedef int SCIP_STATUS + SCIP_RESULT SCIP_DIDNOTRUN + SCIP_RESULT SCIP_DELAYED + SCIP_RESULT SCIP_DIDNOTFIND + SCIP_RESULT SCIP_FEASIBLE + SCIP_RESULT SCIP_INFEASIBLE + SCIP_RESULT SCIP_UNBOUNDED + SCIP_RESULT SCIP_CUTOFF + SCIP_RESULT SCIP_SEPARATED + SCIP_RESULT SCIP_NEWROUND + SCIP_RESULT SCIP_REDUCEDDOM + SCIP_RESULT SCIP_CONSADDED + SCIP_RESULT SCIP_CONSCHANGED + SCIP_RESULT SCIP_BRANCHED + SCIP_RESULT SCIP_SOLVELP + SCIP_RESULT SCIP_FOUNDSOL + SCIP_RESULT SCIP_SUSPENDED + SCIP_RESULT SCIP_SUCCESS + + ctypedef int SCIP_STATUS cdef extern from "scip/type_stat.h": - SCIP_STATUS SCIP_STATUS_UNKNOWN - SCIP_STATUS SCIP_STATUS_USERINTERRUPT - SCIP_STATUS SCIP_STATUS_NODELIMIT - SCIP_STATUS SCIP_STATUS_TOTALNODELIMIT - SCIP_STATUS SCIP_STATUS_STALLNODELIMIT - SCIP_STATUS SCIP_STATUS_TIMELIMIT - SCIP_STATUS SCIP_STATUS_MEMLIMIT - SCIP_STATUS SCIP_STATUS_GAPLIMIT - SCIP_STATUS SCIP_STATUS_SOLLIMIT - SCIP_STATUS SCIP_STATUS_BESTSOLLIMIT + SCIP_STATUS SCIP_STATUS_UNKNOWN + SCIP_STATUS SCIP_STATUS_USERINTERRUPT + SCIP_STATUS SCIP_STATUS_NODELIMIT + SCIP_STATUS SCIP_STATUS_TOTALNODELIMIT + SCIP_STATUS SCIP_STATUS_STALLNODELIMIT + SCIP_STATUS SCIP_STATUS_TIMELIMIT + SCIP_STATUS SCIP_STATUS_MEMLIMIT + SCIP_STATUS SCIP_STATUS_GAPLIMIT + SCIP_STATUS SCIP_STATUS_SOLLIMIT + SCIP_STATUS SCIP_STATUS_BESTSOLLIMIT SCIP_STATUS SCIP_STATUS_RESTARTLIMIT SCIP_STATUS SCIP_STATUS_PRIMALLIMIT SCIP_STATUS SCIP_STATUS_DUALLIMIT - SCIP_STATUS SCIP_STATUS_OPTIMAL - SCIP_STATUS SCIP_STATUS_INFEASIBLE - SCIP_STATUS SCIP_STATUS_UNBOUNDED - SCIP_STATUS SCIP_STATUS_INFORUNBD + SCIP_STATUS SCIP_STATUS_OPTIMAL + SCIP_STATUS SCIP_STATUS_INFEASIBLE + SCIP_STATUS SCIP_STATUS_UNBOUNDED + SCIP_STATUS SCIP_STATUS_INFORUNBD ctypedef int SCIP_STAGE cdef extern from "scip/type_set.h": - SCIP_STAGE SCIP_STAGE_INIT - SCIP_STAGE SCIP_STAGE_PROBLEM - SCIP_STAGE SCIP_STAGE_TRANSFORMING - SCIP_STAGE SCIP_STAGE_TRANSFORMED - SCIP_STAGE SCIP_STAGE_INITPRESOLVE - SCIP_STAGE SCIP_STAGE_PRESOLVING - SCIP_STAGE SCIP_STAGE_EXITPRESOLVE - SCIP_STAGE SCIP_STAGE_PRESOLVED - SCIP_STAGE SCIP_STAGE_INITSOLVE - SCIP_STAGE SCIP_STAGE_SOLVING - SCIP_STAGE SCIP_STAGE_SOLVED - SCIP_STAGE SCIP_STAGE_EXITSOLVE - SCIP_STAGE SCIP_STAGE_FREETRANS - SCIP_STAGE SCIP_STAGE_FREE + SCIP_STAGE SCIP_STAGE_INIT + SCIP_STAGE SCIP_STAGE_PROBLEM + SCIP_STAGE SCIP_STAGE_TRANSFORMING + SCIP_STAGE SCIP_STAGE_TRANSFORMED + SCIP_STAGE SCIP_STAGE_INITPRESOLVE + SCIP_STAGE SCIP_STAGE_PRESOLVING + SCIP_STAGE SCIP_STAGE_EXITPRESOLVE + SCIP_STAGE SCIP_STAGE_PRESOLVED + SCIP_STAGE SCIP_STAGE_INITSOLVE + SCIP_STAGE SCIP_STAGE_SOLVING + SCIP_STAGE SCIP_STAGE_SOLVED + SCIP_STAGE SCIP_STAGE_EXITSOLVE + SCIP_STAGE SCIP_STAGE_FREETRANS + SCIP_STAGE SCIP_STAGE_FREE ctypedef int SCIP_NODETYPE cdef extern from "scip/type_tree.h": - SCIP_NODETYPE SCIP_NODETYPE_FOCUSNODE - SCIP_NODETYPE SCIP_NODETYPE_PROBINGNODE - SCIP_NODETYPE SCIP_NODETYPE_SIBLING - SCIP_NODETYPE SCIP_NODETYPE_CHILD - SCIP_NODETYPE SCIP_NODETYPE_LEAF - SCIP_NODETYPE SCIP_NODETYPE_DEADEND - SCIP_NODETYPE SCIP_NODETYPE_JUNCTION - SCIP_NODETYPE SCIP_NODETYPE_PSEUDOFORK - SCIP_NODETYPE SCIP_NODETYPE_FORK - SCIP_NODETYPE SCIP_NODETYPE_SUBROOT - SCIP_NODETYPE SCIP_NODETYPE_REFOCUSNODE + SCIP_NODETYPE SCIP_NODETYPE_FOCUSNODE + SCIP_NODETYPE SCIP_NODETYPE_PROBINGNODE + SCIP_NODETYPE SCIP_NODETYPE_SIBLING + SCIP_NODETYPE SCIP_NODETYPE_CHILD + SCIP_NODETYPE SCIP_NODETYPE_LEAF + SCIP_NODETYPE SCIP_NODETYPE_DEADEND + SCIP_NODETYPE SCIP_NODETYPE_JUNCTION + SCIP_NODETYPE SCIP_NODETYPE_PSEUDOFORK + SCIP_NODETYPE SCIP_NODETYPE_FORK + SCIP_NODETYPE SCIP_NODETYPE_SUBROOT + SCIP_NODETYPE SCIP_NODETYPE_REFOCUSNODE ctypedef int SCIP_PARAMSETTING cdef extern from "scip/type_paramset.h": - SCIP_PARAMSETTING SCIP_PARAMSETTING_DEFAULT - SCIP_PARAMSETTING SCIP_PARAMSETTING_AGGRESSIVE - SCIP_PARAMSETTING SCIP_PARAMSETTING_FAST - SCIP_PARAMSETTING SCIP_PARAMSETTING_OFF + SCIP_PARAMSETTING SCIP_PARAMSETTING_DEFAULT + SCIP_PARAMSETTING SCIP_PARAMSETTING_AGGRESSIVE + SCIP_PARAMSETTING SCIP_PARAMSETTING_FAST + SCIP_PARAMSETTING SCIP_PARAMSETTING_OFF ctypedef int SCIP_PARAMTYPE cdef extern from "scip/type_paramset.h": @@ -148,33 +148,33 @@ cdef extern from "scip/scip.h": SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_NUMERICS SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_BENCHMARK - ctypedef unsigned long SCIP_PROPTIMING + ctypedef unsigned long SCIP_PROPTIMING cdef extern from "scip/type_timing.h": - SCIP_PROPTIMING SCIP_PROPTIMING_BEFORELP - SCIP_PROPTIMING SCIP_PROPTIMING_DURINGLPLOOP - SCIP_PROPTIMING SCIP_PROPTIMING_AFTERLPLOOP - SCIP_PROPTIMING SCIP_PROPTIMING_AFTERLPNODE + SCIP_PROPTIMING SCIP_PROPTIMING_BEFORELP + SCIP_PROPTIMING SCIP_PROPTIMING_DURINGLPLOOP + SCIP_PROPTIMING SCIP_PROPTIMING_AFTERLPLOOP + SCIP_PROPTIMING SCIP_PROPTIMING_AFTERLPNODE - ctypedef unsigned long SCIP_PRESOLTIMING + ctypedef unsigned long SCIP_PRESOLTIMING cdef extern from "scip/type_timing.h": - SCIP_PRESOLTIMING SCIP_PRESOLTIMING_NONE - SCIP_PRESOLTIMING SCIP_PRESOLTIMING_FAST - SCIP_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM - SCIP_PRESOLTIMING SCIP_PRESOLTIMING_EXHAUSTIVE + SCIP_PRESOLTIMING SCIP_PRESOLTIMING_NONE + SCIP_PRESOLTIMING SCIP_PRESOLTIMING_FAST + SCIP_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM + SCIP_PRESOLTIMING SCIP_PRESOLTIMING_EXHAUSTIVE - ctypedef unsigned long SCIP_HEURTIMING + ctypedef unsigned long SCIP_HEURTIMING cdef extern from "scip/type_timing.h": - SCIP_HEURTIMING SCIP_HEURTIMING_BEFORENODE - SCIP_HEURTIMING SCIP_HEURTIMING_DURINGLPLOOP - SCIP_HEURTIMING SCIP_HEURTIMING_AFTERLPLOOP - SCIP_HEURTIMING SCIP_HEURTIMING_AFTERLPNODE - SCIP_HEURTIMING SCIP_HEURTIMING_AFTERPSEUDONODE - SCIP_HEURTIMING SCIP_HEURTIMING_AFTERLPPLUNGE - SCIP_HEURTIMING SCIP_HEURTIMING_AFTERPSEUDOPLUNGE - SCIP_HEURTIMING SCIP_HEURTIMING_DURINGPRICINGLOOP - SCIP_HEURTIMING SCIP_HEURTIMING_BEFOREPRESOL - SCIP_HEURTIMING SCIP_HEURTIMING_DURINGPRESOLLOOP - SCIP_HEURTIMING SCIP_HEURTIMING_AFTERPROPLOOP + SCIP_HEURTIMING SCIP_HEURTIMING_BEFORENODE + SCIP_HEURTIMING SCIP_HEURTIMING_DURINGLPLOOP + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERLPLOOP + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERLPNODE + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERPSEUDONODE + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERLPPLUNGE + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERPSEUDOPLUNGE + SCIP_HEURTIMING SCIP_HEURTIMING_DURINGPRICINGLOOP + SCIP_HEURTIMING SCIP_HEURTIMING_BEFOREPRESOL + SCIP_HEURTIMING SCIP_HEURTIMING_DURINGPRESOLLOOP + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERPROPLOOP ctypedef int SCIP_EXPR cdef extern from "scip/type_expr.h": @@ -207,57 +207,81 @@ cdef extern from "scip/scip.h": SCIP_EXPR SCIP_EXPR_USER SCIP_EXPR SCIP_EXPR_LAST - ctypedef int SCIP_BASESTAT + ctypedef int SCIP_BASESTAT cdef extern from "lpi/type_lpi.h": - SCIP_BASESTAT SCIP_BASESTAT_LOWER - SCIP_BASESTAT SCIP_BASESTAT_BASIC - SCIP_BASESTAT SCIP_BASESTAT_UPPER - SCIP_BASESTAT SCIP_BASESTAT_ZERO + SCIP_BASESTAT SCIP_BASESTAT_LOWER + SCIP_BASESTAT SCIP_BASESTAT_BASIC + SCIP_BASESTAT SCIP_BASESTAT_UPPER + SCIP_BASESTAT SCIP_BASESTAT_ZERO - ctypedef unsigned long SCIP_EVENTTYPE + + ctypedef int SCIP_LPPARAM + cdef extern from "lpi/type_lpi.h": + SCIP_LPPARAM SCIP_LPPAR_FROMSCRATCH + SCIP_LPPARAM SCIP_LPPAR_FASTMIP + SCIP_LPPARAM SCIP_LPPAR_SCALING + SCIP_LPPARAM SCIP_LPPAR_PRESOLVING + SCIP_LPPARAM SCIP_LPPAR_PRICING + SCIP_LPPARAM SCIP_LPPAR_LPINFO + SCIP_LPPARAM SCIP_LPPAR_FEASTOL + SCIP_LPPARAM SCIP_LPPAR_DUALFEASTOL + SCIP_LPPARAM SCIP_LPPAR_BARRIERCONVTOL + SCIP_LPPARAM SCIP_LPPAR_OBJLIM + SCIP_LPPARAM SCIP_LPPAR_LPITLIM + SCIP_LPPARAM SCIP_LPPAR_LPTILIM + SCIP_LPPARAM SCIP_LPPAR_MARKOWITZ + SCIP_LPPARAM SCIP_LPPAR_ROWREPSWITCH + SCIP_LPPARAM SCIP_LPPAR_THREADS + SCIP_LPPARAM SCIP_LPPAR_CONDITIONLIMIT + SCIP_LPPARAM SCIP_LPPAR_TIMING + SCIP_LPPARAM SCIP_LPPAR_RANDOMSEED + SCIP_LPPARAM SCIP_LPPAR_POLISHING + SCIP_LPPARAM SCIP_LPPAR_REFACTOR + + ctypedef unsigned long SCIP_EVENTTYPE cdef extern from "scip/type_event.h": - SCIP_EVENTTYPE SCIP_EVENTTYPE_DISABLED - SCIP_EVENTTYPE SCIP_EVENTTYPE_VARADDED - SCIP_EVENTTYPE SCIP_EVENTTYPE_VARDELETED - SCIP_EVENTTYPE SCIP_EVENTTYPE_VARFIXED - SCIP_EVENTTYPE SCIP_EVENTTYPE_VARUNLOCKED - SCIP_EVENTTYPE SCIP_EVENTTYPE_OBJCHANGED - SCIP_EVENTTYPE SCIP_EVENTTYPE_GLBCHANGED - SCIP_EVENTTYPE SCIP_EVENTTYPE_GUBCHANGED - SCIP_EVENTTYPE SCIP_EVENTTYPE_LBTIGHTENED - SCIP_EVENTTYPE SCIP_EVENTTYPE_LBRELAXED - SCIP_EVENTTYPE SCIP_EVENTTYPE_UBTIGHTENED - SCIP_EVENTTYPE SCIP_EVENTTYPE_UBRELAXED - SCIP_EVENTTYPE SCIP_EVENTTYPE_GHOLEADDED - SCIP_EVENTTYPE SCIP_EVENTTYPE_GHOLEREMOVED - SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLEADDED - SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLEREMOVED - SCIP_EVENTTYPE SCIP_EVENTTYPE_IMPLADDED - SCIP_EVENTTYPE SCIP_EVENTTYPE_PRESOLVEROUND - SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEFOCUSED - SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEFEASIBLE - SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEINFEASIBLE - SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEBRANCHED - SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEDELETE - SCIP_EVENTTYPE SCIP_EVENTTYPE_FIRSTLPSOLVED - SCIP_EVENTTYPE SCIP_EVENTTYPE_LPSOLVED - SCIP_EVENTTYPE SCIP_EVENTTYPE_POORSOLFOUND - SCIP_EVENTTYPE SCIP_EVENTTYPE_BESTSOLFOUND - SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWADDEDSEPA - SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWDELETEDSEPA - SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWADDEDLP - SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWDELETEDLP - SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCOEFCHANGED - SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCONSTCHANGED - SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWSIDECHANGED - SCIP_EVENTTYPE SCIP_EVENTTYPE_SYNC + SCIP_EVENTTYPE SCIP_EVENTTYPE_DISABLED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VARADDED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VARDELETED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VARFIXED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VARUNLOCKED + SCIP_EVENTTYPE SCIP_EVENTTYPE_OBJCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GLBCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GUBCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LBTIGHTENED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LBRELAXED + SCIP_EVENTTYPE SCIP_EVENTTYPE_UBTIGHTENED + SCIP_EVENTTYPE SCIP_EVENTTYPE_UBRELAXED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GHOLEADDED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GHOLEREMOVED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLEADDED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLEREMOVED + SCIP_EVENTTYPE SCIP_EVENTTYPE_IMPLADDED + SCIP_EVENTTYPE SCIP_EVENTTYPE_PRESOLVEROUND + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEFOCUSED + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEFEASIBLE + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEINFEASIBLE + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEBRANCHED + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEDELETE + SCIP_EVENTTYPE SCIP_EVENTTYPE_FIRSTLPSOLVED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LPSOLVED + SCIP_EVENTTYPE SCIP_EVENTTYPE_POORSOLFOUND + SCIP_EVENTTYPE SCIP_EVENTTYPE_BESTSOLFOUND + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWADDEDSEPA + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWDELETEDSEPA + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWADDEDLP + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWDELETEDLP + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCOEFCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCONSTCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWSIDECHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_SYNC SCIP_EVENTTYPE SCIP_EVENTTYPE_GBDCHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_LBCHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_UBCHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_BOUNDTIGHTENED SCIP_EVENTTYPE SCIP_EVENTTYPE_BOUNDRELAXED SCIP_EVENTTYPE SCIP_EVENTTYPE_BOUNDCHANGED - SCIP_EVENTTYPE SCIP_EVENTTYPE_GHOLECHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GHOLECHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLECHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_HOLECHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_DOMCHANGED @@ -272,53 +296,53 @@ cdef extern from "scip/scip.h": SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWEVENT - ctypedef int SCIP_LPSOLQUALITY + ctypedef int SCIP_LPSOLQUALITY cdef extern from "lpi/type_lpi.h": - SCIP_LPSOLQUALITY SCIP_LPSOLQUALITY_ESTIMCONDITION - SCIP_LPSOLQUALITY SCIP_LPSOLQUALITY_EXACTCONDITION + SCIP_LPSOLQUALITY SCIP_LPSOLQUALITY_ESTIMCONDITION + SCIP_LPSOLQUALITY SCIP_LPSOLQUALITY_EXACTCONDITION - ctypedef int SCIP_LOCKTYPE + ctypedef int SCIP_LOCKTYPE cdef extern from "scip/type_var.h": - SCIP_LOCKTYPE SCIP_LOCKTYPE_MODEL - SCIP_LOCKTYPE SCIP_LOCKTYPE_CONFLICT + SCIP_LOCKTYPE SCIP_LOCKTYPE_MODEL + SCIP_LOCKTYPE SCIP_LOCKTYPE_CONFLICT - ctypedef int SCIP_BENDERSENFOTYPE + ctypedef int SCIP_BENDERSENFOTYPE cdef extern from "scip/type_benders.h": - SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_LP - SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_RELAX - SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_PSEUDO - SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_CHECK + SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_LP + SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_RELAX + SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_PSEUDO + SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_CHECK - ctypedef int SCIP_LPSOLSTAT + ctypedef int SCIP_LPSOLSTAT cdef extern from "scip/type_lp.h": - SCIP_LPSOLSTAT SCIP_LPSOLSTAT_NOTSOLVED - SCIP_LPSOLSTAT SCIP_LPSOLSTAT_OPTIMAL - SCIP_LPSOLSTAT SCIP_LPSOLSTAT_INFEASIBLE - SCIP_LPSOLSTAT SCIP_LPSOLSTAT_UNBOUNDEDRAY - SCIP_LPSOLSTAT SCIP_LPSOLSTAT_OBJLIMIT - SCIP_LPSOLSTAT SCIP_LPSOLSTAT_ITERLIMIT - SCIP_LPSOLSTAT SCIP_LPSOLSTAT_TIMELIMIT - SCIP_LPSOLSTAT SCIP_LPSOLSTAT_ERROR - - ctypedef int SCIP_BRANCHDIR + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_NOTSOLVED + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_OPTIMAL + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_INFEASIBLE + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_UNBOUNDEDRAY + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_OBJLIMIT + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_ITERLIMIT + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_TIMELIMIT + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_ERROR + + ctypedef int SCIP_BRANCHDIR cdef extern from "scip/type_history.h": - SCIP_BRANCHDIR SCIP_BRANCHDIR_DOWNWARDS - SCIP_BRANCHDIR SCIP_BRANCHDIR_UPWARDS - SCIP_BRANCHDIR SCIP_BRANCHDIR_FIXED - SCIP_BRANCHDIR SCIP_BRANCHDIR_AUTO + SCIP_BRANCHDIR SCIP_BRANCHDIR_DOWNWARDS + SCIP_BRANCHDIR SCIP_BRANCHDIR_UPWARDS + SCIP_BRANCHDIR SCIP_BRANCHDIR_FIXED + SCIP_BRANCHDIR SCIP_BRANCHDIR_AUTO - ctypedef int SCIP_BOUNDCHGTYPE + ctypedef int SCIP_BOUNDCHGTYPE cdef extern from "scip/type_var.h": - SCIP_BOUNDCHGTYPE SCIP_BOUNDCHGTYPE_BRANCHING - SCIP_BOUNDCHGTYPE SCIP_BOUNDCHGTYPE_CONSINFER - SCIP_BOUNDCHGTYPE SCIP_BOUNDCHGTYPE_PROPINFER + SCIP_BOUNDCHGTYPE SCIP_BOUNDCHGTYPE_BRANCHING + SCIP_BOUNDCHGTYPE SCIP_BOUNDCHGTYPE_CONSINFER + SCIP_BOUNDCHGTYPE SCIP_BOUNDCHGTYPE_PROPINFER - ctypedef int SCIP_ROWORIGINTYPE + ctypedef int SCIP_ROWORIGINTYPE cdef extern from "scip/type_lp.h": - SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_UNSPEC - SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_CONS - SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_SEPA - SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_REOPT + SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_UNSPEC + SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_CONS + SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_SEPA + SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_REOPT ctypedef int SCIP_SOLORIGIN cdef extern from "scip/type_sol.h": @@ -1375,6 +1399,10 @@ cdef extern from "scip/scip.h": SCIP_RETCODE SCIPlpiGetDualfarkas(SCIP_LPI* lpi, SCIP_Real* dualfarkas) SCIP_RETCODE SCIPlpiGetBasisInd(SCIP_LPI* lpi, int* bind) SCIP_RETCODE SCIPlpiGetRealSolQuality(SCIP_LPI* lpi, SCIP_LPSOLQUALITY qualityindicator, SCIP_Real* quality) + SCIP_RETCODE SCIPlpiGetIntpar(SCIP_LPI* lpi, SCIP_LPPARAM type, int* ival) + SCIP_RETCODE SCIPlpiGetRealpar(SCIP_LPI* lpi, SCIP_LPPARAM type, SCIP_Real* dval) + SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI* lpi, SCIP_LPPARAM type, int ival) + SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI* lpi, SCIP_LPPARAM type, SCIP_Real dval) SCIP_Bool SCIPlpiHasPrimalRay(SCIP_LPI* lpi) SCIP_Bool SCIPlpiHasDualRay(SCIP_LPI* lpi) SCIP_Real SCIPlpiInfinity(SCIP_LPI* lpi) @@ -1836,7 +1864,7 @@ cdef extern from "scip/misc.h": cdef extern from "scip/scip_copy.h": SCIP_RETCODE SCIPtranslateSubSol(SCIP* scip, SCIP* subscip, SCIP_SOL* subsol, SCIP_HEUR* heur, SCIP_VAR** subvars, SCIP_SOL** newsol) - + cdef extern from "scip/heuristics.h": SCIP_RETCODE SCIPcopyLargeNeighborhoodSearch(SCIP* sourcescip, SCIP* subscip, SCIP_HASHMAP* varmap, const char* suffix, SCIP_VAR** fixedvars, SCIP_Real* fixedvals, int nfixedvars, SCIP_Bool uselprows, SCIP_Bool copycuts, SCIP_Bool* success, SCIP_Bool* valid) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index f1dfdf17c..ce5d86ffa 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -85,6 +85,28 @@ cdef class PY_SCIP_PARAMSETTING: FAST = SCIP_PARAMSETTING_FAST OFF = SCIP_PARAMSETTING_OFF +cdef class PY_SCIP_LPPARAM: + FROMSCRATCH = SCIP_LPPAR_FROMSCRATCH + FASTMIP = SCIP_LPPAR_FASTMIP + SCALING = SCIP_LPPAR_SCALING + PRESOLVING = SCIP_LPPAR_PRESOLVING + PRICING = SCIP_LPPAR_PRICING + LPINFO = SCIP_LPPAR_LPINFO + FEASTOL = SCIP_LPPAR_FEASTOL + DUALFEASTOL = SCIP_LPPAR_DUALFEASTOL + BARRIERCONVTOL = SCIP_LPPAR_BARRIERCONVTOL + OBJLIM = SCIP_LPPAR_OBJLIM + LPITLIM = SCIP_LPPAR_LPITLIM + LPTILIM = SCIP_LPPAR_LPTILIM + MARKOWITZ = SCIP_LPPAR_MARKOWITZ + ROWREPSWITCH = SCIP_LPPAR_ROWREPSWITCH + THREADS = SCIP_LPPAR_THREADS + CONDITIONLIMIT = SCIP_LPPAR_CONDITIONLIMIT + TIMING = SCIP_LPPAR_TIMING + RANDOMSEED = SCIP_LPPAR_RANDOMSEED + POLISHING = SCIP_LPPAR_POLISHING + REFACTOR = SCIP_LPPAR_REFACTOR + cdef class PY_SCIP_PARAMEMPHASIS: DEFAULT = SCIP_PARAMEMPHASIS_DEFAULT CPSOLVER = SCIP_PARAMEMPHASIS_CPSOLVER @@ -320,12 +342,12 @@ cdef class Event: cdef create(SCIP_EVENT* scip_event): """ Main method for creating an Event class. Is used instead of __init__. - + Parameters ---------- scip_event : SCIP_EVENT* A pointer to the SCIP_EVENT - + Returns ------- event : Event @@ -368,7 +390,7 @@ cdef class Event: attr = getattr(PY_SCIP_EVENTTYPE, name) if isinstance(attr, int): EventNames[attr] = name - + def __repr__(self): return str(self.getType()) @@ -448,7 +470,7 @@ cdef class Column: cdef create(SCIP_COL* scipcol): """ Main method for creating a Column class. Is used instead of __init__. - + Parameters ---------- scipcol : SCIP_COL* @@ -1000,7 +1022,7 @@ cdef class Solution: var = expr return SCIPgetSolVal(self.scip, self.sol, var.scip_var) return sum(self._evaluate(term)*coeff for term, coeff in expr.terms.items() if coeff != 0) - + def _evaluate(self, term): self._checkStage("SCIPgetSolVal") result = 1 @@ -1023,7 +1045,7 @@ cdef class Solution: name = cname.decode('utf-8') vals[name] = SCIPgetSolVal(self.scip, self.sol, scip_var) return str(vals) - + def _checkStage(self, method): if method in ["SCIPgetSolVal", "getSolObjVal"]: stage_check = SCIPgetStage(self.scip) not in [SCIP_STAGE_INIT, SCIP_STAGE_FREE] @@ -1323,7 +1345,7 @@ cdef class Node: """ return SCIPnodeIsActive(self.scip_node) - + def isPropagatedAgain(self): """ Is the node marked to be propagated again? @@ -2347,7 +2369,7 @@ cdef class Model: PY_SCIP_CALL(SCIPcopy(sourceModel._scip, self._scip, NULL, NULL, n, globalcopy, enablepricing, threadsafe, True, self._valid)) - def attachEventHandlerCallback(self, + def attachEventHandlerCallback(self, callback, events, name="eventhandler", @@ -2359,7 +2381,7 @@ cdef class Model: Parameters ---------- callback : callable - The callback function to be called when an event occurs. + The callback function to be called when an event occurs. The callback function should have the following signature: callback(model, event) events : list of SCIP_EVENTTYPE @@ -2372,7 +2394,7 @@ cdef class Model: self._generated_event_handlers_count += 1 model = self - + class EventHandler(Eventhdlr): def __init__(self, callback): super(EventHandler, self).__init__() @@ -2381,19 +2403,19 @@ cdef class Model: def eventinit(self): for event in events: self.model.catchEvent(event, self) - + def eventexit(self): for event in events: self.model.dropEvent(event, self) - + def eventexec(self, event): self.callback(model, event) - + event_handler = EventHandler(callback) if name == "eventhandler": name = f"eventhandler_{self._generated_event_handlers_count}" - + self.includeEventhdlr(event_handler, name, description) @@ -2414,7 +2436,7 @@ cdef class Model: cdef create(SCIP* scip): """ Creates a model and appropriately assigns the scip and bestsol parameters. - + Parameters ---------- scip : SCIP* @@ -2538,7 +2560,7 @@ cdef class Model: SCIP_STAGE_SOLVING, SCIP_STAGE_SOLVED]: raise Warning("method cannot be called in stage %i." % self.getStage()) - + self._modelvars = { var: value for var, value in self._modelvars.items() @@ -2790,7 +2812,7 @@ cdef class Model: def cutoffNode(self, Node node): """ marks node and whole subtree to be cut off from the branch and bound tree. - + Parameters ---------- node : Node @@ -3155,11 +3177,11 @@ cdef class Model: def getObjlimit(self): """ Returns current limit on objective function. - + Returns ------- float - + """ return SCIPgetObjlimit(self._scip) @@ -3189,7 +3211,7 @@ cdef class Model: if expr.degree() > 1: raise ValueError("SCIP does not support nonlinear objective functions. Consider using set_nonlinear_objective in the pyscipopt.recipe.nonlinear") - + if clear: # clear existing objective function self.addObjoffset(-self.getObjoffset()) @@ -3424,10 +3446,10 @@ cdef class Model: if trans: PY_SCIP_CALL(SCIPwriteTransProblem(self._scip, NULL, str_conversion(ext)[1:], genericnames)) else: - PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, NULL, str_conversion(ext)[1:], genericnames)) + PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, NULL, str_conversion(ext)[1:], genericnames)) locale.setlocale(locale.LC_NUMERIC,user_locale) - + def writeProblem(self, filename='model.cip', trans=False, genericnames=False, verbose=True): """ Write current model/problem to a file. @@ -3458,19 +3480,19 @@ cdef class Model: ext = str_conversion('.cip') fn = fn + ext ext = ext[1:] - + if trans: PY_SCIP_CALL(SCIPwriteTransProblem(self._scip, fn, ext, genericnames)) else: PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, fn, ext, genericnames)) - + if verbose: print('wrote problem to file ' + str_absfile) else: if trans: PY_SCIP_CALL(SCIPwriteTransProblem(self._scip, NULL, str_conversion('.cip')[1:], genericnames)) else: - PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, NULL, str_conversion('.cip')[1:], genericnames)) + PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, NULL, str_conversion('.cip')[1:], genericnames)) locale.setlocale(locale.LC_NUMERIC,user_locale) @@ -3548,7 +3570,7 @@ cdef class Model: PY_SCIP_CALL(SCIPreleaseVar(self._scip, &scip_var)) return pyVar - def addMatrixVar(self, + def addMatrixVar(self, shape: Union[int, Tuple], name: Union[str, np.ndarray] = '', vtype: Union[str, np.ndarray] = 'C', @@ -3587,7 +3609,7 @@ cdef class Model: """ # assert has_numpy, "Numpy is not installed. Please install numpy to use matrix variables." - + if isinstance(name, np.ndarray): assert name.shape == shape if isinstance(vtype, np.ndarray): @@ -4065,7 +4087,7 @@ cdef class Model: """ return SCIPgetNContVars(self._scip) - + def getVarDict(self, transformed=False): """ Gets dictionary with variables names as keys and current variable values as items. @@ -4099,7 +4121,7 @@ cdef class Model: """ PY_SCIP_CALL(SCIPupdateNodeLowerbound(self._scip, node.scip_node, lb)) - + def relax(self): """Relaxes the integrality restrictions of the model.""" if self.getStage() != SCIP_STAGE_PROBLEM: @@ -4925,7 +4947,7 @@ cdef class Model: cdef SCIP_EXPR** monomials cdef SCIP_CONS* scip_cons cdef int* idxs - cdef int i + cdef int i cdef int j terms = cons.expr.terms @@ -5294,7 +5316,7 @@ cdef class Model: """ cdef int n_conss - cdef int i + cdef int i if isinstance(conss, MatrixExprCons): conss = conss.flatten() @@ -5337,16 +5359,16 @@ cdef class Model: return constraints - def addMatrixCons(self, - cons: MatrixExprCons, + def addMatrixCons(self, + cons: MatrixExprCons, name: Union[str, np.ndarray] ='', - initial: Union[bool, np.ndarray] = True, + initial: Union[bool, np.ndarray] = True, separate: Union[bool, np.ndarray] = True, - enforce: Union[bool, np.ndarray] = True, + enforce: Union[bool, np.ndarray] = True, check: Union[bool, np.ndarray] = True, - propagate: Union[bool, np.ndarray] = True, + propagate: Union[bool, np.ndarray] = True, local: Union[bool, np.ndarray] = False, - modifiable: Union[bool, np.ndarray] = False, + modifiable: Union[bool, np.ndarray] = False, dynamic: Union[bool, np.ndarray] = False, removable: Union[bool, np.ndarray] = False, stickingatnode: Union[bool, np.ndarray] = False): @@ -5491,8 +5513,8 @@ cdef class Model: return matrix_cons.view(MatrixConstraint) - def addConsDisjunction(self, conss, name = '', initial = True, - relaxcons = None, enforce=True, check =True, + def addConsDisjunction(self, conss, name = '', initial = True, + relaxcons = None, enforce=True, check =True, local=False, modifiable = False, dynamic = False): """ Add a disjunction constraint. @@ -5543,7 +5565,7 @@ cdef class Model: n_conss = len(conss) PY_SCIP_CALL(SCIPcreateConsDisjunction( - self._scip, &disj_cons, str_conversion(name), 0, &scip_cons, NULL, + self._scip, &disj_cons, str_conversion(name), 0, &scip_cons, NULL, initial, enforce, check, local, modifiable, dynamic )) @@ -5602,10 +5624,10 @@ cdef class Model: If the associated constraint handler does not have this functionality """ - cdef int nvars + cdef int nvars cdef SCIP_Bool success - PY_SCIP_CALL(SCIPgetConsNVars(self._scip, constraint.scip_cons, &nvars, &success)) + PY_SCIP_CALL(SCIPgetConsNVars(self._scip, constraint.scip_cons, &nvars, &success)) if not success: conshdlr = SCIPconsGetHdlr(constraint.scip_cons) @@ -5678,7 +5700,7 @@ cdef class Model: assert cons.isNonlinear(), "addExprNonlinear can only be called with nonlinear constraints." cdef Constraint temp_cons - cdef SCIP_EXPR* scip_expr + cdef SCIP_EXPR* scip_expr temp_cons = self.addCons(expr <= 0) scip_expr = SCIPgetExprNonlinear(temp_cons.scip_cons) @@ -6248,7 +6270,7 @@ cdef class Model: if lincons == NULL: return None return Constraint.create(lincons) - + def getSlackVarIndicator(self, Constraint cons): """ Get slack variable of an indicator constraint. @@ -7086,7 +7108,7 @@ cdef class Model: """Optimize the problem.""" PY_SCIP_CALL(SCIPsolve(self._scip)) self._bestSol = Solution.create(self._scip, SCIPgetBestSol(self._scip)) - + def optimizeNogil(self): """Optimize the problem without GIL.""" cdef SCIP_RETCODE rc; @@ -7100,7 +7122,7 @@ cdef class Model: finding solutions. WARNING: This feature is still experimental and prone to some errors.""" if SCIPtpiGetNumThreads() == 1: - warnings.warn("SCIP was compiled without task processing interface. Parallel solve not possible - using optimize() instead of solveConcurrent()") + warnings.warn("SCIP was compiled without task processing interface. Parallel solve not possible - using optimize() instead of solveConcurrent()") self.optimize() else: PY_SCIP_CALL(SCIPsolveConcurrent(self._scip)) @@ -7181,7 +7203,7 @@ cdef class Model: PY_SCIP_CALL(SCIPsetupBendersSubproblem(self._scip, benders[i], self._bestSol.sol, j, SCIP_BENDERSENFOTYPE_CHECK)) PY_SCIP_CALL(SCIPsolveBendersSubproblem(self._scip, - benders[i], self._bestSol.sol, j, &infeasible, solvecip, NULL)) + benders[i], self._bestSol.sol, j, &infeasible, solvecip, NULL)) def freeBendersSubproblems(self): """Calls the free subproblem function for the Benders' decomposition. @@ -7616,18 +7638,18 @@ cdef class Model: conshdlr.model = weakref.proxy(self) conshdlr.name = name Py_INCREF(conshdlr) - + def copyLargeNeighborhoodSearch(self, to_fix, fix_vals) -> Model: """ Creates a configured copy of the transformed problem and applies provided fixings intended for LNS heuristics. - + Parameters - ---------- + ---------- to_fix : List[Variable] A list of variables to fix in the copy fix_vals : List[Real] A list of the values to which to fix the variables in the copy (care their order) - + Returns ------- model : Model @@ -7666,7 +7688,7 @@ cdef class Model: def translateSubSol(self, Model sub_model, Solution sol, heur) -> Solution: """ Translates a solution of a model copy into a solution of the main model - + Parameters ---------- sub_model : Model @@ -7675,9 +7697,9 @@ cdef class Model: The python-wrapper of the solution of the subscip heur : Heur The python-wrapper of the heuristic that found the solution - + Returns - ------- + ------- solution : Solution The corresponding solution in the main model """ @@ -8733,7 +8755,7 @@ cdef class Model: _heur = SCIPfindHeur(self._scip, n) else: _heur = NULL - + PY_SCIP_CALL(SCIPcreateOrigSol(self._scip, &_sol, _heur)) solution = Solution.create(self._scip, _sol) return solution @@ -8775,7 +8797,7 @@ cdef class Model: PY_SCIP_CALL(SCIPprintSol(self._scip, NULL, NULL, write_zeros)) else: PY_SCIP_CALL(SCIPprintSol(self._scip, solution.sol, NULL, write_zeros)) - + locale.setlocale(locale.LC_NUMERIC,user_locale) def writeBestSol(self, filename="origprob.sol", write_zeros=False): @@ -8822,7 +8844,7 @@ cdef class Model: with open(filename, "w") as f: cfile = fdopen(f.fileno(), "w") PY_SCIP_CALL(SCIPprintBestTransSol(self._scip, cfile, write_zeros)) - + locale.setlocale(locale.LC_NUMERIC,user_locale) def writeSol(self, Solution solution, filename="origprob.sol", write_zeros=False): @@ -8847,7 +8869,7 @@ cdef class Model: with open(filename, "w") as f: cfile = fdopen(f.fileno(), "w") PY_SCIP_CALL(SCIPprintSol(self._scip, solution.sol, cfile, write_zeros)) - + locale.setlocale(locale.LC_NUMERIC,user_locale) def writeTransSol(self, Solution solution, filename="transprob.sol", write_zeros=False): @@ -8872,7 +8894,7 @@ cdef class Model: with open(filename, "w") as f: cfile = fdopen(f.fileno(), "w") PY_SCIP_CALL(SCIPprintTransSol(self._scip, solution.sol, cfile, write_zeros)) - + locale.setlocale(locale.LC_NUMERIC,user_locale) # perhaps this should not be included as it implements duplicated functionality @@ -8949,7 +8971,7 @@ cdef class Model: """ cdef SCIP_SOL* _sol _sol = solution.sol - + assert _sol != NULL, "Cannot set value to a freed solution." PY_SCIP_CALL(SCIPsetSolVal(self._scip, _sol, var.scip_var, val)) @@ -9198,7 +9220,7 @@ cdef class Model: raise Warning("Without a solution, method can only be called in stage SOLVING.") else: assert self._bestSol.sol != NULL - + if SCIPsolIsOriginal(self._bestSol.sol): min_stage_requirement = SCIP_STAGE_PROBLEM else: @@ -9267,9 +9289,9 @@ cdef class Model: result[idx] = self.getSolVal(self._bestSol, expr[idx]) else: result = self.getSolVal(self._bestSol, expr) - + return result - + def hasPrimalRay(self): """ Returns whether a primal ray is stored that proves unboundedness of the LP relaxation. @@ -9280,7 +9302,7 @@ cdef class Model: """ return SCIPhasPrimalRay(self._scip) - + def getPrimalRayVal(self, Variable var): """ Gets value of given variable in primal ray causing unboundedness of the LP relaxation. @@ -9295,7 +9317,7 @@ cdef class Model: """ assert SCIPhasPrimalRay(self._scip), "The problem does not have a primal ray." - + return SCIPgetPrimalRayVal(self._scip, var.scip_var) def getPrimalRay(self): @@ -9377,7 +9399,7 @@ cdef class Model: """ return SCIPgetStage(self._scip) - + def getStageName(self): """ Returns name of current stage as string. @@ -9390,7 +9412,7 @@ cdef class Model: if not StageNames: self._getStageNames() return StageNames[self.getStage()] - + def _getStageNames(self): """Gets names of stages.""" for name in dir(PY_SCIP_STAGE): @@ -9477,7 +9499,7 @@ cdef class Model: _eventhdlr = SCIPfindEventhdlr(self._scip, n) else: raise Warning("event handler not found") - + Py_INCREF(self) PY_SCIP_CALL(SCIPcatchEvent(self._scip, eventtype, _eventhdlr, NULL, NULL)) @@ -9497,7 +9519,7 @@ cdef class Model: _eventhdlr = SCIPfindEventhdlr(self._scip, n) else: raise Warning("event handler not found") - + Py_DECREF(self) PY_SCIP_CALL(SCIPdropEvent(self._scip, eventtype, _eventhdlr, NULL, -1)) @@ -9606,7 +9628,7 @@ cdef class Model: with open(filename, "w") as f: cfile = fdopen(f.fileno(), "w") PY_SCIP_CALL(SCIPprintStatistics(self._scip, cfile)) - + locale.setlocale(locale.LC_NUMERIC,user_locale) def getNLPs(self): @@ -9873,12 +9895,12 @@ cdef class Model: """ absfile = str_conversion(abspath(file)) - + user_locale = locale.getlocale(category=locale.LC_NUMERIC) locale.setlocale(locale.LC_NUMERIC, "C") - + PY_SCIP_CALL(SCIPreadParams(self._scip, absfile)) - + locale.setlocale(locale.LC_NUMERIC, user_locale) def writeParams(self, filename='param.set', comments=True, onlychanged=True, verbose=True): @@ -10206,10 +10228,10 @@ cdef class Model: cdef SCIP_Bool lperror if integral: - PY_SCIP_CALL(SCIPgetVarStrongbranchInt(self._scip, var.scip_var, itlim, idempotent, &down, &up, &downvalid, + PY_SCIP_CALL(SCIPgetVarStrongbranchInt(self._scip, var.scip_var, itlim, idempotent, &down, &up, &downvalid, &upvalid, &downinf, &upinf, &downconflict, &upconflict, &lperror)) else: - PY_SCIP_CALL(SCIPgetVarStrongbranchFrac(self._scip, var.scip_var, itlim, idempotent, &down, &up, &downvalid, + PY_SCIP_CALL(SCIPgetVarStrongbranchFrac(self._scip, var.scip_var, itlim, idempotent, &down, &up, &downvalid, &upvalid, &downinf, &upinf, &downconflict, &upconflict, &lperror)) return down, up, downvalid, upvalid, downinf, upinf, downconflict, upconflict, lperror @@ -10572,7 +10594,7 @@ class Statistics: problem_name: str Name of problem presolved_problem_name: str - Name of presolved problem + Name of presolved problem n_nodes: int The number of nodes explored in the branch-and-bound tree n_solutions_found: int @@ -10580,20 +10602,20 @@ class Statistics: first_solution: float objective value of first found solution primal_bound: float - The best primal bound found + The best primal bound found dual_bound: float The best dual bound found gap: float The gap between the primal and dual bounds primal_dual_integral: float - The primal-dual integral + The primal-dual integral n_vars: int number of variables in the model n_binary_vars: int number of binary variables in the model - n_integer_vars: int + n_integer_vars: int number of integer variables in the model - n_implicit_integer_vars: int + n_implicit_integer_vars: int number of implicit integer variables in the model n_continuous_vars: int number of continuous variables in the model @@ -10625,14 +10647,14 @@ class Statistics: copying_time: float problem_name: str presolved_problem_name: str - _variables: dict # Dictionary with number of variables by type + _variables: dict # Dictionary with number of variables by type _presolved_variables: dict # Dictionary with number of presolved variables by type _constraints: dict # Dictionary with number of constraints by type _presolved_constraints: dict # Dictionary with number of presolved constraints by type n_runs: int = None n_nodes: int = None n_solutions_found: int = -1 - first_solution: float = None + first_solution: float = None primal_bound: float = None dual_bound: float = None gap: float = None @@ -10716,7 +10738,7 @@ def readStatistics(filename): result = {} file = open(filename) data = file.readlines() - + if "optimal solution found" in data[0]: result["status"] = "optimal" elif "infeasible" in data[0]: @@ -10729,9 +10751,9 @@ def readStatistics(filename): raise "readStatistics can only be called if the problem was solved" available_stats = ["Total Time", "solving", "presolving", "reading", "copying", - "Problem name", "Variables", "Constraints", "number of runs", + "Problem name", "Variables", "Constraints", "number of runs", "nodes", "Solutions found"] - + if result["status"] in ["optimal", "user_interrupt"]: available_stats.extend(["First Solution", "Primal Bound", "Dual Bound", "Gap", "primal-dual"]) @@ -10757,12 +10779,12 @@ def readStatistics(filename): for var_type in split_var: split_result = var_type.strip().split(" ") var_stats[split_result[1]] = int(split_result[0]) - + if "Original" in data[i-2]: result["Variables"] = var_stats else: result["Presolved Variables"] = var_stats - + continue if stat_name == "Constraints": @@ -10778,7 +10800,7 @@ def readStatistics(filename): else: result["Presolved Constraints"] = con_stats continue - + relevant_value = relevant_value.split(" ")[0] if stat_name == "Problem name": if "Original" in data[i-1]: @@ -10786,7 +10808,7 @@ def readStatistics(filename): else: result["Presolved Problem name"] = relevant_value continue - + if stat_name == "Gap": relevant_value = relevant_value[:-1] # removing % @@ -10796,11 +10818,11 @@ def readStatistics(filename): break else: # it's a string - result[stat_name] = relevant_value + result[stat_name] = relevant_value # changing keys to pythonic variable names - treated_keys = {"status": "status", "Total Time": "total_time", "solving":"solving_time", "presolving":"presolving_time", "reading":"reading_time", - "copying":"copying_time", "Problem name": "problem_name", "Presolved Problem name": "presolved_problem_name", "Variables":"_variables", + treated_keys = {"status": "status", "Total Time": "total_time", "solving":"solving_time", "presolving":"presolving_time", "reading":"reading_time", + "copying":"copying_time", "Problem name": "problem_name", "Presolved Problem name": "presolved_problem_name", "Variables":"_variables", "Presolved Variables":"_presolved_variables", "Constraints": "_constraints", "Presolved Constraints":"_presolved_constraints", "number of runs": "n_runs", "nodes":"n_nodes", "Solutions found": "n_solutions_found"} @@ -10812,7 +10834,7 @@ def readStatistics(filename): treated_keys["Gap"] = "gap" treated_keys["primal-dual"] = "primal_dual_integral" treated_result = dict((treated_keys[key], value) for (key, value) in result.items()) - + stats = Statistics(**treated_result) return stats diff --git a/tests/test_lp.py b/tests/test_lp.py index 299ce122c..29f3bbd21 100644 --- a/tests/test_lp.py +++ b/tests/test_lp.py @@ -1,9 +1,40 @@ from pyscipopt import LP +from pyscipopt import SCIP_LPPARAM def test_lp(): # create LP instance, minimizing by default myLP = LP() + # get default int parameters. + lpParFromScratch = myLP.getIntParam(SCIP_LPPARAM.FROMSCRATCH) + lpParScaling = myLP.getIntParam(SCIP_LPPARAM.SCALING) + lpParPricing = myLP.getIntParam(SCIP_LPPARAM.PRICING) + lpParLpinfo = myLP.getIntParam(SCIP_LPPARAM.LPINFO) + lpParLpitlim = myLP.getIntParam(SCIP_LPPARAM.LPITLIM) + lpParFastmip = myLP.getIntParam(SCIP_LPPARAM.FASTMIP) + + # get default real parameters + lpParFeastol = myLP.getRealParam(SCIP_LPPARAM.FEASTOL) + lpParDualfeastol = myLP.getRealParam(SCIP_LPPARAM.DUALFEASTOL) + lpParBarrierconvtol = myLP.getRealParam(SCIP_LPPARAM.BARRIERCONVTOL) + lpParObjlim = myLP.getRealParam(SCIP_LPPARAM.OBJLIM) + lpParLptilim = myLP.getRealParam(SCIP_LPPARAM.LPTILIM) + + # set int parameters back + myLP.setIntParam(SCIP_LPPARAM.FROMSCRATCH, lpParFromScratch) + myLP.setIntParam(SCIP_LPPARAM.SCALING, lpParScaling) + myLP.setIntParam(SCIP_LPPARAM.PRICING, lpParPricing) + myLP.setIntParam(SCIP_LPPARAM.LPINFO, lpParLpinfo) + myLP.setIntParam(SCIP_LPPARAM.LPITLIM, lpParLpitlim) + myLP.setIntParam(SCIP_LPPARAM.FASTMIP, lpParFastmip) + + # set real parameters back + myLP.setRealParam(SCIP_LPPARAM.FEASTOL, lpParFeastol) + myLP.setRealParam(SCIP_LPPARAM.DUALFEASTOL, lpParDualfeastol) + myLP.setRealParam(SCIP_LPPARAM.BARRIERCONVTOL, lpParBarrierconvtol) + myLP.setRealParam(SCIP_LPPARAM.OBJLIM, lpParObjlim) + myLP.setRealParam(SCIP_LPPARAM.LPTILIM, lpParLptilim) + # create cols w/o coefficients, 0 objective coefficient and 0,\infty bounds myLP.addCols(2 * [[]]) From 76a9dc71d1cd2a1cf1f8c0924957b97d02f2071d Mon Sep 17 00:00:00 2001 From: lidingxu Date: Wed, 19 Mar 2025 14:24:05 +0100 Subject: [PATCH 02/14] remove some unavailbale set and get functions --- src/pyscipopt/lp.pxi | 2 +- src/pyscipopt/scip.pxi | 36 ++++++++++++++++++------------------ tests/test_lp.py | 9 +++++---- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index b768c9159..afff3b685 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -508,7 +508,7 @@ cdef class LP: PY_SCIP_CALL(SCIPlpiSetRealpar(self.lpi, param, value)) - def getIntParam(self, param): + def getRealParam(self, param): """ Get the value of a parameter of type float. diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index ce5d86ffa..aeeb90b59 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -86,26 +86,26 @@ cdef class PY_SCIP_PARAMSETTING: OFF = SCIP_PARAMSETTING_OFF cdef class PY_SCIP_LPPARAM: - FROMSCRATCH = SCIP_LPPAR_FROMSCRATCH - FASTMIP = SCIP_LPPAR_FASTMIP - SCALING = SCIP_LPPAR_SCALING - PRESOLVING = SCIP_LPPAR_PRESOLVING - PRICING = SCIP_LPPAR_PRICING - LPINFO = SCIP_LPPAR_LPINFO - FEASTOL = SCIP_LPPAR_FEASTOL - DUALFEASTOL = SCIP_LPPAR_DUALFEASTOL + FROMSCRATCH = SCIP_LPPAR_FROMSCRATCH + FASTMIP = SCIP_LPPAR_FASTMIP + SCALING = SCIP_LPPAR_SCALING + PRESOLVING = SCIP_LPPAR_PRESOLVING + PRICING = SCIP_LPPAR_PRICING + LPINFO = SCIP_LPPAR_LPINFO + FEASTOL = SCIP_LPPAR_FEASTOL + DUALFEASTOL = SCIP_LPPAR_DUALFEASTOL BARRIERCONVTOL = SCIP_LPPAR_BARRIERCONVTOL - OBJLIM = SCIP_LPPAR_OBJLIM - LPITLIM = SCIP_LPPAR_LPITLIM - LPTILIM = SCIP_LPPAR_LPTILIM - MARKOWITZ = SCIP_LPPAR_MARKOWITZ - ROWREPSWITCH = SCIP_LPPAR_ROWREPSWITCH - THREADS = SCIP_LPPAR_THREADS + OBJLIM = SCIP_LPPAR_OBJLIM + LPITLIM = SCIP_LPPAR_LPITLIM + LPTILIM = SCIP_LPPAR_LPTILIM + MARKOWITZ = SCIP_LPPAR_MARKOWITZ + ROWREPSWITCH = SCIP_LPPAR_ROWREPSWITCH + THREADS = SCIP_LPPAR_THREADS CONDITIONLIMIT = SCIP_LPPAR_CONDITIONLIMIT - TIMING = SCIP_LPPAR_TIMING - RANDOMSEED = SCIP_LPPAR_RANDOMSEED - POLISHING = SCIP_LPPAR_POLISHING - REFACTOR = SCIP_LPPAR_REFACTOR + TIMING = SCIP_LPPAR_TIMING + RANDOMSEED = SCIP_LPPAR_RANDOMSEED + POLISHING = SCIP_LPPAR_POLISHING + REFACTOR = SCIP_LPPAR_REFACTOR cdef class PY_SCIP_PARAMEMPHASIS: DEFAULT = SCIP_PARAMEMPHASIS_DEFAULT diff --git a/tests/test_lp.py b/tests/test_lp.py index 29f3bbd21..477651ac2 100644 --- a/tests/test_lp.py +++ b/tests/test_lp.py @@ -11,12 +11,13 @@ def test_lp(): lpParPricing = myLP.getIntParam(SCIP_LPPARAM.PRICING) lpParLpinfo = myLP.getIntParam(SCIP_LPPARAM.LPINFO) lpParLpitlim = myLP.getIntParam(SCIP_LPPARAM.LPITLIM) - lpParFastmip = myLP.getIntParam(SCIP_LPPARAM.FASTMIP) + # lpParFastmip = myLP.getIntParam(SCIP_LPPARAM.FASTMIP) + # get default real parameters lpParFeastol = myLP.getRealParam(SCIP_LPPARAM.FEASTOL) lpParDualfeastol = myLP.getRealParam(SCIP_LPPARAM.DUALFEASTOL) - lpParBarrierconvtol = myLP.getRealParam(SCIP_LPPARAM.BARRIERCONVTOL) + # lpParBarrierconvtol = myLP.getRealParam(SCIP_LPPARAM.BARRIERCONVTOL) lpParObjlim = myLP.getRealParam(SCIP_LPPARAM.OBJLIM) lpParLptilim = myLP.getRealParam(SCIP_LPPARAM.LPTILIM) @@ -26,12 +27,12 @@ def test_lp(): myLP.setIntParam(SCIP_LPPARAM.PRICING, lpParPricing) myLP.setIntParam(SCIP_LPPARAM.LPINFO, lpParLpinfo) myLP.setIntParam(SCIP_LPPARAM.LPITLIM, lpParLpitlim) - myLP.setIntParam(SCIP_LPPARAM.FASTMIP, lpParFastmip) + # myLP.setIntParam(SCIP_LPPARAM.FASTMIP, lpParFastmip) # set real parameters back myLP.setRealParam(SCIP_LPPARAM.FEASTOL, lpParFeastol) myLP.setRealParam(SCIP_LPPARAM.DUALFEASTOL, lpParDualfeastol) - myLP.setRealParam(SCIP_LPPARAM.BARRIERCONVTOL, lpParBarrierconvtol) + # myLP.setRealParam(SCIP_LPPARAM.BARRIERCONVTOL, lpParBarrierconvtol) myLP.setRealParam(SCIP_LPPARAM.OBJLIM, lpParObjlim) myLP.setRealParam(SCIP_LPPARAM.LPTILIM, lpParLptilim) From 135840ebf09d121e046be6c18cb7eafd25e8d738 Mon Sep 17 00:00:00 2001 From: lidingxu Date: Wed, 19 Mar 2025 15:06:42 +0100 Subject: [PATCH 03/14] add comments and assertation for lp test --- src/pyscipopt/lp.pxi | 10 +++--- tests/test_lp.py | 86 ++++++++++++++++++++++++++++---------------- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index afff3b685..694b78bb1 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -482,6 +482,7 @@ cdef class LP: def setIntParam(self, param, value): """ Set an int-valued parameter. + If the parameter is not supported by the LP solver, KeyError will be raised. Parameters ---------- @@ -496,6 +497,7 @@ cdef class LP: def setRealParam(self, param, value): """ Set a real-valued parameter. + If the parameter is not supported by the LP solver, KeyError will be raised. Parameters ---------- @@ -510,8 +512,8 @@ cdef class LP: def getRealParam(self, param): """ - Get the value of a parameter of type - float. + Get the value of a parameter of type float. + If the parameter is not supported by the LP solver, KeyError will be raised. Parameters ---------- @@ -531,8 +533,8 @@ cdef class LP: def getIntParam(self, param): """ - Get the value of a parameter of type - int. + Get the value of a parameter of type int. + If the parameter is not supported by the LP solver, KeyError will be raised. Parameters ---------- diff --git a/tests/test_lp.py b/tests/test_lp.py index 477651ac2..35b5900c2 100644 --- a/tests/test_lp.py +++ b/tests/test_lp.py @@ -5,36 +5,62 @@ def test_lp(): # create LP instance, minimizing by default myLP = LP() - # get default int parameters. - lpParFromScratch = myLP.getIntParam(SCIP_LPPARAM.FROMSCRATCH) - lpParScaling = myLP.getIntParam(SCIP_LPPARAM.SCALING) - lpParPricing = myLP.getIntParam(SCIP_LPPARAM.PRICING) - lpParLpinfo = myLP.getIntParam(SCIP_LPPARAM.LPINFO) - lpParLpitlim = myLP.getIntParam(SCIP_LPPARAM.LPITLIM) - # lpParFastmip = myLP.getIntParam(SCIP_LPPARAM.FASTMIP) - - - # get default real parameters - lpParFeastol = myLP.getRealParam(SCIP_LPPARAM.FEASTOL) - lpParDualfeastol = myLP.getRealParam(SCIP_LPPARAM.DUALFEASTOL) - # lpParBarrierconvtol = myLP.getRealParam(SCIP_LPPARAM.BARRIERCONVTOL) - lpParObjlim = myLP.getRealParam(SCIP_LPPARAM.OBJLIM) - lpParLptilim = myLP.getRealParam(SCIP_LPPARAM.LPTILIM) - - # set int parameters back - myLP.setIntParam(SCIP_LPPARAM.FROMSCRATCH, lpParFromScratch) - myLP.setIntParam(SCIP_LPPARAM.SCALING, lpParScaling) - myLP.setIntParam(SCIP_LPPARAM.PRICING, lpParPricing) - myLP.setIntParam(SCIP_LPPARAM.LPINFO, lpParLpinfo) - myLP.setIntParam(SCIP_LPPARAM.LPITLIM, lpParLpitlim) - # myLP.setIntParam(SCIP_LPPARAM.FASTMIP, lpParFastmip) - - # set real parameters back - myLP.setRealParam(SCIP_LPPARAM.FEASTOL, lpParFeastol) - myLP.setRealParam(SCIP_LPPARAM.DUALFEASTOL, lpParDualfeastol) - # myLP.setRealParam(SCIP_LPPARAM.BARRIERCONVTOL, lpParBarrierconvtol) - myLP.setRealParam(SCIP_LPPARAM.OBJLIM, lpParObjlim) - myLP.setRealParam(SCIP_LPPARAM.LPTILIM, lpParLptilim) + # get default int and real parameters, some solver-specific parameters are commented. + defaultLPParFromScratch = myLP.getIntParam(SCIP_LPPARAM.FROMSCRATCH) + defaultLPParScaling = myLP.getIntParam(SCIP_LPPARAM.SCALING) + defaultLPParPricing = myLP.getIntParam(SCIP_LPPARAM.PRICING) + defaultLPParLpinfo = myLP.getIntParam(SCIP_LPPARAM.LPINFO) + defaultLPParLpitlim = myLP.getIntParam(SCIP_LPPARAM.LPITLIM) + # defaultLPParFastmip = myLP.getIntParam(SCIP_LPPARAM.FASTMIP) + defaultLPParFeastol = myLP.getRealParam(SCIP_LPPARAM.FEASTOL) + defaultLPParDualfeastol = myLP.getRealParam(SCIP_LPPARAM.DUALFEASTOL) + # defaultLPParBarrierconvtol = myLP.getRealParam(SCIP_LPPARAM.BARRIERCONVTOL) + defaultLPParObjlim = myLP.getRealParam(SCIP_LPPARAM.OBJLIM) + defaultLPParLptilim = myLP.getRealParam(SCIP_LPPARAM.LPTILIM) + + # try the following nondefault parameters + tryLPParFromScratch = 0 if defaultLPParFromScratch == 1 else 1 + tryLPParScaling = 0 if defaultLPParScaling == 1 else 1 + tryLPParPricing = 0 if defaultLPParPricing == 1 else 1 + tryLPParLpinfo = 0 if defaultLPParLpinfo == 1 else 1 + tryLPParLpitlim = max(defaultLPParLpitlim - 1, 0) + tryLPParFeastol = defaultLPParFeastol + 0.1 + tryLPParDualfeastol = defaultLPParDualfeastol + 0.1 + tryLPParObjlim = defaultLPParObjlim + 1.0 + tryLPParLptilim = defaultLPParLptilim + 1.0 + + myLP.setIntParam(SCIP_LPPARAM.FROMSCRATCH, tryLPParFromScratch) + myLP.setIntParam(SCIP_LPPARAM.SCALING, tryLPParScaling) + myLP.setIntParam(SCIP_LPPARAM.PRICING, tryLPParPricing) + myLP.setIntParam(SCIP_LPPARAM.LPINFO, tryLPParLpinfo) + myLP.setIntParam(SCIP_LPPARAM.LPITLIM, tryLPParLpitlim) + myLP.setRealParam(SCIP_LPPARAM.FEASTOL, tryLPParFeastol) + myLP.setRealParam(SCIP_LPPARAM.DUALFEASTOL, tryLPParDualfeastol) + myLP.setRealParam(SCIP_LPPARAM.OBJLIM, tryLPParObjlim) + myLP.setRealParam(SCIP_LPPARAM.LPTILIM, tryLPParLptilim) + + assert tryLPParFromScratch == myLP.getIntParam(SCIP_LPPARAM.FROMSCRATCH) + assert tryLPParScaling == myLP.getIntParam(SCIP_LPPARAM.SCALING) + assert tryLPParPricing == myLP.getIntParam(SCIP_LPPARAM.PRICING) + assert tryLPParLpinfo == myLP.getIntParam(SCIP_LPPARAM.LPINFO) + assert tryLPParLpitlim == myLP.getIntParam(SCIP_LPPARAM.LPITLIM) + assert tryLPParFeastol == myLP.getRealParam(SCIP_LPPARAM.FEASTOL) + assert tryLPParDualfeastol == myLP.getRealParam(SCIP_LPPARAM.DUALFEASTOL) + assert tryLPParObjlim == myLP.getRealParam(SCIP_LPPARAM.OBJLIM) + assert tryLPParLptilim == myLP.getRealParam(SCIP_LPPARAM.LPTILIM) + + # set back default parameters + myLP.setIntParam(SCIP_LPPARAM.FROMSCRATCH, defaultLPParFromScratch) + myLP.setIntParam(SCIP_LPPARAM.SCALING, defaultLPParScaling) + myLP.setIntParam(SCIP_LPPARAM.PRICING, defaultLPParPricing) + myLP.setIntParam(SCIP_LPPARAM.LPINFO, defaultLPParLpinfo) + myLP.setIntParam(SCIP_LPPARAM.LPITLIM, defaultLPParLpitlim) + # myLP.setIntParam(SCIP_LPPARAM.FASTMIP, defaultLPParFastmip) + myLP.setRealParam(SCIP_LPPARAM.FEASTOL, defaultLPParFeastol) + myLP.setRealParam(SCIP_LPPARAM.DUALFEASTOL, defaultLPParDualfeastol) + # myLP.setRealParam(SCIP_LPPARAM.BARRIERCONVTOL, defaultLPParBarrierconvtol) + myLP.setRealParam(SCIP_LPPARAM.OBJLIM, defaultLPParObjlim) + myLP.setRealParam(SCIP_LPPARAM.LPTILIM, defaultLPParLptilim) # create cols w/o coefficients, 0 objective coefficient and 0,\infty bounds myLP.addCols(2 * [[]]) From a06b88453f5f1765cc4f0d78748636b2035452a9 Mon Sep 17 00:00:00 2001 From: lidingxu Date: Wed, 19 Mar 2025 15:08:57 +0100 Subject: [PATCH 04/14] change function order --- src/pyscipopt/lp.pxi | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index 694b78bb1..85339475b 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -509,10 +509,9 @@ cdef class LP: """ PY_SCIP_CALL(SCIPlpiSetRealpar(self.lpi, param, value)) - - def getRealParam(self, param): + def getIntParam(self, param): """ - Get the value of a parameter of type float. + Get the value of a parameter of type int. If the parameter is not supported by the LP solver, KeyError will be raised. Parameters @@ -522,18 +521,18 @@ cdef class LP: Returns ------- - float + int """ - cdef SCIP_Real value + cdef int value - PY_SCIP_CALL(SCIPlpiGetRealpar(self.lpi, param, &value)) + PY_SCIP_CALL(SCIPlpiGetIntpar(self.lpi, param, &value)) return value - def getIntParam(self, param): + def getRealParam(self, param): """ - Get the value of a parameter of type int. + Get the value of a parameter of type float. If the parameter is not supported by the LP solver, KeyError will be raised. Parameters @@ -543,11 +542,11 @@ cdef class LP: Returns ------- - int + float """ - cdef int value + cdef SCIP_Real value - PY_SCIP_CALL(SCIPlpiGetIntpar(self.lpi, param, &value)) + PY_SCIP_CALL(SCIPlpiGetRealpar(self.lpi, param, &value)) return value From e175c7779508e95c3beeecd1560981eaf44bb894 Mon Sep 17 00:00:00 2001 From: lidingxu Date: Thu, 20 Mar 2025 11:33:59 +0100 Subject: [PATCH 05/14] remove parameter tests and add isFeasPositive --- CHANGELOG.md | 3 ++- src/pyscipopt/scip.pxd | 1 + src/pyscipopt/scip.pxi | 15 +++++++++++++++ tests/test_lp.py | 4 ---- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b2a02324..1b624e14e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## Unreleased ### Added - Added getLinearConsIndicator -- Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam +- Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam for lpi +- Added isFeasPositive ### Fixed ### Changed ### Removed diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 6f6a3d455..afd372728 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -1331,6 +1331,7 @@ cdef extern from "scip/scip.h": SCIP_Bool SCIPisFeasIntegral(SCIP* scip, SCIP_Real val) SCIP_Bool SCIPisFeasZero(SCIP* scip, SCIP_Real val) SCIP_Bool SCIPisFeasNegative(SCIP* scip, SCIP_Real val) + SCIP_Bool SCIPisFeasPositive(SCIP* scip, SCIP_Real val) SCIP_Bool SCIPisInfinity(SCIP* scip, SCIP_Real val) SCIP_Bool SCIPisLE(SCIP* scip, SCIP_Real val1, SCIP_Real val2) SCIP_Bool SCIPisLT(SCIP* scip, SCIP_Real val1, SCIP_Real val2) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index aeeb90b59..cb04c92c1 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -2987,6 +2987,21 @@ cdef class Model: """ return SCIPisFeasNegative(self._scip, value) + def isFeasPositive(self, value): + """ + Returns whether value > feastol. + + Parameters + ---------- + value : float + + Returns + ------- + bool + + """ + return SCIPisFeasPositive(self._scip, value) + def isFeasIntegral(self, value): """ Returns whether value is integral within the LP feasibility bounds. diff --git a/tests/test_lp.py b/tests/test_lp.py index 35b5900c2..1f383c18b 100644 --- a/tests/test_lp.py +++ b/tests/test_lp.py @@ -11,10 +11,8 @@ def test_lp(): defaultLPParPricing = myLP.getIntParam(SCIP_LPPARAM.PRICING) defaultLPParLpinfo = myLP.getIntParam(SCIP_LPPARAM.LPINFO) defaultLPParLpitlim = myLP.getIntParam(SCIP_LPPARAM.LPITLIM) - # defaultLPParFastmip = myLP.getIntParam(SCIP_LPPARAM.FASTMIP) defaultLPParFeastol = myLP.getRealParam(SCIP_LPPARAM.FEASTOL) defaultLPParDualfeastol = myLP.getRealParam(SCIP_LPPARAM.DUALFEASTOL) - # defaultLPParBarrierconvtol = myLP.getRealParam(SCIP_LPPARAM.BARRIERCONVTOL) defaultLPParObjlim = myLP.getRealParam(SCIP_LPPARAM.OBJLIM) defaultLPParLptilim = myLP.getRealParam(SCIP_LPPARAM.LPTILIM) @@ -55,10 +53,8 @@ def test_lp(): myLP.setIntParam(SCIP_LPPARAM.PRICING, defaultLPParPricing) myLP.setIntParam(SCIP_LPPARAM.LPINFO, defaultLPParLpinfo) myLP.setIntParam(SCIP_LPPARAM.LPITLIM, defaultLPParLpitlim) - # myLP.setIntParam(SCIP_LPPARAM.FASTMIP, defaultLPParFastmip) myLP.setRealParam(SCIP_LPPARAM.FEASTOL, defaultLPParFeastol) myLP.setRealParam(SCIP_LPPARAM.DUALFEASTOL, defaultLPParDualfeastol) - # myLP.setRealParam(SCIP_LPPARAM.BARRIERCONVTOL, defaultLPParBarrierconvtol) myLP.setRealParam(SCIP_LPPARAM.OBJLIM, defaultLPParObjlim) myLP.setRealParam(SCIP_LPPARAM.LPTILIM, defaultLPParLptilim) From d823d4dc485cac28724397547870b114f3571961 Mon Sep 17 00:00:00 2001 From: lidingxu Date: Thu, 20 Mar 2025 16:48:41 +0100 Subject: [PATCH 06/14] optimality check before getsol for lpi, fix memory issue --- CHANGELOG.md | 2 +- src/pyscipopt/lp.pxi | 75 +++++++++++++++++++++++++++++++++++++++--- src/pyscipopt/scip.pxd | 1 + tests/test_lp.py | 7 ++++ 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b624e14e..890f87101 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index 85339475b..dc9a22884 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -361,8 +361,39 @@ 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. + If the value does not exists, None will be returned. + """ + if not self.isOptimal(): + return None + + 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.""" + """ + Returns the primal solution of the last LP solve. + If the solution does not exists, None will be returned. + """ + if not self.isOptimal(): + return None + cdef int ncols = self.ncols() cdef SCIP_Real* c_primalsol = malloc(ncols * sizeof(SCIP_Real)) cdef int i @@ -380,7 +411,13 @@ cdef class LP: return SCIPlpiIsPrimalFeasible(self.lpi) def getDual(self): - """Returns the dual solution of the last LP solve.""" + """ + Returns the dual solution of the last LP solve. + If the solution does not exists, None will be returned. + """ + if not self.isOptimal(): + return None + cdef int nrows = self.nrows() cdef SCIP_Real* c_dualsol = malloc(nrows * sizeof(SCIP_Real)) cdef int i @@ -445,17 +482,45 @@ cdef class LP: return niters + def getActivity(self): + """ + Returns the row activity vector of the last LP solve. + If the vecotr does not exists, None will be returned. + """ + if not self.isOptimal(): + return None + + cdef int nrows = self.nrows() + cdef SCIP_Real* c_activity = 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.""" + """ + Returns the reduced cost vector of the last LP solve. + If the vecotr does not exists, None will be returned. + """ + if not self.isOptimal(): + return None + cdef int ncols = self.ncols() cdef SCIP_Real* c_redcost = 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) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index afd372728..f53421164 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -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) diff --git a/tests/test_lp.py b/tests/test_lp.py index 1f383c18b..e71c9c738 100644 --- a/tests/test_lp.py +++ b/tests/test_lp.py @@ -73,4 +73,11 @@ def test_lp(): solval = myLP.solve() + assert(myLP.isOptimal()) + assert(myLP.getPrimal() is not None) + assert(myLP.getDual() is not None) + assert(myLP.getActivity() is not None) + assert(myLP.getRedcost() is not None) + assert round(myLP.getObjVal() == solval) + assert round(5.0 == solval) From 16b36187c4cb5ee3925f0d72b9cdb4cb01062c65 Mon Sep 17 00:00:00 2001 From: local <31465240+lidingxu@users.noreply.github.com> Date: Fri, 21 Mar 2025 08:26:34 +0100 Subject: [PATCH 07/14] Update src/pyscipopt/lp.pxi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Dionísio <57299939+Joao-Dionisio@users.noreply.github.com> --- src/pyscipopt/lp.pxi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index dc9a22884..815436422 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -507,7 +507,7 @@ cdef class LP: def getRedcost(self): """ Returns the reduced cost vector of the last LP solve. - If the vecotr does not exists, None will be returned. + If the vector does not exist, None will be returned. """ if not self.isOptimal(): return None From e718504deaab8a17ee7adcbead7a8a71cd47f882 Mon Sep 17 00:00:00 2001 From: local <31465240+lidingxu@users.noreply.github.com> Date: Fri, 21 Mar 2025 08:26:44 +0100 Subject: [PATCH 08/14] Update src/pyscipopt/lp.pxi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Dionísio <57299939+Joao-Dionisio@users.noreply.github.com> --- src/pyscipopt/lp.pxi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index 815436422..bf4e32243 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -375,7 +375,7 @@ cdef class LP: def getObjVal(self): """ Returns the objective value of the last LP solve. - If the value does not exists, None will be returned. + If the value does not exist, None will be returned. """ if not self.isOptimal(): return None From 31cf96ed1559c286fbcc457f3797de53d38ddc45 Mon Sep 17 00:00:00 2001 From: local <31465240+lidingxu@users.noreply.github.com> Date: Fri, 21 Mar 2025 08:26:51 +0100 Subject: [PATCH 09/14] Update src/pyscipopt/lp.pxi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Dionísio <57299939+Joao-Dionisio@users.noreply.github.com> --- src/pyscipopt/lp.pxi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index bf4e32243..408f19b9d 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -389,7 +389,7 @@ cdef class LP: def getPrimal(self): """ Returns the primal solution of the last LP solve. - If the solution does not exists, None will be returned. + If the solution does not exist, None will be returned. """ if not self.isOptimal(): return None From 7ccee04685c0a561df33ed9aa9376f4a5a64afc3 Mon Sep 17 00:00:00 2001 From: local <31465240+lidingxu@users.noreply.github.com> Date: Fri, 21 Mar 2025 08:27:03 +0100 Subject: [PATCH 10/14] Update src/pyscipopt/lp.pxi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Dionísio <57299939+Joao-Dionisio@users.noreply.github.com> --- src/pyscipopt/lp.pxi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index 408f19b9d..1642946c1 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -485,7 +485,7 @@ cdef class LP: def getActivity(self): """ Returns the row activity vector of the last LP solve. - If the vecotr does not exists, None will be returned. + If the vector does not exist, None will be returned. """ if not self.isOptimal(): return None From 9fe85910f309986b31fcea63df466aa0041c60f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dion=C3=ADsio?= <57299939+Joao-Dionisio@users.noreply.github.com> Date: Fri, 21 Mar 2025 07:37:18 +0000 Subject: [PATCH 11/14] fix conflict --- CHANGELOG.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 498644233..890f87101 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,7 @@ ## Unreleased ### Added - Added getLinearConsIndicator -<<<<<<< HEAD - Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam, isOptimal, getObjVal, getRedcost for lpi -======= -- Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam for lpi ->>>>>>> upstream/master - Added isFeasPositive ### Fixed ### Changed From 15c798a0b7fc46238c270ac67ed4bce52faddcc5 Mon Sep 17 00:00:00 2001 From: lidingxu Date: Fri, 21 Mar 2025 08:47:56 +0100 Subject: [PATCH 12/14] style change --- src/pyscipopt/lp.pxi | 40 ++++++++++------------------------------ tests/test_lp.py | 2 +- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/pyscipopt/lp.pxi b/src/pyscipopt/lp.pxi index 1642946c1..80dbdf2a5 100644 --- a/src/pyscipopt/lp.pxi +++ b/src/pyscipopt/lp.pxi @@ -373,12 +373,8 @@ cdef class LP: return SCIPlpiIsOptimal(self.lpi) def getObjVal(self): - """ - Returns the objective value of the last LP solve. - If the value does not exist, None will be returned. - """ - if not self.isOptimal(): - return None + """Returns the objective value of the last LP solve.""" + assert self.isOptimal(), "LP is not optimal" cdef SCIP_Real objval @@ -387,12 +383,8 @@ cdef class LP: return objval def getPrimal(self): - """ - Returns the primal solution of the last LP solve. - If the solution does not exist, None will be returned. - """ - if not self.isOptimal(): - return None + """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 = malloc(ncols * sizeof(SCIP_Real)) @@ -411,12 +403,8 @@ cdef class LP: return SCIPlpiIsPrimalFeasible(self.lpi) def getDual(self): - """ - Returns the dual solution of the last LP solve. - If the solution does not exists, None will be returned. - """ - if not self.isOptimal(): - return None + """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 = malloc(nrows * sizeof(SCIP_Real)) @@ -483,12 +471,8 @@ cdef class LP: return niters def getActivity(self): - """ - Returns the row activity vector of the last LP solve. - If the vector does not exist, None will be returned. - """ - if not self.isOptimal(): - return None + """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 = malloc(nrows * sizeof(SCIP_Real)) @@ -505,12 +489,8 @@ cdef class LP: return activity def getRedcost(self): - """ - Returns the reduced cost vector of the last LP solve. - If the vector does not exist, None will be returned. - """ - if not self.isOptimal(): - return None + """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 = malloc(ncols * sizeof(SCIP_Real)) diff --git a/tests/test_lp.py b/tests/test_lp.py index e71c9c738..51b9fddd0 100644 --- a/tests/test_lp.py +++ b/tests/test_lp.py @@ -76,8 +76,8 @@ def test_lp(): assert(myLP.isOptimal()) assert(myLP.getPrimal() is not None) assert(myLP.getDual() is not None) - assert(myLP.getActivity() is not None) assert(myLP.getRedcost() is not None) + assert(myLP.getActivity() is not None) assert round(myLP.getObjVal() == solval) assert round(5.0 == solval) From c134f33f37a43890202d09b5a8d184bd1a79e39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dion=C3=ADsio?= <57299939+Joao-Dionisio@users.noreply.github.com> Date: Fri, 21 Mar 2025 08:37:23 +0000 Subject: [PATCH 13/14] Update test_lp.py --- tests/test_lp.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/test_lp.py b/tests/test_lp.py index 51b9fddd0..3e69a5b68 100644 --- a/tests/test_lp.py +++ b/tests/test_lp.py @@ -76,8 +76,16 @@ def test_lp(): assert(myLP.isOptimal()) assert(myLP.getPrimal() is not None) assert(myLP.getDual() is not None) - assert(myLP.getRedcost() is not None) - assert(myLP.getActivity() is not None) - assert round(myLP.getObjVal() == solval) + + 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) From e78518b8a745c2205205ee3646b69c0654c0830f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dion=C3=ADsio?= <57299939+Joao-Dionisio@users.noreply.github.com> Date: Fri, 21 Mar 2025 08:38:30 +0000 Subject: [PATCH 14/14] typo --- tests/test_lp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_lp.py b/tests/test_lp.py index 3e69a5b68..7cc90585d 100644 --- a/tests/test_lp.py +++ b/tests/test_lp.py @@ -82,7 +82,7 @@ def test_lp(): for i in redcost: assert(i is not None) - activity = myLP().getActivity() + activity = myLP.getActivity() assert(activity is not None) for i in activity: assert(i is not None)