From 6a4140bf62c8cec6dd195e16e344be409dbaf561 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 28 May 2025 16:10:54 +0200 Subject: [PATCH 01/24] Add printStatisticsJson --- CHANGELOG.md | 1 + src/pyscipopt/scip.pxd | 1 + src/pyscipopt/scip.pxi | 45 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efd8ed922..ad841ca57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Added support for knapsack constraints - Added isPositive(), isNegative(), isFeasLE(), isFeasLT(), isFeasGE(), isFeasGT(), isHugeValue(), and tests - Added SCIP_LOCKTYPE, addVarLocksType(), getNLocksDown(), getNLocksUp(), getNLocksDownType(), getNLocksUpType(), and tests +- Wrapped SCIPprintStatisticsJson ### Fixed ### Changed ### Removed diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 9453750e3..323f709ed 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -1357,6 +1357,7 @@ cdef extern from "scip/scip.h": # Statistic Methods SCIP_RETCODE SCIPprintStatistics(SCIP* scip, FILE* outfile) + SCIP_RETCODE SCIPprintStatisticsJson(SCIP* scip, FILE* file) SCIP_Longint SCIPgetNNodes(SCIP* scip) SCIP_Longint SCIPgetNTotalNodes(SCIP* scip) SCIP_Longint SCIPgetNFeasibleLeaves(SCIP* scip) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 53bed228f..75cc49965 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -41,9 +41,9 @@ include "nodesel.pxi" include "matrix.pxi" # recommended SCIP version; major version is required -MAJOR = 9 -MINOR = 2 -PATCH = 1 +MAJOR = 10 +MINOR = 0 +PATCH = 0 # for external user functions use def; for functions used only inside the interface (starting with _) use cdef # todo: check whether this is currently done like this @@ -10131,12 +10131,45 @@ cdef class Model: # Statistic Methods - def printStatistics(self): - """Print statistics.""" + def printStatistics(self, filename=None): + """ + Print statistics. + + Parameters + ---------- + filename : str, optional + name of the output file (Default = None) + + """ + + user_locale = locale.getlocale(category=locale.LC_NUMERIC) + locale.setlocale(locale.LC_NUMERIC, "C") + + if not filename: + PY_SCIP_CALL(SCIPprintStatistics(self._scip, NULL)) + else: + PY_SCIP_CALL(SCIPprintStatistics(self._scip, str_conversion(filename))) + + locale.setlocale(locale.LC_NUMERIC,user_locale) + + def printStatisticsJson(self, filename=None): + """ + Print statistics in JSON format. + + Parameters + ---------- + filename : str, optional + name of the output file (Default = None) + + """ + user_locale = locale.getlocale(category=locale.LC_NUMERIC) locale.setlocale(locale.LC_NUMERIC, "C") - PY_SCIP_CALL(SCIPprintStatistics(self._scip, NULL)) + if not filename: + PY_SCIP_CALL(SCIPprintStatisticsJson(self._scip, NULL)) + else: + PY_SCIP_CALL(SCIPprintStatisticsJson(self._scip, str_conversion(filename))) locale.setlocale(locale.LC_NUMERIC,user_locale) From 3c50d404de05a70590a333ff1cbde50033220c7d Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sat, 31 May 2025 10:26:37 +0200 Subject: [PATCH 02/24] Implied integer stuff --- src/pyscipopt/scip.pxd | 11 ++++++++ src/pyscipopt/scip.pxi | 57 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 323f709ed..1295e6b0e 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -304,6 +304,12 @@ cdef extern from "scip/scip.h": cdef extern from "scip/type_var.h": SCIP_LOCKTYPE SCIP_LOCKTYPE_MODEL SCIP_LOCKTYPE SCIP_LOCKTYPE_CONFLICT + + ctypedef int SCIP_IMPLINTTYPE + cdef extern from "scip/type_var.h": + SCIP_IMPLINTTYPE SCIP_IMPLINTTYPE_NONE + SCIP_IMPLINTTYPE SCIP_IMPLINTTYPE_WEAK + SCIP_IMPLINTTYPE SCIP_IMPLINTTYPE_STRONG ctypedef int SCIP_BENDERSENFOTYPE cdef extern from "scip/type_benders.h": @@ -802,6 +808,11 @@ cdef extern from "scip/scip.h": int SCIPgetNImplVars(SCIP* scip) int SCIPgetNContVars(SCIP* scip) SCIP_VARTYPE SCIPvarGetType(SCIP_VAR* var) + SCIP_Bool SCIPvarIsBinary(SCIP_VAR* var) + SCIP_Bool SCIPvarIsIntegral(SCIP_VAR* var) + SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR* var) + SCIP_Bool SCIPvarIsNonImpliedIntegral(SCIP_VAR* var) + SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR* var) SCIP_Bool SCIPvarIsOriginal(SCIP_VAR* var) SCIP_Bool SCIPvarIsTransformed(SCIP_VAR* var) SCIP_COL* SCIPvarGetCol(SCIP_VAR* var) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 75cc49965..64428e3f0 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -259,6 +259,11 @@ cdef class PY_SCIP_LOCKTYPE: MODEL = SCIP_LOCKTYPE_MODEL CONFLICT = SCIP_LOCKTYPE_CONFLICT +cdef class PY_SCIP_IMPLINTTYPE: + NONE = SCIP_IMPLINTTYPE_NONE + WEAK = SCIP_IMPLINTTYPE_WEAK + STRONG = SCIP_IMPLINTTYPE_STRONG + cdef class PY_SCIP_LPSOLSTAT: NOTSOLVED = SCIP_LPSOLSTAT_NOTSOLVED OPTIMAL = SCIP_LPSOLSTAT_OPTIMAL @@ -1510,7 +1515,7 @@ cdef class Variable(Expr): def vtype(self): """ - Retrieve the variables type (BINARY, INTEGER, IMPLINT or CONTINUOUS) + Retrieve the variables type (BINARY, INTEGER, CONTINUOUS, or IMPLINT) Returns ------- @@ -1527,6 +1532,56 @@ cdef class Variable(Expr): return "CONTINUOUS" elif vartype == SCIP_VARTYPE_IMPLINT: return "IMPLINT" + + def isBinary(self): + """ + Returns whether variable is of BINARY type. + + Returns + ------- + bool + """ + return SCIPvarIsBinary(self.scip_var) + + def isIntegral(self): + """ + Returns whether variable is of INTEGER type. + + Returns + ------- + bool + """ + return SCIPvarIsInteger(self.scip_var) + + def isImpliedIntegral(self): + """ + Returns whether variable is implied integral (weakly or strongly). + + Returns + ------- + bool + """ + return SCIPvarIsImpliedIntegral(self.scip_var) + + def isNonImpliedIntegral(self): + """ + Returns TRUE if the variable is integral, but not implied integral.. + + Returns + ------- + bool + """ + return SCIPvarIsImpliedIntegral(self.scip_var) + + def getImplType(self): + """ + Returns the implied integral type of the variable + + Returns + ------- + PY_SCIP_IMPLINTTYPE + """ + return SCIPvarGetImplType(self.scip_var) def isOriginal(self): """ From 45933b9204f8b7166a122034c701ec68c82995ec Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sat, 31 May 2025 10:32:33 +0200 Subject: [PATCH 03/24] Add extra event types --- src/pyscipopt/scip.pxd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 1295e6b0e..7dc98c38d 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -257,12 +257,15 @@ cdef extern from "scip/scip.h": SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLEADDED SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLEREMOVED SCIP_EVENTTYPE SCIP_EVENTTYPE_IMPLADDED + SCIP_EVENTTYPE SCIP_EVENTTYPE_TYPECHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_IMPLTYPECHANGED 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_DUALBOUNDIMPROVED SCIP_EVENTTYPE SCIP_EVENTTYPE_FIRSTLPSOLVED SCIP_EVENTTYPE SCIP_EVENTTYPE_LPSOLVED SCIP_EVENTTYPE SCIP_EVENTTYPE_POORSOLFOUND @@ -292,6 +295,7 @@ cdef extern from "scip/scip.h": SCIP_EVENTTYPE SCIP_EVENTTYPE_LPEVENT SCIP_EVENTTYPE SCIP_EVENTTYPE_SOLFOUND SCIP_EVENTTYPE SCIP_EVENTTYPE_SOLEVENT + SCIP_EVENTTYPE SCIP_EVENTTYPE_GAPUPDATED SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWEVENT From af1645d7365e8b941530d595a856d2f7bb779610 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sat, 31 May 2025 11:13:57 +0200 Subject: [PATCH 04/24] minor fixes in relax.pxi --- src/pyscipopt/relax.pxi | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pyscipopt/relax.pxi b/src/pyscipopt/relax.pxi index 81695e8bb..f61e648a8 100644 --- a/src/pyscipopt/relax.pxi +++ b/src/pyscipopt/relax.pxi @@ -25,9 +25,8 @@ cdef class Relax: pass def relaxexec(self): - '''callls execution method of relaxation handler''' - print("python error in relaxexec: this method needs to be implemented") - return{} + '''calls execution method of relaxation handler''' + raise NotImplementedError("relaxexec() is a fundamental callback and should be implemented in the derived class") cdef SCIP_RETCODE PyRelaxCopy (SCIP* scip, SCIP_RELAX* relax) noexcept with gil: From a310db6d27886ec4142640e1ce2bda060bdaefff Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sat, 31 May 2025 11:14:04 +0200 Subject: [PATCH 05/24] start of iisfinder plugin --- src/pyscipopt/iisfinder.pxi | 37 +++++++++++++++++++++++++++++++++++++ src/pyscipopt/scip.pxd | 23 ++++++++++++++++++++--- src/pyscipopt/scip.pxi | 27 +++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/pyscipopt/iisfinder.pxi diff --git a/src/pyscipopt/iisfinder.pxi b/src/pyscipopt/iisfinder.pxi new file mode 100644 index 000000000..6869757e1 --- /dev/null +++ b/src/pyscipopt/iisfinder.pxi @@ -0,0 +1,37 @@ +##@file iisfinder.pxi +#@brief Base class of the Relaxator Plugin +cdef class IISFinder: + cdef public Model model + cdef public str name + + def iisfinderfree(self): + '''calls destructor and frees memory of iis finder''' + pass + + def iisfinderexec(self): + '''calls execution method of iis finder''' + raise NotImplementedError("iisfinderexec() is a fundamental callback and should be implemented in the derived class") + + +cdef SCIP_RETCODE PyIISFinderCopy (SCIP* scip, SCIP_IISFINDER* iisfinder) noexcept with gil: + return SCIP_OKAY + +cdef SCIP_RETCODE PyIISFinderFree (SCIP* scip, SCIP_IISFINDER* iisfinder) noexcept with gil: + cdef SCIP_IISFINDERDATA* iisfinderdata + iisfinderdata = SCIPIISfinderGetData(iisfinder) + PyRelax = iisfinderdata + PyRelax.iisfinderfree() + Py_DECREF(PyRelax) + return SCIP_OKAY + +cdef SCIP_RETCODE PyRelaxExec (SCIP* scip, SCIP_IISFINDER* iisfinder, SCIP_Real* lowerbound, SCIP_RESULT* result) noexcept with gil: + cdef SCIP_IISFINDERDATA* iisfinderdata + iisfinderdata = SCIPiisfinderGetData(iisfinder) + PyRelax = iisfinderdata + result_dict = PyRelax.iisfinderexec() + assert isinstance(result_dict, dict), "iisfinderexec() must return a dictionary." + #TODO + assert False + lowerbound[0] = result_dict.get("lowerbound", lowerbound[0]) + result[0] = result_dict.get("result", result[0]) + return SCIP_OKAY \ No newline at end of file diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 7dc98c38d..8333eee31 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -436,6 +436,15 @@ cdef extern from "scip/scip.h": ctypedef struct SCIP_HEURDATA: pass + ctypedef struct SCIP_IISFINDER: + pass + + ctypedef struct SCIP_IISFINDERDATA: + pass + + ctypedef struct SCIP_IIS: + pass + ctypedef struct SCIP_RELAX: pass @@ -1171,6 +1180,16 @@ cdef extern from "scip/scip.h": SCIP_HEURTIMING SCIPheurGetTimingmask(SCIP_HEUR* heur) void SCIPheurSetTimingmask(SCIP_HEUR* heur, SCIP_HEURTIMING timingmask) + #IIS finder plugin + SCIP_RETCODE SCIPincludeIISFinder(SCIP* scip, + const char* name, + const char* desc, + int priority, + SCIP_RETCODE (*iisfindercopy) (SCIP* scip, SCIP_IISFINDER* iisfinder), + SCIP_RETCODE (*iisfinderfree) (SCIP* scip, SCIP_IISFINDER* iisfinder), + SCIP_DECL_IISFINDEREXEC (*iisfinderexec) (SCIP_IIS* iis, SCIP_IISFINDER* iisfinder, SCIP_Real timelim, SCIP_Longint nodelim, SCIP_Bool removebounds, SCIP_Bool silent, SCIP_RESULT* result) + SCIP_IISFINDERDATA* iisfinderdata) + #Relaxation plugin SCIP_RETCODE SCIPincludeRelax(SCIP* scip, const char* name, @@ -1449,7 +1468,6 @@ cdef extern from "scip/scip.h": SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP** hashmap, BMS_BLKMEM* blkmem, int mapsize) void SCIPhashmapFree(SCIP_HASHMAP** hashmap) - cdef extern from "scip/tree.h": int SCIPnodeGetNAddedConss(SCIP_NODE* node) @@ -1607,7 +1625,6 @@ cdef extern from "scip/cons_sos1.h": SCIP_CONS* cons, SCIP_VAR* var) - cdef extern from "scip/cons_sos2.h": SCIP_RETCODE SCIPcreateConsSOS2(SCIP* scip, SCIP_CONS** cons, @@ -1705,6 +1722,7 @@ cdef extern from "scip/cons_xor.h": SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode) + cdef extern from "scip/scip_cons.h": SCIP_RETCODE SCIPprintCons(SCIP* scip, SCIP_CONS* cons, @@ -1859,7 +1877,6 @@ cdef extern from "scip/scip_nlp.h": SCIP_RETCODE SCIPgetNlRowActivityBounds(SCIP* scip, SCIP_NLROW* nlrow, SCIP_Real* minactivity, SCIP_Real* maxactivity) SCIP_RETCODE SCIPprintNlRow(SCIP* scip, SCIP_NLROW* nlrow, FILE* file) - cdef extern from "scip/cons_cardinality.h": SCIP_RETCODE SCIPcreateConsCardinality(SCIP* scip, SCIP_CONS** cons, diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 64428e3f0..e76a1e654 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -8531,6 +8531,33 @@ cdef class Model: heur.model = weakref.proxy(self) heur.name = name Py_INCREF(heur) + + def includeIISFinder(self, IISfinder iisfinder, name, desc, priority=10000, freq=1): + """ + Include an IIS (Irreducible Infeasible Set) finder handler. + + Parameters + ---------- + iisfinder : IISfinder + IIS finder + name : str + name of IIS finder + desc : str + description of IIS finder + priority : int, optional + priority of the IISfinder (#todo description) + freq : int, optional + frequency for calling IIS finder + + """ + nam = str_conversion(name) + des = str_conversion(desc) + PY_SCIP_CALL(SCIPincludeIISFinder(self._scip, nam, des, priority, freq, PyIISFinderCopy, PyIISFinderFree, + PyIISFinderExec, iisfinder)) + iisfinder.model = weakref.proxy(self) + iisfinder.name = name + + Py_INCREF(iisfinder) def includeRelax(self, Relax relax, name, desc, priority=10000, freq=1): """ From 2fe76806db7cf93d8be8708da0c7e7f77a338248 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 3 Jun 2025 22:56:47 +0200 Subject: [PATCH 06/24] compilation, left iis for later --- src/pyscipopt/scip.pxd | 22 ++++++--------- src/pyscipopt/scip.pxi | 63 +++++++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 8333eee31..06aa7d5f2 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -1180,15 +1180,15 @@ cdef extern from "scip/scip.h": SCIP_HEURTIMING SCIPheurGetTimingmask(SCIP_HEUR* heur) void SCIPheurSetTimingmask(SCIP_HEUR* heur, SCIP_HEURTIMING timingmask) - #IIS finder plugin - SCIP_RETCODE SCIPincludeIISFinder(SCIP* scip, - const char* name, - const char* desc, - int priority, - SCIP_RETCODE (*iisfindercopy) (SCIP* scip, SCIP_IISFINDER* iisfinder), - SCIP_RETCODE (*iisfinderfree) (SCIP* scip, SCIP_IISFINDER* iisfinder), - SCIP_DECL_IISFINDEREXEC (*iisfinderexec) (SCIP_IIS* iis, SCIP_IISFINDER* iisfinder, SCIP_Real timelim, SCIP_Longint nodelim, SCIP_Bool removebounds, SCIP_Bool silent, SCIP_RESULT* result) - SCIP_IISFINDERDATA* iisfinderdata) + # #IIS finder plugin + # SCIP_RETCODE SCIPincludeIISFinder(SCIP* scip, + # const char* name, + # const char* desc, + # int priority, + # SCIP_RETCODE (*iisfindercopy) (SCIP* scip, SCIP_IISFINDER* iisfinder), + # SCIP_RETCODE (*iisfinderfree) (SCIP* scip, SCIP_IISFINDER* iisfinder), + # SCIP_RETCODE (*iisfinderexec) (SCIP_IIS* iis, SCIP_IISFINDER* iisfinder, SCIP_Real timelim, SCIP_Longint nodelim, SCIP_Bool removebounds, SCIP_Bool silent, SCIP_RESULT* result), + # SCIP_IISFINDERDATA* iisfinderdata) #Relaxation plugin SCIP_RETCODE SCIPincludeRelax(SCIP* scip, @@ -1464,10 +1464,6 @@ cdef extern from "scip/scip.h": BMS_BLKMEM* SCIPblkmem(SCIP* scip) - # pub_misc.h - SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP** hashmap, BMS_BLKMEM* blkmem, int mapsize) - void SCIPhashmapFree(SCIP_HASHMAP** hashmap) - cdef extern from "scip/tree.h": int SCIPnodeGetNAddedConss(SCIP_NODE* node) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index e76a1e654..2d9504d8c 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -31,6 +31,7 @@ include "conshdlr.pxi" include "cutsel.pxi" include "event.pxi" include "heuristic.pxi" +# include "iisfinder.pxi" include "presol.pxi" include "pricer.pxi" include "propagator.pxi" @@ -1551,7 +1552,7 @@ cdef class Variable(Expr): ------- bool """ - return SCIPvarIsInteger(self.scip_var) + return SCIPvarIsIntegral(self.scip_var) def isImpliedIntegral(self): """ @@ -8532,32 +8533,32 @@ cdef class Model: heur.name = name Py_INCREF(heur) - def includeIISFinder(self, IISfinder iisfinder, name, desc, priority=10000, freq=1): - """ - Include an IIS (Irreducible Infeasible Set) finder handler. - - Parameters - ---------- - iisfinder : IISfinder - IIS finder - name : str - name of IIS finder - desc : str - description of IIS finder - priority : int, optional - priority of the IISfinder (#todo description) - freq : int, optional - frequency for calling IIS finder - - """ - nam = str_conversion(name) - des = str_conversion(desc) - PY_SCIP_CALL(SCIPincludeIISFinder(self._scip, nam, des, priority, freq, PyIISFinderCopy, PyIISFinderFree, - PyIISFinderExec, iisfinder)) - iisfinder.model = weakref.proxy(self) - iisfinder.name = name - - Py_INCREF(iisfinder) + # def includeIISFinder(self, IISfinder iisfinder, name, desc, priority=10000, freq=1): + # """ + # Include an IIS (Irreducible Infeasible Set) finder handler. + + # Parameters + # ---------- + # iisfinder : IISfinder + # IIS finder + # name : str + # name of IIS finder + # desc : str + # description of IIS finder + # priority : int, optional + # priority of the IISfinder (#todo description) + # freq : int, optional + # frequency for calling IIS finder + + # """ + # nam = str_conversion(name) + # des = str_conversion(desc) + # PY_SCIP_CALL(SCIPincludeIISFinder(self._scip, nam, des, priority, freq, PyIISFinderCopy, PyIISFinderFree, + # PyIISFinderExec, iisfinder)) + # iisfinder.model = weakref.proxy(self) + # iisfinder.name = name + + # Py_INCREF(iisfinder) def includeRelax(self, Relax relax, name, desc, priority=10000, freq=1): """ @@ -10230,7 +10231,9 @@ cdef class Model: if not filename: PY_SCIP_CALL(SCIPprintStatistics(self._scip, NULL)) else: - PY_SCIP_CALL(SCIPprintStatistics(self._scip, str_conversion(filename))) + 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) @@ -10251,7 +10254,9 @@ cdef class Model: if not filename: PY_SCIP_CALL(SCIPprintStatisticsJson(self._scip, NULL)) else: - PY_SCIP_CALL(SCIPprintStatisticsJson(self._scip, str_conversion(filename))) + 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) From a29aa5cc4b95c4c954070eb08762d9b92c85e41d Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 4 Jun 2025 01:18:34 +0200 Subject: [PATCH 07/24] fix issues with exact scip. still no support --- src/pyscipopt/reader.pxi | 7 ++++--- src/pyscipopt/scip.pxd | 8 ++++++-- tests/test_reader.py | 6 +++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/pyscipopt/reader.pxi b/src/pyscipopt/reader.pxi index 13fc13d1b..c75cab137 100644 --- a/src/pyscipopt/reader.pxi +++ b/src/pyscipopt/reader.pxi @@ -40,9 +40,10 @@ cdef SCIP_RETCODE PyReaderRead (SCIP* scip, SCIP_READER* reader, const char* fil cdef SCIP_RETCODE PyReaderWrite (SCIP* scip, SCIP_READER* reader, FILE* file, const char* name, SCIP_PROBDATA* probdata, SCIP_Bool transformed, - SCIP_OBJSENSE objsense, SCIP_Real objscale, SCIP_Real objoffset, - SCIP_VAR** vars, int nvars, int nbinvars, int nintvars, int nimplvars, int ncontvars, - SCIP_VAR** fixedvars, int nfixedvars, int startnvars, + SCIP_OBJSENSE objsense, SCIP_Real objscale, SCIP_Real objoffset, + SCIP_RATIONAL* objoffsetexact, SCIP_RATIONAL* objscaleexact, + SCIP_VAR** vars, int nvars, int nbinvars, int nintvars, int nimplvars, + int ncontvars, SCIP_VAR** fixedvars, int nfixedvars, int startnvars, SCIP_CONS** conss, int nconss, int maxnconss, int startnconss, SCIP_Bool genericnames, SCIP_RESULT* result) noexcept with gil: cdef SCIP_READERDATA* readerdata = SCIPreaderGetData(reader) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 06aa7d5f2..b3332d4c0 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -370,6 +370,9 @@ cdef extern from "scip/scip.h": ctypedef double SCIP_Real + ctypedef struct SCIP_RATIONAL: + pass + ctypedef struct SCIP: pass @@ -986,8 +989,9 @@ cdef extern from "scip/scip.h": SCIP_RETCODE (*readerwrite) (SCIP* scip, SCIP_READER* reader, FILE* file, const char* name, SCIP_PROBDATA* probdata, SCIP_Bool transformed, SCIP_OBJSENSE objsense, SCIP_Real objscale, SCIP_Real objoffset, - SCIP_VAR** vars, int nvars, int nbinvars, int nintvars, int nimplvars, int ncontvars, - SCIP_VAR** fixedvars, int nfixedvars, int startnvars, + SCIP_RATIONAL* objoffsetexact, SCIP_RATIONAL* objscaleexact, + SCIP_VAR** vars, int nvars, int nbinvars, int nintvars, int nimplvars, + int ncontvars, SCIP_VAR** fixedvars, int nfixedvars, int startnvars, SCIP_CONS** conss, int nconss, int maxnconss, int startnconss, SCIP_Bool genericnames, SCIP_RESULT* result), SCIP_READERDATA* readerdata) diff --git a/tests/test_reader.py b/tests/test_reader.py index 93d10c84b..c4544a018 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -136,4 +136,8 @@ def test_readStatistics(): m.writeStatistics(os.path.join("tests", "data", "readStatistics.stats")) result = readStatistics(os.path.join("tests", "data", "readStatistics.stats")) assert result.status == "user_interrupt" - assert result.gap == None \ No newline at end of file + assert result.gap == None + +def test_writeStatisticsJson(): + + assert False \ No newline at end of file From 6c126f72c8cd20a2b010b6ca8d22fcaf290a25fb Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 5 Jun 2025 16:34:21 +0100 Subject: [PATCH 08/24] fixed some tests --- src/pyscipopt/relax.pxi | 4 ++-- tests/test_reader.py | 13 ++++++++++++- tests/test_vars.py | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/pyscipopt/relax.pxi b/src/pyscipopt/relax.pxi index f61e648a8..db799bf0a 100644 --- a/src/pyscipopt/relax.pxi +++ b/src/pyscipopt/relax.pxi @@ -26,8 +26,8 @@ cdef class Relax: def relaxexec(self): '''calls execution method of relaxation handler''' - raise NotImplementedError("relaxexec() is a fundamental callback and should be implemented in the derived class") - + print("relaxexec() is a fundamental callback and should be implemented in the derived class") + return {} cdef SCIP_RETCODE PyRelaxCopy (SCIP* scip, SCIP_RELAX* relax) noexcept with gil: return SCIP_OKAY diff --git a/tests/test_reader.py b/tests/test_reader.py index c4544a018..028da1050 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -1,7 +1,9 @@ import pytest import os +from json import load from pyscipopt import Model, quicksum, Reader, SCIP_RESULT, readStatistics +from helpers.utils import random_mip_1 class SudokuReader(Reader): @@ -140,4 +142,13 @@ def test_readStatistics(): def test_writeStatisticsJson(): - assert False \ No newline at end of file + model = random_mip_1() + model.optimize() + json_output = model.writeStatisticsJson("statistics.json") + model.writeStatisticsJson("statistics.json") + + with open("statistics.json", "r") as f: + data = load(f) + assert data["origprob"]["problem_name"] == "model" + + os.remove("statistics.json") \ No newline at end of file diff --git a/tests/test_vars.py b/tests/test_vars.py index d8c92ff40..9c77d634f 100644 --- a/tests/test_vars.py +++ b/tests/test_vars.py @@ -58,7 +58,7 @@ def test_vtype(): assert x.vtype() == "CONTINUOUS" assert y.vtype() == "INTEGER" assert z.vtype() == "BINARY" - assert w.vtype() == "IMPLINT" + assert w.vtype() == "CONTINUOUS" #todo check if this is indeed the expected behavior with SCIP10. Used to be IMPLINT, but deprecation and stuff m.chgVarType(x, 'I') assert x.vtype() == "INTEGER" From b841b95bd260ded5c6f73f8d91db8e91214fdb11 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 5 Jun 2025 16:41:45 +0100 Subject: [PATCH 09/24] fix minor typos --- src/pyscipopt/scip.pxi | 2 +- tests/test_reader.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 6d31003de..2f601f0bc 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -10290,7 +10290,7 @@ cdef class Model: else: with open(filename, "w") as f: cfile = fdopen(f.fileno(), "w") - PY_SCIP_CALL(SCIPprintStatistics(self._scip, cfile)) + PY_SCIP_CALL(SCIPprintStatisticsJson(self._scip, cfile)) locale.setlocale(locale.LC_NUMERIC,user_locale) diff --git a/tests/test_reader.py b/tests/test_reader.py index 028da1050..759c9b7fe 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -3,7 +3,7 @@ from json import load from pyscipopt import Model, quicksum, Reader, SCIP_RESULT, readStatistics -from helpers.utils import random_mip_1 +from helpers.utils import random_lp_1 class SudokuReader(Reader): @@ -142,10 +142,9 @@ def test_readStatistics(): def test_writeStatisticsJson(): - model = random_mip_1() + model = random_lp_1() model.optimize() - json_output = model.writeStatisticsJson("statistics.json") - model.writeStatisticsJson("statistics.json") + model.printStatisticsJson("statistics.json") with open("statistics.json", "r") as f: data = load(f) From 79c88a171969e0332cf5c90de9dd386d6fef1ee0 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 5 Jun 2025 16:45:43 +0100 Subject: [PATCH 10/24] changelog so I don't forget --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95b39fe29..4ad446436 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - Added isPositive(), isNegative(), isFeasLE(), isFeasLT(), isFeasGE(), isFeasGT(), isHugeValue(), and tests - Added SCIP_LOCKTYPE, addVarLocksType(), getNLocksDown(), getNLocksUp(), getNLocksDownType(), getNLocksUpType(), and tests - Wrapped SCIPprintStatisticsJson +- Added 4 new events: TYPECHANGED, IMPLTYPECHANGED, DUALBOUNDIMPROVED, GAPUPDATED. +- Support for new implied integrality +- Wrapped varIsBinary(), varIsIntegral(), varIsImpliedIntegral(), varIsNonImpliedIntegral(), varGetImplType() +- Added support for IISFinder ### Fixed - Raised an error when an expression is used when a variable is required ### Changed From 703fd3484456a4b81cb4c30650d004f6936e3f24 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 5 Jun 2025 17:01:57 +0100 Subject: [PATCH 11/24] variable type tests --- src/pyscipopt/scip.pxi | 2 +- tests/test_vars.py | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 2f601f0bc..4139a938c 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -1575,7 +1575,7 @@ cdef class Variable(Expr): ------- bool """ - return SCIPvarIsImpliedIntegral(self.scip_var) + return SCIPvarIsNonImpliedIntegral(self.scip_var) def getImplType(self): """ diff --git a/tests/test_vars.py b/tests/test_vars.py index 9c77d634f..8be02ef5b 100644 --- a/tests/test_vars.py +++ b/tests/test_vars.py @@ -63,5 +63,17 @@ def test_vtype(): m.chgVarType(x, 'I') assert x.vtype() == "INTEGER" - m.chgVarType(y, 'M') - assert y.vtype() == "IMPLINT" \ No newline at end of file + m.chgVarType(y, 'C') + assert y.vtype() == "CONTINUOUS" + + is_int = lambda x: x.isIntegral() == True + is_implint = lambda x: x.isImpliedIntegral() == True + is_nonimplint = lambda x: x.isNonImpliedIntegral() == True + is_bin = lambda x: x.isBinary() == True + + assert not is_int(y) and not is_implint(y) and not is_nonimplint(y) and not is_bin(y) + assert is_int(x) and not is_implint(x) and not is_nonimplint(x) and not is_bin(x) + assert is_int(z) and not is_implint(z) and not is_nonimplint(z) and is_bin(z) + assert w.vtype() == "CONTINUOUS" and is_int(w) and is_implint(w) and is_nonimplint(w) and not is_bin(w) + + assert w.getImplType() == 1 \ No newline at end of file From f352c3027eb6d21eb7d1e4f49286f77c7905a882 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 11 Jun 2025 11:26:15 +0100 Subject: [PATCH 12/24] fix test_pricer bug --- tests/test_pricer.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/test_pricer.py b/tests/test_pricer.py index 647e26e90..9445c278a 100644 --- a/tests/test_pricer.py +++ b/tests/test_pricer.py @@ -42,8 +42,6 @@ def pricerredcost(self): assert type(self.model.getNSolsFound()) == int assert type(self.model.getNBestSolsFound()) == int assert self.model.getNBestSolsFound() <= self.model.getNSolsFound() - - self.model.data["nSols"] = self.model.getNSolsFound() # Adding the column to the master problem (model.LT because of numerics) if self.model.isLT(objval, 0): @@ -51,7 +49,6 @@ def pricerredcost(self): # Creating new var; must set pricedVar to True newVar = self.model.addVar("NewPattern_" + str(currentNumVar), vtype = "C", obj = 1.0, pricedVar = True) - # Adding the new variable to the constraints of the master problem newPattern = [] for i, c in enumerate(self.data['cons']): @@ -87,7 +84,6 @@ def test_cuttingstock(): s.setPresolve(0) s.data = {} - s.data["nSols"] = 0 # creating a pricer pricer = CutPricer() @@ -164,7 +160,7 @@ def test_cuttingstock(): assert s.getObjVal() == 452.25 assert type(s.getNSols()) == int - assert s.getNSols() == s.data["nSols"] + assert s.getNSols() == s.getNSolsFound() # Testing freeTransform s.freeTransform() @@ -189,7 +185,6 @@ def test_deactivate_pricer(): s.setPresolve(0) s.data = {} - s.data["nSols"] = 0 # creating a pricer pricer = CutPricer() From 81395b2b792e8d25dad3dccb3e3b143766e39ccd Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 17 Jun 2025 16:10:38 +0100 Subject: [PATCH 13/24] typo --- src/pyscipopt/scip.pxd | 2 +- src/pyscipopt/scip.pxi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index b3332d4c0..3cdb90e12 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -827,7 +827,7 @@ cdef extern from "scip/scip.h": SCIP_Bool SCIPvarIsBinary(SCIP_VAR* var) SCIP_Bool SCIPvarIsIntegral(SCIP_VAR* var) SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR* var) - SCIP_Bool SCIPvarIsNonImpliedIntegral(SCIP_VAR* var) + SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR* var) SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR* var) SCIP_Bool SCIPvarIsOriginal(SCIP_VAR* var) SCIP_Bool SCIPvarIsTransformed(SCIP_VAR* var) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 4139a938c..eaac85d83 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -1575,7 +1575,7 @@ cdef class Variable(Expr): ------- bool """ - return SCIPvarIsNonImpliedIntegral(self.scip_var) + return SCIPvarIsNonimpliedIntegral(self.scip_var) def getImplType(self): """ From ae60d7ee24262a3a5e0bc4d8dccfd971996901ec Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 17 Jun 2025 17:03:32 +0100 Subject: [PATCH 14/24] IISfinder progress --- src/pyscipopt/iisfinder.pxi | 30 +++++++------- src/pyscipopt/scip.pxd | 22 ++++++----- src/pyscipopt/scip.pxi | 78 ++++++++++++++++++++++++------------- tests/test_iis.py | 34 ++++++++++++++++ 4 files changed, 112 insertions(+), 52 deletions(-) create mode 100644 tests/test_iis.py diff --git a/src/pyscipopt/iisfinder.pxi b/src/pyscipopt/iisfinder.pxi index 6869757e1..d2945fb9a 100644 --- a/src/pyscipopt/iisfinder.pxi +++ b/src/pyscipopt/iisfinder.pxi @@ -1,6 +1,6 @@ ##@file iisfinder.pxi -#@brief Base class of the Relaxator Plugin -cdef class IISFinder: +#@brief Base class of the IIS finder Plugin +cdef class IISfinder: cdef public Model model cdef public str name @@ -11,27 +11,27 @@ cdef class IISFinder: def iisfinderexec(self): '''calls execution method of iis finder''' raise NotImplementedError("iisfinderexec() is a fundamental callback and should be implemented in the derived class") - -cdef SCIP_RETCODE PyIISFinderCopy (SCIP* scip, SCIP_IISFINDER* iisfinder) noexcept with gil: + +cdef SCIP_RETCODE PyiisfinderCopy (SCIP* scip, SCIP_IISFINDER* iisfinder) noexcept with gil: return SCIP_OKAY -cdef SCIP_RETCODE PyIISFinderFree (SCIP* scip, SCIP_IISFINDER* iisfinder) noexcept with gil: +cdef SCIP_RETCODE PyiisfinderFree (SCIP* scip, SCIP_IISFINDER* iisfinder) noexcept with gil: cdef SCIP_IISFINDERDATA* iisfinderdata - iisfinderdata = SCIPIISfinderGetData(iisfinder) - PyRelax = iisfinderdata - PyRelax.iisfinderfree() - Py_DECREF(PyRelax) + iisfinderdata = SCIPiisfinderGetData(iisfinder) + PyIIS = iisfinderdata + PyIIS.iisfinderfree() + Py_DECREF(PyIIS) return SCIP_OKAY -cdef SCIP_RETCODE PyRelaxExec (SCIP* scip, SCIP_IISFINDER* iisfinder, SCIP_Real* lowerbound, SCIP_RESULT* result) noexcept with gil: +cdef SCIP_RETCODE PyiisfinderExec (SCIP_IIS* iis, SCIP_IISFINDER* iisfinder, SCIP_Real timelim, SCIP_Longint nodelim, SCIP_Bool removebounds, SCIP_Bool silent, SCIP_RESULT* result) noexcept with gil: cdef SCIP_IISFINDERDATA* iisfinderdata iisfinderdata = SCIPiisfinderGetData(iisfinder) - PyRelax = iisfinderdata - result_dict = PyRelax.iisfinderexec() + PyIIS = iisfinderdata + result_dict = PyIIS.iisfinderexec() assert isinstance(result_dict, dict), "iisfinderexec() must return a dictionary." #TODO assert False - lowerbound[0] = result_dict.get("lowerbound", lowerbound[0]) - result[0] = result_dict.get("result", result[0]) - return SCIP_OKAY \ No newline at end of file + # lowerbound[0] = result_dict.get("lowerbound", lowerbound[0]) + # result[0] = result_dict.get("result", result[0]) + # return SCIP_OKAY \ No newline at end of file diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 3cdb90e12..ba6f3ab28 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -1184,15 +1184,19 @@ cdef extern from "scip/scip.h": SCIP_HEURTIMING SCIPheurGetTimingmask(SCIP_HEUR* heur) void SCIPheurSetTimingmask(SCIP_HEUR* heur, SCIP_HEURTIMING timingmask) - # #IIS finder plugin - # SCIP_RETCODE SCIPincludeIISFinder(SCIP* scip, - # const char* name, - # const char* desc, - # int priority, - # SCIP_RETCODE (*iisfindercopy) (SCIP* scip, SCIP_IISFINDER* iisfinder), - # SCIP_RETCODE (*iisfinderfree) (SCIP* scip, SCIP_IISFINDER* iisfinder), - # SCIP_RETCODE (*iisfinderexec) (SCIP_IIS* iis, SCIP_IISFINDER* iisfinder, SCIP_Real timelim, SCIP_Longint nodelim, SCIP_Bool removebounds, SCIP_Bool silent, SCIP_RESULT* result), - # SCIP_IISFINDERDATA* iisfinderdata) + #IIS finder plugin + SCIP_RETCODE SCIPincludeIISfinder(SCIP* scip, + const char* name, + const char* desc, + int priority, + SCIP_RETCODE (*iisfindercopy) (SCIP* scip, SCIP_IISFINDER* iisfinder), + SCIP_RETCODE (*iisfinderfree) (SCIP* scip, SCIP_IISFINDER* iisfinder), + SCIP_RETCODE (*iisfinderexec) (SCIP_IIS* iis, SCIP_IISFINDER* iisfinder, SCIP_Real timelim, SCIP_Longint nodelim, SCIP_Bool removebounds, SCIP_Bool silent, SCIP_RESULT* result), + SCIP_IISFINDERDATA* iisfinderdata) + + SCIP_IISFINDERDATA* SCIPiisfinderGetData(SCIP_IISFINDER* iisfinder) + SCIP_RETCODE SCIPincludeIISfinderGreedy(SCIP* scip) + SCIP_RETCODE SCIPiisGreedyMinimize(SCIP_IIS* iis); #Relaxation plugin SCIP_RETCODE SCIPincludeRelax(SCIP* scip, diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index eaac85d83..86dab9cd5 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -31,7 +31,7 @@ include "conshdlr.pxi" include "cutsel.pxi" include "event.pxi" include "heuristic.pxi" -# include "iisfinder.pxi" +include "iisfinder.pxi" include "presol.pxi" include "pricer.pxi" include "propagator.pxi" @@ -8545,7 +8545,10 @@ cdef class Model: maxdepth : int, optional maximal depth level to call heuristic at (Default value = -1) timingmask : PY_SCIP_HEURTIMING, optional - positions in the node solving loop where heuristic should be executed + positions in the node solvingreturn { + 'result': SCIP_RESULT.SUCCESS, + 'lowerbound': 10e4 + } loop where heuristic should be executed (Default value = SCIP_HEURTIMING_BEFORENODE) usessubscip : bool, optional does the heuristic use a secondary SCIP instance? (Default value = False) @@ -8564,32 +8567,51 @@ cdef class Model: heur.name = name Py_INCREF(heur) - # def includeIISFinder(self, IISfinder iisfinder, name, desc, priority=10000, freq=1): - # """ - # Include an IIS (Irreducible Infeasible Set) finder handler. - - # Parameters - # ---------- - # iisfinder : IISfinder - # IIS finder - # name : str - # name of IIS finder - # desc : str - # description of IIS finder - # priority : int, optional - # priority of the IISfinder (#todo description) - # freq : int, optional - # frequency for calling IIS finder - - # """ - # nam = str_conversion(name) - # des = str_conversion(desc) - # PY_SCIP_CALL(SCIPincludeIISFinder(self._scip, nam, des, priority, freq, PyIISFinderCopy, PyIISFinderFree, - # PyIISFinderExec, iisfinder)) - # iisfinder.model = weakref.proxy(self) - # iisfinder.name = name - - # Py_INCREF(iisfinder) + def includeIISfinder(self, IISfinder iisfinder, name, desc, priority=10000, freq=1): + """ + Include an IIS (Irreducible Infeasible Set) finder handler. + + Parameters + ---------- + iisfinder : IISfinder + IIS finder + name : str + name of IIS finder + desc : str + description of IIS finder + priority : int, optional + priority of the IISfinder (#todo description) + freq : int, optional + frequency for calling IIS finder + + """ + nam = str_conversion(name) + des = str_conversion(desc) + PY_SCIP_CALL(SCIPincludeIISfinder(self._scip, nam, des, priority, PyiisfinderCopy, PyiisfinderFree, + PyiisfinderExec, iisfinder)) + iisfinder.model = weakref.proxy(self) + iisfinder.name = name + + Py_INCREF(iisfinder) + + def includeIISfinderGreedy(self): + """ + Include the default greedy IIS finder. + + Returns + ------- + IISfinder + the greedy IIS finder + + """ + PY_SCIP_CALL(SCIPincludeIISfinderGreedy(self._scip)) + + # def iisGreedyMinimize(self, IISfinder iisfinder): + # """ + # Perform the greedy deletion algorithm with singleton batches to obtain an irreducible infeasible subsystem (IIS) + # """ + + # PY_SCIP_CALL(SCIPiisGreedyMinimize(iisfinder._iisfinder)) def includeRelax(self, Relax relax, name, desc, priority=10000, freq=1): """ diff --git a/tests/test_iis.py b/tests/test_iis.py new file mode 100644 index 000000000..f4fc7e3f2 --- /dev/null +++ b/tests/test_iis.py @@ -0,0 +1,34 @@ +import pytest + +from pyscipopt import Model +from pyscipopt.scip import IISfinder + +calls = [] +class myIISfinder(IISfinder): + def iisfinderexec(self): + calls.append('relaxexec') + +def test_iis_custom(): + from helpers.utils import random_mip_1 + + m = random_mip_1() + x = m.addVar() + m.addCons(x >= 1, "inf1") + m.addCons(x <= 0, "inf2") + + iis = myIISfinder() + m.includeIISfinder(iis, name="custom", desc="test") + m.optimize() + assert calls != [] + +def test_iis_greedy(): + m = Model() + x = m.addVar() + m.addCons(x >= 1, "inf1") + m.addCons(x <= 0, "inf2") + + m.includeIISfinderGreedy() + m.optimize() + +test_iis_greedy() +test_iis_custom() From be3022e2791e9281781b7a1aae823d9d1c555140 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 17 Jun 2025 17:28:45 +0100 Subject: [PATCH 15/24] Start of support for exact scip --- src/pyscipopt/scip.pxd | 46 +++++++++++++++++++++++++++++++++ src/pyscipopt/scip.pxi | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index ba6f3ab28..c64768f36 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -384,12 +384,18 @@ cdef extern from "scip/scip.h": ctypedef struct SCIP_ROW: pass + + ctypedef struct SCIP_ROW_EXACT: + pass ctypedef struct SCIP_NLROW: pass ctypedef struct SCIP_COL: pass + + ctypedef struct SCIP_COL_EXACT: + pass ctypedef struct SCIP_SOL: pass @@ -1397,6 +1403,30 @@ cdef extern from "scip/scip.h": SCIP_Bool SCIPisIntegral(SCIP* scip, SCIP_Real val) SCIP_Real SCIPgetTreesizeEstimation(SCIP* scip) + # Exact SCIP methods + SCIP_RETCODE SCIPenableExactSolving(SCIP* scip, SCIP_Bool enable); + SCIP_Bool SCIPisExact(SCIP* scip); + SCIP_Bool SCIPallowNegSlack(SCIP* scip); + SCIP_RETCODE SCIPbranchLPExact(SCIP* scip, SCIP_RESULT* result); + SCIP_RETCODE SCIPaddRowExact(SCIP* scip, SCIP_ROWEXACT* rowexact); + + # Exact LP SCIP methods + SCIP_VAR* SCIPcolExactGetVar(SCIP_COLEXACT* col); + SCIP_RATIONAL* SCIProwExactGetLhs(SCIP_ROWEXACT* row); + SCIP_RATIONAL* SCIProwExactGetRhs(SCIP_ROWEXACT* row); + SCIP_RATIONAL* SCIProwExactGetConstant(SCIP_ROWEXACT* row); + int SCIProwExactGetNNonz(SCIP_ROWEXACT* row); + SCIP_RATIONAL** SCIProwExactGetVals(SCIP_ROWEXACT* row); + SCIP_Bool SCIProwExactIsInLP(SCIP_ROWEXACT* row); + void SCIProwExactSort(SCIP_ROWEXACT* row); + SCIP_COLEXACT** SCIProwExactGetCols(SCIP_ROWEXACT* row); + void SCIProwExactLock(SCIP_ROWEXACT* row); + void SCIProwExactUnlock(SCIP_ROWEXACT* row); + SCIP_ROW* SCIProwExactGetRow(SCIP_ROWEXACT* row); + SCIP_ROW* SCIProwExactGetRowRhs(SCIP_ROWEXACT* row); + SCIP_Bool SCIProwExactHasFpRelax(SCIP_ROWEXACT* row); + SCIP_Bool SCIPlpExactDiving(SCIP_LPEXACT* lpexact); + # Statistic Methods SCIP_RETCODE SCIPprintStatistics(SCIP* scip, FILE* outfile) SCIP_RETCODE SCIPprintStatisticsJson(SCIP* scip, FILE* file) @@ -2053,6 +2083,14 @@ cdef class Column: @staticmethod cdef create(SCIP_COL* scipcol) +cdef class Column: + cdef SCIP_COLEXACT* scip_col_exact + # can be used to store problem data + cdef public object data + + @staticmethod + cdef create(SCIP_COLEXACT* scipcol_exact) + cdef class Row: cdef SCIP_ROW* scip_row # can be used to store problem data @@ -2061,6 +2099,14 @@ cdef class Row: @staticmethod cdef create(SCIP_ROW* sciprow) +cdef class RowExact: + cdef SCIP_ROWEXACT* scip_row_exact + # can be used to store problem data + cdef public object data + + @staticmethod + cdef create(SCIP_ROWEXACT* sciprow_exact) + cdef class NLRow: cdef SCIP_NLROW* scip_nlrow # can be used to store problem data diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 86dab9cd5..eb69ef12d 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -11008,6 +11008,64 @@ cdef class Model: return SCIPgetTreesizeEstimation(self._scip) + # Exact SCIP methods + def enableExactSolving(self, SCIP_Bool enable): + """ + Enables or disables exact solving mode in SCIP. + + Parameters + ---------- + enable : SCIP_Bool + Whether to enable exact solving mode (True) or disable it (False). + """ + + PY_SCIP_CALL(SCIPenableExactSolving(self._scip, enable)) + + def isExact(self): + """ + Returns whether exact solving mode is enabled in SCIP. + + Returns + ------- + bool + """ + + return SCIPisExact(self._scip) + + def allowNegSlack(self): + """ + Returns whether negative slack is allowed in exact solving mode. + + Returns + ------- + bool + """ + + return SCIPallowNegSlack(self._scip) + + def branchLPExact(self): + """ + Performs exact LP branching. + + Returns + ------- + SCIP_RESULT + """ + cdef SCIP_RESULT result + PY_SCIP_CALL(SCIPbranchLPExact(self._scip, &result)) + return result + + def addRowExact(self, rowexact): + """ + Adds an exact row to the LP. + + Parameters + ---------- + rowexact : RowExact + The exact row to add. + """ + PY_SCIP_CALL(SCIPaddRowExact(self._scip, rowexact.scip_row_exact)) + def getBipartiteGraphRepresentation(self, prev_col_features=None, prev_edge_features=None, prev_row_features=None, static_only=False, suppress_warnings=False): """ From dc086540adb40e28fb923bcc5ddadb91e69b5ada Mon Sep 17 00:00:00 2001 From: DominikKamp <130753997+DominikKamp@users.noreply.github.com> Date: Wed, 2 Jul 2025 10:44:26 +0200 Subject: [PATCH 16/24] Fix reader write (#1015) --- src/pyscipopt/reader.pxi | 9 +++++---- src/pyscipopt/scip.pxd | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/pyscipopt/reader.pxi b/src/pyscipopt/reader.pxi index c75cab137..fe02a4443 100644 --- a/src/pyscipopt/reader.pxi +++ b/src/pyscipopt/reader.pxi @@ -12,7 +12,7 @@ cdef class Reader: '''calls read method of reader''' return {} - def readerwrite(self, file, name, transformed, objsense, objscale, objoffset, binvars, intvars, + def readerwrite(self, file, name, transformed, objsense, objoffset, objscale, binvars, intvars, implvars, contvars, fixedvars, startnvars, conss, maxnconss, startnconss, genericnames): '''calls write method of reader''' return {} @@ -40,8 +40,8 @@ cdef SCIP_RETCODE PyReaderRead (SCIP* scip, SCIP_READER* reader, const char* fil cdef SCIP_RETCODE PyReaderWrite (SCIP* scip, SCIP_READER* reader, FILE* file, const char* name, SCIP_PROBDATA* probdata, SCIP_Bool transformed, - SCIP_OBJSENSE objsense, SCIP_Real objscale, SCIP_Real objoffset, - SCIP_RATIONAL* objoffsetexact, SCIP_RATIONAL* objscaleexact, + SCIP_OBJSENSE objsense, SCIP_Real objoffset, SCIP_Real objscale, + SCIP_RATIONAL* objoffsetexact, SCIP_RATIONAL* objscaleexact, SCIP_VAR** vars, int nvars, int nbinvars, int nintvars, int nimplvars, int ncontvars, SCIP_VAR** fixedvars, int nfixedvars, int startnvars, SCIP_CONS** conss, int nconss, int maxnconss, int startnconss, @@ -59,7 +59,8 @@ cdef SCIP_RETCODE PyReaderWrite (SCIP* scip, SCIP_READER* reader, FILE* file, PyFixedVars = [Variable.create(fixedvars[i]) for i in range(nfixedvars)] PyConss = [Constraint.create(conss[i]) for i in range(nconss)] PyReader = readerdata - result_dict = PyReader.readerwrite(PyFile, PyName, transformed, objsense, objscale, objoffset, + #TODO: provide rational objoffsetexact and objscaleexact + result_dict = PyReader.readerwrite(PyFile, PyName, transformed, objsense, objoffset, objscale, PyBinVars, PyIntVars, PyImplVars, PyContVars, PyFixedVars, startnvars, PyConss, maxnconss, startnconss, genericnames) result[0] = result_dict.get("result", result[0]) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index c64768f36..df28c8c97 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -994,8 +994,8 @@ cdef extern from "scip/scip.h": SCIP_RETCODE (*readerread) (SCIP* scip, SCIP_READER* reader, const char* filename, SCIP_RESULT* result), SCIP_RETCODE (*readerwrite) (SCIP* scip, SCIP_READER* reader, FILE* file, const char* name, SCIP_PROBDATA* probdata, SCIP_Bool transformed, - SCIP_OBJSENSE objsense, SCIP_Real objscale, SCIP_Real objoffset, - SCIP_RATIONAL* objoffsetexact, SCIP_RATIONAL* objscaleexact, + SCIP_OBJSENSE objsense, SCIP_Real objoffset, SCIP_Real objscale, + SCIP_RATIONAL* objoffsetexact, SCIP_RATIONAL* objscaleexact, SCIP_VAR** vars, int nvars, int nbinvars, int nintvars, int nimplvars, int ncontvars, SCIP_VAR** fixedvars, int nfixedvars, int startnvars, SCIP_CONS** conss, int nconss, int maxnconss, int startnconss, From ffcf0016b2c05e83324b2d81aa100d2ec3cba795 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 11 Jul 2025 10:34:26 +0100 Subject: [PATCH 17/24] Fix most compilation issues and warnings --- src/pyscipopt/event.pxi | 2 +- src/pyscipopt/scip.pxd | 23 ++++++------------- src/pyscipopt/scip.pxi | 51 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/pyscipopt/event.pxi b/src/pyscipopt/event.pxi index 914e882ed..559d8c44a 100644 --- a/src/pyscipopt/event.pxi +++ b/src/pyscipopt/event.pxi @@ -39,7 +39,7 @@ cdef class Eventhdlr: # local helper functions for the interface -cdef Eventhdlr getPyEventhdlr(SCIP_EVENTHDLR* eventhdlr) noexcept with gil: +cdef Eventhdlr getPyEventhdlr(SCIP_EVENTHDLR* eventhdlr): cdef SCIP_EVENTHDLRDATA* eventhdlrdata eventhdlrdata = SCIPeventhdlrGetData(eventhdlr) return eventhdlrdata diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index df28c8c97..42da95f93 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -385,7 +385,7 @@ cdef extern from "scip/scip.h": ctypedef struct SCIP_ROW: pass - ctypedef struct SCIP_ROW_EXACT: + ctypedef struct SCIP_ROWEXACT: pass ctypedef struct SCIP_NLROW: @@ -394,7 +394,7 @@ cdef extern from "scip/scip.h": ctypedef struct SCIP_COL: pass - ctypedef struct SCIP_COL_EXACT: + ctypedef struct SCIP_COLEXACT: pass ctypedef struct SCIP_SOL: @@ -427,12 +427,6 @@ cdef extern from "scip/scip.h": ctypedef struct SCIP_PROPDATA: pass - ctypedef struct SCIP_PROPTIMING: - pass - - ctypedef struct SCIP_PRESOLTIMING: - pass - ctypedef struct SCIP_PRESOL: pass @@ -484,9 +478,6 @@ cdef extern from "scip/scip.h": ctypedef struct SCIP_PRESOL: pass - ctypedef struct SCIP_HEURTIMING: - pass - ctypedef struct SCIP_SEPA: pass @@ -535,10 +526,10 @@ cdef extern from "scip/scip.h": ctypedef struct SCIP_LPI: pass - ctypedef struct BMS_BLKMEM: + ctypedef struct SCIP_LPEXACT: pass - ctypedef struct SCIP_EXPR: + ctypedef struct BMS_BLKMEM: pass ctypedef struct SCIP_EXPRHDLR: @@ -2083,13 +2074,13 @@ cdef class Column: @staticmethod cdef create(SCIP_COL* scipcol) -cdef class Column: +cdef class ColumnExact: cdef SCIP_COLEXACT* scip_col_exact # can be used to store problem data cdef public object data @staticmethod - cdef create(SCIP_COLEXACT* scipcol_exact) + cdef create(SCIP_COLEXACT* scip_col_exact) cdef class Row: cdef SCIP_ROW* scip_row @@ -2105,7 +2096,7 @@ cdef class RowExact: cdef public object data @staticmethod - cdef create(SCIP_ROWEXACT* sciprow_exact) + cdef create(SCIP_ROWEXACT* scip_row_exact) cdef class NLRow: cdef SCIP_NLROW* scip_nlrow diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index eb69ef12d..2f5b47198 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -625,6 +625,31 @@ cdef class Column: return (self.__class__ == other.__class__ and self.scip_col == (other).scip_col) +cdef class ColumnExact: + """Base class holding a pointer to corresponding SCIP_COLEXACT.""" + + @staticmethod + cdef create(SCIP_COLEXACT* scipcolexact): + """ + Main method for creating a ColumnExact class. Is used instead of __init__. + + Parameters + ---------- + scipcolexact : SCIP_COLEXACT* + A pointer to the SCIP_COLEXACT + + Returns + ------- + col : ColumnExact + The Python representative of the SCIP_COLEXACT + + """ + if scipcolexact == NULL: + raise Warning("cannot create ColumnExact with SCIP_COLEXACT* == NULL") + col = ColumnExact() + col.scip_col_exact = scipcolexact + return col + cdef class Row: """Base class holding a pointer to corresponding SCIP_ROW.""" @@ -909,6 +934,31 @@ cdef class Row: return (self.__class__ == other.__class__ and self.scip_row == (other).scip_row) +cdef class RowExact: + """Base class holding a pointer to corresponding SCIP_ROW.""" + + @staticmethod + cdef create(SCIP_ROWEXACT* sciprowexact): + """ + Main method for creating a RowExact class. Is used instead of __init__. + + Parameters + ---------- + sciprow : SCIP_ROWEXACT* + A pointer to the SCIP_ROWEXACT + + Returns + ------- + row : Row + The Python representative of the SCIP_ROWEXACT + + """ + if sciprowexact == NULL: + raise Warning("cannot create Row with SCIP_ROWEXACT* == NULL") + row_exact = RowExact() + row_exact.scip_row_exact = sciprowexact + return row_exact + cdef class NLRow: """Base class holding a pointer to corresponding SCIP_NLROW.""" @@ -7615,7 +7665,6 @@ cdef class Model: """ raise Warning("model.getDualMultiplier(cons) is deprecated: please use model.getDualsolLinear(cons)") - return self.getDualsolLinear(cons) def getDualfarkasLinear(self, Constraint cons): """ From b417a920bdd75e58b8bdba1b76c2ca90f66ceb3e Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 11 Jul 2025 10:50:09 +0100 Subject: [PATCH 18/24] Update IIS method and remove redeclaration --- src/pyscipopt/scip.pxd | 3 +-- src/pyscipopt/scip.pxi | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 42da95f93..08b2951ed 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -726,7 +726,6 @@ cdef extern from "scip/scip.h": SCIP_Real SCIPgetLocalTransEstimate(SCIP* scip) # Solve Methods - SCIP_RETCODE SCIPsolve(SCIP* scip) SCIP_RETCODE SCIPsolve(SCIP* scip) noexcept nogil SCIP_RETCODE SCIPsolveConcurrent(SCIP* scip) SCIP_RETCODE SCIPfreeTransform(SCIP* scip) @@ -1193,7 +1192,7 @@ cdef extern from "scip/scip.h": SCIP_IISFINDERDATA* SCIPiisfinderGetData(SCIP_IISFINDER* iisfinder) SCIP_RETCODE SCIPincludeIISfinderGreedy(SCIP* scip) - SCIP_RETCODE SCIPiisGreedyMinimize(SCIP_IIS* iis); + SCIP_RETCODE SCIPiisGreedyMakeIrreducible(SCIP_IIS* iis); #Relaxation plugin SCIP_RETCODE SCIPincludeRelax(SCIP* scip, diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 2f5b47198..1e7136505 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -8660,7 +8660,7 @@ cdef class Model: # Perform the greedy deletion algorithm with singleton batches to obtain an irreducible infeasible subsystem (IIS) # """ - # PY_SCIP_CALL(SCIPiisGreedyMinimize(iisfinder._iisfinder)) + # PY_SCIP_CALL(SCIPiisGreedyMakeIrreducible(iisfinder._iisfinder)) def includeRelax(self, Relax relax, name, desc, priority=10000, freq=1): """ From 389ac7499ce9cb6e1eb5628b7f753fce2c921905 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 24 Jul 2025 17:50:56 +0100 Subject: [PATCH 19/24] Fix build error --- src/pyscipopt/scip.pxi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index c4cdb4796..21ba32f49 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -11479,7 +11479,7 @@ cdef class Model: PY_SCIP_CALL(SCIPbranchLPExact(self._scip, &result)) return result - def addRowExact(self, rowexact): + def addRowExact(self, RowExact rowexact): """ Adds an exact row to the LP. From e2d9038dc377fdefbe3d7afe3de7291699498592 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 24 Jul 2025 18:21:57 +0100 Subject: [PATCH 20/24] little IIS progress --- src/pyscipopt/scip.pxi | 10 ++++---- tests/test_iis.py | 56 ++++++++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 21ba32f49..5779b3b84 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -9018,12 +9018,12 @@ cdef class Model: """ PY_SCIP_CALL(SCIPincludeIISfinderGreedy(self._scip)) - # def iisGreedyMinimize(self, IISfinder iisfinder): - # """ - # Perform the greedy deletion algorithm with singleton batches to obtain an irreducible infeasible subsystem (IIS) - # """ + def iisGreedyMakeIrreducible(self, IISfinder iisfinder): + """ + Perform the greedy deletion algorithm with singleton batches to obtain an irreducible infeasible subsystem (IIS) + """ - # PY_SCIP_CALL(SCIPiisGreedyMakeIrreducible(iisfinder._iisfinder)) + PY_SCIP_CALL(SCIPiisGreedyMakeIrreducible(iisfinder._iisfinder)) def includeRelax(self, Relax relax, name, desc, priority=10000, freq=1): """ diff --git a/tests/test_iis.py b/tests/test_iis.py index f4fc7e3f2..e4d7ec2f6 100644 --- a/tests/test_iis.py +++ b/tests/test_iis.py @@ -1,34 +1,42 @@ import pytest -from pyscipopt import Model -from pyscipopt.scip import IISfinder +from pyscipopt import Model, IISfinder -calls = [] -class myIISfinder(IISfinder): - def iisfinderexec(self): - calls.append('relaxexec') +class myIIS(IISfinder): + def __init__(self): + super().__init__() + self._iisfinder = None -def test_iis_custom(): - from helpers.utils import random_mip_1 + def isIISFound(self): + return self._iisfinder is not None - m = random_mip_1() - x = m.addVar() - m.addCons(x >= 1, "inf1") - m.addCons(x <= 0, "inf2") +def test_iis_greedy_make_irreducible(): + m = Model() + x1 = m.addVar("x1") + x2 = m.addVar("x2") + x3 = m.addVar("x3") + + m.addCons(x1 + x2 >= 5) + m.addCons(x2 + x3 >= 5) + m.addCons(x1 + x3 <= 3) + + iisfinder = IISfinder() - iis = myIISfinder() - m.includeIISfinder(iis, name="custom", desc="test") - m.optimize() - assert calls != [] + m.iisGreedyMakeIrreducible(iisfinder) -def test_iis_greedy(): + assert iisfinder.isIISFound() == True + +def test_custom_iis(): m = Model() - x = m.addVar() - m.addCons(x >= 1, "inf1") - m.addCons(x <= 0, "inf2") + x1 = m.addVar("x1") + x2 = m.addVar("x2") + x3 = m.addVar("x3") + + m.addCons(x1 + x2 >= 5) + m.addCons(x2 + x3 >= 5) + m.addCons(x1 + x3 <= 3) + + iisfinder = myIIS() - m.includeIISfinderGreedy() - m.optimize() + pass -test_iis_greedy() -test_iis_custom() From 55c99bbf9b8e788478d82a9887525860394a6027 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 24 Jul 2025 18:31:22 +0100 Subject: [PATCH 21/24] iis compilation --- src/pyscipopt/iisfinder.pxi | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pyscipopt/iisfinder.pxi b/src/pyscipopt/iisfinder.pxi index d2945fb9a..5e94dbe98 100644 --- a/src/pyscipopt/iisfinder.pxi +++ b/src/pyscipopt/iisfinder.pxi @@ -3,6 +3,7 @@ cdef class IISfinder: cdef public Model model cdef public str name + cdef SCIP_IIS* _iisfinder def iisfinderfree(self): '''calls destructor and frees memory of iis finder''' From 3914760eabaabbba7d9c8831059231d0103f5996 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 24 Jul 2025 18:39:14 +0100 Subject: [PATCH 22/24] some iis methods --- src/pyscipopt/scip.pxd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index b8890d593..e2c2e0ba2 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -1197,6 +1197,9 @@ cdef extern from "scip/scip.h": SCIP_IISFINDERDATA* SCIPiisfinderGetData(SCIP_IISFINDER* iisfinder) SCIP_RETCODE SCIPincludeIISfinderGreedy(SCIP* scip) SCIP_RETCODE SCIPiisGreedyMakeIrreducible(SCIP_IIS* iis); + SCIP_Bool SCIPiisIsSubscipInfeasible(SCIP_IIS* iis); + SCIP_Bool SCIPiisIsSubscipIrreducible(SCIP_IIS* iis); + SCIP* SCIPiisGetSubscip(SCIP_IIS* iis); #Relaxation plugin SCIP_RETCODE SCIPincludeRelax(SCIP* scip, From e9238a1b5fd645d2eececd0d8c86070b9639893c Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 24 Jul 2025 18:41:51 +0100 Subject: [PATCH 23/24] remove semicolons --- src/pyscipopt/scip.pxd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index e2c2e0ba2..0c293f48d 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -1196,10 +1196,10 @@ cdef extern from "scip/scip.h": SCIP_IISFINDERDATA* SCIPiisfinderGetData(SCIP_IISFINDER* iisfinder) SCIP_RETCODE SCIPincludeIISfinderGreedy(SCIP* scip) - SCIP_RETCODE SCIPiisGreedyMakeIrreducible(SCIP_IIS* iis); - SCIP_Bool SCIPiisIsSubscipInfeasible(SCIP_IIS* iis); - SCIP_Bool SCIPiisIsSubscipIrreducible(SCIP_IIS* iis); - SCIP* SCIPiisGetSubscip(SCIP_IIS* iis); + SCIP_RETCODE SCIPiisGreedyMakeIrreducible(SCIP_IIS* iis) + SCIP_Bool SCIPiisIsSubscipInfeasible(SCIP_IIS* iis) + SCIP_Bool SCIPiisIsSubscipIrreducible(SCIP_IIS* iis) + SCIP* SCIPiisGetSubscip(SCIP_IIS* iis) #Relaxation plugin SCIP_RETCODE SCIPincludeRelax(SCIP* scip, From f9a781d215a06cd757395f4c4f34df33aec8be77 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sat, 26 Jul 2025 12:43:17 +0100 Subject: [PATCH 24/24] Change IIS methods imported --- src/pyscipopt/scip.pxd | 2 +- src/pyscipopt/scip.pxi | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 0c293f48d..3905085c3 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -1195,7 +1195,7 @@ cdef extern from "scip/scip.h": SCIP_IISFINDERDATA* iisfinderdata) SCIP_IISFINDERDATA* SCIPiisfinderGetData(SCIP_IISFINDER* iisfinder) - SCIP_RETCODE SCIPincludeIISfinderGreedy(SCIP* scip) + SCIP_RETCODE SCIPgenerateIIS(SCIP* scip) SCIP_RETCODE SCIPiisGreedyMakeIrreducible(SCIP_IIS* iis) SCIP_Bool SCIPiisIsSubscipInfeasible(SCIP_IIS* iis) SCIP_Bool SCIPiisIsSubscipIrreducible(SCIP_IIS* iis) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 5779b3b84..db122f7c9 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -9006,17 +9006,13 @@ cdef class Model: Py_INCREF(iisfinder) - def includeIISfinderGreedy(self): + def generateIIS(self): """ - Include the default greedy IIS finder. - - Returns - ------- - IISfinder - the greedy IIS finder - + Generates an Irreducible Infeasible Subsystem (IIS) from the current + problem. """ - PY_SCIP_CALL(SCIPincludeIISfinderGreedy(self._scip)) + + PY_SCIP_CALL(SCIPgenerateIIS(self._scip)) def iisGreedyMakeIrreducible(self, IISfinder iisfinder): """