Skip to content

Commit 112a8fc

Browse files
Support for AND-constraints (#980)
* Support for AND-constraints * better spacing in pxd * some debugging * Add two missing methods. Will not test * fix memory leak
1 parent bc0e229 commit 112a8fc

File tree

4 files changed

+179
-0
lines changed

4 files changed

+179
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44
### Added
5+
- More support for AND-Constraints
56
- Added support for knapsack constraints
67
- Added isPositive(), isNegative(), isFeasLE(), isFeasLT(), isFeasGE(), isFeasGT(), isHugeValue(), and tests
78
- Added SCIP_LOCKTYPE, addVarLocksType(), getNLocksDown(), getNLocksUp(), getNLocksDownType(), getNLocksUpType(), and tests

src/pyscipopt/scip.pxd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,6 +1653,13 @@ cdef extern from "scip/cons_and.h":
16531653
SCIP_Bool dynamic,
16541654
SCIP_Bool removable,
16551655
SCIP_Bool stickingatnode)
1656+
int SCIPgetNVarsAnd(SCIP* scip, SCIP_CONS* cons)
1657+
SCIP_VAR** SCIPgetVarsAnd(SCIP* scip, SCIP_CONS* cons)
1658+
SCIP_VAR* SCIPgetResultantAnd(SCIP* scip, SCIP_CONS* cons)
1659+
SCIP_Bool SCIPisAndConsSorted(SCIP* scip, SCIP_CONS* cons)
1660+
SCIP_RETCODE SCIPsortAndCons(SCIP* scip, SCIP_CONS* cons)
1661+
SCIP_RETCODE SCIPchgAndConsCheckFlagWhenUpgr(SCIP* scip, SCIP_CONS* cons, SCIP_Bool flag)
1662+
SCIP_RETCODE SCIPchgAndConsRemovableFlagWhenUpgr(SCIP* scip, SCIP_CONS* cons, SCIP_Bool flag)
16561663

