Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Run tests with coverage
env:
version: 9.2.3
version: 9.2.4

on:
push:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Integration test

env:
version: 9.2.3
version: 9.2.4

on:
push:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-release.yml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-packages-and-documentation.yml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion docs/build.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 2 additions & 57 deletions src/pyscipopt/scip.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
# 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
Expand Down Expand Up @@ -308,7 +308,7 @@
if rc == SCIP_OKAY:
pass
elif rc == SCIP_ERROR:
raise Exception('SCIP: unspecified error!')

Check failure on line 311 in src/pyscipopt/scip.pxi

View workflow job for this annotation

GitHub Actions / test-coverage (3.11)

SCIP: unspecified error!
elif rc == SCIP_NOMEMORY:
raise MemoryError('SCIP: insufficient memory error!')
elif rc == SCIP_READERROR:
Expand Down Expand Up @@ -1052,12 +1052,10 @@
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)
Expand All @@ -1072,7 +1070,6 @@
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
Expand All @@ -1081,12 +1078,6 @@
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.
Expand Down Expand Up @@ -2768,14 +2759,6 @@
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
Expand Down Expand Up @@ -6335,7 +6318,6 @@
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
Expand Down Expand Up @@ -7545,9 +7527,6 @@
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:
Expand Down Expand Up @@ -7584,10 +7563,6 @@
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:
Expand Down Expand Up @@ -8195,10 +8170,6 @@

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))
Expand Down Expand Up @@ -10290,8 +10261,6 @@
if sol == None:
sol = Solution.create(self._scip, NULL)

sol._checkStage("getSolObjVal")

if original:
objval = SCIPgetSolOrigObj(self._scip, sol.sol)
else:
Expand Down Expand Up @@ -10328,21 +10297,9 @@
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):
Expand Down Expand Up @@ -10393,10 +10350,6 @@
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)
Expand Down Expand Up @@ -11142,14 +11095,6 @@
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'):
Expand Down
7 changes: 6 additions & 1 deletion tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
Loading