From d2d55221570a4d0c89206f8a94567eec3011ed15 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 28 Oct 2025 15:46:19 +0000 Subject: [PATCH 1/5] some cleanup --- CHANGELOG.md | 6 ++++++ docs/build.rst | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4d64a6d1..3dda9f241 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased ### Added +### Fixed +### Changed +### Removed + +## 5.6.0 - 2025.11.01 +### Added - Added possibility of having variables in exponent. - Added basic type stubs to help with IDE autocompletion and type checking. ### Fixed diff --git a/docs/build.rst b/docs/build.rst index 062c636cc..31f14c27a 100644 --- a/docs/build.rst +++ b/docs/build.rst @@ -22,7 +22,7 @@ To download SCIP please either use the pre-built SCIP Optimization Suite availab * - SCIP - PySCIPOpt * - 9.2 - - 5.3, 5.4+ + - 5.3, 5.4, 5.5, 5.6, 5.7 * - 9.1 - 5.1, 5.2.x * - 9.0 From 9b9d20754586381dc96b216a99be7b1806e01c3f Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 29 Oct 2025 13:41:12 +0000 Subject: [PATCH 2/5] update scip version --- .github/workflows/coverage.yml | 2 +- .github/workflows/integration-test.yml | 2 +- .github/workflows/test-release.yml | 2 +- .github/workflows/update-packages-and-documentation.yml | 2 +- src/pyscipopt/scip.pxi | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index b3cf96bb7..bcb30cb14 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,6 +1,6 @@ name: Run tests with coverage env: - version: 9.2.3 + version: 9.2.4 on: push: diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 0a58eec27..e374983e4 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -1,7 +1,7 @@ name: Integration test env: - version: 9.2.3 + version: 9.2.4 on: push: diff --git a/.github/workflows/test-release.yml b/.github/workflows/test-release.yml index b42b12b47..89c880a29 100644 --- a/.github/workflows/test-release.yml +++ b/.github/workflows/test-release.yml @@ -1,7 +1,7 @@ name: TestPyPI release env: - version: 9.2.3 + version: 9.2.4 # runs only when a release is published, not on drafts diff --git a/.github/workflows/update-packages-and-documentation.yml b/.github/workflows/update-packages-and-documentation.yml index 8cc9f0dcf..402321635 100644 --- a/.github/workflows/update-packages-and-documentation.yml +++ b/.github/workflows/update-packages-and-documentation.yml @@ -1,7 +1,7 @@ name: Test and Release PyPI Package env: - version: 9.2.3 + version: 9.2.4 # runs only when a release is published, not on drafts diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index cdb093a3c..1ae8166b2 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -43,7 +43,7 @@ include "matrix.pxi" # recommended SCIP version; major version is required MAJOR = 9 MINOR = 2 -PATCH = 1 +PATCH = 4 # 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 From 4b878042e1860ec7a6e29069f886aadf705852f8 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 29 Oct 2025 13:51:54 +0000 Subject: [PATCH 3/5] explicitely install pytest --- .github/workflows/build_wheels.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml index dd00cac94..ba75752f9 100644 --- a/.github/workflows/build_wheels.yml +++ b/.github/workflows/build_wheels.yml @@ -45,6 +45,8 @@ jobs: env: CIBW_ARCHS: ${{ matrix.arch }} CIBW_TEST_GROUPS: test + CIBW_BEFORE_TEST: "python -m pip install -r {project}/requirements/test.txt" + CIBW_TEST_REQUIRES: "pytest" CIBW_TEST_COMMAND: "pytest {project}/tests" CIBW_MANYLINUX_*_IMAGE: manylinux_2_28 From 550e1d236f57f5a1ed36dcf53a2e9f79da642838 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 30 Oct 2025 15:32:05 +0000 Subject: [PATCH 4/5] removing stage checks due to new default interface preset --- src/pyscipopt/scip.pxi | 57 +----------------------------------------- 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 1ae8166b2..69c598c9a 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -1052,12 +1052,10 @@ cdef class Solution: cdef _VarArray wrapper if isinstance(expr, Variable): wrapper = _VarArray(expr) - self._checkStage("SCIPgetSolVal") return SCIPgetSolVal(self.scip, self.sol, wrapper.ptr[0]) 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 cdef _VarArray wrapper wrapper = _VarArray(term.vartuple) @@ -1072,7 +1070,6 @@ cdef class Solution: cdef SCIP_VAR* scip_var cdef int i vals = {} - self._checkStage("SCIPgetSolVal") for i in range(SCIPgetNOrigVars(self.scip)): scip_var = SCIPgetOrigVars(self.scip)[i] # extract name @@ -1081,12 +1078,6 @@ cdef class Solution: 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] - if not stage_check or self.sol == NULL and SCIPgetStage(self.scip) != SCIP_STAGE_SOLVING: - raise Warning(f"{method} can only be called with a valid solution or in stage SOLVING (current stage: {SCIPgetStage(self.scip)})") - def getOrigin(self): """ Returns origin of solution: where to retrieve uncached elements. @@ -2768,14 +2759,6 @@ cdef class Model: def freeTransform(self): """Frees all solution process data including presolving and transformed problem, only original problem is kept.""" - if self.getStage() not in [SCIP_STAGE_INIT, - SCIP_STAGE_PROBLEM, - SCIP_STAGE_TRANSFORMED, - SCIP_STAGE_PRESOLVING, - SCIP_STAGE_PRESOLVED, - SCIP_STAGE_SOLVING, - SCIP_STAGE_SOLVED]: - raise Warning("method cannot be called in stage %i." % self.getStage()) self._modelvars = { var: value @@ -6335,7 +6318,6 @@ cdef class Model: coef : float """ - assert self.getStage() == 1, "addExprNonlinear cannot be called in stage %i." % self.getStage() assert cons.isNonlinear(), "addExprNonlinear can only be called with nonlinear constraints." cdef Constraint temp_cons @@ -7545,9 +7527,6 @@ cdef class Model: cdef SCIP_Real activity cdef SCIP_SOL* scip_sol - if not self.getStage() >= SCIP_STAGE_SOLVING: - raise Warning("method cannot be called before problem is solved") - if isinstance(sol, Solution): scip_sol = sol.sol else: @@ -7584,10 +7563,6 @@ cdef class Model: cdef SCIP_Real activity cdef SCIP_SOL* scip_sol - - if not self.getStage() >= SCIP_STAGE_SOLVING: - raise Warning("method cannot be called before problem is solved") - if isinstance(sol, Solution): scip_sol = sol.sol else: @@ -8195,10 +8170,6 @@ cdef class Model: def presolve(self): """Presolve the problem.""" - if self.getStage() not in [SCIP_STAGE_PROBLEM, SCIP_STAGE_TRANSFORMED,\ - SCIP_STAGE_PRESOLVING, SCIP_STAGE_PRESOLVED, \ - SCIP_STAGE_SOLVED]: - raise Warning("method cannot be called in stage %i." % self.getStage()) PY_SCIP_CALL(SCIPpresolve(self._scip)) self._bestSol = Solution.create(self._scip, SCIPgetBestSol(self._scip)) @@ -10290,8 +10261,6 @@ cdef class Model: if sol == None: sol = Solution.create(self._scip, NULL) - sol._checkStage("getSolObjVal") - if original: objval = SCIPgetSolOrigObj(self._scip, sol.sol) else: @@ -10328,21 +10297,9 @@ cdef class Model: float """ - - if SCIPgetNSols(self._scip) == 0: - if self.getStage() != SCIP_STAGE_SOLVING: - raise Warning("Without a solution, method can only be called in stage SOLVING.") - else: + if SCIPgetNSols(self._scip) != 0: assert self._bestSol.sol != NULL - if SCIPsolIsOriginal(self._bestSol.sol): - min_stage_requirement = SCIP_STAGE_PROBLEM - else: - min_stage_requirement = SCIP_STAGE_TRANSFORMING - - if not self.getStage() >= min_stage_requirement: - raise Warning("method cannot be called in stage %i." % self.getStage) - return self.getSolObjVal(self._bestSol, original) def getSolVal(self, Solution sol, Expr expr): @@ -10393,10 +10350,6 @@ cdef class Model: A variable is also an expression. """ - stage_check = SCIPgetStage(self._scip) not in [SCIP_STAGE_INIT, SCIP_STAGE_FREE] - - if not stage_check or self._bestSol.sol == NULL and SCIPgetStage(self._scip) != SCIP_STAGE_SOLVING: - raise Warning("Method cannot be called in stage ", self.getStage()) if isinstance(expr, MatrixExpr): result = np.empty(expr.shape, dtype=float) @@ -11142,14 +11095,6 @@ cdef class Model: def freeReoptSolve(self): """Frees all solution process data and prepares for reoptimization.""" - if self.getStage() not in [SCIP_STAGE_INIT, - SCIP_STAGE_PROBLEM, - SCIP_STAGE_TRANSFORMED, - SCIP_STAGE_PRESOLVING, - SCIP_STAGE_PRESOLVED, - SCIP_STAGE_SOLVING, - SCIP_STAGE_SOLVED]: - raise Warning("method cannot be called in stage %i." % self.getStage()) PY_SCIP_CALL(SCIPfreeReoptSolve(self._scip)) def chgReoptObjective(self, coeffs, sense = 'minimize'): From 01bfcecbf2e9f8308022e248daa1a5719d56aa5f Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 31 Oct 2025 09:34:00 +0000 Subject: [PATCH 5/5] test stage checking --- tests/test_model.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_model.py b/tests/test_model.py index 391b21c41..565139544 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -303,7 +303,12 @@ def test_getObjective(): assert str(m.getObjective()) == "Expr({Term(x1): 2.0, Term(x2): 3.0})" - +def test_SCIP_stage_check(): + m = Model() + + with pytest.raises(Exception): # default interface preset should check the stage inside SCIP + m.getPrimalbound() + def test_getTreesizeEstimation(): m = Model()