Skip to content

Commit 2354ad6

Browse files
committed
Expose captureCons and releaseCons on Model
1 parent aa0e243 commit 2354ad6

3 files changed

Lines changed: 46 additions & 1 deletion

File tree

src/pyscipopt/scip.pxi

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8568,7 +8568,31 @@ cdef class Model:
85688568
85698569
"""
85708570
PY_SCIP_CALL(SCIPdelConsLocal(self._scip, cons.scip_cons))
8571-
8571+
8572+
def captureCons(self, Constraint cons):
8573+
"""
8574+
Increase the usage counter of a constraint. Must be matched by a releaseCons.
8575+
8576+
Parameters
8577+
----------
8578+
cons : Constraint
8579+
constraint to capture
8580+
8581+
"""
8582+
PY_SCIP_CALL(SCIPcaptureCons(self._scip, cons.scip_cons))
8583+
8584+
def releaseCons(self, Constraint cons):
8585+
"""
8586+
Decrease the usage counter of a constraint; frees it when the counter reaches zero.
8587+
8588+
Parameters
8589+
----------
8590+
cons : Constraint
8591+
constraint to release
8592+
8593+
"""
8594+
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &cons.scip_cons))
8595+
85728596
def getValsLinear(self, Constraint cons):
85738597
"""
85748598
Retrieve the coefficients of a linear constraint

src/pyscipopt/scip.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,7 @@ class Model:
922922
def calcNodeselPriority(
923923
self, variable: Incomplete, branchdir: Incomplete, targetvalue: Incomplete
924924
) -> Incomplete: ...
925+
def captureCons(self, cons: Incomplete) -> Incomplete: ...
925926
def catchEvent(
926927
self, eventtype: Incomplete, eventhdlr: Incomplete
927928
) -> Incomplete: ...
@@ -1487,6 +1488,7 @@ class Model:
14871488
def readSolFile(self, filename: Incomplete) -> Incomplete: ...
14881489
def redirectOutput(self) -> Incomplete: ...
14891490
def relax(self) -> Incomplete: ...
1491+
def releaseCons(self, cons: Incomplete) -> Incomplete: ...
14901492
def releaseRow(self, row: Incomplete) -> Incomplete: ...
14911493
def repropagateNode(self, node: Incomplete) -> Incomplete: ...
14921494
def resetParam(self, name: Incomplete) -> Incomplete: ...

tests/test_cons.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,22 @@ def test_getValsLinear():
368368
@pytest.mark.skip(reason="TODO: test getRowLinear()")
369369
def test_getRowLinear():
370370
assert True
371+
372+
373+
def test_captureCons_releaseCons():
374+
m = Model()
375+
x = m.addVar("x")
376+
c = m.addCons(x <= 1)
377+
378+
# Pair capture+release: problem still holds its own capture, so this is safe.
379+
m.captureCons(c)
380+
m.releaseCons(c)
381+
382+
# Model continues to function — problem's capture survived.
383+
m.optimize()
384+
assert m.getStatus() == "optimal"
385+
386+
with pytest.raises(TypeError):
387+
m.captureCons("not a constraint")
388+
with pytest.raises(TypeError):
389+
m.releaseCons("not a constraint")

0 commit comments

Comments
 (0)