@@ -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' ))
@@ -3422,6 +3544,9 @@ cdef class Model:
34223544 """ Presolve the problem."""
34233545 PY_SCIP_CALL(SCIPpresolve(self ._scip))
34243546
3547+ def addDecomposition (self , Decomposition decomp ):
3548+ PY_SCIP_CALL(SCIPaddDecomp(self ._scip, decomp.scip_decomp))
3549+
34253550 # Benders' decomposition methods
34263551 def initBendersDefault (self , subproblems ):
34273552 """ initialises the default Benders' decomposition with a dictionary of subproblems
0 commit comments