4 from os.path
import abspath
5 from os.path
import splitext
12 from cpython cimport Py_INCREF, Py_DECREF
13 from cpython.pycapsule cimport PyCapsule_New, PyCapsule_IsValid, PyCapsule_GetPointer
14 from libc.stdlib cimport malloc, free
15 from libc.stdio cimport fdopen, fclose
16 from posix.stdio cimport fileno
18 from collections.abc
import Iterable
19 from itertools
import repeat
20 from dataclasses
import dataclass
25 include
"benderscut.pxi"
26 include
"branchrule.pxi"
27 include
"conshdlr.pxi"
30 include
"heuristic.pxi"
33 include
"propagator.pxi"
47 if sys.version_info >= (3, 0):
48 str_conversion =
lambda x:bytes(x,
'utf-8')
50 str_conversion =
lambda x:x
52 _SCIP_BOUNDTYPE_TO_STRING = {SCIP_BOUNDTYPE_UPPER:
'<=',
53 SCIP_BOUNDTYPE_LOWER:
'>='}
59 cdef
class PY_SCIP_RESULT:
60 DIDNOTRUN = SCIP_DIDNOTRUN
61 DELAYED = SCIP_DELAYED
62 DIDNOTFIND = SCIP_DIDNOTFIND
63 FEASIBLE = SCIP_FEASIBLE
64 INFEASIBLE = SCIP_INFEASIBLE
65 UNBOUNDED = SCIP_UNBOUNDED
67 SEPARATED = SCIP_SEPARATED
68 NEWROUND = SCIP_NEWROUND
69 REDUCEDDOM = SCIP_REDUCEDDOM
70 CONSADDED = SCIP_CONSADDED
71 CONSCHANGED = SCIP_CONSCHANGED
72 BRANCHED = SCIP_BRANCHED
73 SOLVELP = SCIP_SOLVELP
74 FOUNDSOL = SCIP_FOUNDSOL
75 SUSPENDED = SCIP_SUSPENDED
76 SUCCESS = SCIP_SUCCESS
78 cdef
class PY_SCIP_PARAMSETTING:
79 DEFAULT = SCIP_PARAMSETTING_DEFAULT
80 AGGRESSIVE = SCIP_PARAMSETTING_AGGRESSIVE
81 FAST = SCIP_PARAMSETTING_FAST
82 OFF = SCIP_PARAMSETTING_OFF
84 cdef
class PY_SCIP_PARAMEMPHASIS:
85 DEFAULT = SCIP_PARAMEMPHASIS_DEFAULT
86 CPSOLVER = SCIP_PARAMEMPHASIS_CPSOLVER
87 EASYCIP = SCIP_PARAMEMPHASIS_EASYCIP
88 FEASIBILITY = SCIP_PARAMEMPHASIS_FEASIBILITY
89 HARDLP = SCIP_PARAMEMPHASIS_HARDLP
90 OPTIMALITY = SCIP_PARAMEMPHASIS_OPTIMALITY
91 COUNTER = SCIP_PARAMEMPHASIS_COUNTER
92 PHASEFEAS = SCIP_PARAMEMPHASIS_PHASEFEAS
93 PHASEIMPROVE = SCIP_PARAMEMPHASIS_PHASEIMPROVE
94 PHASEPROOF = SCIP_PARAMEMPHASIS_PHASEPROOF
95 NUMERICS = SCIP_PARAMEMPHASIS_NUMERICS
96 BENCHMARK = SCIP_PARAMEMPHASIS_BENCHMARK
98 cdef
class PY_SCIP_STATUS:
99 UNKNOWN = SCIP_STATUS_UNKNOWN
100 USERINTERRUPT = SCIP_STATUS_USERINTERRUPT
101 NODELIMIT = SCIP_STATUS_NODELIMIT
102 TOTALNODELIMIT = SCIP_STATUS_TOTALNODELIMIT
103 STALLNODELIMIT = SCIP_STATUS_STALLNODELIMIT
104 TIMELIMIT = SCIP_STATUS_TIMELIMIT
105 MEMLIMIT = SCIP_STATUS_MEMLIMIT
106 GAPLIMIT = SCIP_STATUS_GAPLIMIT
107 SOLLIMIT = SCIP_STATUS_SOLLIMIT
108 BESTSOLLIMIT = SCIP_STATUS_BESTSOLLIMIT
109 RESTARTLIMIT = SCIP_STATUS_RESTARTLIMIT
110 PRIMALLIMIT = SCIP_STATUS_PRIMALLIMIT
111 DUALLIMIT = SCIP_STATUS_DUALLIMIT
112 OPTIMAL = SCIP_STATUS_OPTIMAL
113 INFEASIBLE = SCIP_STATUS_INFEASIBLE
114 UNBOUNDED = SCIP_STATUS_UNBOUNDED
115 INFORUNBD = SCIP_STATUS_INFORUNBD
119 cdef
class PY_SCIP_STAGE:
120 INIT = SCIP_STAGE_INIT
121 PROBLEM = SCIP_STAGE_PROBLEM
122 TRANSFORMING = SCIP_STAGE_TRANSFORMING
123 TRANSFORMED = SCIP_STAGE_TRANSFORMED
124 INITPRESOLVE = SCIP_STAGE_INITPRESOLVE
125 PRESOLVING = SCIP_STAGE_PRESOLVING
126 EXITPRESOLVE = SCIP_STAGE_EXITPRESOLVE
127 PRESOLVED = SCIP_STAGE_PRESOLVED
128 INITSOLVE = SCIP_STAGE_INITSOLVE
129 SOLVING = SCIP_STAGE_SOLVING
130 SOLVED = SCIP_STAGE_SOLVED
131 EXITSOLVE = SCIP_STAGE_EXITSOLVE
132 FREETRANS = SCIP_STAGE_FREETRANS
133 FREE = SCIP_STAGE_FREE
135 cdef
class PY_SCIP_NODETYPE:
136 FOCUSNODE = SCIP_NODETYPE_FOCUSNODE
137 PROBINGNODE = SCIP_NODETYPE_PROBINGNODE
138 SIBLING = SCIP_NODETYPE_SIBLING
139 CHILD = SCIP_NODETYPE_CHILD
140 LEAF = SCIP_NODETYPE_LEAF
141 DEADEND = SCIP_NODETYPE_DEADEND
142 JUNCTION = SCIP_NODETYPE_JUNCTION
143 PSEUDOFORK = SCIP_NODETYPE_PSEUDOFORK
144 FORK = SCIP_NODETYPE_FORK
145 SUBROOT = SCIP_NODETYPE_SUBROOT
146 REFOCUSNODE = SCIP_NODETYPE_REFOCUSNODE
149 cdef
class PY_SCIP_PROPTIMING:
150 BEFORELP = SCIP_PROPTIMING_BEFORELP
151 DURINGLPLOOP = SCIP_PROPTIMING_DURINGLPLOOP
152 AFTERLPLOOP = SCIP_PROPTIMING_AFTERLPLOOP
153 AFTERLPNODE = SCIP_PROPTIMING_AFTERLPNODE
155 cdef
class PY_SCIP_PRESOLTIMING:
156 NONE = SCIP_PRESOLTIMING_NONE
157 FAST = SCIP_PRESOLTIMING_FAST
158 MEDIUM = SCIP_PRESOLTIMING_MEDIUM
159 EXHAUSTIVE = SCIP_PRESOLTIMING_EXHAUSTIVE
161 cdef
class PY_SCIP_HEURTIMING:
162 BEFORENODE = SCIP_HEURTIMING_BEFORENODE
163 DURINGLPLOOP = SCIP_HEURTIMING_DURINGLPLOOP
164 AFTERLPLOOP = SCIP_HEURTIMING_AFTERLPLOOP
165 AFTERLPNODE = SCIP_HEURTIMING_AFTERLPNODE
166 AFTERPSEUDONODE = SCIP_HEURTIMING_AFTERPSEUDONODE
167 AFTERLPPLUNGE = SCIP_HEURTIMING_AFTERLPPLUNGE
168 AFTERPSEUDOPLUNGE = SCIP_HEURTIMING_AFTERPSEUDOPLUNGE
169 DURINGPRICINGLOOP = SCIP_HEURTIMING_DURINGPRICINGLOOP
170 BEFOREPRESOL = SCIP_HEURTIMING_BEFOREPRESOL
171 DURINGPRESOLLOOP = SCIP_HEURTIMING_DURINGPRESOLLOOP
172 AFTERPROPLOOP = SCIP_HEURTIMING_AFTERPROPLOOP
176 cdef
class PY_SCIP_EVENTTYPE:
177 DISABLED = SCIP_EVENTTYPE_DISABLED
178 VARADDED = SCIP_EVENTTYPE_VARADDED
179 VARDELETED = SCIP_EVENTTYPE_VARDELETED
180 VARFIXED = SCIP_EVENTTYPE_VARFIXED
181 VARUNLOCKED = SCIP_EVENTTYPE_VARUNLOCKED
182 OBJCHANGED = SCIP_EVENTTYPE_OBJCHANGED
183 GLBCHANGED = SCIP_EVENTTYPE_GLBCHANGED
184 GUBCHANGED = SCIP_EVENTTYPE_GUBCHANGED
185 LBTIGHTENED = SCIP_EVENTTYPE_LBTIGHTENED
186 LBRELAXED = SCIP_EVENTTYPE_LBRELAXED
187 UBTIGHTENED = SCIP_EVENTTYPE_UBTIGHTENED
188 UBRELAXED = SCIP_EVENTTYPE_UBRELAXED
189 GHOLEADDED = SCIP_EVENTTYPE_GHOLEADDED
190 GHOLEREMOVED = SCIP_EVENTTYPE_GHOLEREMOVED
191 LHOLEADDED = SCIP_EVENTTYPE_LHOLEADDED
192 LHOLEREMOVED = SCIP_EVENTTYPE_LHOLEREMOVED
193 IMPLADDED = SCIP_EVENTTYPE_IMPLADDED
194 PRESOLVEROUND = SCIP_EVENTTYPE_PRESOLVEROUND
195 NODEFOCUSED = SCIP_EVENTTYPE_NODEFOCUSED
196 NODEFEASIBLE = SCIP_EVENTTYPE_NODEFEASIBLE
197 NODEINFEASIBLE = SCIP_EVENTTYPE_NODEINFEASIBLE
198 NODEBRANCHED = SCIP_EVENTTYPE_NODEBRANCHED
199 NODEDELETE = SCIP_EVENTTYPE_NODEDELETE
200 FIRSTLPSOLVED = SCIP_EVENTTYPE_FIRSTLPSOLVED
201 LPSOLVED = SCIP_EVENTTYPE_LPSOLVED
202 LPEVENT = SCIP_EVENTTYPE_LPEVENT
203 POORSOLFOUND = SCIP_EVENTTYPE_POORSOLFOUND
204 BESTSOLFOUND = SCIP_EVENTTYPE_BESTSOLFOUND
205 ROWADDEDSEPA = SCIP_EVENTTYPE_ROWADDEDSEPA
206 ROWDELETEDSEPA = SCIP_EVENTTYPE_ROWDELETEDSEPA
207 ROWADDEDLP = SCIP_EVENTTYPE_ROWADDEDLP
208 ROWDELETEDLP = SCIP_EVENTTYPE_ROWDELETEDLP
209 ROWCOEFCHANGED = SCIP_EVENTTYPE_ROWCOEFCHANGED
210 ROWCONSTCHANGED = SCIP_EVENTTYPE_ROWCONSTCHANGED
211 ROWSIDECHANGED = SCIP_EVENTTYPE_ROWSIDECHANGED
212 SYNC = SCIP_EVENTTYPE_SYNC
213 GBDCHANGED = SCIP_EVENTTYPE_GBDCHANGED
214 LBCHANGED = SCIP_EVENTTYPE_LBCHANGED
215 UBCHANGED = SCIP_EVENTTYPE_UBCHANGED
216 BOUNDTIGHTENED = SCIP_EVENTTYPE_BOUNDTIGHTENED
217 BOUNDRELAXED = SCIP_EVENTTYPE_BOUNDRELAXED
218 BOUNDCHANGED = SCIP_EVENTTYPE_BOUNDCHANGED
219 GHOLECHANGED = SCIP_EVENTTYPE_GHOLECHANGED
220 LHOLECHANGED = SCIP_EVENTTYPE_LHOLECHANGED
221 HOLECHANGED = SCIP_EVENTTYPE_HOLECHANGED
222 DOMCHANGED = SCIP_EVENTTYPE_DOMCHANGED
223 VARCHANGED = SCIP_EVENTTYPE_VARCHANGED
224 VAREVENT = SCIP_EVENTTYPE_VAREVENT
225 NODESOLVED = SCIP_EVENTTYPE_NODESOLVED
226 NODEEVENT = SCIP_EVENTTYPE_NODEEVENT
227 SOLFOUND = SCIP_EVENTTYPE_SOLFOUND
228 SOLEVENT = SCIP_EVENTTYPE_SOLEVENT
229 ROWCHANGED = SCIP_EVENTTYPE_ROWCHANGED
230 ROWEVENT = SCIP_EVENTTYPE_ROWEVENT
233 cdef
class PY_SCIP_LPSOLSTAT:
234 NOTSOLVED = SCIP_LPSOLSTAT_NOTSOLVED
235 OPTIMAL = SCIP_LPSOLSTAT_OPTIMAL
236 INFEASIBLE = SCIP_LPSOLSTAT_INFEASIBLE
237 UNBOUNDEDRAY = SCIP_LPSOLSTAT_UNBOUNDEDRAY
238 OBJLIMIT = SCIP_LPSOLSTAT_OBJLIMIT
239 ITERLIMIT = SCIP_LPSOLSTAT_ITERLIMIT
240 TIMELIMIT = SCIP_LPSOLSTAT_TIMELIMIT
241 ERROR = SCIP_LPSOLSTAT_ERROR
243 cdef
class PY_SCIP_BRANCHDIR:
244 DOWNWARDS = SCIP_BRANCHDIR_DOWNWARDS
245 UPWARDS = SCIP_BRANCHDIR_UPWARDS
246 FIXED = SCIP_BRANCHDIR_FIXED
247 AUTO = SCIP_BRANCHDIR_AUTO
249 cdef
class PY_SCIP_BENDERSENFOTYPE:
250 LP = SCIP_BENDERSENFOTYPE_LP
251 RELAX = SCIP_BENDERSENFOTYPE_RELAX
252 PSEUDO = SCIP_BENDERSENFOTYPE_PSEUDO
253 CHECK = SCIP_BENDERSENFOTYPE_CHECK
255 cdef
class PY_SCIP_ROWORIGINTYPE:
256 UNSPEC = SCIP_ROWORIGINTYPE_UNSPEC
257 CONS = SCIP_ROWORIGINTYPE_CONS
258 SEPA = SCIP_ROWORIGINTYPE_SEPA
259 REOPT = SCIP_ROWORIGINTYPE_REOPT
261 def PY_SCIP_CALL(SCIP_RETCODE rc):
264 elif rc == SCIP_ERROR:
265 raise Exception(
'SCIP: unspecified error!')
266 elif rc == SCIP_NOMEMORY:
267 raise MemoryError(
'SCIP: insufficient memory error!')
268 elif rc == SCIP_READERROR:
269 raise IOError(
'SCIP: read error!')
270 elif rc == SCIP_WRITEERROR:
271 raise IOError(
'SCIP: write error!')
272 elif rc == SCIP_NOFILE:
273 raise IOError(
'SCIP: file not found error!')
274 elif rc == SCIP_FILECREATEERROR:
275 raise IOError(
'SCIP: cannot create file!')
276 elif rc == SCIP_LPERROR:
277 raise Exception(
'SCIP: error in LP solver!')
278 elif rc == SCIP_NOPROBLEM:
279 raise Exception(
'SCIP: no problem exists!')
280 elif rc == SCIP_INVALIDCALL:
281 raise Exception(
'SCIP: method cannot be called at this time'
282 +
' in solution process!')
283 elif rc == SCIP_INVALIDDATA:
284 raise Exception(
'SCIP: error in input data!')
285 elif rc == SCIP_INVALIDRESULT:
286 raise Exception(
'SCIP: method returned an invalid result code!')
287 elif rc == SCIP_PLUGINNOTFOUND:
288 raise Exception(
'SCIP: a required plugin was not found !')
289 elif rc == SCIP_PARAMETERUNKNOWN:
290 raise KeyError(
'SCIP: the parameter with the given name was not found!')
291 elif rc == SCIP_PARAMETERWRONGTYPE:
292 raise LookupError(
'SCIP: the parameter is not of the expected type!')
293 elif rc == SCIP_PARAMETERWRONGVAL:
294 raise ValueError(
'SCIP: the value is invalid for the given parameter!')
295 elif rc == SCIP_KEYALREADYEXISTING:
296 raise KeyError(
'SCIP: the given key is already existing in table!')
297 elif rc == SCIP_MAXDEPTHLEVEL:
298 raise Exception(
'SCIP: maximal branching depth level exceeded!')
300 raise Exception(
'SCIP: unknown return code!')
303 """Base class holding a pointer to corresponding SCIP_EVENT"""
306 cdef create(SCIP_EVENT* scip_event):
307 if scip_event == NULL:
308 raise Warning(
"cannot create Event with SCIP_EVENT* == NULL")
310 event.event = scip_event
314 """gets type of event"""
318 """gets name of event"""
321 return EventNames[self.
getType()]
323 def _getEventNames(self):
324 """gets event names"""
325 for name
in dir(PY_SCIP_EVENTTYPE):
326 attr = getattr(PY_SCIP_EVENTTYPE, name)
327 if isinstance(attr, int):
328 EventNames[attr] = name
337 """gets new bound for a bound change event"""
341 """gets old bound for a bound change event"""
345 """gets variable for a variable event (var added, var deleted, var fixed, objective value or domain change, domain hole added or removed)"""
347 return Variable.create(var)
350 """gets node for a node or LP event"""
352 return Node.create(node)
355 """gets row for a row event"""
357 return Row.create(row)
360 return hash(<size_t>self.
event)
363 return (self.
__class__ == other.__class__
364 and self.
event == (<Event>other).event)
367 """Base class holding a pointer to corresponding SCIP_COL"""
370 cdef create(SCIP_COL* scipcol):
372 raise Warning(
"cannot create Column with SCIP_COL* == NULL")
374 col.scip_col = scipcol
378 """gets position of column in current LP, or -1 if it is not in LP"""
382 """gets the basis status of a column in the LP solution, Note: returns basis status `zero` for columns not in the current SCIP LP"""
384 if stat == SCIP_BASESTAT_LOWER:
386 elif stat == SCIP_BASESTAT_BASIC:
388 elif stat == SCIP_BASESTAT_UPPER:
390 elif stat == SCIP_BASESTAT_ZERO:
393 raise Exception(
'SCIP returned unknown base status!')
396 """returns whether the associated variable is of integral type (binary, integer, implicit integer)"""
400 """gets variable this column represents"""
402 return Variable.create(var)
405 """gets the primal LP solution of a column"""
409 """gets lower bound of column"""
413 """gets upper bound of column"""
417 """gets objective value coefficient of a column"""
421 """Gets the age of the column, i.e., the total number of successive times a column was in the LP
422 and was 0.0 in the solution"""
429 return (self.
__class__ == other.__class__
430 and self.
scip_col == (<Column>other).scip_col)
433 """Base class holding a pointer to corresponding SCIP_ROW"""
436 cdef create(SCIP_ROW* sciprow):
438 raise Warning(
"cannot create Row with SCIP_ROW* == NULL")
440 row.scip_row = sciprow
446 return cname.decode(
'utf-8')
449 """returns the left hand side of row"""
453 """returns the right hand side of row"""
457 """gets constant shift of row"""
461 """gets position of row in current LP, or -1 if it is not in LP"""
465 """gets the basis status of a row in the LP solution, Note: returns basis status `basic` for rows not in the current SCIP LP"""
467 if stat == SCIP_BASESTAT_LOWER:
469 elif stat == SCIP_BASESTAT_BASIC:
471 elif stat == SCIP_BASESTAT_UPPER:
473 elif stat == SCIP_BASESTAT_ZERO:
475 raise Exception(
'SCIP returned base status zero for a row!')
477 raise Exception(
'SCIP returned unknown base status!')
480 """returns TRUE iff the activity of the row (without the row's constant) is always integral in a feasible solution """
484 """returns TRUE iff the row is only valid locally """
488 """returns TRUE iff row is modifiable during node processing (subject to column generation) """
492 """returns TRUE iff row is removable from the LP (due to aging or cleanup)"""
496 """return TRUE iff row is a member of the global cut pool"""
500 """returns type of origin that created the row"""
504 """returns type of constraint handler that created the row"""
509 """get number of nonzero entries in row vector"""
513 """get number of nonzero entries in row vector that correspond to columns currently in the SCIP LP"""
517 """gets list with columns of nonzero entries"""
519 return [Column.create(cols[i])
for i
in range(self.
getNNonz())]
522 """gets list with coefficients of nonzero entries"""
524 return [vals[i]
for i
in range(self.
getNNonz())]
527 """Gets the age of the row. (The consecutive times the row has been non-active in the LP)"""
531 """gets Euclidean norm of row vector """
538 return (self.
__class__ == other.__class__
539 and self.
scip_row == (<Row>other).scip_row)
542 """Base class holding a pointer to corresponding SCIP_NLROW"""
545 cdef create(SCIP_NLROW* scipnlrow):
546 if scipnlrow == NULL:
547 raise Warning(
"cannot create NLRow with SCIP_NLROW* == NULL")
549 nlrow.scip_nlrow = scipnlrow
555 return cname.decode(
'utf-8')
558 """returns the constant of a nonlinear row"""
562 """returns a list of tuples (var, coef) representing the linear part of a nonlinear row"""
566 return [(Variable.create(linvars[i]), lincoefs[i])
for i
in range(nlinvars)]
569 """returns the left hand side of a nonlinear row"""
573 """returns the right hand side of a nonlinear row"""
577 """gets the dual NLP solution of a nonlinear row"""
584 return (self.
__class__ == other.__class__
585 and self.
scip_nlrow == (<NLRow>other).scip_nlrow)
588 """Base class holding a pointer to corresponding SCIP_SOL"""
593 raise ValueError(
"To create a solution you should use the createSol method of the Model class.")
596 cdef create(SCIP* scip, SCIP_SOL* scip_sol):
598 raise Warning(
"cannot create Solution with SCIP* == NULL")
606 if isinstance(expr, Variable):
608 var = <Variable> expr
610 return sum(self.
_evaluate(term)*coeff
for term, coeff
in expr.terms.items()
if coeff != 0)
612 def _evaluate(self, term):
615 for var
in term.vartuple:
623 cdef SCIP_VAR* scip_var
632 name = cname.decode(
'utf-8')
637 def _checkStage(self, method):
638 if method
in [
"SCIPgetSolVal",
"getSolObjVal"]:
639 stage_check =
SCIPgetStage(self.
scip)
not in [SCIP_STAGE_INIT, SCIP_STAGE_FREE]
642 raise Warning(f
"{method} can only be called with a valid solution or in stage SOLVING (current stage: {SCIPgetStage(self.scip)})")
649 cdef create(SCIP_BOUNDCHG* scip_boundchg):
650 if scip_boundchg == NULL:
651 raise Warning(
"cannot create BoundChange with SCIP_BOUNDCHG* == NULL")
653 boundchg.scip_boundchg = scip_boundchg
657 """Returns the new value of the bound in the bound change."""
661 """Returns the variable of the bound change."""
665 """Returns the bound change type of the bound change."""
669 """Returns the bound type of the bound change."""
673 """Returns whether the bound change is redundant due to a more global bound that is at least as strong."""
677 return "{} {} {}".format(self.
getVar(),
682 """Set of domain changes."""
685 cdef create(SCIP_DOMCHG* scip_domchg):
686 if scip_domchg == NULL:
687 raise Warning(
"cannot create DomainChanges with SCIP_DOMCHG* == NULL")
689 domchg.scip_domchg = scip_domchg
693 """Returns the bound changes in the domain change."""
696 for i
in range(nboundchgs)]
699 """Base class holding a pointer to corresponding SCIP_NODE"""
702 cdef create(SCIP_NODE* scipnode):
706 node.scip_node = scipnode
710 """Retrieve parent node (or None if the node has no parent node)."""
714 """Retrieve number of node."""
718 """Retrieve depth of node."""
722 """Retrieve type of node."""
726 """Retrieve lower bound of node."""
730 """Retrieve the estimated value of the best feasible solution in subtree of the node"""
734 """Retrieve all constraints added at this node."""
736 if addedconsssize == 0:
738 cdef SCIP_CONS** addedconss = <SCIP_CONS**> malloc(addedconsssize * sizeof(SCIP_CONS*))
741 assert nconss == addedconsssize
742 constraints = [Constraint.create(addedconss[i])
for i
in range(nconss)]
747 """Retrieve number of added constraints at this node"""
751 """Is the node in the path to the current node?"""
755 """Is the node marked to be propagated again?"""
759 """Retrieve the number of variable branchings that were performed in the parent node to create this node."""
760 cdef SCIP_VAR* dummy_branchvars
761 cdef SCIP_Real dummy_branchbounds
762 cdef SCIP_BOUNDTYPE dummy_boundtypes
768 &dummy_branchbounds, &dummy_boundtypes,
773 """Retrieve the set of variable branchings that were performed in the parent node to create this node."""
778 cdef SCIP_VAR** branchvars = <SCIP_VAR**> malloc(nbranchvars * sizeof(SCIP_VAR*))
779 cdef SCIP_Real* branchbounds = <SCIP_Real*> malloc(nbranchvars * sizeof(SCIP_Real))
780 cdef SCIP_BOUNDTYPE* boundtypes = <SCIP_BOUNDTYPE*> malloc(nbranchvars * sizeof(SCIP_BOUNDTYPE))
783 boundtypes, &nbranchvars, nbranchvars)
785 py_variables = [Variable.create(branchvars[i])
for i
in range(nbranchvars)]
786 py_branchbounds = [branchbounds[i]
for i
in range(nbranchvars)]
787 py_boundtypes = [boundtypes[i]
for i
in range(nbranchvars)]
792 return py_variables, py_branchbounds, py_boundtypes
795 """Retrieve the number of bound changes due to branching, constraint propagation, and propagation."""
800 return nbranchings, nconsprop, nprop
803 """Retrieve domain changes for this node."""
807 return DomainChanges.create(domchg)
813 return (self.
__class__ == other.__class__
814 and self.
scip_node == (<Node>other).scip_node)
817 """Is a linear expression and has SCIP_VAR*"""
820 cdef create(SCIP_VAR* scipvar):
822 raise Warning(
"cannot create Variable with SCIP_VAR* == NULL")
824 var.scip_var = scipvar
825 Expr.__init__(var, {Term(var) : 1.0})
831 return cname.decode(
'utf-8')
841 """Retrieve the variables type (BINARY, INTEGER, IMPLINT or CONTINUOUS)"""
843 if vartype == SCIP_VARTYPE_BINARY:
845 elif vartype == SCIP_VARTYPE_INTEGER:
847 elif vartype == SCIP_VARTYPE_CONTINUOUS:
849 elif vartype == SCIP_VARTYPE_IMPLINT:
853 """Retrieve whether the variable belongs to the original problem"""
857 """Retrieve whether the variable is a COLUMN variable that is member of the current LP"""
862 """Retrieve the unique index of the variable."""
866 """Retrieve column of COLUMN variable"""
867 cdef SCIP_COL* scip_col
869 return Column.create(scip_col)
872 """Retrieve original lower bound of variable"""
876 """Retrieve original upper bound of variable"""
880 """Retrieve global lower bound of variable"""
884 """Retrieve global upper bound of variable"""
888 """Retrieve current lower bound of variable"""
892 """Retrieve current upper bound of variable"""
896 """Retrieve current objective value of variable"""
900 """Retrieve the current LP solution value of variable"""
904 """Get the weighted average solution of variable in all feasible primal solutions found"""
908 """Base class holding a pointer to corresponding SCIP_CONS"""
911 cdef create(SCIP_CONS* scipcons):
913 raise Warning(
"cannot create Constraint with SCIP_CONS* == NULL")
915 cons.scip_cons = scipcons
921 return cname.decode(
'utf-8')
927 """Retrieve whether the constraint belongs to the original problem"""
931 """Retrieve True if the relaxation of the constraint should be in the initial LP"""
935 """Retrieve True if constraint should be separated during LP processing"""
939 """Retrieve True if constraint should be enforced during node processing"""
943 """Retrieve True if constraint should be checked for feasibility"""
947 """Retrieve True if constraint should be propagated during node processing"""
951 """Retrieve True if constraint is only locally valid or not added to any (sub)problem"""
955 """Retrieve True if constraint is modifiable (subject to column generation)"""
959 """Retrieve True if constraint is subject to aging"""
963 """Retrieve True if constraint's relaxation should be removed from the LP due to aging or cleanup"""
967 """Retrieve True if constraint is only locally valid or not added to any (sub)problem"""
971 """returns True iff constraint is active in the current node"""
975 """Retrieve True if constraint is linear"""
977 return constype ==
'linear'
980 """Retrieve True if constraint is nonlinear"""
982 return constype ==
'nonlinear'
985 """Return the constraint handler's name"""
993 return (self.
__class__ == other.__class__
994 and self.
scip_cons == (<Constraint>other).scip_cons)
997 cdef void relayMessage(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *msg) noexcept:
998 sys.stdout.write(msg.decode(
'UTF-8'))
1000 cdef void relayErrorMessage(void *messagehdlr, FILE *file, const char *msg) noexcept:
1001 sys.stderr.write(msg.decode(
'UTF-8'))
1010 """Main class holding a pointer to SCIP for managing most interactions"""
1012 def __init__(self, problemName='model', defaultPlugins=True, Model sourceModel=None, origcopy=False, globalcopy=True, enablepricing=False, createscip=True, threadsafe=False):
1014 :param problemName: name of the problem (default 'model')
1015 :param defaultPlugins: use default plugins? (default True)
1016 :param sourceModel: create a copy of the given Model instance (default None)
1017 :param origcopy: whether to call copy or copyOrig (default False)
1018 :param globalcopy: whether to create a global or a local copy (default True)
1019 :param enablepricing: whether to enable pricing in copy (default False)
1020 :param createscip: initialize the Model object and creates a SCIP instance
1021 :param threadsafe: False if data can be safely shared between the source and target problem
1024 raise Exception(
"linked SCIP is not compatible to this version of PySCIPOpt - use at least version", MAJOR)
1025 if self.
version() < MAJOR + MINOR/10.0 + PATCH/100.0:
1026 warnings.warn(
"linked SCIP {} is not recommended for this version of PySCIPOpt - use version {}.{}.{}".format(self.
version(), MAJOR, MINOR, PATCH))
1036 elif sourceModel
is None:
1044 self.
_bestSol = <Solution> sourceModel._bestSol
1047 PY_SCIP_CALL(
SCIPcopyOrig(sourceModel._scip, self.
_scip, NULL, NULL, n, enablepricing, threadsafe,
True, self._valid))
1049 PY_SCIP_CALL(
SCIPcopy(sourceModel._scip, self.
_scip, NULL, NULL, n, globalcopy, enablepricing, threadsafe,
True, self._valid))
1058 return hash(<size_t>self.
_scip)
1061 return (self.
__class__ == other.__class__
1062 and self.
_scip == (<Model>other)._scip)
1065 cdef create(SCIP* scip):
1066 """Creates a model and appropriately assigns the scip and bestsol parameters
1069 raise Warning(
"cannot create Model with SCIP* == NULL")
1076 def _freescip(self):
1077 """Return whether the underlying Scip pointer gets deallocted when the current
1083 def _freescip(self, val):
1084 """Set whether the underlying Scip pointer gets deallocted when the current
1089 @cython.always_allow_keywords(
True)
1092 """Create a Model from a given pointer.
1094 :param cpasule: The PyCapsule containing the SCIP pointer under the name "scip".
1095 :param take_ownership: Whether the newly created Model assumes ownership of the
1096 underlying Scip pointer (see `_freescip`).
1098 if not PyCapsule_IsValid(capsule,
"scip"):
1099 raise ValueError(
"The given capsule does not contain a valid scip pointer")
1100 model = Model.create(<SCIP*>PyCapsule_GetPointer(capsule,
"scip"))
1101 model._freescip = take_ownership
1104 @cython.always_allow_keywords(
True)
1106 """Return the underlying Scip pointer to the current Model.
1108 :param give_ownership: Whether the current Model gives away ownership of the
1109 underlying Scip pointer (see `_freescip`).
1110 :return capsule: The underlying pointer to the current Model, wrapped in a
1111 PyCapsule under the name "scip".
1113 capsule = PyCapsule_New(<void*>self.
_scip,
"scip", NULL)
1119 """Includes all default plug-ins into SCIP"""
1120 PY_SCIP_CALL(SCIPincludeDefaultPlugins(self.
_scip))
1123 """Create new problem instance with given name
1125 :param problemName: name of model or problem (Default value = 'model')
1132 """Frees problem and solution process data"""
1136 """Frees all solution process data including presolving and transformed problem, only original problem is kept"""
1140 if value.isOriginal()
1145 """Retrieve SCIP version"""
1149 """Print version, copyright information and compile mode"""
1150 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
1151 locale.setlocale(locale.LC_NUMERIC,
"C")
1155 locale.setlocale(locale.LC_NUMERIC,user_locale)
1158 """Print external code versions, e.g. symmetry, non-linear solver, lp solver"""
1159 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
1160 locale.setlocale(locale.LC_NUMERIC,
"C")
1164 locale.setlocale(locale.LC_NUMERIC,user_locale)
1167 """Retrieve problem name"""
1171 """Retrieve the current total SCIP time in seconds, i.e. the total time since the SCIP instance has been created"""
1175 """Retrieve the current solving time in seconds"""
1179 """Retrieve the current reading time in seconds"""
1183 """Retrieve the curernt presolving time in seconds"""
1187 """Retrieve the total number of LP iterations so far."""
1191 """gets number of processed nodes in current run, including the focus node."""
1195 """gets number of processed nodes in all runs, including the focus node."""
1199 """Retrieve number of leaf nodes processed with feasible relaxation solution."""
1203 """gets number of infeasible leaf nodes processed."""
1207 """gets number of leaves in the tree."""
1211 """gets number of children of focus node."""
1215 """gets number of siblings of focus node."""
1219 """Retrieve current node."""
1223 """Retrieve the gap, i.e. |(primalbound - dualbound)/min(|primalbound|,|dualbound|)|."""
1227 """Retrieve the depth of the current node"""
1231 """Retrieve SCIP's infinity value"""
1235 """Retrieve epsilon for e.g. equality checks"""
1239 """Retrieve feasibility tolerance"""
1243 """returns fractional part of value, i.e. x - floor(x) in feasible tolerance: x - floor(x+feastol)"""
1247 """returns fractional part of value, i.e. x - floor(x) in epsilon tolerance: x - floor(x+eps)"""
1251 """returns whether abs(value) < eps"""
1255 """returns whether abs(value) < feastol"""
1259 """returns whether value is SCIP's infinity"""
1263 """returns whether value < -feastol"""
1267 """returns whether value is integral within the LP feasibility bounds"""
1271 """checks, if values are in range of epsilon"""
1275 """checks, if relative difference of values is in range of feasibility tolerance"""
1279 """returns whether val1 <= val2 + eps"""
1283 """returns whether val1 < val2 - eps"""
1287 """returns whether val1 >= val2 - eps"""
1291 """returns whether val1 > val2 + eps"""
1295 """Get the current LP's condition number
1297 :param exact: whether to get an estimate or the exact value (Default value = False)
1302 cdef SCIP_Real quality = 0
1311 """include specific heuristics and branching rules for reoptimization"""
1315 """Get the iteration count of the last solved LP"""
1325 """Set the objective sense to minimization."""
1329 """Set the objective sense to maximization."""
1333 """Set a limit on the objective function.
1334 Only solutions with objective value better than this limit are accepted.
1336 :param objlimit: limit on the objective function
1342 """returns current limit on objective function."""
1346 """Establish the objective function as a linear expression.
1348 :param expr: the objective function SCIP Expr, or constant value
1349 :param sense: the objective sense (Default value = 'minimize')
1350 :param clear: set all other variables objective coefficient to zero (Default value = 'true')
1354 cdef SCIP_VAR** _vars
1358 if not isinstance(expr, Expr):
1359 assert(_is_number(expr)),
"given coefficients are neither Expr or number but %s" % expr.__class__.__name__
1360 expr = Expr() + expr
1362 if expr.degree() > 1:
1363 raise ValueError(
"SCIP does not support nonlinear objective functions. Consider using set_nonlinear_objective in the pyscipopt.recipe.nonlinear")
1370 for i
in range(_nvars):
1373 if expr[CONST] != 0.0:
1376 for term, coef
in expr.terms.items():
1379 assert len(term) == 1
1380 var = <Variable>term[0]
1383 if sense ==
"minimize":
1385 elif sense ==
"maximize":
1388 raise Warning(
"unrecognized optimization sense: %s" % sense)
1391 """Retrieve objective function as Expr"""
1394 for var
in variables:
1395 coeff = var.getObj()
1397 objective += coeff * var
1398 objective.normalize()
1402 """Add constant offset to objective
1404 :param offset: offset to add
1405 :param solutions: add offset also to existing solutions (Default value = False)
1414 """Retrieve constant objective offset
1416 :param original: offset of original or transformed problem (Default value = True)
1425 """informs SCIP that the objective value is always integral in every feasible solution
1426 Note: This function should be used to inform SCIP that the objective function is integral, helping to improve the
1427 performance. This is useful when using column generation. If no column generation (pricing) is used, SCIP
1428 automatically detects whether the objective function is integral or can be scaled to be integral. However, in
1429 any case, the user has to make sure that no variable is added during the solving process that destroys this
1435 """gets estimate of best primal solution w.r.t. original or transformed problem contained in current subtree
1437 :param original: estimate of original or transformed problem (Default value = False)
1446 """Set presolving parameter settings.
1448 :param setting: the parameter settings (SCIP_PARAMSETTING)
1454 """Set problem name"""
1459 """Set separating parameter settings.
1461 :param setting: the parameter settings (SCIP_PARAMSETTING)
1467 """Set heuristics parameter settings.
1469 :param setting: the parameter setting (SCIP_PARAMSETTING)
1475 """Disables propagation in SCIP to avoid modifying the original problem during transformation.
1477 :param onlyroot: use propagation when root processing is finished (Default value = False)
1484 def writeProblem(self, filename='model.cip', trans=False, genericnames=False, verbose=True):
1485 """Write current model/problem to a file.
1487 :param filename: the name of the file to be used (Default value = 'model.cip'). Should have an extension corresponding to one of the readable file formats, described in https://www.scipopt.org/doc/html/group__FILEREADERS.php.
1488 :param trans: indicates whether the transformed problem is written to file (Default value = False)
1489 :param genericnames: indicates whether the problem should be written with generic variable and constraint names (Default value = False)
1490 :param verbose: indicates whether a success message should be printed
1492 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
1493 locale.setlocale(locale.LC_NUMERIC,
"C")
1495 str_absfile = abspath(filename)
1497 fn, ext = splitext(absfile)
1510 print(
'wrote problem to file ' + str_absfile)
1512 locale.setlocale(locale.LC_NUMERIC,user_locale)
1516 def addVar(self, name='', vtype='C', lb=0.0, ub=None, obj=0.0, pricedVar=False, pricedVarScore=1.0):
1517 """Create a new variable. Default variable is non-negative and continuous.
1519 :param name: name of the variable, generic if empty (Default value = '')
1520 :param vtype: type of the variable: 'C' continuous, 'I' integer, 'B' binary, and 'M' implicit integer
1521 (see https://www.scipopt.org/doc/html/FAQ.php#implicitinteger) (Default value = 'C')
1522 :param lb: lower bound of the variable, use None for -infinity (Default value = 0.0)
1523 :param ub: upper bound of the variable, use None for +infinity (Default value = None)
1524 :param obj: objective value of variable (Default value = 0.0)
1525 :param pricedVar: is the variable a pricing candidate? (Default value = False)
1526 :param pricedVarScore: score of variable in case it is priced, the higher the better (Default value = 1.0)
1529 cdef SCIP_VAR* scip_var
1542 vtype = vtype.upper()
1543 if vtype
in [
'C',
'CONTINUOUS']:
1545 elif vtype
in [
'B',
'BINARY']:
1551 elif vtype
in [
'I',
'INTEGER']:
1553 elif vtype
in [
'M',
'IMPLINT']:
1556 raise Warning(
"unrecognized variable type")
1563 pyVar = Variable.create(scip_var)
1575 """Retrieve the transformed variable.
1577 :param Variable var: original variable to get the transformed of
1580 cdef SCIP_VAR* _tvar
1583 return Variable.create(_tvar)
1586 """adds given values to lock numbers of variable for rounding
1588 :param Variable var: variable to adjust the locks for
1589 :param nlocksdown: new number of down locks
1590 :param nlocksup: new number of up locks
1596 """Fixes the variable var to the value val if possible.
1598 :param Variable var: variable to fix
1599 :param val: float, the fix value
1600 :return: tuple (infeasible, fixed) of booleans
1603 cdef SCIP_Bool infeasible
1604 cdef SCIP_Bool fixed
1605 PY_SCIP_CALL(
SCIPfixVar(self.
_scip, var.scip_var, val, &infeasible, &fixed))
1606 return infeasible, fixed
1609 """Delete a variable.
1611 :param var: the variable which shall be deleted
1612 :return: bool, was deleting succesful
1615 cdef SCIP_Bool deleted
1622 """Tighten the lower bound in preprocessing or current node, if the bound is tighter.
1624 :param var: SCIP variable
1625 :param lb: possible new lower bound
1626 :param force: force tightening even if below bound strengthening tolerance
1627 :return: tuple of bools, (infeasible, tightened)
1628 infeasible: whether new domain is empty
1629 tightened: whether the bound was tightened
1632 cdef SCIP_Bool infeasible
1633 cdef SCIP_Bool tightened
1635 return infeasible, tightened
1638 """Tighten the upper bound in preprocessing or current node, if the bound is tighter.
1640 :param var: SCIP variable
1641 :param ub: possible new upper bound
1642 :param force: force tightening even if below bound strengthening tolerance
1643 :return: tuple of bools, (infeasible, tightened)
1644 infeasible: whether new domain is empty
1645 tightened: whether the bound was tightened
1648 cdef SCIP_Bool infeasible
1649 cdef SCIP_Bool tightened
1651 return infeasible, tightened
1654 """Tighten the global upper bound, if the bound is tighter.
1656 :param var: SCIP variable
1657 :param ub: possible new upper bound
1658 :param force: force tightening even if below bound strengthening tolerance
1659 :return: tuple of bools, (infeasible, tightened)
1660 infeasible: whether new domain is empty
1661 tightened: whether the bound was tightened
1664 cdef SCIP_Bool infeasible
1665 cdef SCIP_Bool tightened
1667 return infeasible, tightened
1670 """Tighten the global upper bound, if the bound is tighter.
1672 :param var: SCIP variable
1673 :param lb: possible new upper bound
1674 :param force: force tightening even if below bound strengthening tolerance
1675 :return: tuple of bools, (infeasible, tightened)
1676 infeasible: whether new domain is empty
1677 tightened: whether the bound was tightened
1680 cdef SCIP_Bool infeasible
1681 cdef SCIP_Bool tightened
1683 return infeasible, tightened
1686 """Changes the lower bound of the specified variable.
1688 :param Variable var: variable to change bound of
1689 :param lb: new lower bound (set to None for -infinity)
1697 """Changes the upper bound of the specified variable.
1699 :param Variable var: variable to change bound of
1700 :param ub: new upper bound (set to None for +infinity)
1708 """Changes the global lower bound of the specified variable.
1710 :param Variable var: variable to change bound of
1711 :param lb: new lower bound (set to None for -infinity)
1719 """Changes the global upper bound of the specified variable.
1721 :param Variable var: variable to change bound of
1722 :param ub: new upper bound (set to None for +infinity)
1730 """Changes the lower bound of the specified variable at the given node.
1732 :param Variable var: variable to change bound of
1733 :param lb: new lower bound (set to None for -infinity)
1741 """Changes the upper bound of the specified variable at the given node.
1743 :param Variable var: variable to change bound of
1744 :param ub: new upper bound (set to None for +infinity)
1752 """Changes the type of a variable
1754 :param Variable var: variable to change type of
1755 :param vtype: new variable type
1758 cdef SCIP_Bool infeasible
1759 if vtype
in [
'C',
'CONTINUOUS']:
1760 PY_SCIP_CALL(
SCIPchgVarType(self.
_scip, var.scip_var, SCIP_VARTYPE_CONTINUOUS, &infeasible))
1761 elif vtype
in [
'B',
'BINARY']:
1763 elif vtype
in [
'I',
'INTEGER']:
1765 elif vtype
in [
'M',
'IMPLINT']:
1768 raise Warning(
"unrecognized variable type")
1770 print(
'could not change variable type of variable %s' % var)
1773 """Retrieve all variables.
1775 :param transformed: get transformed variables instead of original (Default value = False)
1778 cdef SCIP_VAR** _vars
1790 for i
in range(_nvars):
1791 ptr = <size_t>(_vars[i])
1798 var = Variable.create(_vars[i])
1799 assert var.ptr() == ptr
1806 """Retrieve number of variables in the problems.
1808 :param transformed: get transformed variables instead of original (Default value = True)
1816 """gets number of integer active problem variables"""
1820 """gets number of binary active problem variables"""
1824 """gets dictionary with variables names as keys and current variable values as items"""
1827 var_dict[var.name] = self.
getVal(var)
1831 """if given value is larger than the node's lower bound (in transformed problem),
1832 sets the node's lower bound to the new value
1834 :param node: Node, the node to update
1835 :param newbound: float, new bound (if greater) for the node
1841 """Relaxes the integrality restrictions of the model"""
1842 if self.
getStage() != SCIP_STAGE_PROBLEM:
1843 raise Warning(
"method can only be called in stage PROBLEM")
1850 """gets the best child of the focus node w.r.t. the node selection strategy."""
1854 """gets the best sibling of the focus node w.r.t. the node selection strategy."""
1858 """gets the best leaf from the node queue w.r.t. the node selection strategy."""
1862 """gets the best node from the tree (child, sibling, or leaf) w.r.t. the node selection strategy."""
1866 """gets the node with smallest lower bound from the tree (child, sibling, or leaf)."""
1870 """access to all data of open nodes (leaves, children, and siblings)
1872 :return: three lists containing open leaves, children, siblings
1874 cdef SCIP_NODE** _leaves
1875 cdef SCIP_NODE** _children
1876 cdef SCIP_NODE** _siblings
1883 leaves = [Node.create(_leaves[i])
for i
in range(_nleaves)]
1884 children = [Node.create(_children[i])
for i
in range(_nchildren)]
1885 siblings = [Node.create(_siblings[i])
for i
in range(_nsiblings)]
1887 return leaves, children, siblings
1890 """marks the given node to be propagated again the next time a node of its subtree is processed"""
1896 """Gets solution status of current LP"""
1901 """makes sure that the LP of the current node is loaded and
1902 may be accessed through the LP information methods
1904 :return: bool cutoff, i.e. can the node be cut off?
1907 cdef SCIP_Bool cutoff
1912 """gets objective value of current LP (which is the sum of column and loose objective value)"""
1917 """Retrieve current LP columns"""
1918 cdef SCIP_COL** cols
1922 return [Column.create(cols[i])
for i
in range(ncols)]
1925 """Retrieve current LP rows"""
1926 cdef SCIP_ROW** rows
1930 return [Row.create(rows[i])
for i
in range(nrows)]
1933 """Retrieve the number of rows currently in the LP"""
1937 """Retrieve the number of cols currently in the LP"""
1941 """Gets all indices of basic columns and rows: index i >= 0 corresponds to column i, index i < 0 to row -i-1"""
1943 cdef int* inds = <int *> malloc(nrows * sizeof(int))
1946 result = [inds[i]
for i
in range(nrows)]
1951 """gets a row from the inverse basis matrix B^-1"""
1954 cdef SCIP_Real* coefs = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
1957 result = [coefs[i]
for i
in range(nrows)]
1962 """gets a row from B^-1 * A"""
1965 cdef SCIP_Real* coefs = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
1968 result = [coefs[i]
for i
in range(ncols)]
1973 """returns whether the current LP solution is basic, i.e. is defined by a valid simplex basis"""
1977 """checks if all columns, i.e. every variable with non-empty column is present in the LP.
1978 This is not True when performing pricing for instance."""
1984 """gets the reduced cost of the column in the current LP
1986 :param Column col: the column of the LP for which the reduced cost will be retrieved
1992 def createEmptyRowSepa(self, Sepa sepa, name="row", lhs = 0.0, rhs = None, local = True, modifiable = False, removable = True):
1993 """creates and captures an LP row without any coefficients from a separator
1995 :param sepa: separator that creates the row
1996 :param name: name of row (Default value = "row")
1997 :param lhs: left hand side of row (Default value = 0)
1998 :param rhs: right hand side of row (Default value = None)
1999 :param local: is row only valid locally? (Default value = True)
2000 :param modifiable: is row modifiable during node processing (subject to column generation)? (Default value = False)
2001 :param removable: should the row be removed from the LP due to aging or cleanup? (Default value = True)
2008 PyRow = Row.create(row)
2011 def createEmptyRowUnspec(self, name="row", lhs = 0.0, rhs = None, local = True, modifiable = False, removable = True):
2012 """creates and captures an LP row without any coefficients from an unspecified source
2014 :param name: name of row (Default value = "row")
2015 :param lhs: left hand side of row (Default value = 0)
2016 :param rhs: right hand side of row (Default value = None)
2017 :param local: is row only valid locally? (Default value = True)
2018 :param modifiable: is row modifiable during node processing (subject to column generation)? (Default value = False)
2019 :param removable: should the row be removed from the LP due to aging or cleanup? (Default value = True)
2025 PyRow = Row.create(row)
2029 """returns the activity of a row in the last LP or pseudo solution"""
2033 """returns the activity of a row in the last LP solution"""
2038 """decreases usage counter of LP row, and frees memory if necessary"""
2042 """informs row, that all subsequent additions of variables to the row should be cached and not directly applied;
2043 after all additions were applied, flushRowExtensions() must be called;
2044 while the caching of row extensions is activated, information methods of the row give invalid results;
2045 caching should be used, if a row is build with addVarToRow() calls variable by variable to increase the performance"""
2049 """flushes all cached row extensions after a call of cacheRowExtensions() and merges coefficients with equal columns into a single coefficient"""
2052 def addVarToRow(self, Row row not None, Variable var not None, value):
2053 """resolves variable to columns and adds them with the coefficient to the row"""
2061 """Returns number of intergal columns in the row"""
2065 """Returns 1 if the row is parallel, and 0 if orthogonal"""
2069 """Returns the degree of parallelism between hyplerplanes. 1 if perfectly parallel, 0 if orthogonal.
2070 For two row vectors v, w the parallelism is calculated as: |v*w|/(|v|*|w|).
2071 101 in this case is an 'e' (euclidean) in ASCII. The other acceptable input is 100 (d for discrete)."""
2075 """Gets the dual LP solution of a row"""
2080 """if not already existing, adds row to global cut pool"""
2084 """returns efficacy of the cut with respect to the given primal solution or the current LP solution: e = -feasibility/norm"""
2088 """ returns whether the cut's efficacy with respect to the given primal solution or the current LP solution is greater than the minimal cut efficacy"""
2092 """ returns row's cutoff distance in the direction of the given primal solution"""
2095 def addCut(self, Row cut not None, forcecut = False):
2096 """adds cut to separation storage and returns whether cut has been detected to be infeasible for local bounds"""
2097 cdef SCIP_Bool infeasible
2098 PY_SCIP_CALL(
SCIPaddRow(self.
_scip, cut.scip_row, forcecut, &infeasible))
2102 """Retrieve total number of cuts in storage"""
2106 """Retrieve number of currently applied cuts"""
2110 """Retrieve the number of separation rounds that have been performed
2111 at the current node"""
2114 def separateSol(self, Solution sol = None, pretendroot = False, allowlocal = True, onlydelayed = False):
2115 """separates the given primal solution or the current LP solution by calling the separators and constraint handlers'
2117 the generated cuts are stored in the separation storage and can be accessed with the methods SCIPgetCuts() and
2119 after evaluating the cuts, you have to call SCIPclearCuts() in order to remove the cuts from the
2121 it is possible to call SCIPseparateSol() multiple times with different solutions and evaluate the found cuts
2123 :param Solution sol: solution to separate, None to use current lp solution (Default value = None)
2124 :param pretendroot: should the cut separators be called as if we are at the root node? (Default value = "False")
2125 :param allowlocal: should the separator be asked to separate local cuts (Default value = True)
2126 :param onlydelayed: should only separators be called that were delayed in the previous round? (Default value = False)
2128 delayed -- whether a separator was delayed
2129 cutoff -- whether the node can be cut off
2131 cdef SCIP_Bool delayed
2132 cdef SCIP_Bool cutoff
2134 PY_SCIP_CALL(
SCIPseparateSol(self.
_scip, NULL
if sol
is None else sol.sol, pretendroot, allowlocal, onlydelayed, &delayed, &cutoff) )
2135 return delayed, cutoff
2137 def _createConsLinear(self, ExprCons lincons, **kwargs):
2138 assert isinstance(lincons, ExprCons),
"given constraint is not ExprCons but %s" % lincons.__class__.__name__
2140 assert lincons.expr.degree() <= 1,
"given constraint is not linear, degree == %d" % lincons.expr.degree()
2141 terms = lincons.expr.terms
2143 cdef SCIP_CONS* scip_cons
2145 cdef int nvars = len(terms.items())
2147 vars_array = <SCIP_VAR**> malloc(nvars * sizeof(SCIP_VAR*))
2148 coeffs_array = <SCIP_Real*> malloc(nvars * sizeof(SCIP_Real))
2150 for i, (key, coeff)
in enumerate(terms.items()):
2151 vars_array[i] = <SCIP_VAR*>(<Variable>key[0]).scip_var
2152 coeffs_array[i] = <SCIP_Real>coeff
2156 kwargs[
'lhs'], kwargs[
'rhs'], kwargs[
'initial'],
2157 kwargs[
'separate'], kwargs[
'enforce'], kwargs[
'check'],
2158 kwargs[
'propagate'], kwargs[
'local'], kwargs[
'modifiable'],
2159 kwargs[
'dynamic'], kwargs[
'removable'], kwargs[
'stickingatnode']))
2161 PyCons = Constraint.create(scip_cons)
2167 def _createConsQuadratic(self, ExprCons quadcons, **kwargs):
2168 terms = quadcons.expr.terms
2169 assert quadcons.expr.degree() <= 2,
"given constraint is not quadratic, degree == %d" % quadcons.expr.degree()
2171 cdef SCIP_CONS* scip_cons
2172 cdef SCIP_EXPR* prodexpr
2176 0, NULL, NULL, NULL,
2177 kwargs[
'lhs'], kwargs[
'rhs'],
2178 kwargs[
'initial'], kwargs[
'separate'], kwargs[
'enforce'],
2179 kwargs[
'check'], kwargs[
'propagate'], kwargs[
'local'],
2180 kwargs[
'modifiable'], kwargs[
'dynamic'], kwargs[
'removable']))
2182 for v, c
in terms.items():
2184 var = <Variable>v[0]
2187 assert len(v) == 2,
'term length must be 1 or 2 but it is %s' % len(v)
2189 varexprs = <SCIP_EXPR**> malloc(2 * sizeof(SCIP_EXPR*))
2190 var1, var2 = <Variable>v[0], <Variable>v[1]
2202 PyCons = Constraint.create(scip_cons)
2206 def _createConsNonlinear(self, cons, **kwargs):
2207 cdef SCIP_EXPR* expr
2208 cdef SCIP_EXPR** varexprs
2209 cdef SCIP_EXPR** monomials
2211 cdef SCIP_CONS* scip_cons
2213 terms = cons.expr.terms
2216 variables = {var.ptr():var
for term
in terms
for var
in term}
2217 variables = list(variables.values())
2218 varindex = {var.ptr():idx
for (idx,var)
in enumerate(variables)}
2221 monomials = <SCIP_EXPR**> malloc(len(terms) * sizeof(SCIP_EXPR*))
2222 termcoefs = <SCIP_Real*> malloc(len(terms) * sizeof(SCIP_Real))
2223 for i, (term, coef)
in enumerate(terms.items()):
2224 termvars = <SCIP_VAR**> malloc(len(term) * sizeof(SCIP_VAR*))
2225 for j, var
in enumerate(term):
2226 termvars[j] = (<Variable>var).scip_var
2228 termcoefs[i] = <SCIP_Real>coef
2232 PY_SCIP_CALL(
SCIPcreateExprSum(self.
_scip, &expr, <int>len(terms), monomials, termcoefs, 0.0, NULL, NULL))
2246 kwargs[
'propagate'],
2248 kwargs[
'modifiable'],
2250 kwargs[
'removable']) )
2252 PyCons = Constraint.create(scip_cons)
2255 for i
in range(<int>len(terms)):
2261 def _createConsGenNonlinear(self, cons, **kwargs):
2262 cdef SCIP_EXPR** childrenexpr
2263 cdef SCIP_EXPR** scipexprs
2264 cdef SCIP_CONS* scip_cons
2281 if node[0] == Operator.varidx:
2283 vars = <SCIP_VAR**> malloc(nvars * sizeof(SCIP_VAR*))
2286 scipexprs = <SCIP_EXPR**> malloc(len(nodes) * sizeof(SCIP_EXPR*))
2287 for i,node
in enumerate(nodes):
2289 if opidx == Operator.varidx:
2290 assert len(node[1]) == 1
2293 vars[varpos] = (<Variable>pyvar).scip_var
2296 if opidx == Operator.const:
2297 assert len(node[1]) == 1
2301 if opidx == Operator.add:
2302 nchildren = len(node[1])
2303 childrenexpr = <SCIP_EXPR**> malloc(nchildren * sizeof(SCIP_EXPR*))
2304 coefs = <SCIP_Real*> malloc(nchildren * sizeof(SCIP_Real))
2305 for c, pos
in enumerate(node[1]):
2306 childrenexpr[c] = scipexprs[pos]
2308 PY_SCIP_CALL(
SCIPcreateExprSum(self.
_scip, &scipexprs[i], nchildren, childrenexpr, coefs, 0, NULL, NULL))
2312 if opidx == Operator.prod:
2313 nchildren = len(node[1])
2314 childrenexpr = <SCIP_EXPR**> malloc(nchildren * sizeof(SCIP_EXPR*))
2315 for c, pos
in enumerate(node[1]):
2316 childrenexpr[c] = scipexprs[pos]
2320 if opidx == Operator.power:
2322 valuenode = nodes[node[1][1]]
2323 assert valuenode[0] == Operator.const
2324 exponent = valuenode[1][0]
2325 PY_SCIP_CALL(
SCIPcreateExprPow(self.
_scip, &scipexprs[i], scipexprs[node[1][0]], <SCIP_Real>exponent, NULL, NULL ))
2327 if opidx == Operator.exp:
2328 assert len(node[1]) == 1
2331 if opidx == Operator.log:
2332 assert len(node[1]) == 1
2335 if opidx == Operator.sqrt:
2336 assert len(node[1]) == 1
2337 PY_SCIP_CALL(
SCIPcreateExprPow(self.
_scip, &scipexprs[i], scipexprs[node[1][0]], <SCIP_Real>0.5, NULL, NULL) )
2339 if opidx == Operator.sin:
2340 assert len(node[1]) == 1
2343 if opidx == Operator.cos:
2344 assert len(node[1]) == 1
2347 if opidx == Operator.fabs:
2348 assert len(node[1]) == 1
2352 raise NotImplementedError
2353 assert varpos == nvars
2360 scipexprs[len(nodes) - 1],
2367 kwargs[
'propagate'],
2369 kwargs[
'modifiable'],
2371 kwargs[
'removable']) )
2372 PyCons = Constraint.create(scip_cons)
2373 for i
in range(len(nodes)):
2383 enforce=True, check=True, propagate=True, local=False,
2384 modifiable=False, dynamic=False, removable=False,
2385 stickingatnode=False):
2386 """Create a linear or nonlinear constraint without adding it to the SCIP problem. This is useful for creating disjunction constraints
2387 without also enforcing the individual constituents. Currently, this can only be used as an argument to `.addConsElemDisjunction`. To add
2388 an individual linear/nonlinear constraint, prefer `.addCons()`.
2390 :param cons: constraint object
2391 :param name: the name of the constraint, generic name if empty (Default value = '')
2392 :param initial: should the LP relaxation of constraint be in the initial LP? (Default value = True)
2393 :param separate: should the constraint be separated during LP processing? (Default value = True)
2394 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2395 :param check: should the constraint be checked for feasibility? (Default value = True)
2396 :param propagate: should the constraint be propagated during node processing? (Default value = True)
2397 :param local: is the constraint only valid locally? (Default value = False)
2398 :param modifiable: is the constraint modifiable (subject to column generation)? (Default value = False)
2399 :param dynamic: is the constraint subject to aging? (Default value = False)
2400 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2401 :param stickingatnode: should the constraint always be kept at the node where it was added, even if it may be moved to a more global node? (Default value = False)
2402 :return The created @ref scip#Constraint "Constraint" object.
2408 kwargs = dict(name=name, initial=initial, separate=separate,
2409 enforce=enforce, check=check,
2410 propagate=propagate, local=local,
2411 modifiable=modifiable, dynamic=dynamic,
2412 removable=removable,
2413 stickingatnode=stickingatnode)
2417 deg = cons.expr.degree()
2422 elif deg == float(
'inf'):
2428 def addCons(self, cons, name='', initial=True, separate=True,
2429 enforce=True, check=True, propagate=True, local=False,
2430 modifiable=False, dynamic=False, removable=False,
2431 stickingatnode=False):
2432 """Add a linear or nonlinear constraint.
2434 :param cons: constraint object
2435 :param name: the name of the constraint, generic name if empty (Default value = '')
2436 :param initial: should the LP relaxation of constraint be in the initial LP? (Default value = True)
2437 :param separate: should the constraint be separated during LP processing? (Default value = True)
2438 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2439 :param check: should the constraint be checked for feasibility? (Default value = True)
2440 :param propagate: should the constraint be propagated during node processing? (Default value = True)
2441 :param local: is the constraint only valid locally? (Default value = False)
2442 :param modifiable: is the constraint modifiable (subject to column generation)? (Default value = False)
2443 :param dynamic: is the constraint subject to aging? (Default value = False)
2444 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2445 :param stickingatnode: should the constraint always be kept at the node where it was added, even if it may be moved to a more global node? (Default value = False)
2446 :return The added @ref scip#Constraint "Constraint" object.
2449 assert isinstance(cons, ExprCons),
"given constraint is not ExprCons but %s" % cons.__class__.__name__
2451 cdef SCIP_CONS* scip_cons
2453 kwargs = dict(name=name, initial=initial, separate=separate,
2454 enforce=enforce, check=check,
2455 propagate=propagate, local=local,
2456 modifiable=modifiable, dynamic=dynamic,
2457 removable=removable,
2458 stickingatnode=stickingatnode)
2464 scip_cons = (<Constraint>pycons_initial).scip_cons
2467 pycons = Constraint.create(scip_cons)
2472 def addConss(self, conss, name='', initial=True, separate=True,
2473 enforce=True, check=True, propagate=True, local=False,
2474 modifiable=False, dynamic=False, removable=False,
2475 stickingatnode=False):
2476 """Adds multiple linear or quadratic constraints.
2478 Each of the constraints is added to the model using Model.addCons().
2480 For all parameters, except @p conss, this method behaves differently depending on the type of the passed argument:
2481 1. If the value is iterable, it must be of the same length as @p conss. For each constraint, Model.addCons() will be called with the value at the corresponding index.
2482 2. Else, the (default) value will be applied to all of the constraints.
2484 :param conss An iterable of constraint objects. Any iterable will be converted into a list before further processing.
2485 :param name: the names of the constraints, generic name if empty (Default value = ''). If a single string is passed, it will be suffixed by an underscore and the enumerated index of the constraint (starting with 0).
2486 :param initial: should the LP relaxation of constraints be in the initial LP? (Default value = True)
2487 :param separate: should the constraints be separated during LP processing? (Default value = True)
2488 :param enforce: should the constraints be enforced during node processing? (Default value = True)
2489 :param check: should the constraints be checked for feasibility? (Default value = True)
2490 :param propagate: should the constraints be propagated during node processing? (Default value = True)
2491 :param local: are the constraints only valid locally? (Default value = False)
2492 :param modifiable: are the constraints modifiable (subject to column generation)? (Default value = False)
2493 :param dynamic: are the constraints subject to aging? (Default value = False)
2494 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2495 :param stickingatnode: should the constraints always be kept at the node where it was added, even if it may be @oved to a more global node? (Default value = False)
2496 :return A list of added @ref scip#Constraint "Constraint" objects.
2500 def ensure_iterable(elem, length):
2501 if isinstance(elem, Iterable):
2504 return list(repeat(elem, length))
2506 assert isinstance(conss, Iterable),
"Given constraint list is not iterable."
2509 n_conss = len(conss)
2511 if isinstance(name, str):
2513 name = [
"" for idx
in range(n_conss)]
2515 name = [
"%s_%s" % (name, idx)
for idx
in range(n_conss)]
2516 initial = ensure_iterable(initial, n_conss)
2517 separate = ensure_iterable(separate, n_conss)
2518 enforce = ensure_iterable(enforce, n_conss)
2519 check = ensure_iterable(check, n_conss)
2520 propagate = ensure_iterable(propagate, n_conss)
2521 local = ensure_iterable(local, n_conss)
2522 modifiable = ensure_iterable(modifiable, n_conss)
2523 dynamic = ensure_iterable(dynamic, n_conss)
2524 removable = ensure_iterable(removable, n_conss)
2525 stickingatnode = ensure_iterable(stickingatnode, n_conss)
2528 for i, cons
in enumerate(conss):
2530 self.
addCons(cons, name[i], initial[i], separate[i], enforce[i],
2531 check[i], propagate[i], local[i], modifiable[i],
2532 dynamic[i], removable[i], stickingatnode[i])
2538 relaxcons = None, enforce=True, check =True,
2539 local=False, modifiable = False, dynamic = False):
2540 """Add a disjunction constraint.
2542 :param Iterable[Constraint] conss: An iterable of constraint objects to be included initially in the disjunction. Currently, these must be expressions.
2543 :param name: the name of the disjunction constraint.
2544 :param initial: should the LP relaxation of disjunction constraint be in the initial LP? (Default value = True)
2545 :param relaxcons: a conjunction constraint containing the linear relaxation of the disjunction constraint, or None. (Default value = None)
2546 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2547 :param check: should the constraint be checked for feasibility? (Default value = True)
2548 :param local: is the constraint only valid locally? (Default value = False)
2549 :param modifiable: is the constraint modifiable (subject to column generation)? (Default value = False)
2550 :param dynamic: is the constraint subject to aging? (Default value = False)
2551 :return The added @ref scip#Constraint "Constraint" object.
2553 def ensure_iterable(elem, length):
2554 if isinstance(elem, Iterable):
2557 return list(repeat(elem, length))
2558 assert isinstance(conss, Iterable),
"Given constraint list is not iterable"
2561 n_conss = len(conss)
2563 cdef SCIP_CONS* disj_cons
2565 cdef SCIP_CONS* scip_cons
2567 cdef SCIP_EXPR* scip_expr
2571 initial, enforce, check, local, modifiable, dynamic
2576 for i, cons
in enumerate(conss):
2578 enforce=enforce, check=check,
2579 local=local, modifiable=modifiable, dynamic=dynamic
2584 PyCons = Constraint.create(disj_cons)
2589 """Appends a constraint to a disjunction.
2591 :param Constraint disj_cons: the disjunction constraint to append to.
2592 :param Constraint cons: the Constraint to append
2593 :return The disjunction constraint with added @ref scip#Constraint object.
2601 Gets number of variables in a constraint.
2603 :param constraint: Constraint to get the number of variables from.
2606 cdef SCIP_Bool success
2613 raise TypeError(
"The constraint handler %s does not have this functionality." % conshdrlname)
2619 Gets variables in a constraint.
2621 :param constraint: Constraint to get the variables from.
2623 cdef SCIP_Bool success
2628 cdef SCIP_VAR** _vars = <SCIP_VAR**> malloc(_nvars * sizeof(SCIP_VAR*))
2632 for i
in range(_nvars):
2633 ptr = <size_t>(_vars[i])
2639 var = Variable.create(_vars[i])
2640 assert var.ptr() == ptr
2649 from typing
import Union
2652 Add coef*expr to nonlinear constraint.
2654 assert self.
getStage() == 1,
"addExprNonlinear cannot be called in stage %i." % self.
getStage()
2655 assert cons.isNonlinear(),
"addExprNonlinear can only be called with nonlinear constraints."
2657 cdef Constraint temp_cons
2658 cdef SCIP_EXPR* scip_expr
2660 temp_cons = self.
addCons(expr <= 0)
2667 """Add coefficient to the linear constraint (if non-zero).
2669 :param Constraint cons: constraint to be changed
2670 :param Variable var: variable to be added
2671 :param coeff: coefficient of new variable
2676 def addConsNode(self, Node node, Constraint cons, Node validnode=None):
2677 """Add a constraint to the given node
2679 :param Node node: node to add the constraint to
2680 :param Constraint cons: constraint to add
2681 :param Node validnode: more global node where cons is also valid
2684 if isinstance(validnode, Node):
2691 """Add a constraint to the current node
2693 :param Constraint cons: constraint to add
2694 :param Node validnode: more global node where cons is also valid
2697 if isinstance(validnode, Node):
2704 initial=True, separate=True, enforce=True, check=True,
2705 propagate=True, local=False, dynamic=False,
2706 removable=False, stickingatnode=False):
2707 """Add an SOS1 constraint.
2709 :param vars: list of variables to be included
2710 :param weights: list of weights (Default value = None)
2711 :param name: name of the constraint (Default value = "SOS1cons")
2712 :param initial: should the LP relaxation of constraint be in the initial LP? (Default value = True)
2713 :param separate: should the constraint be separated during LP processing? (Default value = True)
2714 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2715 :param check: should the constraint be checked for feasibility? (Default value = True)
2716 :param propagate: should the constraint be propagated during node processing? (Default value = True)
2717 :param local: is the constraint only valid locally? (Default value = False)
2718 :param dynamic: is the constraint subject to aging? (Default value = False)
2719 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2720 :param stickingatnode: should the constraint always be kept at the node where it was added, even if it may be moved to a more global node? (Default value = False)
2723 cdef SCIP_CONS* scip_cons
2727 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode))
2735 for i
in range(nvars):
2736 var = <Variable>vars[i]
2740 return Constraint.create(scip_cons)
2743 initial=True, separate=True, enforce=True, check=True,
2744 propagate=True, local=False, dynamic=False,
2745 removable=False, stickingatnode=False):
2746 """Add an SOS2 constraint.
2748 :param vars: list of variables to be included
2749 :param weights: list of weights (Default value = None)
2750 :param name: name of the constraint (Default value = "SOS2cons")
2751 :param initial: should the LP relaxation of constraint be in the initial LP? (Default value = True)
2752 :param separate: should the constraint be separated during LP processing? (Default value = True)
2753 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2754 :param check: should the constraint be checked for feasibility? (Default value = True)
2755 :param propagate: is the constraint only valid locally? (Default value = True)
2756 :param local: is the constraint only valid locally? (Default value = False)
2757 :param dynamic: is the constraint subject to aging? (Default value = False)
2758 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2759 :param stickingatnode: should the constraint always be kept at the node where it was added, even if it may be moved to a more global node? (Default value = False)
2762 cdef SCIP_CONS* scip_cons
2766 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode))
2774 for i
in range(nvars):
2775 var = <Variable>vars[i]
2779 return Constraint.create(scip_cons)
2782 initial=True, separate=True, enforce=True, check=True,
2783 propagate=True, local=False, modifiable=False, dynamic=False,
2784 removable=False, stickingatnode=False):
2785 """Add an AND-constraint.
2786 :param vars: list of BINARY variables to be included (operators)
2787 :param resvar: BINARY variable (resultant)
2788 :param name: name of the constraint (Default value = "ANDcons")
2789 :param initial: should the LP relaxation of constraint be in the initial LP? (Default value = True)
2790 :param separate: should the constraint be separated during LP processing? (Default value = True)
2791 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2792 :param check: should the constraint be checked for feasibility? (Default value = True)
2793 :param propagate: should the constraint be propagated during node processing? (Default value = True)
2794 :param local: is the constraint only valid locally? (Default value = False)
2795 :param modifiable: is the constraint modifiable (subject to column generation)? (Default value = False)
2796 :param dynamic: is the constraint subject to aging? (Default value = False)
2797 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2798 :param stickingatnode: should the constraint always be kept at the node where it was added, even if it may be moved to a more global node? (Default value = False)
2800 cdef SCIP_CONS* scip_cons
2804 _vars = <SCIP_VAR**> malloc(len(vars) * sizeof(SCIP_VAR*))
2805 for idx, var
in enumerate(vars):
2806 _vars[idx] = (<Variable>var).scip_var
2807 _resVar = (<Variable>resvar).scip_var
2810 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode))
2813 pyCons = Constraint.create(scip_cons)
2821 initial=True, separate=True, enforce=True, check=True,
2822 propagate=True, local=False, modifiable=False, dynamic=False,
2823 removable=False, stickingatnode=False):
2824 """Add an OR-constraint.
2825 :param vars: list of BINARY variables to be included (operators)
2826 :param resvar: BINARY variable (resultant)
2827 :param name: name of the constraint (Default value = "ORcons")
2828 :param initial: should the LP relaxation of constraint be in the initial LP? (Default value = True)
2829 :param separate: should the constraint be separated during LP processing? (Default value = True)
2830 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2831 :param check: should the constraint be checked for feasibility? (Default value = True)
2832 :param propagate: should the constraint be propagated during node processing? (Default value = True)
2833 :param local: is the constraint only valid locally? (Default value = False)
2834 :param modifiable: is the constraint modifiable (subject to column generation)? (Default value = False)
2835 :param dynamic: is the constraint subject to aging? (Default value = False)
2836 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2837 :param stickingatnode: should the constraint always be kept at the node where it was added, even if it may be moved to a more global node? (Default value = False)
2839 cdef SCIP_CONS* scip_cons
2843 _vars = <SCIP_VAR**> malloc(len(vars) * sizeof(SCIP_VAR*))
2844 for idx, var
in enumerate(vars):
2845 _vars[idx] = (<Variable>var).scip_var
2846 _resVar = (<Variable>resvar).scip_var
2849 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode))
2852 pyCons = Constraint.create(scip_cons)
2860 initial=True, separate=True, enforce=True, check=True,
2861 propagate=True, local=False, modifiable=False, dynamic=False,
2862 removable=False, stickingatnode=False):
2863 """Add a XOR-constraint.
2864 :param vars: list of BINARY variables to be included (operators)
2865 :param rhsvar: BOOLEAN value, explicit True, False or bool(obj) is needed (right-hand side)
2866 :param name: name of the constraint (Default value = "XORcons")
2867 :param initial: should the LP relaxation of constraint be in the initial LP? (Default value = True)
2868 :param separate: should the constraint be separated during LP processing? (Default value = True)
2869 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2870 :param check: should the constraint be checked for feasibility? (Default value = True)
2871 :param propagate: should the constraint be propagated during node processing? (Default value = True)
2872 :param local: is the constraint only valid locally? (Default value = False)
2873 :param modifiable: is the constraint modifiable (subject to column generation)? (Default value = False)
2874 :param dynamic: is the constraint subject to aging? (Default value = False)
2875 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2876 :param stickingatnode: should the constraint always be kept at the node where it was added, even if it may be moved to a more global node? (Default value = False)
2878 cdef SCIP_CONS* scip_cons
2882 assert type(rhsvar)
is type(bool()),
"Provide BOOLEAN value as rhsvar, you gave %s." % type(rhsvar)
2883 _vars = <SCIP_VAR**> malloc(len(vars) * sizeof(SCIP_VAR*))
2884 for idx, var
in enumerate(vars):
2885 _vars[idx] = (<Variable>var).scip_var
2888 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode))
2891 pyCons = Constraint.create(scip_cons)
2899 initial=True, separate=True, enforce=True, check=True,
2900 propagate=True, local=False, dynamic=False,
2901 removable=False, stickingatnode=False):
2902 """Add a cardinality constraint that allows at most 'cardval' many nonzero variables.
2904 :param consvars: list of variables to be included
2905 :param cardval: nonnegative integer
2906 :param indvars: indicator variables indicating which variables may be treated as nonzero in cardinality constraint, or None if new indicator variables should be introduced automatically (Default value = None)
2907 :param weights: weights determining the variable order, or None if variables should be ordered in the same way they were added to the constraint (Default value = None)
2908 :param name: name of the constraint (Default value = "CardinalityCons")
2909 :param initial: should the LP relaxation of constraint be in the initial LP? (Default value = True)
2910 :param separate: should the constraint be separated during LP processing? (Default value = True)
2911 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2912 :param check: should the constraint be checked for feasibility? (Default value = True)
2913 :param propagate: should the constraint be propagated during node processing? (Default value = True)
2914 :param local: is the constraint only valid locally? (Default value = False)
2915 :param dynamic: is the constraint subject to aging? (Default value = False)
2916 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2917 :param stickingatnode: should the constraint always be kept at the node where it was added, even if it may be moved to a more global node? (Default value = False)
2920 cdef SCIP_CONS* scip_cons
2921 cdef SCIP_VAR* indvar
2924 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode))
2928 weights = list(range(1, len(consvars) + 1))
2930 for i, v
in enumerate(consvars):
2933 indvar = (<Variable>indvars[i]).scip_var
2942 pyCons = Constraint.create(scip_cons)
2949 initial=True, separate=True, enforce=True, check=True,
2950 propagate=True, local=False, dynamic=False,
2951 removable=False, stickingatnode=False):
2952 """Add an indicator constraint for the linear inequality 'cons'.
2954 The 'binvar' argument models the redundancy of the linear constraint. A solution for which
2955 'binvar' is 1 must satisfy the constraint.
2957 :param cons: a linear inequality of the form "<="
2958 :param binvar: binary indicator variable, or None if it should be created (Default value = None)
2959 :param activeone: constraint should active if binvar is 1 (0 if activeone = False)
2960 :param name: name of the constraint (Default value = "IndicatorCons")
2961 :param initial: should the LP relaxation of constraint be in the initial LP? (Default value = True)
2962 :param separate: should the constraint be separated during LP processing? (Default value = True)
2963 :param enforce: should the constraint be enforced during node processing? (Default value = True)
2964 :param check: should the constraint be checked for feasibility? (Default value = True)
2965 :param propagate: should the constraint be propagated during node processing? (Default value = True)
2966 :param local: is the constraint only valid locally? (Default value = False)
2967 :param dynamic: is the constraint subject to aging? (Default value = False)
2968 :param removable: should the relaxation be removed from the LP due to aging or cleanup? (Default value = False)
2969 :param stickingatnode: should the constraint always be kept at the node where it was added, even if it may be moved to a more global node? (Default value = False)
2972 assert isinstance(cons, ExprCons),
"given constraint is not ExprCons but %s" % cons.__class__.__name__
2973 cdef SCIP_CONS* scip_cons
2974 cdef SCIP_VAR* _binVar
2975 if cons._lhs
is not None and cons._rhs
is not None:
2976 raise ValueError(
"expected inequality that has either only a left or right hand side")
2978 if cons.expr.degree() > 1:
2979 raise ValueError(
"expected linear inequality, expression has degree %d" % cons.expr.degree())
2981 if cons._rhs
is not None:
2988 if binvar
is not None:
2989 _binVar = (<Variable>binvar).scip_var
2996 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode))
2997 terms = cons.expr.terms
2999 for key, coeff
in terms.items():
3000 var = <Variable>key[0]
3006 pyCons = Constraint.create(scip_cons)
3013 """Get slack variable of an indicator constraint.
3015 :param Constraint cons: indicator constraint
3019 return Variable.create(var)
3022 """Adds a customly created cons.
3024 :param Constraint cons: constraint to add
3031 """Add variable to SOS1 constraint.
3033 :param Constraint cons: SOS1 constraint
3034 :param Variable var: new variable
3035 :param weight: weight of new variable
3041 """Append variable to SOS1 constraint.
3043 :param Constraint cons: SOS1 constraint
3044 :param Variable var: variable to append
3050 """Add variable to SOS2 constraint.
3052 :param Constraint cons: SOS2 constraint
3053 :param Variable var: new variable
3054 :param weight: weight of new variable
3060 """Append variable to SOS2 constraint.
3062 :param Constraint cons: SOS2 constraint
3063 :param Variable var: variable to append
3069 """Set "initial" flag of a constraint.
3073 newInit -- new initial value
3078 """Set "removable" flag of a constraint.
3082 newRem -- new removable value
3087 """Set "enforced" flag of a constraint.
3091 newEnf -- new enforced value
3096 """Set "check" flag of a constraint.
3100 newCheck -- new check value
3105 """Change right hand side value of a constraint.
3107 :param Constraint cons: linear or quadratic constraint
3108 :param rhs: new right hand side (set to None for +infinity)
3116 if constype ==
'linear':
3118 elif constype ==
'nonlinear':
3121 raise Warning(
"method cannot be called for constraints of type " + constype)
3124 """Change left hand side value of a constraint.
3126 :param Constraint cons: linear or quadratic constraint
3127 :param lhs: new left hand side (set to None for -infinity)
3135 if constype ==
'linear':
3137 elif constype ==
'nonlinear':
3140 raise Warning(
"method cannot be called for constraints of type " + constype)
3143 """Retrieve right hand side value of a constraint.
3145 :param Constraint cons: linear or quadratic constraint
3149 if constype ==
'linear':
3151 elif constype ==
'quadratic':
3154 raise Warning(
"method cannot be called for constraints of type " + constype)
3157 """Retrieve left hand side value of a constraint.
3159 :param Constraint cons: linear or quadratic constraint
3163 if constype ==
'linear':
3165 elif constype ==
'quadratic':
3168 raise Warning(
"method cannot be called for constraints of type " + constype)
3171 """Changes coefficient of variable in linear constraint;
3172 deletes the variable if coefficient is zero; adds variable if not yet contained in the constraint
3173 This method may only be called during problem creation stage for an original constraint and variable.
3174 This method requires linear time to search for occurences of the variable in the constraint data.
3176 :param Constraint cons: linear constraint
3177 :param Variable var: variable of constraint entry
3178 :param value: new coefficient of constraint entry
3184 """Deletes variable from linear constraint
3185 This method may only be called during problem creation stage for an original constraint and variable.
3186 This method requires linear time to search for occurences of the variable in the constraint data.
3188 :param Constraint cons: linear constraint
3189 :param Variable var: variable of constraint entry
3196 """Adds coefficient to linear constraint (if it is not zero)
3198 :param Constraint cons: linear constraint
3199 :param Variable var: variable of constraint entry
3200 :param value: coefficient of constraint entry
3207 """Retrieve activity of given constraint.
3208 Can only be called after solving is completed.
3210 :param Constraint cons: linear or quadratic constraint
3211 :param Solution sol: solution to compute activity of, None to use current node's solution (Default value = None)
3214 cdef SCIP_Real activity
3215 cdef SCIP_SOL* scip_sol
3217 if not self.
getStage() >= SCIP_STAGE_SOLVING:
3218 raise Warning(
"method cannot be called before problem is solved")
3220 if isinstance(sol, Solution):
3226 if constype ==
'linear':
3229 raise Warning(
"method cannot be called for constraints of type " + constype)
3234 def getSlack(self, Constraint cons, Solution sol = None, side = None):
3235 """Retrieve slack of given constraint.
3236 Can only be called after solving is completed.
3239 :param Constraint cons: linear or quadratic constraint
3240 :param Solution sol: solution to compute slack of, None to use current node's solution (Default value = None)
3241 :param side: whether to use 'lhs' or 'rhs' for ranged constraints, None to return minimum (Default value = None)
3244 cdef SCIP_Real activity
3245 cdef SCIP_SOL* scip_sol
3248 if not self.
getStage() >= SCIP_STAGE_SOLVING:
3249 raise Warning(
"method cannot be called before problem is solved")
3251 if isinstance(sol, Solution):
3257 if constype ==
'linear':
3262 raise Warning(
"method cannot be called for constraints of type " + constype)
3264 lhsslack = activity - lhs
3265 rhsslack = rhs - activity
3272 return min(lhsslack, rhsslack)
3275 """Retrieve transformed constraint.
3277 :param Constraint cons: constraint
3280 cdef SCIP_CONS* transcons
3282 return Constraint.create(transcons)
3285 """returns whether SCIP's internal NLP has been constructed"""
3289 """gets current number of nonlinear rows in SCIP's internal NLP"""
3293 """returns a list with the nonlinear rows in SCIP's internal NLP"""
3294 cdef SCIP_NLROW** nlrows
3297 return [NLRow.create(nlrows[i])
for i
in range(self.
getNNlRows())]
3300 """gives the activity of a nonlinear row for a given primal solution
3302 nlrow -- nonlinear row
3303 solution -- a primal solution, if None, then the current LP solution is used
3305 cdef SCIP_Real activity
3306 cdef SCIP_SOL* solptr
3308 solptr = sol.sol
if not sol
is None else NULL
3313 """gives the feasibility of a nonlinear row for a given primal solution
3315 nlrow -- nonlinear row
3316 solution -- a primal solution, if None, then the current LP solution is used
3318 cdef SCIP_Real feasibility
3319 cdef SCIP_SOL* solptr
3321 solptr = sol.sol
if not sol
is None else NULL
3326 """gives the minimal and maximal activity of a nonlinear row w.r.t. the variable's bounds"""
3327 cdef SCIP_Real minactivity
3328 cdef SCIP_Real maxactivity
3331 return (minactivity, maxactivity)
3334 """prints nonlinear row"""
3338 """returns if the given constraint is quadratic
3340 :param Constraint cons: constraint
3343 cdef SCIP_Bool isquadratic
3348 """Retrieve bilinear, quadratic, and linear terms of a quadratic constraint.
3350 :param Constraint cons: constraint
3353 cdef SCIP_EXPR* expr
3356 cdef SCIP_EXPR** _linexprs
3357 cdef SCIP_Real* _lincoefs
3361 cdef int _nbilinterms
3362 cdef SCIP_EXPR* bilinterm1
3363 cdef SCIP_EXPR* bilinterm2
3364 cdef SCIP_Real bilincoef
3367 cdef int _nquadterms
3368 cdef SCIP_Real sqrcoef
3369 cdef SCIP_Real lincoef
3370 cdef SCIP_EXPR* sqrexpr
3373 cdef SCIP_VAR* scipvar1
3374 cdef SCIP_VAR* scipvar2
3376 assert cons.isNonlinear(),
"constraint is not nonlinear"
3386 for termidx
in range(_nlinvars):
3388 linterms.append((var,_lincoefs[termidx]))
3390 for termidx
in range(_nbilinterms):
3394 var1 = Variable.create(scipvar1)
3395 var2 = Variable.create(scipvar2)
3396 if scipvar1 != scipvar2:
3397 bilinterms.append((var1,var2,bilincoef))
3399 quadterms.append((var1,bilincoef,0.0))
3401 for termidx
in range(_nquadterms):
3406 quadterms.append((var,sqrcoef,lincoef))
3408 return (bilinterms, quadterms, linterms)
3411 """sets the value of the given variable in the global relaxation solution"""
3415 """Retrieve all constraints.
3417 :param transformed: get transformed variables instead of original (Default value = True)
3419 cdef SCIP_CONS** _conss
3429 return [Constraint.create(_conss[i])
for i
in range(_nconss)]
3432 """Retrieve number of all constraints"""
3439 """Delete constraint from the model
3441 :param Constraint cons: constraint to be deleted
3447 """Delete constraint from the current node and it's children
3449 :param Constraint cons: constraint to be deleted
3455 """Retrieve the coefficients of a linear constraint
3457 :param Constraint cons: linear constraint to get the coefficients of
3460 cdef SCIP_Real* _vals
3461 cdef SCIP_VAR** _vars
3464 if not constype ==
'linear':
3465 raise Warning(
"coefficients not available for constraints of type ", constype)
3472 valsdict[bytes(
SCIPvarGetName(_vars[i])).decode(
'utf-8')] = _vals[i]
3476 """Retrieve the linear relaxation of the given linear constraint as a row.
3477 may return NULL if no LP row was yet created; the user must not modify the row!
3479 :param Constraint cons: linear constraint to get the coefficients of
3483 if not constype ==
'linear':
3484 raise Warning(
"coefficients not available for constraints of type ", constype)
3487 return Row.create(row)
3490 """Retrieve the dual solution to a linear constraint.
3492 :param Constraint cons: linear constraint
3496 if not constype ==
'linear':
3497 raise Warning(
"dual solution values not available for constraints of type ", constype)
3498 if cons.isOriginal():
3505 """DEPRECATED: Retrieve the dual solution to a linear constraint.
3507 :param Constraint cons: linear constraint
3510 raise Warning(
"model.getDualMultiplier(cons) is deprecated: please use model.getDualsolLinear(cons)")
3514 """Retrieve the dual farkas value to a linear constraint.
3516 :param Constraint cons: linear constraint
3520 if cons.isOriginal():
3527 """Retrieve the reduced cost of a variable.
3529 :param Variable var: variable to get the reduced cost of
3538 raise Warning(
"no reduced cost available for variable " + var.name)
3542 """Retrieve returns dual solution value of a constraint.
3544 :param Constraint cons: constraint to get the dual solution value of
3545 :param boundconstraint bool: Decides whether to store a bool if the constraint is a bound constraint
3548 cdef SCIP_Real _dualsol
3549 cdef SCIP_Bool _bounded
3559 """Optimize the problem."""
3564 """Transforms, presolves, and solves problem using additional solvers which emphasize on
3565 finding solutions."""
3566 if SCIPtpiGetNumThreads() == 1:
3567 warnings.warn(
"SCIP was compiled without task processing interface. Parallel solve not possible - using optimize() instead of solveConcurrent()")
3574 """Presolve the problem."""
3580 """initialises the default Benders' decomposition with a dictionary of subproblems
3583 subproblems -- a single Model instance or dictionary of Model instances
3585 cdef SCIP** subprobs
3586 cdef SCIP_BENDERS* benders
3589 if isinstance(subproblems, dict):
3591 nsubproblems = len(subproblems)
3597 subprobs = <SCIP**> malloc(nsubproblems * sizeof(SCIP*))
3601 for idx, subprob
in enumerate(subproblems.values()):
3602 subprobs[idx] = (<Model>subprob)._scip
3604 subprobs[0] = (<Model>subproblems)._scip
3611 self.
setBoolParam(
"constraints/benderslp/active",
True)
3616 """Solves the subproblems with the best solution to the master problem.
3617 Afterwards, the best solution from each subproblem can be queried to get
3618 the solution to the original problem.
3620 If the user wants to resolve the subproblems, they must free them by
3621 calling freeBendersSubproblems()
3623 cdef SCIP_BENDERS** _benders
3624 cdef SCIP_Bool _infeasible
3626 cdef int nsubproblems
3634 for i
in range(nbenders):
3636 for j
in range(nsubproblems):
3638 _benders[i], self.
_bestSol.sol, j, SCIP_BENDERSENFOTYPE_CHECK))
3640 _benders[i], self.
_bestSol.sol, j, &_infeasible, solvecip, NULL))
3643 """Calls the free subproblem function for the Benders' decomposition.
3644 This will free all subproblems for all decompositions.
3646 cdef SCIP_BENDERS** _benders
3648 cdef int nsubproblems
3654 for i
in range(nbenders):
3656 for j
in range(nsubproblems):
3661 """"updates the subproblem lower bounds for benders using
3662 the lowerbounds dict. If benders is None, then the default
3663 Benders' decomposition is updated
3665 cdef SCIP_BENDERS* _benders
3667 assert type(lowerbounds)
is dict
3672 _benders = benders._benders
3674 for d
in lowerbounds.keys():
3678 """Activates the Benders' decomposition plugin with the input name
3681 benders -- the Benders' decomposition to which the subproblem belongs to
3682 nsubproblems -- the number of subproblems in the Benders' decomposition
3687 """adds a subproblem to the Benders' decomposition given by the input
3691 benders -- the Benders' decomposition to which the subproblem belongs to
3692 subproblem -- the subproblem to add to the decomposition
3693 isconvex -- can be used to specify whether the subproblem is convex
3698 """sets a flag indicating whether the subproblem is convex
3701 benders -- the Benders' decomposition which contains the subproblem
3702 probnumber -- the problem number of the subproblem that the convexity will be set for
3703 isconvex -- flag to indicate whether the subproblem is convex
3707 def setupBendersSubproblem(self, probnumber, Benders benders = None, Solution solution = None, checktype = PY_SCIP_BENDERSENFOTYPE.LP):
3708 """ sets up the Benders' subproblem given the master problem solution
3711 probnumber -- the index of the problem that is to be set up
3712 benders -- the Benders' decomposition to which the subproblem belongs to
3713 solution -- the master problem solution that is used for the set up, if None, then the LP solution is used
3714 checktype -- the type of solution check that prompted the solving of the Benders' subproblems, either
3715 PY_SCIP_BENDERSENFOTYPE: LP, RELAX, PSEUDO or CHECK. Default is LP
3717 cdef SCIP_BENDERS* scip_benders
3718 cdef SCIP_SOL* scip_sol
3720 if isinstance(solution, Solution):
3721 scip_sol = solution.sol
3728 scip_benders = benders._benders
3732 PY_SCIP_CALL(retcode)
3735 """ solves the Benders' decomposition subproblem. The convex relaxation will be solved unless
3736 the parameter solvecip is set to True.
3739 probnumber -- the index of the problem that is to be set up
3740 solvecip -- should the CIP of the subproblem be solved, if False, then only the convex relaxation is solved
3741 benders -- the Benders' decomposition to which the subproblem belongs to
3742 solution -- the master problem solution that is used for the set up, if None, then the LP solution is used
3745 cdef SCIP_BENDERS* scip_benders
3746 cdef SCIP_SOL* scip_sol
3747 cdef SCIP_Real objective
3748 cdef SCIP_Bool infeasible
3750 if isinstance(solution, Solution):
3751 scip_sol = solution.sol
3758 scip_benders = benders._benders
3761 probnumber, &infeasible, solvecip, &objective))
3763 return infeasible, objective
3766 """Returns a Model object that wraps around the SCIP instance of the subproblem.
3767 NOTE: This Model object is just a place holder and SCIP instance will not be freed when the object is destroyed.
3770 probnumber -- the problem number for subproblem that is required
3771 benders -- the Benders' decomposition object for the that the subproblem belongs to (Default = None)
3773 cdef SCIP_BENDERS* scip_benders
3774 cdef SCIP* scip_subprob
3779 scip_benders = benders._benders
3783 return Model.create(scip_subprob)
3786 """Returns the variable for the subproblem or master problem
3787 depending on the input probnumber
3790 var -- the source variable for which the target variable is requested
3791 benders -- the Benders' decomposition to which the subproblem variables belong to
3792 probnumber -- the problem number for which the target variable belongs, -1 for master problem
3794 cdef SCIP_BENDERS* _benders
3795 cdef SCIP_VAR* _mappedvar
3800 _benders = benders._benders
3802 if probnumber == -1:
3807 if _mappedvar == NULL:
3810 mappedvar = Variable.create(_mappedvar)
3815 """Returns the auxiliary variable that is associated with the input problem number
3818 probnumber -- the problem number for which the target variable belongs, -1 for master problem
3819 benders -- the Benders' decomposition to which the subproblem variables belong to
3821 cdef SCIP_BENDERS* _benders
3822 cdef SCIP_VAR* _auxvar
3827 _benders = benders._benders
3830 auxvar = Variable.create(_auxvar)
3835 """Returns whether the subproblem is optimal w.r.t the master problem auxiliary variables.
3838 solution -- the master problem solution that is being checked for optimamlity
3839 probnumber -- the problem number for which optimality is being checked
3840 benders -- the Benders' decomposition to which the subproblem belongs to
3842 cdef SCIP_BENDERS* _benders
3843 cdef SCIP_SOL* scip_sol
3844 cdef SCIP_Bool optimal
3849 _benders = benders._benders
3851 if isinstance(solution, Solution):
3852 scip_sol = solution.sol
3857 scip_sol, probnumber, &optimal) )
3862 """includes the default Benders' decomposition cuts to the custom Benders' decomposition plugin
3865 benders -- the Benders' decomposition that the default cuts will be applied to
3867 PY_SCIP_CALL( SCIPincludeBendersDefaultCuts(self.
_scip, benders._benders) )
3871 """Include an event handler.
3874 eventhdlr -- event handler
3875 name -- name of event handler
3876 desc -- description of event handler
3889 <SCIP_EVENTHDLRDATA*>eventhdlr))
3890 eventhdlr.model = <Model>weakref.proxy(self)
3891 eventhdlr.name = name
3892 Py_INCREF(eventhdlr)
3895 """Include a pricer.
3897 :param Pricer pricer: pricer
3898 :param name: name of pricer
3899 :param desc: description of pricer
3900 :param priority: priority of pricer (Default value = 1)
3901 :param delay: should the pricer be delayed until no other pricers or already existing problem variables with negative reduced costs are found? (Default value = True)
3908 PyPricerCopy, PyPricerFree, PyPricerInit, PyPricerExit, PyPricerInitsol, PyPricerExitsol, PyPricerRedcost, PyPricerFarkas,
3909 <SCIP_PRICERDATA*>pricer))
3910 cdef SCIP_PRICER* scip_pricer
3913 pricer.model = <Model>weakref.proxy(self)
3917 enfopriority=0, chckpriority=0, sepafreq=-1, propfreq=-1,
3918 eagerfreq=100, maxprerounds=-1, delaysepa=False,
3919 delayprop=False, needscons=True,
3920 proptiming=PY_SCIP_PROPTIMING.BEFORELP,
3921 presoltiming=PY_SCIP_PRESOLTIMING.MEDIUM):
3922 """Include a constraint handler
3924 :param Conshdlr conshdlr: constraint handler
3925 :param name: name of constraint handler
3926 :param desc: description of constraint handler
3927 :param sepapriority: priority for separation (Default value = 0)
3928 :param enfopriority: priority for constraint enforcing (Default value = 0)
3929 :param chckpriority: priority for checking feasibility (Default value = 0)
3930 :param sepafreq: frequency for separating cuts; 0 = only at root node (Default value = -1)
3931 :param propfreq: frequency for propagating domains; 0 = only preprocessing propagation (Default value = -1)
3932 :param eagerfreq: frequency for using all instead of only the useful constraints in separation, propagation and enforcement; -1 = no eager evaluations, 0 = first only (Default value = 100)
3933 :param maxprerounds: maximal number of presolving rounds the constraint handler participates in (Default value = -1)
3934 :param delaysepa: should separation method be delayed, if other separators found cuts? (Default value = False)
3935 :param delayprop: should propagation method be delayed, if other propagators found reductions? (Default value = False)
3936 :param needscons: should the constraint handler be skipped, if no constraints are available? (Default value = True)
3937 :param proptiming: positions in the node solving loop where propagation method of constraint handlers should be executed (Default value = SCIP_PROPTIMING.BEFORELP)
3938 :param presoltiming: timing mask of the constraint handler's presolving method (Default value = SCIP_PRESOLTIMING.MEDIUM)
3943 PY_SCIP_CALL(
SCIPincludeConshdlr(self.
_scip, n, d, sepapriority, enfopriority, chckpriority, sepafreq, propfreq, eagerfreq,
3944 maxprerounds, delaysepa, delayprop, needscons, proptiming, presoltiming,
3945 PyConshdlrCopy, PyConsFree, PyConsInit, PyConsExit, PyConsInitpre, PyConsExitpre,
3946 PyConsInitsol, PyConsExitsol, PyConsDelete, PyConsTrans, PyConsInitlp, PyConsSepalp, PyConsSepasol,
3947 PyConsEnfolp, PyConsEnforelax, PyConsEnfops, PyConsCheck, PyConsProp, PyConsPresol, PyConsResprop, PyConsLock,
3948 PyConsActive, PyConsDeactive, PyConsEnable, PyConsDisable, PyConsDelvars, PyConsPrint, PyConsCopy,
3949 PyConsParse, PyConsGetvars, PyConsGetnvars, PyConsGetdivebdchgs, PyConsGetPermSymGraph, PyConsGetSignedPermSymGraph,
3950 <SCIP_CONSHDLRDATA*>conshdlr))
3951 conshdlr.model = <Model>weakref.proxy(self)
3952 conshdlr.name = name
3955 def createCons(self, Conshdlr conshdlr, name, initial=True, separate=True, enforce=True, check=True, propagate=True,
3956 local=False, modifiable=False, dynamic=False, removable=False, stickingatnode=False):
3957 """Create a constraint of a custom constraint handler
3959 :param Conshdlr conshdlr: constraint handler
3960 :param name: name of constraint
3961 :param initial: (Default value = True)
3962 :param separate: (Default value = True)
3963 :param enforce: (Default value = True)
3964 :param check: (Default value = True)
3965 :param propagate: (Default value = True)
3966 :param local: (Default value = False)
3967 :param modifiable: (Default value = False)
3968 :param dynamic: (Default value = False)
3969 :param removable: (Default value = False)
3970 :param stickingatnode: (Default value = False)
3975 cdef SCIP_CONSHDLR* scip_conshdlr
3978 PY_SCIP_CALL(
SCIPcreateCons(self.
_scip, &(constraint.scip_cons), n, scip_conshdlr, <SCIP_CONSDATA*>constraint,
3979 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode))
3982 def includePresol(self, Presol presol, name, desc, priority, maxrounds, timing=SCIP_PRESOLTIMING_FAST):
3983 """Include a presolver
3985 :param Presol presol: presolver
3986 :param name: name of presolver
3987 :param desc: description of presolver
3988 :param priority: priority of the presolver (>= 0: before, < 0: after constraint handlers)
3989 :param maxrounds: maximal number of presolving rounds the presolver participates in (-1: no limit)
3990 :param timing: timing mask of presolver (Default value = SCIP_PRESOLTIMING_FAST)
3995 PY_SCIP_CALL(
SCIPincludePresol(self.
_scip, n, d, priority, maxrounds, timing, PyPresolCopy, PyPresolFree, PyPresolInit,
3996 PyPresolExit, PyPresolInitpre, PyPresolExitpre, PyPresolExec, <SCIP_PRESOLDATA*>presol))
3997 presol.model = <Model>weakref.proxy(self)
4000 def includeSepa(self, Sepa sepa, name, desc, priority=0, freq=10, maxbounddist=1.0, usessubscip=False, delay=False):
4001 """Include a separator
4003 :param Sepa sepa: separator
4004 :param name: name of separator
4005 :param desc: description of separator
4006 :param priority: priority of separator (>= 0: before, < 0: after constraint handlers)
4007 :param freq: frequency for calling separator
4008 :param maxbounddist: maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for applying separation
4009 :param usessubscip: does the separator use a secondary SCIP instance? (Default value = False)
4010 :param delay: should separator be delayed, if other separators found cuts? (Default value = False)
4015 PY_SCIP_CALL(
SCIPincludeSepa(self.
_scip, n, d, priority, freq, maxbounddist, usessubscip, delay, PySepaCopy, PySepaFree,
4016 PySepaInit, PySepaExit, PySepaInitsol, PySepaExitsol, PySepaExeclp, PySepaExecsol, <SCIP_SEPADATA*>sepa))
4017 sepa.model = <Model>weakref.proxy(self)
4024 :param Reader reader: reader
4025 :param name: name of reader
4026 :param desc: description of reader
4027 :param ext: file extension of reader
4034 PyReaderRead, PyReaderWrite, <SCIP_READERDATA*>reader))
4035 reader.model = <Model>weakref.proxy(self)
4039 def includeProp(self, Prop prop, name, desc, presolpriority, presolmaxrounds,
4040 proptiming, presoltiming=SCIP_PRESOLTIMING_FAST, priority=1, freq=1, delay=True):
4041 """Include a propagator.
4043 :param Prop prop: propagator
4044 :param name: name of propagator
4045 :param desc: description of propagator
4046 :param presolpriority: presolving priority of the propgator (>= 0: before, < 0: after constraint handlers)
4047 :param presolmaxrounds: maximal number of presolving rounds the propagator participates in (-1: no limit)
4048 :param proptiming: positions in the node solving loop where propagation method of constraint handlers should be executed
4049 :param presoltiming: timing mask of the constraint handler's presolving method (Default value = SCIP_PRESOLTIMING_FAST)
4050 :param priority: priority of the propagator (Default value = 1)
4051 :param freq: frequency for calling propagator (Default value = 1)
4052 :param delay: should propagator be delayed if other propagators have found reductions? (Default value = True)
4058 priority, freq, delay,
4059 proptiming, presolpriority, presolmaxrounds,
4060 presoltiming, PyPropCopy, PyPropFree, PyPropInit, PyPropExit,
4061 PyPropInitpre, PyPropExitpre, PyPropInitsol, PyPropExitsol,
4062 PyPropPresol, PyPropExec, PyPropResProp,
4063 <SCIP_PROPDATA*> prop))
4064 prop.model = <Model>weakref.proxy(self)
4067 def includeHeur(self, Heur heur, name, desc, dispchar, priority=10000, freq=1, freqofs=0,
4068 maxdepth=-1, timingmask=SCIP_HEURTIMING_BEFORENODE, usessubscip=False):
4069 """Include a primal heuristic.
4071 :param Heur heur: heuristic
4072 :param name: name of heuristic
4073 :param desc: description of heuristic
4074 :param dispchar: display character of heuristic
4075 :param priority: priority of the heuristic (Default value = 10000)
4076 :param freq: frequency for calling heuristic (Default value = 1)
4077 :param freqofs: frequency offset for calling heuristic (Default value = 0)
4078 :param maxdepth: maximal depth level to call heuristic at (Default value = -1)
4079 :param timingmask: positions in the node solving loop where heuristic should be executed (Default value = SCIP_HEURTIMING_BEFORENODE)
4080 :param usessubscip: does the heuristic use a secondary SCIP instance? (Default value = False)
4087 priority, freq, freqofs,
4088 maxdepth, timingmask, usessubscip,
4089 PyHeurCopy, PyHeurFree, PyHeurInit, PyHeurExit,
4090 PyHeurInitsol, PyHeurExitsol, PyHeurExec,
4091 <SCIP_HEURDATA*> heur))
4092 heur.model = <Model>weakref.proxy(self)
4097 """Include a relaxation handler.
4099 :param Relax relax: relaxation handler
4100 :param name: name of relaxation handler
4101 :param desc: description of relaxation handler
4102 :param priority: priority of the relaxation handler (negative: after LP, non-negative: before LP, Default value = 10000)
4103 :param freq: frequency for calling relaxation handler
4108 PY_SCIP_CALL(
SCIPincludeRelax(self.
_scip, nam, des, priority, freq, PyRelaxCopy, PyRelaxFree, PyRelaxInit, PyRelaxExit,
4109 PyRelaxInitsol, PyRelaxExitsol, PyRelaxExec, <SCIP_RELAXDATA*> relax))
4110 relax.model = <Model>weakref.proxy(self)
4116 """include a cut selector
4118 :param Cutsel cutsel: cut selector
4119 :param name: name of cut selector
4120 :param desc: description of cut selector
4121 :param priority: priority of the cut selector
4127 priority, PyCutselCopy, PyCutselFree, PyCutselInit, PyCutselExit,
4128 PyCutselInitsol, PyCutselExitsol, PyCutselSelect,
4129 <SCIP_CUTSELDATA*> cutsel))
4130 cutsel.model = <Model>weakref.proxy(self)
4134 """Include a branching rule.
4136 :param Branchrule branchrule: branching rule
4137 :param name: name of branching rule
4138 :param desc: description of branching rule
4139 :param priority: priority of branching rule
4140 :param maxdepth: maximal depth level up to which this branching rule should be used (or -1)
4141 :param maxbounddist: maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for applying branching rule (0.0: only on current best node, 1.0: on all nodes)
4147 priority, maxdepth, maxbounddist,
4148 PyBranchruleCopy, PyBranchruleFree, PyBranchruleInit, PyBranchruleExit,
4149 PyBranchruleInitsol, PyBranchruleExitsol, PyBranchruleExeclp, PyBranchruleExecext,
4150 PyBranchruleExecps, <SCIP_BRANCHRULEDATA*> branchrule))
4151 branchrule.model = <Model>weakref.proxy(self)
4152 Py_INCREF(branchrule)
4155 """Include a node selector.
4157 :param Nodesel nodesel: node selector
4158 :param name: name of node selector
4159 :param desc: description of node selector
4160 :param stdpriority: priority of the node selector in standard mode
4161 :param memsavepriority: priority of the node selector in memory saving mode
4167 stdpriority, memsavepriority,
4168 PyNodeselCopy, PyNodeselFree, PyNodeselInit, PyNodeselExit,
4169 PyNodeselInitsol, PyNodeselExitsol, PyNodeselSelect, PyNodeselComp,
4170 <SCIP_NODESELDATA*> nodesel))
4171 nodesel.model = <Model>weakref.proxy(self)
4174 def includeBenders(self, Benders benders, name, desc, priority=1, cutlp=True, cutpseudo=True, cutrelax=True,
4176 """Include a Benders' decomposition.
4179 benders -- the Benders decomposition
4181 desc -- the description
4182 priority -- priority of the Benders' decomposition
4183 cutlp -- should Benders' cuts be generated from LP solutions
4184 cutpseudo -- should Benders' cuts be generated from pseudo solutions
4185 cutrelax -- should Benders' cuts be generated from relaxation solutions
4186 shareaux -- should the Benders' decomposition share the auxiliary variables of the highest priority Benders' decomposition
4191 priority, cutlp, cutrelax, cutpseudo, shareaux,
4192 PyBendersCopy, PyBendersFree, PyBendersInit, PyBendersExit, PyBendersInitpre,
4193 PyBendersExitpre, PyBendersInitsol, PyBendersExitsol, PyBendersGetvar,
4194 PyBendersCreatesub, PyBendersPresubsolve, PyBendersSolvesubconvex,
4195 PyBendersSolvesub, PyBendersPostsolve, PyBendersFreesub,
4196 <SCIP_BENDERSDATA*>benders))
4197 cdef SCIP_BENDERS* scip_benders
4199 benders.model = <Model>weakref.proxy(self)
4201 benders._benders = scip_benders
4204 def includeBenderscut(self, Benders benders, Benderscut benderscut, name, desc, priority=1, islpcut=True):
4205 """ Include a Benders' decomposition cutting method
4208 benders -- the Benders' decomposition that this cutting method is attached to
4209 benderscut --- the Benders' decomposition cutting method
4211 desc -- the description
4212 priority -- priority of the Benders' decomposition
4213 islpcut -- is this cutting method suitable for generating cuts for convex relaxations?
4215 cdef SCIP_BENDERS* _benders
4217 _benders = benders._benders
4222 PyBenderscutCopy, PyBenderscutFree, PyBenderscutInit, PyBenderscutExit,
4223 PyBenderscutInitsol, PyBenderscutExitsol, PyBenderscutExec,
4224 <SCIP_BENDERSCUTDATA*>benderscut))
4226 cdef SCIP_BENDERSCUT* scip_benderscut
4228 benderscut.model = <Model>weakref.proxy(self)
4229 benderscut.benders = benders
4230 benderscut.name = name
4232 Py_INCREF(benderscut)
4236 """gets branching candidates for LP solution branching (fractional variables) along with solution values,
4237 fractionalities, and number of branching candidates; The number of branching candidates does NOT account
4238 for fractional implicit integer variables which should not be used for branching decisions. Fractional
4239 implicit integer variables are stored at the positions *nlpcands to *nlpcands + *nfracimplvars - 1
4240 branching rules should always select the branching candidate among the first npriolpcands of the candidate list
4242 :return tuple (lpcands, lpcandssol, lpcadsfrac, nlpcands, npriolpcands, nfracimplvars) where
4244 lpcands: list of variables of LP branching candidates
4245 lpcandssol: list of LP candidate solution values
4246 lpcandsfrac list of LP candidate fractionalities
4247 nlpcands: number of LP branching candidates
4248 npriolpcands: number of candidates with maximal priority
4249 nfracimplvars: number of fractional implicit integer variables
4254 cdef int npriolpcands
4255 cdef int nfracimplvars
4257 cdef SCIP_VAR** lpcands
4258 cdef SCIP_Real* lpcandssol
4259 cdef SCIP_Real* lpcandsfrac
4262 &nlpcands, &npriolpcands, &nfracimplvars))
4264 return ([Variable.create(lpcands[i])
for i
in range(nlpcands)], [lpcandssol[i]
for i
in range(nlpcands)],
4265 [lpcandsfrac[i]
for i
in range(nlpcands)], nlpcands, npriolpcands, nfracimplvars)
4268 """gets branching candidates for pseudo solution branching (non-fixed variables)
4269 along with the number of candidates.
4271 :return tuple (pseudocands, npseudocands, npriopseudocands) where
4273 pseudocands: list of variables of pseudo branching candidates
4274 npseudocands: number of pseudo branching candidates
4275 npriopseudocands: number of candidates with maximal priority
4278 cdef int npseudocands
4279 cdef int npriopseudocands
4281 cdef SCIP_VAR** pseudocands
4285 return ([Variable.create(pseudocands[i])
for i
in range(npseudocands)], npseudocands, npriopseudocands)
4288 """Branch on a non-continuous variable.
4290 :param variable: Variable to branch on
4291 :return: tuple(downchild, eqchild, upchild) of Nodes of the left, middle and right child. Middle child only exists
4292 if branch variable is integer (it is None otherwise)
4295 cdef SCIP_NODE* downchild
4296 cdef SCIP_NODE* eqchild
4297 cdef SCIP_NODE* upchild
4299 PY_SCIP_CALL(
SCIPbranchVar(self.
_scip, (<Variable>variable).scip_var, &downchild, &eqchild, &upchild))
4300 return Node.create(downchild), Node.create(eqchild), Node.create(upchild)
4304 """Branches on variable using a value which separates the domain of the variable.
4306 :param variable: Variable to branch on
4307 :param value: float, value to branch on
4308 :return: tuple(downchild, eqchild, upchild) of Nodes of the left, middle and right child. Middle child only exists
4309 if branch variable is integer (it is None otherwise)
4312 cdef SCIP_NODE* downchild
4313 cdef SCIP_NODE* eqchild
4314 cdef SCIP_NODE* upchild
4316 PY_SCIP_CALL(
SCIPbranchVarVal(self.
_scip, (<Variable>variable).scip_var, value, &downchild, &eqchild, &upchild))
4318 return Node.create(downchild), Node.create(eqchild), Node.create(upchild)
4321 """calculates the node selection priority for moving the given variable's LP value
4322 to the given target value;
4323 this node selection priority can be given to the SCIPcreateChild() call
4325 :param variable: variable on which the branching is applied
4326 :param branchdir: type of branching that was performed
4327 :param targetvalue: new value of the variable in the child node
4328 :return: node selection priority for moving the given variable's LP value to the given target value
4334 """Calculates an estimate for the objective of the best feasible solution
4335 contained in the subtree after applying the given branching;
4336 this estimate can be given to the SCIPcreateChild() call
4338 :param variable: Variable to compute the estimate for
4339 :param targetvalue: new value of the variable in the child node
4340 :return: objective estimate of the best solution in the subtree after applying the given branching
4346 """Create a child node of the focus node.
4348 :param nodeselprio: float, node selection priority of new node
4349 :param estimate: float, estimate for(transformed) objective value of best feasible solution in subtree
4350 :return: Node, the child which was created
4353 cdef SCIP_NODE* child
4355 return Node.create(child)
4359 """Initiates LP diving
4360 It allows the user to change the LP in several ways, solve, change again, etc, without affecting the actual LP that has. When endDive() is called,
4361 SCIP will undo all changes done and recover the LP it had before startDive
4366 """Quits probing and resets bounds and constraints to the focus node's environment"""
4370 """changes (column) variable's objective value in current dive"""
4374 """changes variable's current lb in current dive"""
4378 """changes variable's current ub in current dive"""
4382 """returns variable's current lb in current dive"""
4386 """returns variable's current ub in current dive"""
4390 """changes row lhs in current dive, change will be undone after diving
4391 ends, for permanent changes use SCIPchgRowLhs()
4396 """changes row rhs in current dive, change will be undone after diving
4397 ends, for permanent changes use SCIPchgRowLhs()
4402 """adds a row to the LP in current dive"""
4406 """solves the LP of the current dive no separation or pricing is applied
4407 no separation or pricing is applied
4408 :param itlim: maximal number of LP iterations to perform (Default value = -1, that is, no limit)
4409 returns two booleans:
4410 lperror -- if an unresolved lp error occured
4411 cutoff -- whether the LP was infeasible or the objective limit was reached
4413 cdef SCIP_Bool lperror
4414 cdef SCIP_Bool cutoff
4417 return lperror, cutoff
4420 """returns if the current node is already solved and only propagated again."""
4425 """Initiates probing, making methods SCIPnewProbingNode(), SCIPbacktrackProbing(), SCIPchgVarLbProbing(),
4426 SCIPchgVarUbProbing(), SCIPfixVarProbing(), SCIPpropagateProbing(), SCIPsolveProbingLP(), etc available
4431 """Quits probing and resets bounds and constraints to the focus node's environment"""
4435 """creates a new probing sub node, whose changes can be undone by backtracking to a higher node in the
4436 probing path with a call to backtrackProbing()
4441 """undoes all changes to the problem applied in probing up to the given probing depth
4442 :param probingdepth: probing depth of the node in the probing path that should be reactivated
4447 """returns the current probing depth"""
4451 """changes (column) variable's objective value during probing mode"""
4455 """changes the variable lower bound during probing mode
4457 :param Variable var: variable to change bound of
4458 :param lb: new lower bound (set to None for -infinity)
4465 """changes the variable upper bound during probing mode
4467 :param Variable var: variable to change bound of
4468 :param ub: new upper bound (set to None for +infinity)
4475 """Fixes a variable at the current probing node."""
4479 """returns whether the objective function has changed during probing mode"""
4483 """returns whether we are in probing mode; probing mode is activated via startProbing() and stopped via endProbing()"""
4487 """solves the LP at the current probing node (cannot be applied at preprocessing stage)
4488 no separation or pricing is applied
4489 :param itlim: maximal number of LP iterations to perform (Default value = -1, that is, no limit)
4490 returns two booleans:
4491 lperror -- if an unresolved lp error occured
4492 cutoff -- whether the LP was infeasible or the objective limit was reached
4494 cdef SCIP_Bool lperror
4495 cdef SCIP_Bool cutoff
4498 return lperror, cutoff
4501 """applies the cuts in the separation storage to the LP and clears the storage afterwards;
4502 this method can only be applied during probing; the user should resolve the probing LP afterwards
4503 in order to get a new solution
4505 cutoff -- whether an empty domain was created
4507 cdef SCIP_Bool cutoff
4513 """applies domain propagation on the probing sub problem, that was changed after SCIPstartProbing() was called;
4514 the propagated domains of the variables can be accessed with the usual bound accessing calls SCIPvarGetLbLocal()
4515 and SCIPvarGetUbLocal(); the propagation is only valid locally, i.e. the local bounds as well as the changed
4516 bounds due to SCIPchgVarLbProbing(), SCIPchgVarUbProbing(), and SCIPfixVarProbing() are used for propagation
4517 :param maxproprounds: maximal number of propagation rounds (Default value = -1, that is, no limit)
4519 cutoff -- whether the probing node can be cutoff
4520 ndomredsfound -- number of domain reductions found
4522 cdef SCIP_Bool cutoff
4523 cdef SCIP_Longint ndomredsfound
4526 return cutoff, ndomredsfound
4529 """Interrupt the solving process as soon as possible."""
4533 """Restarts the solving process as soon as possible."""
4539 """writes current LP to a file
4540 :param filename: file name (Default value = "LP.lp")
4542 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4543 locale.setlocale(locale.LC_NUMERIC,
"C")
4548 locale.setlocale(locale.LC_NUMERIC,user_locale)
4551 """Create a new primal solution in the transformed space.
4553 :param Heur heur: heuristic that found the solution (Default value = None)
4556 cdef SCIP_HEUR* _heur
4559 if isinstance(heur, Heur):
4565 solution = Solution.create(self.
_scip, _sol)
4569 """Create a partial primal solution, initialized to unknown values.
4570 :param Heur heur: heuristic that found the solution (Default value = None)
4573 cdef SCIP_HEUR* _heur
4576 if isinstance(heur, Heur):
4582 partialsolution = Solution.create(self.
_scip, _sol)
4583 return partialsolution
4586 """Create a new primal solution in the original space.
4588 :param Heur heur: heuristic that found the solution (Default value = None)
4591 cdef SCIP_HEUR* _heur
4594 if isinstance(heur, Heur):
4601 solution = Solution.create(self.
_scip, _sol)
4605 """Prints the best feasible primal solution."""
4606 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4607 locale.setlocale(locale.LC_NUMERIC,
"C")
4611 locale.setlocale(locale.LC_NUMERIC,user_locale)
4613 def printSol(self, Solution solution=None, write_zeros=False):
4614 """Print the given primal solution.
4617 solution -- solution to print
4618 write_zeros -- include variables that are set to zero
4621 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4622 locale.setlocale(locale.LC_NUMERIC,
"C")
4624 if solution
is None:
4629 locale.setlocale(locale.LC_NUMERIC,user_locale)
4632 """Write the best feasible primal solution to a file.
4635 filename -- name of the output file
4636 write_zeros -- include variables that are set to zero
4639 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4640 locale.setlocale(locale.LC_NUMERIC,
"C")
4644 with open(filename,
"w")
as f:
4645 cfile = fdopen(f.fileno(),
"w")
4648 locale.setlocale(locale.LC_NUMERIC,user_locale)
4651 """Write the best feasible primal solution for the transformed problem to a file.
4654 filename -- name of the output file
4655 write_zeros -- include variables that are set to zero
4657 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4658 locale.setlocale(locale.LC_NUMERIC,
"C")
4662 with open(filename,
"w")
as f:
4663 cfile = fdopen(f.fileno(),
"w")
4666 locale.setlocale(locale.LC_NUMERIC,user_locale)
4668 def writeSol(self, Solution solution, filename="origprob.sol", write_zeros=False):
4669 """Write the given primal solution to a file.
4672 solution -- solution to write
4673 filename -- name of the output file
4674 write_zeros -- include variables that are set to zero
4676 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4677 locale.setlocale(locale.LC_NUMERIC,
"C")
4681 with open(filename,
"w")
as f:
4682 cfile = fdopen(f.fileno(),
"w")
4685 locale.setlocale(locale.LC_NUMERIC,user_locale)
4687 def writeTransSol(self, Solution solution, filename="transprob.sol", write_zeros=False):
4688 """Write the given transformed primal solution to a file.
4691 solution -- transformed solution to write
4692 filename -- name of the output file
4693 write_zeros -- include variables that are set to zero
4695 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4696 locale.setlocale(locale.LC_NUMERIC,
"C")
4700 with open(filename,
"w")
as f:
4701 cfile = fdopen(f.fileno(),
"w")
4704 locale.setlocale(locale.LC_NUMERIC,user_locale)
4709 """Reads a given solution file, problem has to be transformed in advance.
4712 filename -- name of the input file
4714 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4715 locale.setlocale(locale.LC_NUMERIC,
"C")
4720 locale.setlocale(locale.LC_NUMERIC, user_locale)
4723 """Reads a given solution file.
4725 Solution is created but not added to storage/the model.
4726 Use 'addSol' OR 'trySol' to add it.
4729 filename -- name of the input file
4731 cdef SCIP_Bool partial
4732 cdef SCIP_Bool error
4733 cdef SCIP_Bool stored
4734 cdef Solution solution
4736 str_absfile = abspath(filename)
4740 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4741 locale.setlocale(locale.LC_NUMERIC,
"C")
4745 locale.setlocale(locale.LC_NUMERIC, user_locale)
4748 raise Exception(
"SCIP: reading solution from file " + str_absfile +
" failed!")
4753 """Set a variable in a solution.
4755 :param Solution solution: solution to be modified
4756 :param Variable var: variable in the solution
4757 :param val: value of the specified variable
4761 _sol = <SCIP_SOL*>solution.sol
4763 assert _sol != NULL,
"Cannot set value to a freed solution."
4766 def trySol(self, Solution solution, printreason=True, completely=False, checkbounds=True, checkintegrality=True, checklprows=True, free=True):
4767 """Check given primal solution for feasibility and try to add it to the storage.
4769 :param Solution solution: solution to store
4770 :param printreason: should all reasons of violations be printed? (Default value = True)
4771 :param completely: should all violation be checked? (Default value = False)
4772 :param checkbounds: should the bounds of the variables be checked? (Default value = True)
4773 :param checkintegrality: has integrality to be checked? (Default value = True)
4774 :param checklprows: have current LP rows (both local and global) to be checked? (Default value = True)
4775 :param free: should solution be freed? (Default value = True)
4778 cdef SCIP_Bool stored
4780 PY_SCIP_CALL(
SCIPtrySolFree(self.
_scip, &solution.sol, printreason, completely, checkbounds, checkintegrality, checklprows, &stored))
4782 PY_SCIP_CALL(
SCIPtrySol(self.
_scip, solution.sol, printreason, completely, checkbounds, checkintegrality, checklprows, &stored))
4785 def checkSol(self, Solution solution, printreason=True, completely=False, checkbounds=True, checkintegrality=True, checklprows=True, original=False):
4786 """Check given primal solution for feasibility without adding it to the storage.
4788 :param Solution solution: solution to store
4789 :param printreason: should all reasons of violations be printed? (Default value = True)
4790 :param completely: should all violation be checked? (Default value = False)
4791 :param checkbounds: should the bounds of the variables be checked? (Default value = True)
4792 :param checkintegrality: has integrality to be checked? (Default value = True)
4793 :param checklprows: have current LP rows (both local and global) to be checked? (Default value = True)
4794 :param original: must the solution be checked against the original problem (Default value = False)
4797 cdef SCIP_Bool feasible
4801 PY_SCIP_CALL(
SCIPcheckSol(self.
_scip, solution.sol, printreason, completely, checkbounds, checkintegrality, checklprows, &feasible))
4804 def addSol(self, Solution solution, free=True):
4805 """Try to add a solution to the storage.
4807 :param Solution solution: solution to store
4808 :param free: should solution be freed afterwards? (Default value = True)
4811 cdef SCIP_Bool stored
4819 """Free given solution
4821 :param Solution solution: solution to be freed
4827 """gets number of feasible primal solutions stored in the solution storage in case the problem is transformed;
4828 in case the problem stage is SCIP_STAGE_PROBLEM, the number of solution in the original solution candidate
4834 """gets number of feasible primal solutions found so far"""
4838 """gets number of feasible primal solutions respecting the objective limit found so far"""
4842 """gets number of feasible primal solutions found so far, that improved the primal bound at the time they were found"""
4846 """Retrieve list of all feasible primal solutions stored in the solution storage."""
4847 cdef SCIP_SOL** _sols
4853 for i
in range(nsols):
4854 sols.append(Solution.create(self.
_scip, _sols[i]))
4859 """Retrieve currently best known feasible primal solution."""
4864 """Retrieve the objective value of the solution.
4866 :param Solution sol: solution
4867 :param original: objective value in original space (Default value = True)
4871 sol = Solution.create(self.
_scip, NULL)
4873 sol._checkStage(
"getSolObjVal")
4883 """Get clock time, when this solution was found.
4885 :param Solution sol: solution
4891 """Retrieve the objective value of value of best solution.
4893 :param original: objective value in original space (Default value = True)
4897 if self.
getStage() != SCIP_STAGE_SOLVING:
4898 raise Warning(
"Without a solution, method can only be called in stage SOLVING.")
4903 min_stage_requirement = SCIP_STAGE_PROBLEM
4905 min_stage_requirement = SCIP_STAGE_TRANSFORMING
4907 if not self.
getStage() >= min_stage_requirement:
4908 raise Warning(
"method cannot be called in stage %i." % self.
getStage)
4913 """Retrieve value of given variable or expression in the given solution or in
4914 the LP/pseudo solution if sol == None
4916 :param Solution sol: solution
4917 :param Expr expr: polynomial expression to query the value of
4919 Note: a variable is also an expression
4922 if sol ==
None and isinstance(expr, Variable):
4923 var = <Variable> expr
4926 sol = Solution.create(self.
_scip, NULL)
4930 """Retrieve the value of the given variable or expression in the best known solution.
4931 Can only be called after solving is completed.
4933 :param Expr expr: polynomial expression to query the value of
4935 Note: a variable is also an expression
4937 stage_check =
SCIPgetStage(self.
_scip)
not in [SCIP_STAGE_INIT, SCIP_STAGE_FREE]
4940 raise Warning(
"Method cannot be called in stage ", self.
getStage())
4946 Returns whether a primal ray is stored that proves unboundedness of the LP relaxation
4952 Gets value of given variable in primal ray causing unboundedness of the LP relaxation
4960 Gets primal ray causing unboundedness of the LP relaxation
4968 for i
in range(_nvars):
4974 """Retrieve the best primal bound."""
4978 """Retrieve the best dual bound."""
4982 """Retrieve the best root dual bound."""
4986 """Write the name of the variable to the std out.
4988 :param Variable var: variable
4991 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
4992 locale.setlocale(locale.LC_NUMERIC,
"C")
4996 locale.setlocale(locale.LC_NUMERIC,user_locale)
4999 """Retrieve current SCIP stage"""
5003 """Returns name of current stage as string"""
5008 def _getStageNames(self):
5009 """Gets names of stages"""
5010 for name
in dir(PY_SCIP_STAGE):
5011 attr = getattr(PY_SCIP_STAGE, name)
5012 if isinstance(attr, int):
5013 StageNames[attr] = name
5016 """Retrieve solution status."""
5018 if stat == SCIP_STATUS_OPTIMAL:
5020 elif stat == SCIP_STATUS_TIMELIMIT:
5022 elif stat == SCIP_STATUS_INFEASIBLE:
5024 elif stat == SCIP_STATUS_UNBOUNDED:
5026 elif stat == SCIP_STATUS_USERINTERRUPT:
5027 return "userinterrupt"
5028 elif stat == SCIP_STATUS_INFORUNBD:
5030 elif stat == SCIP_STATUS_NODELIMIT:
5032 elif stat == SCIP_STATUS_TOTALNODELIMIT:
5033 return "totalnodelimit"
5034 elif stat == SCIP_STATUS_STALLNODELIMIT:
5035 return "stallnodelimit"
5036 elif stat == SCIP_STATUS_GAPLIMIT:
5038 elif stat == SCIP_STATUS_MEMLIMIT:
5040 elif stat == SCIP_STATUS_SOLLIMIT:
5042 elif stat == SCIP_STATUS_BESTSOLLIMIT:
5043 return "bestsollimit"
5044 elif stat == SCIP_STATUS_RESTARTLIMIT:
5045 return "restartlimit"
5046 elif stat == SCIP_STATUS_PRIMALLIMIT:
5047 return "primallimit"
5048 elif stat == SCIP_STATUS_DUALLIMIT:
5054 """Retrieve objective sense."""
5056 if sense == SCIP_OBJSENSE_MAXIMIZE:
5058 elif sense == SCIP_OBJSENSE_MINIMIZE:
5064 """catches a global (not variable or row dependent) event"""
5065 cdef SCIP_EVENTHDLR* _eventhdlr
5066 if isinstance(eventhdlr, Eventhdlr):
5070 raise Warning(
"event handler not found")
5076 """drops a global event (stops to track event)"""
5077 cdef SCIP_EVENTHDLR* _eventhdlr
5078 if isinstance(eventhdlr, Eventhdlr):
5082 raise Warning(
"event handler not found")
5088 """catches an objective value or domain change event on the given transformed variable"""
5089 cdef SCIP_EVENTHDLR* _eventhdlr
5090 if isinstance(eventhdlr, Eventhdlr):
5094 raise Warning(
"event handler not found")
5098 """drops an objective value or domain change event (stops to track event) on the given transformed variable"""
5099 cdef SCIP_EVENTHDLR* _eventhdlr
5100 if isinstance(eventhdlr, Eventhdlr):
5104 raise Warning(
"event handler not found")
5108 """catches a row coefficient, constant, or side change event on the given row"""
5109 cdef SCIP_EVENTHDLR* _eventhdlr
5110 if isinstance(eventhdlr, Eventhdlr):
5114 raise Warning(
"event handler not found")
5118 """drops a row coefficient, constant, or side change event (stops to track event) on the given row"""
5119 cdef SCIP_EVENTHDLR* _eventhdlr
5120 if isinstance(eventhdlr, Eventhdlr):
5124 raise Warning(
"event handler not found")
5130 """Print statistics."""
5131 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
5132 locale.setlocale(locale.LC_NUMERIC,
"C")
5136 locale.setlocale(locale.LC_NUMERIC,user_locale)
5139 """Write statistics to a file.
5142 filename -- name of the output file
5144 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
5145 locale.setlocale(locale.LC_NUMERIC,
"C")
5149 with open(filename,
"w")
as f:
5150 cfile = fdopen(f.fileno(),
"w")
5153 locale.setlocale(locale.LC_NUMERIC,user_locale)
5157 Given a .stats file of a solved model, reads it and returns an instance of the Statistics class
5158 holding some statistics.
5161 filename -- name of the input file
5164 file = open(filename)
5165 data = file.readlines()
5167 assert "problem is solved" in data[0],
"readStatistics can only be called if the problem was solved"
5168 available_stats = [
"Total Time",
"solving",
"presolving",
"reading",
"copying",
5169 "Problem name",
"Variables",
"Constraints",
"number of runs",
5170 "nodes",
"Solutions found",
"First Solution",
"Primal Bound",
5171 "Dual Bound",
"Gap",
"primal-dual"]
5174 for i, line
in enumerate(data):
5175 split_line = line.split(
":")
5176 split_line[1] = split_line[1][:-1]
5177 stat_name = split_line[0].strip()
5179 if seen_cons == 2
and stat_name ==
"Constraints":
5182 if stat_name
in available_stats:
5183 cur_stat = split_line[0].strip()
5184 relevant_value = split_line[1].strip()
5186 if stat_name ==
"Variables":
5187 relevant_value = relevant_value[:-1]
5189 split_var = relevant_value.split(
"(")
5190 var_stats[
"total"] = int(split_var[0])
5191 split_var = split_var[1].split(
",")
5193 for var_type
in split_var:
5194 split_result = var_type.strip().split(
" ")
5195 var_stats[split_result[1]] = int(split_result[0])
5197 if "Original" in data[i-2]:
5198 result[
"Variables"] = var_stats
5200 result[
"Presolved Variables"] = var_stats
5204 if stat_name ==
"Constraints":
5207 split_con = relevant_value.split(
",")
5208 for con_type
in split_con:
5209 split_result = con_type.strip().split(
" ")
5210 con_stats[split_result[1]] = int(split_result[0])
5212 if "Original" in data[i-3]:
5213 result[
"Constraints"] = con_stats
5215 result[
"Presolved Constraints"] = con_stats
5218 relevant_value = relevant_value.split(
" ")[0]
5219 if stat_name ==
"Problem name":
5220 if "Original" in data[i-1]:
5221 result[
"Problem name"] = relevant_value
5223 result[
"Presolved Problem name"] = relevant_value
5226 if stat_name ==
"Gap":
5227 result[
"Gap (%)"] = float(relevant_value[:-1])
5230 if _is_number(relevant_value):
5231 result[cur_stat] = float(relevant_value)
5233 result[cur_stat] = relevant_value
5236 treated_keys = {
"Total Time":
"total_time",
"solving":
"solving_time",
"presolving":
"presolving_time",
"reading":
"reading_time",
"copying":
"copying_time",
5237 "Problem name":
"problem_name",
"Presolved Problem name":
"presolved_problem_name",
"Variables":
"_variables",
5238 "Presolved Variables":
"_presolved_variables",
"Constraints":
"_constraints",
"Presolved Constraints":
"_presolved_constraints",
5239 "number of runs":
"n_runs",
"nodes":
"n_nodes",
"Solutions found":
"n_solutions_found",
"First Solution":
"first_solution",
5240 "Primal Bound":
"primal_bound",
"Dual Bound":
"dual_bound",
"Gap (%)":
"gap",
"primal-dual":
"primal_dual_integral"}
5241 treated_result = dict((treated_keys[key], value)
for (key, value)
in result.items())
5247 """gets total number of LPs solved so far"""
5255 :param quiet: hide output? (Default value = True)
5263 """Send output to python instead of terminal."""
5265 cdef SCIP_MESSAGEHDLR *myMessageHandler
5267 PY_SCIP_CALL(SCIPmessagehdlrCreate(&myMessageHandler,
False, NULL,
False, relayMessage, relayMessage, relayMessage, NULL, NULL))
5269 SCIPmessageSetErrorPrinting(relayErrorMessage, NULL)
5272 """sets the log file name for the currently installed message handler
5273 :param path: name of log file, or None (no log)
5284 """Set a boolean-valued parameter.
5286 :param name: name of parameter
5287 :param value: value of parameter
5294 """Set an int-valued parameter.
5296 :param name: name of parameter
5297 :param value: value of parameter
5304 """Set a long-valued parameter.
5306 :param name: name of parameter
5307 :param value: value of parameter
5314 """Set a real-valued parameter.
5316 :param name: name of parameter
5317 :param value: value of parameter
5324 """Set a char-valued parameter.
5326 :param name: name of parameter
5327 :param value: value of parameter
5334 """Set a string-valued parameter.
5336 :param name: name of parameter
5337 :param value: value of parameter
5345 """Set a parameter with value in int, bool, real, long, char or str.
5347 :param name: name of parameter
5348 :param value: value of parameter
5350 cdef SCIP_PARAM* param
5356 raise KeyError(
"Not a valid parameter name")
5358 paramtype = SCIPparamGetType(param)
5360 if paramtype == SCIP_PARAMTYPE_BOOL:
5362 elif paramtype == SCIP_PARAMTYPE_INT:
5364 elif paramtype == SCIP_PARAMTYPE_LONGINT:
5366 elif paramtype == SCIP_PARAMTYPE_REAL:
5368 elif paramtype == SCIP_PARAMTYPE_CHAR:
5370 elif paramtype == SCIP_PARAMTYPE_STRING:
5376 """Get the value of a parameter of type
5377 int, bool, real, long, char or str.
5379 :param name: name of parameter
5381 cdef SCIP_PARAM* param
5387 raise KeyError(
"Not a valid parameter name")
5389 paramtype = SCIPparamGetType(param)
5391 if paramtype == SCIP_PARAMTYPE_BOOL:
5392 return SCIPparamGetBool(param)
5393 elif paramtype == SCIP_PARAMTYPE_INT:
5394 return SCIPparamGetInt(param)
5395 elif paramtype == SCIP_PARAMTYPE_LONGINT:
5396 return SCIPparamGetLongint(param)
5397 elif paramtype == SCIP_PARAMTYPE_REAL:
5398 return SCIPparamGetReal(param)
5399 elif paramtype == SCIP_PARAMTYPE_CHAR:
5400 return chr(SCIPparamGetChar(param))
5401 elif paramtype == SCIP_PARAMTYPE_STRING:
5402 return SCIPparamGetString(param).decode(
'utf-8')
5405 """Gets the values of all parameters as a dict mapping parameter names
5407 cdef SCIP_PARAM** params
5412 name = SCIPparamGetName(params[i]).decode(
'utf-8')
5417 """Sets multiple parameters at once.
5419 :param params: dict mapping parameter names to their values.
5421 for name, value
in params.items():
5425 """Read an external parameter file.
5427 :param file: file to be read
5432 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
5433 locale.setlocale(locale.LC_NUMERIC,
"C")
5437 locale.setlocale(locale.LC_NUMERIC, user_locale)
5439 def writeParams(self, filename='param.set', comments=True, onlychanged=True, verbose=True):
5440 """Write parameter settings to an external file.
5442 :param filename: file to be written (Default value = 'param.set')
5443 :param comments: write parameter descriptions as comments? (Default value = True)
5444 :param onlychanged: write only modified parameters (Default value = True)
5445 :param verbose: indicates whether a success message should be printed
5447 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
5448 locale.setlocale(locale.LC_NUMERIC,
"C")
5450 str_absfile = abspath(filename)
5455 print(
'wrote parameter settings to file ' + str_absfile)
5457 locale.setlocale(locale.LC_NUMERIC,user_locale)
5460 """Reset parameter setting to its default value
5462 :param name: parameter to reset
5469 """Reset parameter settings to their default values"""
5473 """Set emphasis settings
5475 :param paraemphasis: emphasis to set
5476 :param quiet: hide output? (Default value = True)
5482 """Read a problem instance from an external file.
5484 :param filename: problem file name
5485 :param extension: specify file extension/type (Default value = None)
5488 user_locale = locale.getlocale(category=locale.LC_NUMERIC)
5489 locale.setlocale(locale.LC_NUMERIC,
"C")
5492 if extension
is None:
5498 locale.setlocale(locale.LC_NUMERIC, user_locale)
5503 """Counts the number of feasible points of problem."""
5507 """Get number of currently available readers."""
5511 """Get number of feasible solution."""
5512 cdef SCIP_Bool valid
5513 cdef SCIP_Longint nsols
5517 print(
'total number of solutions found is not valid!')
5521 """Sets SCIP parameters such that a valid counting process is possible."""
5525 """Frees all solution process data and prepares for reoptimization"""
5529 """Establish the objective function as a linear expression.
5531 :param coeffs: the coefficients
5532 :param sense: the objective sense (Default value = 'minimize')
5536 cdef SCIP_OBJSENSE objsense
5538 if sense ==
"minimize":
5539 objsense = SCIP_OBJSENSE_MINIMIZE
5540 elif sense ==
"maximize":
5541 objsense = SCIP_OBJSENSE_MAXIMIZE
5543 raise Warning(
"unrecognized optimization sense: %s" % sense)
5545 assert isinstance(coeffs, Expr),
"given coefficients are not Expr but %s" % coeffs.__class__.__name__
5547 if coeffs.degree() > 1:
5548 raise ValueError(
"Nonlinear objective functions are not supported!")
5549 if coeffs[CONST] != 0.0:
5550 raise ValueError(
"Constant offsets in objective are not supported!")
5552 cdef SCIP_VAR** _vars
5556 _coeffs = <SCIP_Real*> malloc(_nvars * sizeof(SCIP_Real))
5558 for i
in range(_nvars):
5561 for term, coef
in coeffs.terms.items():
5564 assert len(term) == 1
5565 var = <Variable>term[0]
5566 for i
in range(_nvars):
5567 if _vars[i] == var.scip_var:
5575 """Sets the branch priority of the variable.
5576 Variables with higher branch priority are always preferred to variables with lower priority in selection of branching variable.
5578 :param Variable var: variable to change priority of
5579 :param priority: the new priority of the variable (the default branching priority is 0)
5581 assert isinstance(var, Variable),
"The given variable is not a pyvar, but %s" % var.__class__.__name__
5585 """Start strong branching. Needs to be called before any strong branching. Must also later end strong branching.
5586 TODO: Propagation option has currently been disabled via Python.
5587 If propagation is enabled then strong branching is not done on the LP, but on additionally created nodes (has some overhead)"""
5592 """End strong branching. Needs to be called if startStrongBranching was called previously.
5593 Between these calls the user can access all strong branching functionality. """
5598 """Get the results of the last strong branching call on this variable (potentially was called
5601 down - The dual bound of the LP after branching down on the variable
5602 up - The dual bound of the LP after branchign up on the variable
5603 downvalid - Whether down stores a valid dual bound or is NULL
5604 upvalid - Whether up stores a valid dual bound or is NULL
5605 solval - The solution value of the variable at the last strong branching call
5606 lpobjval - The LP objective value at the time of the last strong branching call
5608 :param Variable var: variable to get the previous strong branching information from
5613 cdef SCIP_Real solval
5614 cdef SCIP_Real lpobjval
5615 cdef SCIP_Bool downvalid
5616 cdef SCIP_Bool upvalid
5620 return down, up, downvalid, upvalid, solval, lpobjval
5623 """Get the node number from the last time strong branching was called on the variable
5625 :param Variable var: variable to get the previous strong branching node from
5628 cdef SCIP_Longint node_num
5634 """ Strong branches and gets information on column variable.
5636 :param Variable var: Variable to get strong branching information on
5637 :param itlim: LP iteration limit for total strong branching calls
5638 :param idempotent: Should SCIP's state remain the same after the call?
5639 :param integral: Boolean on whether the variable is currently integer.
5644 cdef SCIP_Bool downvalid
5645 cdef SCIP_Bool upvalid
5646 cdef SCIP_Bool downinf
5647 cdef SCIP_Bool upinf
5648 cdef SCIP_Bool downconflict
5649 cdef SCIP_Bool upconflict
5650 cdef SCIP_Bool lperror
5654 &upvalid, &downinf, &upinf, &downconflict, &upconflict, &lperror))
5657 &upvalid, &downinf, &upinf, &downconflict, &upconflict, &lperror))
5659 return down, up, downvalid, upvalid, downinf, upinf, downconflict, upconflict, lperror
5662 """Updates the pseudo costs of the given variable and the global pseudo costs after a change of valdelta
5663 in the variable's solution value and resulting change of objdelta in the LP's objective value.
5664 Update is ignored if objdelts is infinite. Weight is in range (0, 1], and affects how it updates
5665 the global weighted sum.
5667 :param Variable var: Variable whos pseudo cost will be updated
5668 :param valdelta: The change in variable value (e.g. the fractional amount removed or added by branching)
5669 :param objdelta: The change in objective value of the LP after valdelta change of the variable
5670 :param weight: the weight in range (0,1] of how the update affects the stored weighted sum.
5676 """Calculates the branching score out of the gain predictions for a branching with
5677 arbitrary many children.
5679 :param Variable var: variable to calculate the score for
5680 :param gains: list of gains for each child.
5683 assert isinstance(gains, list)
5684 nchildren = len(gains)
5686 cdef int _nchildren = nchildren
5687 _gains = <SCIP_Real*> malloc(_nchildren * sizeof(SCIP_Real))
5688 for i
in range(_nchildren):
5689 _gains[i] = gains[i]
5698 """Get an estimation of the final tree size """
5699 return SCIPgetTreesizeEstimation(self.
_scip)
5703 static_only=False, suppress_warnings=False):
5704 """This function generates the bipartite graph representation of an LP, which was first used in
5705 the following paper:
5706 @inproceedings{conf/nips/GasseCFCL19,
5707 title={Exact Combinatorial Optimization with Graph Convolutional Neural Networks},
5708 author={Gasse, Maxime and Chételat, Didier and Ferroni, Nicola and Charlin, Laurent and Lodi, Andrea},
5709 booktitle={Advances in Neural Information Processing Systems 32},
5712 The exact features have been modified compared to the original implementation.
5713 This function is used mainly in the machine learning community for MIP.
5714 A user can only call it during the solving process, when there is an LP object. This means calling it
5715 from some user defined plugin on the Python side.
5716 An example plugin is a branching rule or an event handler, which is exclusively created to call this function.
5717 The user must then make certain to return the appropriate SCIP_RESULT (e.g. DIDNOTRUN)
5719 :param prev_col_features: The list of column features previously returned by this function
5720 :param prev_edge_features: The list of edge features previously returned by this function
5721 :param prev_row_features: The list of row features previously returned by this function
5722 :param static_only: Whether exclusively static features should be generated
5723 :param suppress_warnings: Whether warnings should be suppressed
5726 cdef SCIP* scip = self.
_scip
5727 cdef int i, j, k, col_i
5728 cdef SCIP_VARTYPE vtype
5729 cdef SCIP_Real sim, prod
5733 raise Warning(
"This functionality can only been called in SCIP_STAGE SOLVING. The row and column"
5734 "information is then accessible")
5742 col_feature_map = {
"continuous": 0,
"binary": 1,
"integer": 2,
"implicit_integer": 3,
"obj_coef": 4}
5745 col_feature_map = {
"continuous": 0,
"binary": 1,
"integer": 2,
"implicit_integer": 3,
"obj_coef": 4,
5746 "has_lb": 5,
"has_ub": 6,
"sol_at_lb": 7,
"sol_at_ub": 8,
"sol_val": 9,
"sol_frac": 10,
5747 "red_cost": 11,
"basis_lower": 12,
"basis_basic": 13,
"basis_upper": 14,
5748 "basis_zero": 15,
"best_incumbent_val": 16,
"avg_incumbent_val": 17,
"age": 18}
5750 if prev_col_features
is None:
5751 col_features = [[0
for _
in range(n_col_features)]
for _
in range(ncols)]
5753 assert len(prev_col_features) > 0,
"Previous column features is empty"
5754 col_features = prev_col_features
5755 if len(prev_col_features) != ncols:
5756 if not suppress_warnings:
5757 raise Warning(f
"The number of columns has changed. Previous column data being ignored")
5759 col_features = [[0
for _
in range(n_col_features)]
for _
in range(ncols)]
5760 prev_col_features =
None
5761 if len(prev_col_features[0]) != n_col_features:
5762 raise Warning(f
"Dimension mismatch in provided previous features and new features:"
5763 f
"{len(prev_col_features[0])} != {n_col_features}")
5767 cdef SCIP_Real lb, ub, solval
5768 cdef SCIP_BASESTAT basis_status
5769 for i
in range(ncols):
5778 if prev_col_features
is None:
5781 if vtype == SCIP_VARTYPE_BINARY:
5782 col_features[col_i][col_feature_map[
"binary"]] = 1
5783 elif vtype == SCIP_VARTYPE_INTEGER:
5784 col_features[col_i][col_feature_map[
"integer"]] = 1
5785 elif vtype == SCIP_VARTYPE_CONTINUOUS:
5786 col_features[col_i][col_feature_map[
"continuous"]] = 1
5787 elif vtype == SCIP_VARTYPE_IMPLINT:
5788 col_features[col_i][col_feature_map[
"implicit_integer"]] = 1
5790 col_features[col_i][col_feature_map[
"obj_coef"]] =
SCIPcolGetObj(cols[i])
5796 col_features[col_i][col_feature_map[
"has_lb"]] = 1
5800 col_features[col_i][col_feature_map[
"has_ub"]] = 1
5804 if basis_status == SCIP_BASESTAT_LOWER:
5805 col_features[col_i][col_feature_map[
"basis_lower"]] = 1
5806 elif basis_status == SCIP_BASESTAT_BASIC:
5807 col_features[col_i][col_feature_map[
"basis_basic"]] = 1
5808 elif basis_status == SCIP_BASESTAT_UPPER:
5809 col_features[col_i][col_feature_map[
"basis_upper"]] = 1
5810 elif basis_status == SCIP_BASESTAT_ZERO:
5811 col_features[col_i][col_feature_map[
"basis_zero"]] = 1
5814 col_features[col_i][col_feature_map[
"red_cost"]] =
SCIPgetColRedcost(scip, cols[i])
5817 col_features[col_i][col_feature_map[
"age"]] =
SCIPcolGetAge(cols[i])
5820 col_features[col_i][col_feature_map[
"sol_val"]] = solval
5821 col_features[col_i][col_feature_map[
"sol_frac"]] =
SCIPfeasFrac(scip, solval)
5822 col_features[col_i][col_feature_map[
"sol_at_lb"]] = int(
SCIPisEQ(scip, solval, lb))
5823 col_features[col_i][col_feature_map[
"sol_at_ub"]] = int(
SCIPisEQ(scip, solval, ub))
5827 col_features[col_i][col_feature_map[
"best_incumbent_val"]] =
None
5828 col_features[col_i][col_feature_map[
"avg_incumbent_val"]] =
None
5830 col_features[col_i][col_feature_map[
"best_incumbent_val"]] =
SCIPgetSolVal(scip, sol, var)
5831 col_features[col_i][col_feature_map[
"avg_incumbent_val"]] =
SCIPvarGetAvgSol(var)
5839 row_feature_map = {
"has_lhs": 0,
"has_rhs": 1,
"n_non_zeros": 2,
"obj_cosine": 3,
"bias": 4,
"norm": 5}
5842 row_feature_map = {
"has_lhs": 0,
"has_rhs": 1,
"n_non_zeros": 2,
"obj_cosine": 3,
"bias": 4,
"norm": 5,
5843 "sol_at_lhs": 6,
"sol_at_rhs": 7,
"dual_sol": 8,
"age": 9,
5844 "basis_lower": 10,
"basis_basic": 11,
"basis_upper": 12,
"basis_zero": 13}
5846 if prev_row_features
is None:
5847 row_features = [[0
for _
in range(n_row_features)]
for _
in range(nrows)]
5849 assert len(prev_row_features) > 0,
"Previous row features is empty"
5850 row_features = prev_row_features
5851 if len(prev_row_features) != nrows:
5852 if not suppress_warnings:
5853 raise Warning(f
"The number of rows has changed. Previous row data being ignored")
5855 row_features = [[0
for _
in range(n_row_features)]
for _
in range(nrows)]
5856 prev_row_features =
None
5857 if len(prev_row_features[0]) != n_row_features:
5858 raise Warning(f
"Dimension mismatch in provided previous features and new features:"
5859 f
"{len(prev_row_features[0])} != {n_row_features}")
5862 cdef SCIP_Real lhs, rhs, cst
5863 for i
in range(nrows):
5871 if prev_row_features
is None:
5874 nnzrs += row_features[i][row_feature_map[
"n_non_zeros"]]
5878 row_features[i][row_feature_map[
"has_lhs"]] = 1
5882 row_features[i][row_feature_map[
"has_rhs"]] = 1
5885 row_features[i][row_feature_map[
"bias"]] = cst
5891 row_features[i][row_feature_map[
"norm"]] =
SCIProwGetNorm(rows[i])
5900 if basis_status == SCIP_BASESTAT_LOWER:
5901 row_features[i][row_feature_map[
"basis_lower"]] = 1
5902 elif basis_status == SCIP_BASESTAT_BASIC:
5903 row_features[i][row_feature_map[
"basis_basic"]] = 1
5904 elif basis_status == SCIP_BASESTAT_UPPER:
5905 row_features[i][row_feature_map[
"basis_upper"]] = 1
5906 elif basis_status == SCIP_BASESTAT_ZERO:
5907 row_features[i][row_feature_map[
"basis_zero"]] = 1
5910 row_features[i][row_feature_map[
"age"]] =
SCIProwGetAge(rows[i])
5913 row_features[i][row_feature_map[
"sol_at_lhs"]] = int(
SCIPisEQ(scip, activity, lhs))
5914 row_features[i][row_feature_map[
"sol_at_rhs"]] = int(
SCIPisEQ(scip, activity, rhs))
5917 cdef SCIP_COL** row_cols
5918 cdef SCIP_Real * row_vals
5920 edge_feature_map = {
"col_idx": 0,
"row_idx": 1,
"coef": 2}
5921 if prev_edge_features
is None:
5922 edge_features = [[0
for _
in range(n_edge_features)]
for _
in range(nnzrs)]
5924 for i
in range(nrows):
5928 for k
in range(row_features[i][row_feature_map[
"n_non_zeros"]]):
5929 edge_features[j][edge_feature_map[
"col_idx"]] =
SCIPcolGetLPPos(row_cols[k])
5930 edge_features[j][edge_feature_map[
"row_idx"]] = i
5931 edge_features[j][edge_feature_map[
"coef"]] = row_vals[k]
5934 assert len(prev_edge_features) > 0,
"Previous edge features is empty"
5935 edge_features = prev_edge_features
5936 if len(prev_edge_features) != nnzrs:
5937 if not suppress_warnings:
5938 raise Warning(f
"The number of coefficients in the LP has changed. Previous edge data being ignored")
5940 edge_features = [[0
for _
in range(3)]
for _
in range(nnzrs)]
5941 prev_edge_features =
None
5942 if len(prev_edge_features[0]) != 3:
5943 raise Warning(f
"Dimension mismatch in provided previous features and new features:"
5944 f
"{len(prev_edge_features[0])} != 3")
5947 return (col_features, edge_features, row_features,
5948 {
"col": col_feature_map,
"edge": edge_feature_map,
"row": row_feature_map})
5956 Total time since model was created
5958 Time spent solving the problem
5959 presolving_time: float
5960 Time spent on presolving
5962 Time spent on reading
5964 Time spent on copying
5967 presolved_problem_name: str
5968 Name of presolved problem
5970 The number of nodes explored in the branch-and-bound tree
5971 n_solutions_found: int
5972 number of found solutions
5973 first_solution: float
5974 objective value of first found solution
5976 The best primal bound found
5978 The best dual bound found
5980 The gap between the primal and dual bounds
5981 primal_dual_integral: float
5982 The primal-dual integral
5984 number of variables in the model
5986 number of binary variables in the model
5988 number of integer variables in the model
5989 n_implicit_integer_vars: int
5990 number of implicit integer variables in the model
5991 n_continuous_vars: int
5992 number of continuous variables in the model
5993 n_presolved_vars: int
5994 number of variables in the presolved model
5995 n_presolved_continuous_vars: int
5996 number of continuous variables in the presolved model
5997 n_presolved_binary_vars: int
5998 number of binary variables in the presolved model
5999 n_presolved_integer_vars: int
6000 number of integer variables in the presolved model
6001 n_presolved_implicit_integer_vars: int
6002 number of implicit integer variables in the presolved model
6004 number of maximal constraints in the model
6006 number of initial constraints in the presolved model
6007 n_presolved_maximal_cons: int
6008 number of maximal constraints in the presolved model
6009 n_presolved_conss: int
6010 number of initial constraints in the model
6015 presolving_time: float
6019 presolved_problem_name: str
6021 _presolved_variables: dict
6023 _presolved_constraints: dict
6026 n_solutions_found: int
6027 first_solution: float
6031 primal_dual_integral: float
6037 return self._variables[
"total"]
6041 return self._variables[
"binary"]
6045 return self._variables[
"integer"]
6049 return self._variables[
"implicit"]
6053 return self._variables[
"continuous"]
6057 return self._presolved_variables[
"total"]
6061 return self._presolved_variables[
"binary"]
6065 return self._presolved_variables[
"integer"]
6069 return self._presolved_variables[
"implicit"]
6073 return self._presolved_variables[
"continuous"]
6077 return self._constraints[
"initial"]
6081 return self._constraints[
"maximal"]
6085 return self._presolved_constraints[
"initial"]
6089 return self._presolved_constraints[
"maximal"]
6093 return BMSgetMemoryUsed() == 0
6096 BMScheckEmptyMemory()