Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased
### Added
- Added `Model.captureCons()` and `Model.releaseCons()`
### Fixed
### Changed
- Speed up `Expr.__add__` and `Expr.__iadd__` via the C-level API
Expand Down
26 changes: 25 additions & 1 deletion src/pyscipopt/scip.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -8568,7 +8568,31 @@ cdef class Model:

"""
PY_SCIP_CALL(SCIPdelConsLocal(self._scip, cons.scip_cons))


def captureCons(self, Constraint cons):
"""
Increase the usage counter of a constraint. Must be matched by a releaseCons.
Comment thread
Joao-Dionisio marked this conversation as resolved.
Outdated

Parameters
----------
cons : Constraint
constraint to capture

"""
PY_SCIP_CALL(SCIPcaptureCons(self._scip, cons.scip_cons))

def releaseCons(self, Constraint cons):
"""
Decrease the usage counter of a constraint; frees it when the counter reaches zero.

Parameters
----------
cons : Constraint
constraint to release
Comment thread
DominikKamp marked this conversation as resolved.

"""
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &cons.scip_cons))
Comment thread
Joao-Dionisio marked this conversation as resolved.
Outdated

def getValsLinear(self, Constraint cons):
"""
Retrieve the coefficients of a linear constraint
Expand Down
2 changes: 2 additions & 0 deletions src/pyscipopt/scip.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,7 @@ class Model:
def calcNodeselPriority(
self, variable: Incomplete, branchdir: Incomplete, targetvalue: Incomplete
) -> Incomplete: ...
def captureCons(self, cons: Incomplete) -> Incomplete: ...
def catchEvent(
self, eventtype: Incomplete, eventhdlr: Incomplete
) -> Incomplete: ...
Expand Down Expand Up @@ -1487,6 +1488,7 @@ class Model:
def readSolFile(self, filename: Incomplete) -> Incomplete: ...
def redirectOutput(self) -> Incomplete: ...
def relax(self) -> Incomplete: ...
def releaseCons(self, cons: Incomplete) -> Incomplete: ...
def releaseRow(self, row: Incomplete) -> Incomplete: ...
def repropagateNode(self, node: Incomplete) -> Incomplete: ...
def resetParam(self, name: Incomplete) -> Incomplete: ...
Expand Down
19 changes: 19 additions & 0 deletions tests/test_cons.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,3 +368,22 @@ def test_getValsLinear():
@pytest.mark.skip(reason="TODO: test getRowLinear()")
def test_getRowLinear():
assert True


def test_captureCons_releaseCons():
m = Model()
x = m.addVar("x")
c = m.addCons(x <= 1)

# Pair capture+release: problem still holds its own capture, so this is safe.
m.captureCons(c)
m.releaseCons(c)

Comment thread
Joao-Dionisio marked this conversation as resolved.
# Model continues to function — problem's capture survived.
m.optimize()
assert m.getStatus() == "optimal"

with pytest.raises(TypeError):
m.captureCons("not a constraint")
with pytest.raises(TypeError):
m.releaseCons("not a constraint")
Loading