Skip to content

Commit 860b888

Browse files
committed
completely untested user-provided decomps
1 parent f39c02b commit 860b888

File tree

2 files changed

+234
-6
lines changed

2 files changed

+234
-6
lines changed

src/pyscipopt/scip.pxd

+102
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ cdef extern from "scip/scip.h":
333333
ctypedef struct SCIP_CONS:
334334
pass
335335

336+
ctypedef struct SCIP_DECOMP:
337+
pass
338+
336339
ctypedef struct SCIP_ROW:
337340
pass
338341

@@ -1586,6 +1589,97 @@ cdef extern from "scip/scip_cons.h":
15861589
SCIP_CONS* cons,
15871590
FILE* file)
15881591

1592+
cdef extern from "scip/pub_dcmp.h":
1593+
SCIP_RETCODE SCIPdecompCreate(SCIP_DECOMP** decomp,
1594+
BMS_BLKMEM* blkmem,
1595+
int nblocks,
1596+
SCIP_Bool original,
1597+
SCIP_Bool benderslabels)
1598+
1599+
SCIP_Bool SCIPdecompIsOriginal(SCIP_DECOMP *decomp)
1600+
1601+
void SCIPdecompSetUseBendersLabels(SCIP_DECOMP *decomp, SCIP_Bool benderslabels)
1602+
1603+
SCIP_Bool SCIPdecompUseBendersLabels(SCIP_DECOMP *decomp)
1604+
1605+
int SCIPdecompGetNBlocks(SCIP_DECOMP *decomp)
1606+
1607+
SCIP_Real SCIPdecompGetAreaScore(SCIP_DECOMP *decomp)
1608+
1609+
SCIP_Real SCIPdecompGetModularity(SCIP_DECOMP *decomp)
1610+
1611+
SCIP_RETCODE SCIPdecompGetVarsSize(SCIP_DECOMP *decomp, int *varssize, int nblocks)
1612+
1613+
SCIP_RETCODE SCIPdecompGetConssSize(SCIP_DECOMP *decomp, int *consssize, int nblocks)
1614+
1615+
int SCIPdecompGetNBorderVars(SCIP_DECOMP *decomp)
1616+
1617+
int SCIPdecompGetNBorderConss(SCIP_DECOMP *decomp)
1618+
1619+
int SCIPdecompGetNBlockGraphEdges(SCIP_DECOMP *decomp)
1620+
1621+
int SCIPdecompGetNBlockGraphComponents(SCIP_DECOMP *decomp)
1622+
1623+
int SCIPdecompGetNBlockGraphArticulations(SCIP_DECOMP *decomp)
1624+
1625+
int SCIPdecompGetBlockGraphMaxDegree(SCIP_DECOMP *decomp)
1626+
1627+
int SCIPdecompGetBlockGraphMinDegree(SCIP_DECOMP *decomp)
1628+
1629+
SCIP_RETCODE SCIPdecompSetVarsLabels(SCIP_DECOMP *decomp, SCIP_VAR **vrs, int *labels, int nvars)
1630+
1631+
void SCIPdecompGetVarsLabels(SCIP_DECOMP *decomp, SCIP_VAR **vrs, int *labels, int nvars)
1632+
1633+
SCIP_RETCODE SCIPdecompSetConsLabels(SCIP_DECOMP *decomp, SCIP_CONS **conss, int *labels, int nconss)
1634+
1635+
void SCIPdecompGetConsLabels(SCIP_DECOMP *decomp, SCIP_CONS **conss, int *labels, int nconss)
1636+
1637+
SCIP_RETCODE SCIPdecompClear(SCIP_DECOMP *decomp, SCIP_Bool clearvarlabels, SCIP_Bool clearconslabels)
1638+
1639+
char* SCIPdecompPrintStats(SCIP_DECOMP *decomp, char *strbuf)
1640+
1641+
1642+
cdef extern from "scip/scip_dcmp.h":
1643+
SCIP_RETCODE SCIPcreateDecomp(SCIP* scip,
1644+
SCIP_DECOMP** decomp,
1645+
int nblocks,
1646+
SCIP_Bool original,
1647+
SCIP_Bool benderslabels)
1648+
1649+
SCIP_RETCODE SCIPaddDecomp(SCIP* scip, SCIP_DECOMP* decomp)
1650+
1651+
void SCIPfreeDecomp(SCIP* scip, SCIP_DECOMP** decomp)
1652+
1653+
void SCIPgetDecomps(SCIP* scip,
1654+
SCIP_DECOMP*** decomp,
1655+
int* ndecomps,
1656+
SCIP_Bool original)
1657+
1658+
SCIP_RETCODE SCIPhasConsOnlyLinkVars(SCIP* scip,
1659+
SCIP_DECOMP* decomp,
1660+
SCIP_CONS *cons,
1661+
SCIP_Bool* hasonlylinkvars)
1662+
1663+
SCIP_RETCODE SCIPcomputeDecompConsLabels(SCIP* scip,
1664+
SCIP_DECOMP* decomp,
1665+
SCIP_CONS** conss,
1666+
int nconss)
1667+
1668+
SCIP_RETCODE SCIPcomputeDecompVarsLabels(SCIP* scip,
1669+
SCIP_DECOMP* decomp,
1670+
SCIP_CONS** conss,
1671+
int nconss)
1672+
SCIP_RETCODE SCIPassignDecompLinkConss(SCIP* scip,
1673+
SCIP_DECOMP* decomp,
1674+
SCIP_CONS** conss,
1675+
int* nskipconss)
1676+
1677+
SCIP_RETCODE SCIPcomputeDecompStats(SCIP* scip,
1678+
SCIP_DECOMP *decomp,
1679+
SCIP_CONS** conss,
1680+
int nconss,
1681+
int* nskipconss)
1682+
15891683
cdef extern from "blockmemshell/memory.h":
15901684
void BMScheckEmptyMemory()
15911685
long long BMSgetMemoryUsed()
@@ -1950,6 +2044,14 @@ cdef class Constraint:
19502044
@staticmethod
19512045
cdef create(SCIP_CONS* scipcons)
19522046

