diff --git a/CHANGELOG.md b/CHANGELOG.md index 98d9cd53..b2fa0952 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased ### Added - Added support for knapsack constraints +- More support for AND-Constraints ### Fixed ### Changed ### Removed diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index f00f9a66..a989980c 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -1646,6 +1646,16 @@ cdef extern from "scip/cons_and.h": 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) + cdef extern from "scip/cons_or.h": SCIP_RETCODE SCIPcreateConsOr(SCIP* scip, SCIP_CONS** cons, diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 970e6f03..f38deec4 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -5778,6 +5778,129 @@ cdef class Model: 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 + 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 = malloc(nvars * sizeof(SCIP_VAR*)) + _vars = SCIPgetVarsAnd(self._scip, and_cons.scip_cons) + + vars = [] + for i in range(nvars): + ptr = (_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 = (_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 printCons(self, Constraint constraint): """ Print the constraint diff --git a/tests/test_cons.py b/tests/test_cons.py index a3c663ee..2c5503af 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -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_SOScons(): m = Model() x = {}