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/CHANGELOG.md b/CHANGELOG.md index d4556c30e..eb5318ccf 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. - MatrixVariable comparisons (<=, >=, ==) now support numpy's broadcast feature. diff --git a/docs/build.rst b/docs/build.rst index 4f9e39fde..5c377d9b9 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 diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index cdb093a3c..69c598c9a 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 @@ -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'): 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()