Skip to content

Commit

Permalink
completely untested user-provided decomps
Browse files Browse the repository at this point in the history
  • Loading branch information
ctdunc committed Apr 11, 2024
1 parent f39c02b commit 860b888
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 6 deletions.
102 changes: 102 additions & 0 deletions src/pyscipopt/scip.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@ cdef extern from "scip/scip.h":
ctypedef struct SCIP_CONS:
pass

ctypedef struct SCIP_DECOMP:
pass

ctypedef struct SCIP_ROW:
pass

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

cdef extern from "scip/pub_dcmp.h":
SCIP_RETCODE SCIPdecompCreate(SCIP_DECOMP** decomp,
BMS_BLKMEM* blkmem,
int nblocks,
SCIP_Bool original,
SCIP_Bool benderslabels)

SCIP_Bool SCIPdecompIsOriginal(SCIP_DECOMP *decomp)

void SCIPdecompSetUseBendersLabels(SCIP_DECOMP *decomp, SCIP_Bool benderslabels)

SCIP_Bool SCIPdecompUseBendersLabels(SCIP_DECOMP *decomp)

int SCIPdecompGetNBlocks(SCIP_DECOMP *decomp)

SCIP_Real SCIPdecompGetAreaScore(SCIP_DECOMP *decomp)

SCIP_Real SCIPdecompGetModularity(SCIP_DECOMP *decomp)

SCIP_RETCODE SCIPdecompGetVarsSize(SCIP_DECOMP *decomp, int *varssize, int nblocks)

SCIP_RETCODE SCIPdecompGetConssSize(SCIP_DECOMP *decomp, int *consssize, int nblocks)

int SCIPdecompGetNBorderVars(SCIP_DECOMP *decomp)

int SCIPdecompGetNBorderConss(SCIP_DECOMP *decomp)

int SCIPdecompGetNBlockGraphEdges(SCIP_DECOMP *decomp)

int SCIPdecompGetNBlockGraphComponents(SCIP_DECOMP *decomp)

int SCIPdecompGetNBlockGraphArticulations(SCIP_DECOMP *decomp)

int SCIPdecompGetBlockGraphMaxDegree(SCIP_DECOMP *decomp)

int SCIPdecompGetBlockGraphMinDegree(SCIP_DECOMP *decomp)

SCIP_RETCODE SCIPdecompSetVarsLabels(SCIP_DECOMP *decomp, SCIP_VAR **vrs, int *labels, int nvars)

void SCIPdecompGetVarsLabels(SCIP_DECOMP *decomp, SCIP_VAR **vrs, int *labels, int nvars)

SCIP_RETCODE SCIPdecompSetConsLabels(SCIP_DECOMP *decomp, SCIP_CONS **conss, int *labels, int nconss)

void SCIPdecompGetConsLabels(SCIP_DECOMP *decomp, SCIP_CONS **conss, int *labels, int nconss)

SCIP_RETCODE SCIPdecompClear(SCIP_DECOMP *decomp, SCIP_Bool clearvarlabels, SCIP_Bool clearconslabels)

char* SCIPdecompPrintStats(SCIP_DECOMP *decomp, char *strbuf)


cdef extern from "scip/scip_dcmp.h":
SCIP_RETCODE SCIPcreateDecomp(SCIP* scip,
SCIP_DECOMP** decomp,
int nblocks,
SCIP_Bool original,
SCIP_Bool benderslabels)

SCIP_RETCODE SCIPaddDecomp(SCIP* scip, SCIP_DECOMP* decomp)

void SCIPfreeDecomp(SCIP* scip, SCIP_DECOMP** decomp)

void SCIPgetDecomps(SCIP* scip,
SCIP_DECOMP*** decomp,
int* ndecomps,
SCIP_Bool original)

SCIP_RETCODE SCIPhasConsOnlyLinkVars(SCIP* scip,
SCIP_DECOMP* decomp,
SCIP_CONS *cons,
SCIP_Bool* hasonlylinkvars)

SCIP_RETCODE SCIPcomputeDecompConsLabels(SCIP* scip,
SCIP_DECOMP* decomp,
SCIP_CONS** conss,
int nconss)

