Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
- More support for AND-Constraints
- Added support for knapsack constraints
- Added isPositive(), isNegative(), isFeasLE(), isFeasLT(), isFeasGE(), isFeasGT(), isHugeValue(), and tests
- Added SCIP_LOCKTYPE, addVarLocksType(), getNLocksDown(), getNLocksUp(), getNLocksDownType(), getNLocksUpType(), and tests
Expand Down
7 changes: 7 additions & 0 deletions src/pyscipopt/scip.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -1653,6 +1653,13 @@ cdef extern from "scip/cons_and.h":
SCIP_Bool dynamic,
SCIP_Bool removable,
SCIP_Bool stickingatnode)
int SCIPgetNVarsAnd(SCIP* scip, SCIP_CONS* cons)
SCIP_VAR** SCIPgetVarsAnd(SCIP* scip, SCIP_CONS* cons)
SCIP_VAR* SCIPgetResultantAnd(SCIP* scip, SCIP_CONS* cons)
SCIP_Bool SCIPisAndConsSorted(SCIP* scip, SCIP_CONS* cons)
SCIP_RETCODE SCIPsortAndCons(SCIP* scip, SCIP_CONS* cons)
SCIP_RETCODE SCIPchgAndConsCheckFlagWhenUpgr(SCIP* scip, SCIP_CONS* cons, SCIP_Bool flag)
SCIP_RETCODE SCIPchgAndConsRemovableFlagWhenUpgr(SCIP* scip, SCIP_CONS* cons, SCIP_Bool flag)

cdef extern from "scip/cons_or.h":
SCIP_RETCODE SCIPcreateConsOr(SCIP* scip,
Expand Down
155 changes: 155 additions & 0 deletions src/pyscipopt/scip.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@
if rc == SCIP_OKAY:
pass
elif rc == SCIP_ERROR:
raise Exception('SCIP: unspecified error!')

Check failure on line 304 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 @@ -5990,6 +5990,161 @@

return vars

def getNVarsAnd(self, Constraint and_cons):
"""
Gets number of variables in and constraint.

Parameters
----------
and_cons : Constraint
AND constraint to get the number of variables from.

Returns
-------
int

"""
cdef int nvars
cdef SCIP_Bool success

return SCIPgetNVarsAnd(self._scip, and_cons.scip_cons)

def getVarsAnd(self, Constraint and_cons):
"""
Gets variables in AND constraint.

Parameters
----------
and_cons : Constraint
AND Constraint to get the variables from.

Returns
-------
list of Variable

"""
cdef SCIP_VAR** _vars
Comment thread
Joao-Dionisio marked this conversation as resolved.
cdef int nvars
cdef SCIP_Bool success
cdef int i

constype = bytes(SCIPconshdlrGetName(SCIPconsGetHdlr(and_cons.scip_cons))).decode('UTF-8')
assert(constype == 'and', "The constraint handler %s does not have this functionality." % constype)

nvars = SCIPgetNVarsAnd(self._scip, and_cons.scip_cons)
_vars = <SCIP_VAR**> malloc(nvars * sizeof(SCIP_VAR*))
Comment thread
Joao-Dionisio marked this conversation as resolved.
Outdated
_vars = SCIPgetVarsAnd(self._scip, and_cons.scip_cons)

vars = []
for i in range(nvars):
ptr = <size_t>(_vars[i])
# check whether the corresponding variable exists already
if ptr in self._modelvars:
vars.append(self._modelvars[ptr])
else:
# create a new variable
var = Variable.create(_vars[i])
assert var.ptr() == ptr
self._modelvars[ptr] = var
vars.append(var)

return vars

def getResultantAnd(self, Constraint and_cons):
"""
Gets the resultant variable in And constraint.

Parameters
----------
and_cons : Constraint
Constraint to get the resultant variable from.

Returns
-------
Variable

"""
cdef SCIP_VAR* _resultant
cdef SCIP_Bool success

_resultant = SCIPgetResultantAnd(self._scip, and_cons.scip_cons)

ptr = <size_t>(_resultant)
# check whether the corresponding variable exists already
if ptr not in self._modelvars:
# create a new variable
resultant = Variable.create(_resultant)
assert resultant.ptr() == ptr
self._modelvars[ptr] = resultant
else:
resultant = self._modelvars[ptr]

return resultant

def isAndConsSorted(self, Constraint and_cons):
"""
Returns if the variables of the AND-constraint are sorted with respect to their indices.

Parameters
----------
and_cons : Constraint
Constraint to check.

Returns
-------
bool

"""
cdef SCIP_Bool success

return SCIPisAndConsSorted(self._scip, and_cons.scip_cons)

def sortAndCons(self, Constraint and_cons):
"""
Sorts the variables of the AND-constraint with respect to their indices.

Parameters
----------
and_cons : Constraint
Constraint to sort.

"""
cdef SCIP_Bool success

PY_SCIP_CALL(SCIPsortAndCons(self._scip, and_cons.scip_cons))

def chgAndConsCheckFlagWhenUpgr(self, Constraint cons, flag):
"""
when 'upgrading' the given AND-constraint, should the check flag for the upgraded
constraint be set to TRUE, even if the check flag of this AND-constraint is set to FALSE?

Parameters
----------
cons : Constraint
The AND constraint to change.
flag : bool
The new value for the check flag.

"""

PY_SCIP_CALL(SCIPchgAndConsCheckFlagWhenUpgr(self._scip, cons.scip_cons, flag))

def chgAndConsRemovableFlagWhenUpgr(self, Constraint cons, flag):
"""
when 'upgrading' the given AND-constraint, should the removable flag for the upgraded
constraint be set to TRUE, even if the removable flag of this AND-constraint is set to FALSE?

Parameters
----------
cons : Constraint
The AND constraint to change.
flag : bool
The new value for the removable flag.

"""

PY_SCIP_CALL(SCIPchgAndConsRemovableFlagWhenUpgr(self._scip, cons.scip_cons, flag))

def printCons(self, Constraint constraint):
"""
Print the constraint
Expand Down
17 changes: 17 additions & 0 deletions tests/test_cons.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,23 @@ def test_cons_logical():
assert m.isEQ(m.getVal(result1), 1)
assert m.isEQ(m.getVal(result2), 0)

def test_cons_and():
m = Model()
x1 = m.addVar(vtype="B")
x2 = m.addVar(vtype="B")
result = m.addVar(vtype="B")

and_cons = m.addConsAnd([x1, x2], result)

assert m.getNVarsAnd(and_cons) == 2
assert m.getVarsAnd(and_cons) == [x1, x2]
resultant_var = m.getResultantAnd(and_cons)
assert resultant_var is result
m.optimize()

m.sortAndCons(and_cons)
assert m.isAndConsSorted(and_cons)

def test_cons_logical_fail():
m = Model()
x1 = m.addVar(vtype="B")
Expand Down