2047+
cdef class Decomposition:
2048+
cdef SCIP_DECOMP* scip_decomp
2049+
2050+
cdef public object data
2051+
2052+
@staticmethod
2053+
cdef create(SCIP_DECOMP* scip_decomp)
2054+
19532055
cdef class Model:
19542056
cdef SCIP* _scip
19552057
cdef SCIP_Bool* _valid

src/pyscipopt/scip.pxi

+132-6
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ cdef class Event:
323323
attr = getattr(PY_SCIP_EVENTTYPE, name)
324324
if isinstance(attr, int):
325325
EventNames[attr] = name
326-
326+
327327
def __repr__(self):
328328
return str(self.getType())
329329

@@ -975,6 +975,128 @@ cdef class Constraint:
975975
return (self.__class__ == other.__class__
976976
and self.scip_cons == (<Constraint>other).scip_cons)
977977

978+
cdef class Decomposition:
979+
"""Base class holding a pointer to SCIP decomposition"""
980+
981+
@staticmethod
982+
cdef create(SCIP_DECOMP* scip_decomp):
983+
if scip_decomp == NULL:
984+
raise Warning("cannot create Constraint with SCIP_CONS* == NULL")
985+
decomp = Decomposition()
986+
decomp.scip_decomp = scip_decomp
987+
return decomp
988+
989+
def isOriginal(self):
990+
return SCIPdecompIsOriginal(self.scip_decomp)
991+
992+
def getAreaScore(self):
993+
return SCIPdecompGetAreaScore(self.scip_decomp)
994+
995+
def getModularity(self):
996+
return SCIPdecompGetModularity(self.scip_decomp)
997+
998+
def getNBorderVars(self):
999+
return SCIPdecompGetNBorderVars(self.scip_decomp)
1000+
1001+
def getNBorderConss(self):
1002+
return SCIPdecompGetNBorderConss(self.scip_decomp)
1003+
1004+
def getNBlockGraphEdges(self):
1005+
return SCIPdecompGetNBlockGraphEdges(self.scip_decomp)
1006+
1007+
def getNBlockGraphComponents(self):
1008+
return SCIPdecompGetNBlockGraphComponents(self.scip_decomp)
1009+
1010+
def getNblockGraphArticulations(self):
1011+
return SCIPdecompGetNBlockGraphArticulations(self.scip_decomp)
1012+
1013+
def getBlockGraphMaxDegree(self):
1014+
return SCIPdecompGetBlockGraphMaxDegree(self.scip_decomp)
1015+
1016+
def getBlockGraphMinDegree(self):
1017+
return SCIPdecompGetBlockGraphMinDegree(self.scip_decomp)
1018+
1019+
def getConsLabels(self, conss):
1020+
"""get {cons: label} pair for python constraints conss"""
1021+
cdef int nconss = <int> len(conss)
1022+
cdef int* labels = <int *> malloc(nconss * sizeof(int))
1023+
cdef SCIP_CONS** scip_conss = <SCIP_CONS**> malloc(nconss * sizeof(SCIP_CONS*))
1024+
1025+
for i in range(nconss):
1026+
scip_conss[i] = (<Constraint>conss[i]).scip_cons
1027+
1028+
PY_SCIP_CALL(SCIPdecompGetConsLabels(self.scip_decomp, scip_conss, labels, nconss))
1029+
1030+
cons_labels = {}
1031+
for i in range(nconss):
1032+
cons_labels[conss[i]] = labels[i]
1033+
free(labels)
1034+
free(scip_conss)
1035+
return cons_labels
1036+
1037+
def setConsLabels(self, cons_labels):
1038+
""" applies labels to constraints in decomposition.
1039+
:param cons_labels dict of {constraint: label} pairs to be applied
1040+
"""
1041+
cons_labels = cons_labels.items()
1042+
1043+
cdef int nconss = len(cons_labels)
1044+
cdef SCIP_CONS** scip_conss = <SCIP_CONS**> malloc(nconss* sizeof(SCIP_CONS*))
1045+
cdef int* labels = <int*> malloc(nconss * sizeof(int))
1046+
1047+
for i in range(nconss):
1048+
scip_conss[i] = (<Constraint>cons_labels[i][0]).scip_cons
1049+
labels[i] = cons_labels[i][1]
1050+
1051+
PY_SCIP_CALL(SCIPdecompSetConsLabels(self.scip_decomp, scip_conss, labels, nconss))
1052+
1053+
free(scip_conss)
1054+
free(labels)
1055+
1056+
def getVarsLabels(self, vrs):
1057+
"""get {var: label} pairs for python variables vrs"""
1058+
1059+
cdef int nvars = <int> len(vrs)
1060+
cdef int* labels = <int*> malloc(nvars * sizeof(int))
1061+
cdef SCIP_VAR** scip_vars = <SCIP_VAR**> malloc(nvars * sizeof(SCIP_VAR*))
1062+
1063+
for i in range(nvars):
1064+
scip_vars[i] = (<Variable>vrs[i]).scip_var
1065+
1066+
PY_SCIP_CALL(SCIPdecompGetVarsLabels(self.scip_decomp, scip_vars, labels, nvars))
1067+
1068+
var_labels = {}
1069+
for i in range(nvars):
1070+
var_labels[vrs[i]] = labels[i]
1071+
1072+
free(labels)
1073+
free(scip_vars)
1074+
return var_labels
1075+
1076+
def setVarLabels(self, var_labels):
1077+
"""set {var: label} pairs in decomposition"""
1078+
var_labels = var_labels.items()
1079+
1080+
cdef int nvars= len(var_labels)
1081+
cdef SCIP_VAR** scip_vars = <SCIP_VAR**> malloc(nvars * sizeof(SCIP_VAR*))
1082+
cdef int* labels = <int*> malloc(nvars * sizeof(int))
1083+
1084+
for i in range(nvars):
1085+
scip_vars[i] = (<Variable>var_labels[i][0]).scip_var
1086+
labels[i] = var_labels[i][1]
1087+
1088+
PY_SCIP_CALL(SCIPdecompSetVarsLabels(self.scip_decomp, scip_vars, labels, nvars))
1089+
1090+
free(scip_vars)
1091+
free(labels)
1092+
1093+
def clear(self, varlabels =True, conslabels = True):
1094+
"""clears variable and/or constraint labels from decomposition"""
1095+
1096+
if not (varlabels or conslabels):
1097+
... # TODO does decomp clear do anything if both options are false?
1098+
else:
1099+
PY_SCIP_CALL(SCIPdecompClear(self.scip_decomp, varlabels, conslabels))
9781100