16571664
cdef extern from "scip/cons_or.h":
16581665
SCIP_RETCODE SCIPcreateConsOr(SCIP* scip,

src/pyscipopt/scip.pxi

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5990,6 +5990,160 @@ cdef class Model:
59905990

59915991
return vars
59925992

5993+
def getNVarsAnd(self, Constraint and_cons):
5994+
"""
5995+
Gets number of variables in and constraint.
5996+
5997+
Parameters
5998+
----------
5999+
and_cons : Constraint
6000+
AND constraint to get the number of variables from.
6001+
6002+
Returns
6003+
-------
6004+
int
6005+
6006+
"""
6007+
cdef int nvars
6008+
cdef SCIP_Bool success
6009+
6010+
return SCIPgetNVarsAnd(self._scip, and_cons.scip_cons)
6011+
6012+
def getVarsAnd(self, Constraint and_cons):
6013+
"""
6014+
Gets variables in AND constraint.
6015+
6016+
Parameters
6017+
----------
6018+
and_cons : Constraint
6019+
AND Constraint to get the variables from.
6020+
6021+
Returns
6022+
-------
6023+
list of Variable
6024+
6025+
"""
6026+
cdef SCIP_VAR** _vars
6027+
cdef int nvars
6028+
cdef SCIP_Bool success
6029+
cdef int i
6030+
6031+
constype = bytes(SCIPconshdlrGetName(SCIPconsGetHdlr(and_cons.scip_cons))).decode('UTF-8')
6032+
assert(constype == 'and', "The constraint handler %s does not have this functionality." % constype)
6033+
6034+
nvars = SCIPgetNVarsAnd(self._scip, and_cons.scip_cons)
6035+
_vars = SCIPgetVarsAnd(self._scip, and_cons.scip_cons)
6036+
6037+
vars = []
6038+
for i in range(nvars):
6039+
ptr = <size_t>(_vars[i])
6040+
# check whether the corresponding variable exists already
6041+
if ptr in self._modelvars:
6042+
vars.append(self._modelvars[ptr])
6043+
else:
6044+
# create a new variable
6045+
var = Variable.create(_vars[i])
6046+
assert var.ptr() == ptr
6047+
self._modelvars[ptr] = var
6048+
vars.append(var)
6049+
6050+
return vars
6051+
6052+
def getResultantAnd(self, Constraint and_cons):
6053+
"""
6054+
Gets the resultant variable in And constraint.
6055+
6056+
Parameters
6057+
----------
6058+
and_cons : Constraint
6059+
Constraint to get the resultant variable from.
6060+
6061+
Returns
6062+
-------
6063+
Variable
6064+
6065+
"""
6066+
cdef SCIP_VAR* _resultant
6067+
cdef SCIP_Bool success
6068+
6069+
_resultant = SCIPgetResultantAnd(self._scip, and_cons.scip_cons)
6070+
6071+
ptr = <size_t>(_resultant)
6072+
# check whether the corresponding variable exists already
6073+
if ptr not in self._modelvars:
6074+
# create a new variable
6075+
resultant = Variable.create(_resultant)
6076+
assert resultant.ptr() == ptr
6077+
self._modelvars[ptr] = resultant
6078+
else:
6079+
resultant = self._modelvars[ptr]
6080+
6081+
return resultant
6082+
6083+
def isAndConsSorted(self, Constraint and_cons):
6084+
"""
6085+
Returns if the variables of the AND-constraint are sorted with respect to their indices.
6086+
6087+
Parameters
6088+
----------
6089+
and_cons : Constraint
6090+
Constraint to check.
6091+
6092+
Returns
6093+
-------
6094+
bool
6095+
6096+
"""
6097+
cdef SCIP_Bool success
6098+
6099+
return SCIPisAndConsSorted(self._scip, and_cons.scip_cons)
6100+
6101+
def sortAndCons(self, Constraint and_cons):
6102+
"""
6103+
Sorts the variables of the AND-constraint with respect to their indices.
6104+
6105+
Parameters
6106+
----------
6107+
and_cons : Constraint
6108+
Constraint to sort.
6109+
6110+
"""
6111+
cdef SCIP_Bool success
6112+
6113+
PY_SCIP_CALL(SCIPsortAndCons(self._scip, and_cons.scip_cons))
6114+
6115+
def chgAndConsCheckFlagWhenUpgr(self, Constraint cons, flag):
6116+
"""
6117+
when 'upgrading' the given AND-constraint, should the check flag for the upgraded
6118+
constraint be set to TRUE, even if the check flag of this AND-constraint is set to FALSE?
6119+
6120+
Parameters
6121+
----------
6122+
cons : Constraint
6123+
The AND constraint to change.
6124+
flag : bool
6125+
The new value for the check flag.
6126+
6127+
"""
6128+
6129+
PY_SCIP_CALL(SCIPchgAndConsCheckFlagWhenUpgr(self._scip, cons.scip_cons, flag))
6130+
6131+
def chgAndConsRemovableFlagWhenUpgr(self, Constraint cons, flag):
6132+
"""
6133+
when 'upgrading' the given AND-constraint, should the removable flag for the upgraded
6134+
constraint be set to TRUE, even if the removable flag of this AND-constraint is set to FALSE?
6135+
6136+
Parameters
6137+
----------
6138+
cons : Constraint
6139+
The AND constraint to change.
6140+
flag : bool
6141+
The new value for the removable flag.
6142+
6143+
"""
6144+
6145+
PY_SCIP_CALL(SCIPchgAndConsRemovableFlagWhenUpgr(self._scip, cons.scip_cons, flag))
6146+
59936147
def printCons(self, Constraint constraint):
59946148
"""
59956149
Print the constraint

tests/test_cons.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ def test_cons_logical():
7272
assert m.isEQ(m.getVal(result1), 1)
7373
assert m.isEQ(m.getVal(result2), 0)
7474

75+
def test_cons_and():
76+
m = Model()
77+
x1 = m.addVar(vtype="B")
78+
x2 = m.addVar(vtype="B")
79+
result = m.addVar(vtype="B")
80+
81+
and_cons = m.addConsAnd([x1, x2], result)
82+
83+
assert m.getNVarsAnd(and_cons) == 2
84+
assert m.getVarsAnd(and_cons) == [x1, x2]
85+
resultant_var = m.getResultantAnd(and_cons)
86+
assert resultant_var is result
87+
m.optimize()
88+
89+
m.sortAndCons(and_cons)
90+
assert m.isAndConsSorted(and_cons)
91+
7592
def test_cons_logical_fail():
7693
m = Model()
7794
x1 = m.addVar(vtype="B")

0 commit comments

Comments
 (0)