SCIP_RETCODE SCIPcomputeDecompVarsLabels(SCIP* scip,
SCIP_DECOMP* decomp,
SCIP_CONS** conss,
int nconss)
SCIP_RETCODE SCIPassignDecompLinkConss(SCIP* scip,
SCIP_DECOMP* decomp,
SCIP_CONS** conss,
int* nskipconss)

SCIP_RETCODE SCIPcomputeDecompStats(SCIP* scip,
SCIP_DECOMP *decomp,
SCIP_CONS** conss,
int nconss,
int* nskipconss)

cdef extern from "blockmemshell/memory.h":
void BMScheckEmptyMemory()
long long BMSgetMemoryUsed()
Expand Down Expand Up @@ -1950,6 +2044,14 @@ cdef class Constraint:
@staticmethod
cdef create(SCIP_CONS* scipcons)

cdef class Decomposition:
cdef SCIP_DECOMP* scip_decomp

cdef public object data

@staticmethod
cdef create(SCIP_DECOMP* scip_decomp)

cdef class Model:
cdef SCIP* _scip
cdef SCIP_Bool* _valid
Expand Down
138 changes: 132 additions & 6 deletions src/pyscipopt/scip.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ cdef class Event:
attr = getattr(PY_SCIP_EVENTTYPE, name)
if isinstance(attr, int):
EventNames[attr] = name

def __repr__(self):
return str(self.getType())

Expand Down Expand Up @@ -975,6 +975,128 @@ cdef class Constraint:
return (self.__class__ == other.__class__
and self.scip_cons == (<Constraint>other).scip_cons)

cdef class Decomposition:
"""Base class holding a pointer to SCIP decomposition"""

@staticmethod
cdef create(SCIP_DECOMP* scip_decomp):
if scip_decomp == NULL:
raise Warning("cannot create Constraint with SCIP_CONS* == NULL")
decomp = Decomposition()
decomp.scip_decomp = scip_decomp
return decomp

def isOriginal(self):
return SCIPdecompIsOriginal(self.scip_decomp)

def getAreaScore(self):
return SCIPdecompGetAreaScore(self.scip_decomp)

def getModularity(self):
return SCIPdecompGetModularity(self.scip_decomp)

def getNBorderVars(self):
return SCIPdecompGetNBorderVars(self.scip_decomp)

def getNBorderConss(self):
return SCIPdecompGetNBorderConss(self.scip_decomp)

def getNBlockGraphEdges(self):
return SCIPdecompGetNBlockGraphEdges(self.scip_decomp)

def getNBlockGraphComponents(self):
return SCIPdecompGetNBlockGraphComponents(self.scip_decomp)

def getNblockGraphArticulations(self):
return SCIPdecompGetNBlockGraphArticulations(self.scip_decomp)

def getBlockGraphMaxDegree(self):
return SCIPdecompGetBlockGraphMaxDegree(self.scip_decomp)

def getBlockGraphMinDegree(self):
return SCIPdecompGetBlockGraphMinDegree(self.scip_decomp)

def getConsLabels(self, conss):
"""get {cons: label} pair for python constraints conss"""
cdef int nconss = <int> len(conss)
cdef int* labels = <int *> malloc(nconss * sizeof(int))
cdef SCIP_CONS** scip_conss = <SCIP_CONS**> malloc(nconss * sizeof(SCIP_CONS*))

for i in range(nconss):
scip_conss[i] = (<Constraint>conss[i]).scip_cons

PY_SCIP_CALL(SCIPdecompGetConsLabels(self.scip_decomp, scip_conss, labels, nconss))

cons_labels = {}
for i in range(nconss):
cons_labels[conss[i]] = labels[i]
free(labels)
free(scip_conss)
return cons_labels

def setConsLabels(self, cons_labels):
""" applies labels to constraints in decomposition.
:param cons_labels dict of {constraint: label} pairs to be applied
"""
cons_labels = cons_labels.items()

cdef int nconss = len(cons_labels)
cdef SCIP_CONS** scip_conss = <SCIP_CONS**> malloc(nconss* sizeof(SCIP_CONS*))
cdef int* labels = <int*> malloc(nconss * sizeof(int))