9791101
cdef void relayMessage(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *msg) noexcept:
9801102
sys.stdout.write(msg.decode('UTF-8'))
@@ -2600,7 +2722,7 @@ cdef class Model:
26002722

26012723
PyCons = Constraint.create(conj_cons)
26022724
return PyCons
2603-
2725+
26042726
def addConsDisjunction(self, conss, name = '', initial = True,
26052727
relaxcons = None, enforce=True, check =True,
26062728
local=False, modifiable = False, dynamic = False):
@@ -2651,7 +2773,7 @@ cdef class Model:
26512773
PyCons = Constraint.create(disj_cons)
26522774
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &disj_cons))
26532775
return PyCons
2654-
2776+
26552777
def createConsDisjunction(self, conss, name = '', initial = True,
26562778
relaxcons = None, enforce=True, check =True,
26572779
local=False, modifiable = False, dynamic = False):
@@ -2700,6 +2822,7 @@ cdef class Model:
27002822
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &(<Constraint>pycons).scip_cons))
27012823
PyCons = Constraint.create(disj_cons)
27022824
return PyCons
2825+
27032826
def addConsElemDisjunction(self, Constraint disj_cons, Constraint cons):
27042827
"""Appends a constraint to a disjunction.
27052828
@@ -2713,7 +2836,6 @@ cdef class Model:
27132836

27142837
return disj_cons
27152838

2716-
27172839
def getConsNVars(self, Constraint constraint):
27182840
"""
27192841
Gets number of variables in a constraint.
@@ -3682,6 +3804,10 @@ cdef class Model:
36823804
"""Presolve the problem."""
36833805
PY_SCIP_CALL(SCIPpresolve(self._scip))
36843806

3807+
# custom decomposition methods
3808+
def addDecomposition(self, Decomposition decomp):
3809+
PY_SCIP_CALL(SCIPaddDecomp(self._scip, decomp.scip_decomp))
3810+
36853811
# Benders' decomposition methods
36863812
def initBendersDefault(self, subproblems):
36873813
"""initialises the default Benders' decomposition with a dictionary of subproblems
@@ -5057,13 +5183,13 @@ cdef class Model:
50575183
def getStage(self):
50585184
"""Retrieve current SCIP stage"""
50595185
return SCIPgetStage(self._scip)
5060-
5186+
50615187
def getStageName(self):
50625188
"""Returns name of current stage as string"""
50635189
if not StageNames:
50645190
self._getStageNames()
50655191
return StageNames[self.getStage()]
5066-
5192+
50675193
def _getStageNames(self):
50685194
"""Gets names of stages"""
50695195
for name in dir(PY_SCIP_STAGE):

0 commit comments

Comments
 (0)