@@ -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
9791101cdef 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