for i in range(nconss):
scip_conss[i] = (<Constraint>cons_labels[i][0]).scip_cons
labels[i] = cons_labels[i][1]

PY_SCIP_CALL(SCIPdecompSetConsLabels(self.scip_decomp, scip_conss, labels, nconss))

free(scip_conss)
free(labels)

def getVarsLabels(self, vrs):
"""get {var: label} pairs for python variables vrs"""

cdef int nvars = <int> len(vrs)
cdef int* labels = <int*> malloc(nvars * sizeof(int))
cdef SCIP_VAR** scip_vars = <SCIP_VAR**> malloc(nvars * sizeof(SCIP_VAR*))

for i in range(nvars):
scip_vars[i] = (<Variable>vrs[i]).scip_var

PY_SCIP_CALL(SCIPdecompGetVarsLabels(self.scip_decomp, scip_vars, labels, nvars))

var_labels = {}
for i in range(nvars):
var_labels[vrs[i]] = labels[i]

free(labels)
free(scip_vars)
return var_labels

def setVarLabels(self, var_labels):
"""set {var: label} pairs in decomposition"""
var_labels = var_labels.items()

cdef int nvars= len(var_labels)
cdef SCIP_VAR** scip_vars = <SCIP_VAR**> malloc(nvars * sizeof(SCIP_VAR*))
cdef int* labels = <int*> malloc(nvars * sizeof(int))

for i in range(nvars):
scip_vars[i] = (<Variable>var_labels[i][0]).scip_var
labels[i] = var_labels[i][1]

PY_SCIP_CALL(SCIPdecompSetVarsLabels(self.scip_decomp, scip_vars, labels, nvars))

free(scip_vars)
free(labels)

def clear(self, varlabels =True, conslabels = True):
"""clears variable and/or constraint labels from decomposition"""

if not (varlabels or conslabels):
... # TODO does decomp clear do anything if both options are false?
else:
PY_SCIP_CALL(SCIPdecompClear(self.scip_decomp, varlabels, conslabels))

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

PyCons = Constraint.create(conj_cons)
return PyCons

def addConsDisjunction(self, conss, name = '', initial = True,
relaxcons = None, enforce=True, check =True,
local=False, modifiable = False, dynamic = False):
Expand Down Expand Up @@ -2651,7 +2773,7 @@ cdef class Model:
PyCons = Constraint.create(disj_cons)
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &disj_cons))
return PyCons

def createConsDisjunction(self, conss, name = '', initial = True,
relaxcons = None, enforce=True, check =True,
local=False, modifiable = False, dynamic = False):
Expand Down Expand Up @@ -2700,6 +2822,7 @@ cdef class Model:
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &(<Constraint>pycons).scip_cons))
PyCons = Constraint.create(disj_cons)
return PyCons

def addConsElemDisjunction(self, Constraint disj_cons, Constraint cons):
"""Appends a constraint to a disjunction.
Expand All @@ -2713,7 +2836,6 @@ cdef class Model:

return disj_cons


def getConsNVars(self, Constraint constraint):
"""
Gets number of variables in a constraint.
Expand Down Expand Up @@ -3682,6 +3804,10 @@ cdef class Model:
"""Presolve the problem."""
PY_SCIP_CALL(SCIPpresolve(self._scip))

# custom decomposition methods
def addDecomposition(self, Decomposition decomp):
PY_SCIP_CALL(SCIPaddDecomp(self._scip, decomp.scip_decomp))

# Benders' decomposition methods
def initBendersDefault(self, subproblems):
"""initialises the default Benders' decomposition with a dictionary of subproblems
Expand Down Expand Up @@ -5057,13 +5183,13 @@ cdef class Model:
def getStage(self):
"""Retrieve current SCIP stage"""
return SCIPgetStage(self._scip)

def getStageName(self):
"""Returns name of current stage as string"""
if not StageNames:
self._getStageNames()
return StageNames[self.getStage()]

def _getStageNames(self):
"""Gets names of stages"""
for name in dir(PY_SCIP_STAGE):
Expand Down

0 comments on commit 860b888

Please sign in to comment.