PySCIPOpt 5.7.1__cp39-cp39-win_amd64.whl → 6.1.0__cp39-cp39-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyscipopt/__init__.py +8 -6
- pyscipopt/_version.py +1 -1
- pyscipopt/benders.pxi +2 -4
- pyscipopt/benderscut.pxi +1 -2
- pyscipopt/conshdlr.pxi +5 -10
- pyscipopt/event.pxi +1 -2
- pyscipopt/expr.pxi +185 -42
- pyscipopt/heuristic.pxi +1 -2
- pyscipopt/iisfinder.pxi +37 -0
- pyscipopt/matrix.pxi +236 -93
- pyscipopt/presol.pxi +1 -2
- pyscipopt/propagator.pxi +2 -4
- pyscipopt/reader.pxi +8 -6
- pyscipopt/recipes/getLocalConss.py +1 -1
- pyscipopt/recipes/infeasibilities.py +1 -1
- pyscipopt/recipes/primal_dual_evolution.py +8 -15
- pyscipopt/recipes/structured_optimization_trace.py +37 -0
- pyscipopt/relax.pxi +2 -4
- pyscipopt/scip.cp39-win_amd64.pyd +0 -0
- pyscipopt/scip.pxd +141 -13
- pyscipopt/scip.pxi +913 -278
- pyscipopt/scip.pyi +1760 -843
- {pyscipopt-5.7.1.dist-info → pyscipopt-6.1.0.dist-info}/DELVEWHEEL +2 -2
- {pyscipopt-5.7.1.dist-info → pyscipopt-6.1.0.dist-info}/METADATA +22 -2
- pyscipopt-6.1.0.dist-info/RECORD +49 -0
- {pyscipopt-5.7.1.dist-info → pyscipopt-6.1.0.dist-info}/WHEEL +1 -1
- pyscipopt-6.1.0.dist-info/licenses/LICENSE +10 -0
- pyscipopt.libs/{.load-order-pyscipopt-5.7.1 → .load-order-pyscipopt-6.1.0} +4 -4
- pyscipopt.libs/{libscip-816134cbcb1f780ba53e6a867561d578.dll → libscip-1a4d5a21deba20278cffa088924e6323.dll} +0 -0
- pyscipopt-5.7.1.dist-info/RECORD +0 -47
- pyscipopt-5.7.1.dist-info/licenses/LICENSE +0 -21
- {pyscipopt-5.7.1.dist-info → pyscipopt-6.1.0.dist-info}/top_level.txt +0 -0
pyscipopt/scip.pxi
CHANGED
|
@@ -31,6 +31,7 @@ include "conshdlr.pxi"
|
|
|
31
31
|
include "cutsel.pxi"
|
|
32
32
|
include "event.pxi"
|
|
33
33
|
include "heuristic.pxi"
|
|
34
|
+
include "iisfinder.pxi"
|
|
34
35
|
include "presol.pxi"
|
|
35
36
|
include "pricer.pxi"
|
|
36
37
|
include "propagator.pxi"
|
|
@@ -41,9 +42,9 @@ include "nodesel.pxi"
|
|
|
41
42
|
include "matrix.pxi"
|
|
42
43
|
|
|
43
44
|
# recommended SCIP version; major version is required
|
|
44
|
-
MAJOR =
|
|
45
|
-
MINOR =
|
|
46
|
-
PATCH =
|
|
45
|
+
MAJOR = 10
|
|
46
|
+
MINOR = 0
|
|
47
|
+
PATCH = 0
|
|
47
48
|
|
|
48
49
|
# for external user functions use def; for functions used only inside the interface (starting with _) use cdef
|
|
49
50
|
# todo: check whether this is currently done like this
|
|
@@ -207,65 +208,72 @@ cdef class PY_SCIP_HEURTIMING:
|
|
|
207
208
|
|
|
208
209
|
EventNames = {}
|
|
209
210
|
cdef class PY_SCIP_EVENTTYPE:
|
|
210
|
-
DISABLED
|
|
211
|
-
VARADDED
|
|
212
|
-
VARDELETED
|
|
213
|
-
VARFIXED
|
|
214
|
-
VARUNLOCKED
|
|
215
|
-
OBJCHANGED
|
|
216
|
-
GLBCHANGED
|
|
217
|
-
GUBCHANGED
|
|
218
|
-
LBTIGHTENED
|
|
219
|
-
LBRELAXED
|
|
220
|
-
UBTIGHTENED
|
|
221
|
-
UBRELAXED
|
|
222
|
-
GHOLEADDED
|
|
223
|
-
GHOLEREMOVED
|
|
224
|
-
LHOLEADDED
|
|
225
|
-
LHOLEREMOVED
|
|
226
|
-
IMPLADDED
|
|
227
|
-
PRESOLVEROUND
|
|
228
|
-
NODEFOCUSED
|
|
229
|
-
NODEFEASIBLE
|
|
230
|
-
NODEINFEASIBLE
|
|
231
|
-
NODEBRANCHED
|
|
232
|
-
NODEDELETE
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
211
|
+
DISABLED = SCIP_EVENTTYPE_DISABLED
|
|
212
|
+
VARADDED = SCIP_EVENTTYPE_VARADDED
|
|
213
|
+
VARDELETED = SCIP_EVENTTYPE_VARDELETED
|
|
214
|
+
VARFIXED = SCIP_EVENTTYPE_VARFIXED
|
|
215
|
+
VARUNLOCKED = SCIP_EVENTTYPE_VARUNLOCKED
|
|
216
|
+
OBJCHANGED = SCIP_EVENTTYPE_OBJCHANGED
|
|
217
|
+
GLBCHANGED = SCIP_EVENTTYPE_GLBCHANGED
|
|
218
|
+
GUBCHANGED = SCIP_EVENTTYPE_GUBCHANGED
|
|
219
|
+
LBTIGHTENED = SCIP_EVENTTYPE_LBTIGHTENED
|
|
220
|
+
LBRELAXED = SCIP_EVENTTYPE_LBRELAXED
|
|
221
|
+
UBTIGHTENED = SCIP_EVENTTYPE_UBTIGHTENED
|
|
222
|
+
UBRELAXED = SCIP_EVENTTYPE_UBRELAXED
|
|
223
|
+
GHOLEADDED = SCIP_EVENTTYPE_GHOLEADDED
|
|
224
|
+
GHOLEREMOVED = SCIP_EVENTTYPE_GHOLEREMOVED
|
|
225
|
+
LHOLEADDED = SCIP_EVENTTYPE_LHOLEADDED
|
|
226
|
+
LHOLEREMOVED = SCIP_EVENTTYPE_LHOLEREMOVED
|
|
227
|
+
IMPLADDED = SCIP_EVENTTYPE_IMPLADDED
|
|
228
|
+
PRESOLVEROUND = SCIP_EVENTTYPE_PRESOLVEROUND
|
|
229
|
+
NODEFOCUSED = SCIP_EVENTTYPE_NODEFOCUSED
|
|
230
|
+
NODEFEASIBLE = SCIP_EVENTTYPE_NODEFEASIBLE
|
|
231
|
+
NODEINFEASIBLE = SCIP_EVENTTYPE_NODEINFEASIBLE
|
|
232
|
+
NODEBRANCHED = SCIP_EVENTTYPE_NODEBRANCHED
|
|
233
|
+
NODEDELETE = SCIP_EVENTTYPE_NODEDELETE
|
|
234
|
+
DUALBOUNDIMPROVED = SCIP_EVENTTYPE_DUALBOUNDIMPROVED
|
|
235
|
+
FIRSTLPSOLVED = SCIP_EVENTTYPE_FIRSTLPSOLVED
|
|
236
|
+
LPSOLVED = SCIP_EVENTTYPE_LPSOLVED
|
|
237
|
+
LPEVENT = SCIP_EVENTTYPE_LPEVENT
|
|
238
|
+
POORSOLFOUND = SCIP_EVENTTYPE_POORSOLFOUND
|
|
239
|
+
BESTSOLFOUND = SCIP_EVENTTYPE_BESTSOLFOUND
|
|
240
|
+
ROWADDEDSEPA = SCIP_EVENTTYPE_ROWADDEDSEPA
|
|
241
|
+
ROWDELETEDSEPA = SCIP_EVENTTYPE_ROWDELETEDSEPA
|
|
242
|
+
ROWADDEDLP = SCIP_EVENTTYPE_ROWADDEDLP
|
|
243
|
+
ROWDELETEDLP = SCIP_EVENTTYPE_ROWDELETEDLP
|
|
244
|
+
ROWCOEFCHANGED = SCIP_EVENTTYPE_ROWCOEFCHANGED
|
|
245
|
+
ROWCONSTCHANGED = SCIP_EVENTTYPE_ROWCONSTCHANGED
|
|
246
|
+
ROWSIDECHANGED = SCIP_EVENTTYPE_ROWSIDECHANGED
|
|
247
|
+
SYNC = SCIP_EVENTTYPE_SYNC
|
|
248
|
+
GBDCHANGED = SCIP_EVENTTYPE_GBDCHANGED
|
|
249
|
+
LBCHANGED = SCIP_EVENTTYPE_LBCHANGED
|
|
250
|
+
UBCHANGED = SCIP_EVENTTYPE_UBCHANGED
|
|
251
|
+
BOUNDTIGHTENED = SCIP_EVENTTYPE_BOUNDTIGHTENED
|
|
252
|
+
BOUNDRELAXED = SCIP_EVENTTYPE_BOUNDRELAXED
|
|
253
|
+
BOUNDCHANGED = SCIP_EVENTTYPE_BOUNDCHANGED
|
|
254
|
+
GHOLECHANGED = SCIP_EVENTTYPE_GHOLECHANGED
|
|
255
|
+
LHOLECHANGED = SCIP_EVENTTYPE_LHOLECHANGED
|
|
256
|
+
HOLECHANGED = SCIP_EVENTTYPE_HOLECHANGED
|
|
257
|
+
DOMCHANGED = SCIP_EVENTTYPE_DOMCHANGED
|
|
258
|
+
VARCHANGED = SCIP_EVENTTYPE_VARCHANGED
|
|
259
|
+
VAREVENT = SCIP_EVENTTYPE_VAREVENT
|
|
260
|
+
NODESOLVED = SCIP_EVENTTYPE_NODESOLVED
|
|
261
|
+
NODEEVENT = SCIP_EVENTTYPE_NODEEVENT
|
|
262
|
+
SOLFOUND = SCIP_EVENTTYPE_SOLFOUND
|
|
263
|
+
SOLEVENT = SCIP_EVENTTYPE_SOLEVENT
|
|
264
|
+
GAPUPDATED = SCIP_EVENTTYPE_GAPUPDATED
|
|
265
|
+
ROWCHANGED = SCIP_EVENTTYPE_ROWCHANGED
|
|
266
|
+
ROWEVENT = SCIP_EVENTTYPE_ROWEVENT
|
|
264
267
|
|
|
265
268
|
cdef class PY_SCIP_LOCKTYPE:
|
|
266
269
|
MODEL = SCIP_LOCKTYPE_MODEL
|
|
267
270
|
CONFLICT = SCIP_LOCKTYPE_CONFLICT
|
|
268
271
|
|
|
272
|
+
cdef class PY_SCIP_IMPLINTTYPE:
|
|
273
|
+
NONE = SCIP_IMPLINTTYPE_NONE
|
|
274
|
+
WEAK = SCIP_IMPLINTTYPE_WEAK
|
|
275
|
+
STRONG = SCIP_IMPLINTTYPE_STRONG
|
|
276
|
+
|
|
269
277
|
cdef class PY_SCIP_LPSOLSTAT:
|
|
270
278
|
NOTSOLVED = SCIP_LPSOLSTAT_NOTSOLVED
|
|
271
279
|
OPTIMAL = SCIP_LPSOLSTAT_OPTIMAL
|
|
@@ -626,6 +634,31 @@ cdef class Column:
|
|
|
626
634
|
return (self.__class__ == other.__class__
|
|
627
635
|
and self.scip_col == (<Column>other).scip_col)
|
|
628
636
|
|
|
637
|
+
cdef class ColumnExact:
|
|
638
|
+
"""Base class holding a pointer to corresponding SCIP_COLEXACT."""
|
|
639
|
+
|
|
640
|
+
@staticmethod
|
|
641
|
+
cdef create(SCIP_COLEXACT* scipcolexact):
|
|
642
|
+
"""
|
|
643
|
+
Main method for creating a ColumnExact class. Is used instead of __init__.
|
|
644
|
+
|
|
645
|
+
Parameters
|
|
646
|
+
----------
|
|
647
|
+
scipcolexact : SCIP_COLEXACT*
|
|
648
|
+
A pointer to the SCIP_COLEXACT
|
|
649
|
+
|
|
650
|
+
Returns
|
|
651
|
+
-------
|
|
652
|
+
col : ColumnExact
|
|
653
|
+
The Python representative of the SCIP_COLEXACT
|
|
654
|
+
|
|
655
|
+
"""
|
|
656
|
+
if scipcolexact == NULL:
|
|
657
|
+
raise Warning("cannot create ColumnExact with SCIP_COLEXACT* == NULL")
|
|
658
|
+
col = ColumnExact()
|
|
659
|
+
col.scip_col_exact = scipcolexact
|
|
660
|
+
return col
|
|
661
|
+
|
|
629
662
|
cdef class Row:
|
|
630
663
|
"""Base class holding a pointer to corresponding SCIP_ROW."""
|
|
631
664
|
|
|
@@ -910,6 +943,31 @@ cdef class Row:
|
|
|
910
943
|
return (self.__class__ == other.__class__
|
|
911
944
|
and self.scip_row == (<Row>other).scip_row)
|
|
912
945
|
|
|
946
|
+
cdef class RowExact:
|
|
947
|
+
"""Base class holding a pointer to corresponding SCIP_ROW."""
|
|
948
|
+
|
|
949
|
+
@staticmethod
|
|
950
|
+
cdef create(SCIP_ROWEXACT* sciprowexact):
|
|
951
|
+
"""
|
|
952
|
+
Main method for creating a RowExact class. Is used instead of __init__.
|
|
953
|
+
|
|
954
|
+
Parameters
|
|
955
|
+
----------
|
|
956
|
+
sciprow : SCIP_ROWEXACT*
|
|
957
|
+
A pointer to the SCIP_ROWEXACT
|
|
958
|
+
|
|
959
|
+
Returns
|
|
960
|
+
-------
|
|
961
|
+
row : Row
|
|
962
|
+
The Python representative of the SCIP_ROWEXACT
|
|
963
|
+
|
|
964
|
+
"""
|
|
965
|
+
if sciprowexact == NULL:
|
|
966
|
+
raise Warning("cannot create Row with SCIP_ROWEXACT* == NULL")
|
|
967
|
+
row_exact = RowExact()
|
|
968
|
+
row_exact.scip_row_exact = sciprowexact
|
|
969
|
+
return row_exact
|
|
970
|
+
|
|
913
971
|
cdef class NLRow:
|
|
914
972
|
"""Base class holding a pointer to corresponding SCIP_NLROW."""
|
|
915
973
|
|
|
@@ -1010,8 +1068,8 @@ cdef class Solution:
|
|
|
1010
1068
|
"""Base class holding a pointer to corresponding SCIP_SOL."""
|
|
1011
1069
|
|
|
1012
1070
|
# We are raising an error here to avoid creating a solution without an associated model. See Issue #625
|
|
1013
|
-
def __init__(self, raise_error =
|
|
1014
|
-
if
|
|
1071
|
+
def __init__(self, raise_error = True):
|
|
1072
|
+
if raise_error:
|
|
1015
1073
|
raise ValueError("To create a solution you should use the createSol method of the Model class.")
|
|
1016
1074
|
|
|
1017
1075
|
@staticmethod
|
|
@@ -1035,35 +1093,23 @@ cdef class Solution:
|
|
|
1035
1093
|
"""
|
|
1036
1094
|
if scip == NULL:
|
|
1037
1095
|
raise Warning("cannot create Solution with SCIP* == NULL")
|
|
1038
|
-
sol = Solution(
|
|
1096
|
+
sol = Solution(raise_error=False)
|
|
1039
1097
|
sol.sol = scip_sol
|
|
1040
1098
|
sol.scip = scip
|
|
1041
1099
|
return sol
|
|
1042
1100
|
|
|
1043
|
-
def __getitem__(
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
cdef _VarArray wrapper
|
|
1053
|
-
if isinstance(expr, Variable):
|
|
1054
|
-
wrapper = _VarArray(expr)
|
|
1055
|
-
self._checkStage("SCIPgetSolVal")
|
|
1056
|
-
return SCIPgetSolVal(self.scip, self.sol, wrapper.ptr[0])
|
|
1057
|
-
return sum(self._evaluate(term)*coeff for term, coeff in expr.terms.items() if coeff != 0)
|
|
1101
|
+
def __getitem__(
|
|
1102
|
+
self,
|
|
1103
|
+
expr: Union[Expr, GenExpr, MatrixExpr],
|
|
1104
|
+
) -> Union[float, np.ndarray]:
|
|
1105
|
+
if not isinstance(expr, (Expr, GenExpr, MatrixExpr)):
|
|
1106
|
+
raise TypeError(
|
|
1107
|
+
"Argument 'expr' has incorrect type, expected 'Expr', 'GenExpr', or "
|
|
1108
|
+
f"'MatrixExpr', got {type(expr).__name__!r}"
|
|
1109
|
+
)
|
|
1058
1110
|
|
|
1059
|
-
def _evaluate(self, term):
|
|
1060
1111
|
self._checkStage("SCIPgetSolVal")
|
|
1061
|
-
|
|
1062
|
-
cdef _VarArray wrapper
|
|
1063
|
-
wrapper = _VarArray(term.vartuple)
|
|
1064
|
-
for i in range(len(term.vartuple)):
|
|
1065
|
-
result *= SCIPgetSolVal(self.scip, self.sol, wrapper.ptr[i])
|
|
1066
|
-
return result
|
|
1112
|
+
return expr._evaluate(self)
|
|
1067
1113
|
|
|
1068
1114
|
def __setitem__(self, Variable var, value):
|
|
1069
1115
|
PY_SCIP_CALL(SCIPsetSolVal(self.scip, self.sol, var.scip_var, value))
|
|
@@ -1507,6 +1553,8 @@ cdef class Variable(Expr):
|
|
|
1507
1553
|
|
|
1508
1554
|
property name:
|
|
1509
1555
|
def __get__(self):
|
|
1556
|
+
if self.scip_var == NULL:
|
|
1557
|
+
return ""
|
|
1510
1558
|
cname = bytes( SCIPvarGetName(self.scip_var) )
|
|
1511
1559
|
return cname.decode('utf-8')
|
|
1512
1560
|
|
|
@@ -1519,7 +1567,7 @@ cdef class Variable(Expr):
|
|
|
1519
1567
|
|
|
1520
1568
|
def vtype(self):
|
|
1521
1569
|
"""
|
|
1522
|
-
Retrieve the variables type (BINARY, INTEGER,
|
|
1570
|
+
Retrieve the variables type (BINARY, INTEGER, CONTINUOUS, or IMPLINT)
|
|
1523
1571
|
|
|
1524
1572
|
Returns
|
|
1525
1573
|
-------
|
|
@@ -1534,8 +1582,58 @@ cdef class Variable(Expr):
|
|
|
1534
1582
|
return "INTEGER"
|
|
1535
1583
|
elif vartype == SCIP_VARTYPE_CONTINUOUS:
|
|
1536
1584
|
return "CONTINUOUS"
|
|
1537
|
-
elif vartype ==
|
|
1585
|
+
elif vartype == SCIP_DEPRECATED_VARTYPE_IMPLINT:
|
|
1538
1586
|
return "IMPLINT"
|
|
1587
|
+
|
|
1588
|
+
def isBinary(self):
|
|
1589
|
+
"""
|
|
1590
|
+
Returns whether variable is of BINARY type.
|
|
1591
|
+
|
|
1592
|
+
Returns
|
|
1593
|
+
-------
|
|
1594
|
+
bool
|
|
1595
|
+
"""
|
|
1596
|
+
return SCIPvarIsBinary(self.scip_var)
|
|
1597
|
+
|
|
1598
|
+
def isIntegral(self):
|
|
1599
|
+
"""
|
|
1600
|
+
Returns whether variable is of INTEGER type.
|
|
1601
|
+
|
|
1602
|
+
Returns
|
|
1603
|
+
-------
|
|
1604
|
+
bool
|
|
1605
|
+
"""
|
|
1606
|
+
return SCIPvarIsIntegral(self.scip_var)
|
|
1607
|
+
|
|
1608
|
+
def isImpliedIntegral(self):
|
|
1609
|
+
"""
|
|
1610
|
+
Returns whether variable is implied integral (weakly or strongly).
|
|
1611
|
+
|
|
1612
|
+
Returns
|
|
1613
|
+
-------
|
|
1614
|
+
bool
|
|
1615
|
+
"""
|
|
1616
|
+
return SCIPvarIsImpliedIntegral(self.scip_var)
|
|
1617
|
+
|
|
1618
|
+
def isNonImpliedIntegral(self):
|
|
1619
|
+
"""
|
|
1620
|
+
Returns TRUE if the variable is integral, but not implied integral..
|
|
1621
|
+
|
|
1622
|
+
Returns
|
|
1623
|
+
-------
|
|
1624
|
+
bool
|
|
1625
|
+
"""
|
|
1626
|
+
return SCIPvarIsNonimpliedIntegral(self.scip_var)
|
|
1627
|
+
|
|
1628
|
+
def getImplType(self):
|
|
1629
|
+
"""
|
|
1630
|
+
Returns the implied integral type of the variable
|
|
1631
|
+
|
|
1632
|
+
Returns
|
|
1633
|
+
-------
|
|
1634
|
+
PY_SCIP_IMPLINTTYPE
|
|
1635
|
+
"""
|
|
1636
|
+
return SCIPvarGetImplType(self.scip_var)
|
|
1539
1637
|
|
|
1540
1638
|
def getStatus(self):
|
|
1541
1639
|
"""
|
|
@@ -1762,6 +1860,16 @@ cdef class Variable(Expr):
|
|
|
1762
1860
|
"""
|
|
1763
1861
|
return SCIPvarIsDeletable(self.scip_var)
|
|
1764
1862
|
|
|
1863
|
+
def isActive(self):
|
|
1864
|
+
"""
|
|
1865
|
+
Returns whether variable is an active (neither fixed nor aggregated) variable.
|
|
1866
|
+
|
|
1867
|
+
Returns
|
|
1868
|
+
-------
|
|
1869
|
+
boolean
|
|
1870
|
+
"""
|
|
1871
|
+
return SCIPvarIsActive(self.scip_var)
|
|
1872
|
+
|
|
1765
1873
|
def getNLocksDown(self):
|
|
1766
1874
|
"""
|
|
1767
1875
|
Returns the number of locks for rounding down.
|
|
@@ -2105,9 +2213,14 @@ cdef class Constraint:
|
|
|
2105
2213
|
|
|
2106
2214
|
property name:
|
|
2107
2215
|
def __get__(self):
|
|
2216
|
+
if self.scip_cons == NULL:
|
|
2217
|
+
return ""
|
|
2108
2218
|
cname = bytes( SCIPconsGetName(self.scip_cons) )
|
|
2109
2219
|
return cname.decode('utf-8')
|
|
2110
2220
|
|
|
2221
|
+
def ptr(self):
|
|
2222
|
+
return <size_t>(self.scip_cons)
|
|
2223
|
+
|
|
2111
2224
|
def __repr__(self):
|
|
2112
2225
|
return self.name
|
|
2113
2226
|
|
|
@@ -2555,6 +2668,115 @@ cdef class _VarArray:
|
|
|
2555
2668
|
if self.ptr != NULL:
|
|
2556
2669
|
free(self.ptr)
|
|
2557
2670
|
|
|
2671
|
+
cdef class IIS:
|
|
2672
|
+
|
|
2673
|
+
@staticmethod
|
|
2674
|
+
cdef create(SCIP_IIS* scip_iis):
|
|
2675
|
+
"""
|
|
2676
|
+
Main method for creating an IIS class.
|
|
2677
|
+
|
|
2678
|
+
Parameters
|
|
2679
|
+
----------
|
|
2680
|
+
scip : SCIP_IIS*
|
|
2681
|
+
A pointer to the SCIP_IIS
|
|
2682
|
+
|
|
2683
|
+
Returns
|
|
2684
|
+
-------
|
|
2685
|
+
sol : IIS
|
|
2686
|
+
The Python representative of the IIS
|
|
2687
|
+
|
|
2688
|
+
"""
|
|
2689
|
+
iis = IIS()
|
|
2690
|
+
iis._iis = scip_iis
|
|
2691
|
+
return iis
|
|
2692
|
+
|
|
2693
|
+
def getTime(self):
|
|
2694
|
+
"""
|
|
2695
|
+
Retrieve the solving time of the IIS.
|
|
2696
|
+
|
|
2697
|
+
Returns
|
|
2698
|
+
-------
|
|
2699
|
+
float
|
|
2700
|
+
"""
|
|
2701
|
+
return SCIPiisGetTime(self._iis)
|
|
2702
|
+
|
|
2703
|
+
def isSubscipIrreducible(self):
|
|
2704
|
+
"""
|
|
2705
|
+
Returns whether the IIS is irreducible.
|
|
2706
|
+
|
|
2707
|
+
Returns
|
|
2708
|
+
-------
|
|
2709
|
+
bool
|
|
2710
|
+
"""
|
|
2711
|
+
return SCIPiisIsSubscipIrreducible(self._iis)
|
|
2712
|
+
|
|
2713
|
+
def isSubscipInfeasible(self):
|
|
2714
|
+
"""
|
|
2715
|
+
Returns whether the IIS is infeasible.
|
|
2716
|
+
|
|
2717
|
+
Returns
|
|
2718
|
+
-------
|
|
2719
|
+
bool
|
|
2720
|
+
"""
|
|
2721
|
+
return SCIPiisIsSubscipInfeasible(self._iis)
|
|
2722
|
+
|
|
2723
|
+
def setSubscipIrreducible(self, irreducible):
|
|
2724
|
+
"""
|
|
2725
|
+
Sets the flag that states whether the IIS subscip is irreducible.
|
|
2726
|
+
|
|
2727
|
+
Parameters
|
|
2728
|
+
----------
|
|
2729
|
+
irreducible : bool
|
|
2730
|
+
the value to set the irreducible flag to
|
|
2731
|
+
"""
|
|
2732
|
+
|
|
2733
|
+
SCIPiisSetSubscipIrreducible(self._iis, irreducible)
|
|
2734
|
+
|
|
2735
|
+
def setSubscipInfeasible(self, infeasible):
|
|
2736
|
+
"""
|
|
2737
|
+
Sets the flag that states whether the IIS subscip is infeasible.
|
|
2738
|
+
|
|
2739
|
+
Parameters
|
|
2740
|
+
----------
|
|
2741
|
+
infeasible : bool
|
|
2742
|
+
the value to set the infeasible flag to
|
|
2743
|
+
"""
|
|
2744
|
+
|
|
2745
|
+
SCIPiisSetSubscipInfeasible(self._iis, infeasible)
|
|
2746
|
+
|
|
2747
|
+
def getNNodes(self):
|
|
2748
|
+
"""
|
|
2749
|
+
Gets number of nodes in the IIS solve.
|
|
2750
|
+
|
|
2751
|
+
Returns
|
|
2752
|
+
-------
|
|
2753
|
+
int
|
|
2754
|
+
|
|
2755
|
+
"""
|
|
2756
|
+
return SCIPiisGetNNodes(self._iis)
|
|
2757
|
+
|
|
2758
|
+
def getSubscip(self):
|
|
2759
|
+
"""
|
|
2760
|
+
Get the subscip of an IIS.
|
|
2761
|
+
|
|
2762
|
+
Returns
|
|
2763
|
+
-------
|
|
2764
|
+
Model
|
|
2765
|
+
"""
|
|
2766
|
+
cdef SCIP* subscip
|
|
2767
|
+
|
|
2768
|
+
subscip = SCIPiisGetSubscip(self._iis)
|
|
2769
|
+
model = Model.create(subscip)
|
|
2770
|
+
return model
|
|
2771
|
+
|
|
2772
|
+
def greedyMakeIrreducible(self):
|
|
2773
|
+
"""
|
|
2774
|
+
Perform the greedy deletion algorithm with singleton batches to obtain an irreducible infeasible subsystem (IIS)
|
|
2775
|
+
"""
|
|
2776
|
+
|
|
2777
|
+
PY_SCIP_CALL(SCIPiisGreedyMakeIrreducible(self._iis))
|
|
2778
|
+
|
|
2779
|
+
|
|
2558
2780
|
# - remove create(), includeDefaultPlugins(), createProbBasic() methods
|
|
2559
2781
|
# - replace free() by "destructor"
|
|
2560
2782
|
# - interface SCIPfreeProb()
|
|
@@ -2563,7 +2785,7 @@ cdef class _VarArray:
|
|
|
2563
2785
|
##
|
|
2564
2786
|
cdef class Model:
|
|
2565
2787
|
|
|
2566
|
-
def __init__(self, problemName='model', defaultPlugins=True, Model sourceModel=None, origcopy=False, globalcopy=True, enablepricing=
|
|
2788
|
+
def __init__(self, problemName='model', defaultPlugins=True, Model sourceModel=None, origcopy=False, globalcopy=True, enablepricing=True, createscip=True, threadsafe=False):
|
|
2567
2789
|
"""
|
|
2568
2790
|
Main class holding a pointer to SCIP for managing most interactions
|
|
2569
2791
|
|
|
@@ -2580,7 +2802,7 @@ cdef class Model:
|
|
|
2580
2802
|
globalcopy : bool, optional
|
|
2581
2803
|
whether to create a global or a local copy (default True)
|
|
2582
2804
|
enablepricing : bool, optional
|
|
2583
|
-
whether to enable pricing in copy (default
|
|
2805
|
+
whether to enable pricing in copy (default True)
|
|
2584
2806
|
createscip : bool, optional
|
|
2585
2807
|
initialize the Model object and creates a SCIP instance (default True)
|
|
2586
2808
|
threadsafe : bool, optional
|
|
@@ -2596,8 +2818,10 @@ cdef class Model:
|
|
|
2596
2818
|
|
|
2597
2819
|
self._freescip = True
|
|
2598
2820
|
self._modelvars = {}
|
|
2821
|
+
self._modelconss = {}
|
|
2599
2822
|
self._generated_event_handlers_count = 0
|
|
2600
2823
|
self._benders_subproblems = [] # Keep references to Benders subproblem Models
|
|
2824
|
+
self._iis = NULL
|
|
2601
2825
|
|
|
2602
2826
|
if not createscip:
|
|
2603
2827
|
# if no SCIP instance should be created, then an empty Model object is created.
|
|
@@ -2691,6 +2915,16 @@ cdef class Model:
|
|
|
2691
2915
|
# Clear the references to allow Python GC to clean up the Model objects
|
|
2692
2916
|
self._benders_subproblems = []
|
|
2693
2917
|
|
|
2918
|
+
# Invalidate all variable and constraint pointers before freeing SCIP. See issue #604.
|
|
2919
|
+
if self._modelvars:
|
|
2920
|
+
for var in self._modelvars.values():
|
|
2921
|
+
(<Variable>var).scip_var = NULL
|
|
2922
|
+
self._modelvars = {}
|
|
2923
|
+
if self._modelconss:
|
|
2924
|
+
for cons in self._modelconss.values():
|
|
2925
|
+
(<Constraint>cons).scip_cons = NULL
|
|
2926
|
+
self._modelconss = {}
|
|
2927
|
+
|
|
2694
2928
|
PY_SCIP_CALL( SCIPfree(&self._scip) )
|
|
2695
2929
|
|
|
2696
2930
|
def __hash__(self):
|
|
@@ -2723,6 +2957,24 @@ cdef class Model:
|
|
|
2723
2957
|
model._benders_subproblems = [] # Initialize Benders subproblems list
|
|
2724
2958
|
return model
|
|
2725
2959
|
|
|
2960
|
+
cdef _getOrCreateCons(self, SCIP_CONS* scip_cons):
|
|
2961
|
+
"""Get existing Constraint wrapper or create and track a new one."""
|
|
2962
|
+
cdef size_t ptr = <size_t>scip_cons
|
|
2963
|
+
if ptr in self._modelconss:
|
|
2964
|
+
return self._modelconss[ptr]
|
|
2965
|
+
pyCons = Constraint.create(scip_cons)
|
|
2966
|
+
self._modelconss[ptr] = pyCons
|
|
2967
|
+
return pyCons
|
|
2968
|
+
|
|
2969
|
+
cdef _getOrCreateVar(self, SCIP_VAR* scip_var):
|
|
2970
|
+
"""Get existing Variable wrapper or create and track a new one."""
|
|
2971
|
+
cdef size_t ptr = <size_t>scip_var
|
|
2972
|
+
if ptr in self._modelvars:
|
|
2973
|
+
return self._modelvars[ptr]
|
|
2974
|
+
pyVar = Variable.create(scip_var)
|
|
2975
|
+
self._modelvars[ptr] = pyVar
|
|
2976
|
+
return pyVar
|
|
2977
|
+
|
|
2726
2978
|
@property
|
|
2727
2979
|
def _freescip(self):
|
|
2728
2980
|
"""
|
|
@@ -2830,11 +3082,20 @@ cdef class Model:
|
|
|
2830
3082
|
SCIP_STAGE_SOLVED]:
|
|
2831
3083
|
raise Warning("method cannot be called in stage %i." % self.getStage())
|
|
2832
3084
|
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
if
|
|
2837
|
-
|
|
3085
|
+
# Invalidate transformed variables. See issue #604.
|
|
3086
|
+
origvars = {ptr: var for ptr, var in self._modelvars.items() if var.isOriginal()}
|
|
3087
|
+
for ptr, var in self._modelvars.items():
|
|
3088
|
+
if ptr not in origvars:
|
|
3089
|
+
(<Variable>var).scip_var = NULL
|
|
3090
|
+
self._modelvars = origvars
|
|
3091
|
+
|
|
3092
|
+
# Invalidate transformed constraints. See issue #604.
|
|
3093
|
+
origconss = {ptr: cons for ptr, cons in self._modelconss.items() if cons.isOriginal()}
|
|
3094
|
+
for ptr, cons in self._modelconss.items():
|
|
3095
|
+
if ptr not in origconss:
|
|
3096
|
+
(<Constraint>cons).scip_cons = NULL
|
|
3097
|
+
self._modelconss = origconss
|
|
3098
|
+
|
|
2838
3099
|
PY_SCIP_CALL(SCIPfreeTransform(self._scip))
|
|
2839
3100
|
|
|
2840
3101
|
def version(self):
|
|
@@ -3143,6 +3404,16 @@ cdef class Model:
|
|
|
3143
3404
|
"""
|
|
3144
3405
|
return SCIPgetNStrongbranchLPIterations(self._scip)
|
|
3145
3406
|
|
|
3407
|
+
def getPrimalDualIntegral(self):
|
|
3408
|
+
"""
|
|
3409
|
+
Recomputes and returns the primal dual gap stored in the stats
|
|
3410
|
+
|
|
3411
|
+
Returns
|
|
3412
|
+
------
|
|
3413
|
+
float
|
|
3414
|
+
"""
|
|
3415
|
+
return SCIPgetPrimalDualIntegral(self._scip)
|
|
3416
|
+
|
|
3146
3417
|
def cutoffNode(self, Node node):
|
|
3147
3418
|
"""
|
|
3148
3419
|
marks node and whole subtree to be cut off from the branch and bound tree.
|
|
@@ -3351,6 +3622,62 @@ cdef class Model:
|
|
|
3351
3622
|
"""
|
|
3352
3623
|
return SCIPisFeasIntegral(self._scip, value)
|
|
3353
3624
|
|
|
3625
|
+
def isIntegral(self, value):
|
|
3626
|
+
"""
|
|
3627
|
+
Returns whether value is integral within epsilon tolerance.
|
|
3628
|
+
|
|
3629
|
+
Parameters
|
|
3630
|
+
----------
|
|
3631
|
+
value : float
|
|
3632
|
+
value to check
|
|
3633
|
+
|
|
3634
|
+
Returns
|
|
3635
|
+
-------
|
|
3636
|
+
bool
|
|
3637
|
+
|
|
3638
|
+
"""
|
|
3639
|
+
return SCIPisIntegral(self._scip, value)
|
|
3640
|
+
|
|
3641
|
+
def adjustedVarLb(self, Variable var, lb):
|
|
3642
|
+
"""
|
|
3643
|
+
Returns the adjusted (i.e. rounded, if the given variable is of integral type) lower bound value;
|
|
3644
|
+
does not change the bounds of the variable.
|
|
3645
|
+
|
|
3646
|
+
Parameters
|
|
3647
|
+
----------
|
|
3648
|
+
var : Variable
|
|
3649
|
+
variable for which the bound is adjusted
|
|
3650
|
+
lb : float
|
|
3651
|
+
lower bound value to adjust
|
|
3652
|
+
|
|
3653
|
+
Returns
|
|
3654
|
+
-------
|
|
3655
|
+
float
|
|
3656
|
+
adjusted lower bound
|
|
3657
|
+
|
|
3658
|
+
"""
|
|
3659
|
+
return SCIPadjustedVarLb(self._scip, var.scip_var, lb)
|
|
3660
|
+
|
|
3661
|
+
def adjustedVarUb(self, Variable var, ub):
|
|
3662
|
+
"""
|
|
3663
|
+
Returns the adjusted (i.e. rounded, if the given variable is of integral type) upper bound value;
|
|
3664
|
+
does not change the bounds of the variable.
|
|
3665
|
+
|
|
3666
|
+
Parameters
|
|
3667
|
+
----------
|
|
3668
|
+
var : Variable
|
|
3669
|
+
variable for which the bound is adjusted
|
|
3670
|
+
ub : float
|
|
3671
|
+
upper bound value to adjust
|
|
3672
|
+
|
|
3673
|
+
Returns
|
|
3674
|
+
-------
|
|
3675
|
+
float
|
|
3676
|
+
adjusted upper bound
|
|
3677
|
+
|
|
3678
|
+
"""
|
|
3679
|
+
return SCIPadjustedVarUb(self._scip, var.scip_var, ub)
|
|
3680
|
+
|
|
3354
3681
|
def isEQ(self, val1, val2):
|
|
3355
3682
|
"""
|
|
3356
3683
|
Checks, if values are in range of epsilon.
|
|
@@ -3763,6 +4090,17 @@ cdef class Model:
|
|
|
3763
4090
|
"""
|
|
3764
4091
|
PY_SCIP_CALL(SCIPsetObjIntegral(self._scip))
|
|
3765
4092
|
|
|
4093
|
+
def isObjIntegral(self):
|
|
4094
|
+
"""
|
|
4095
|
+
Returns whether the objective function is integral.
|
|
4096
|
+
|
|
4097
|
+
Returns
|
|
4098
|
+
-------
|
|
4099
|
+
bool
|
|
4100
|
+
|
|
4101
|
+
"""
|
|
4102
|
+
return SCIPisObjIntegral(self._scip)
|
|
4103
|
+
|
|
3766
4104
|
def getLocalEstimate(self, original = False):
|
|
3767
4105
|
"""
|
|
3768
4106
|
Gets estimate of best primal solution w.r.t. original or transformed problem contained in current subtree.
|
|
@@ -4008,7 +4346,7 @@ cdef class Model:
|
|
|
4008
4346
|
elif vtype in ['I', 'INTEGER']:
|
|
4009
4347
|
PY_SCIP_CALL(SCIPcreateVarBasic(self._scip, &scip_var, cname, lb, ub, obj, SCIP_VARTYPE_INTEGER))
|
|
4010
4348
|
elif vtype in ['M', 'IMPLINT']:
|
|
4011
|
-
PY_SCIP_CALL(SCIPcreateVarBasic(self._scip, &scip_var, cname, lb, ub, obj,
|
|
4349
|
+
PY_SCIP_CALL(SCIPcreateVarBasic(self._scip, &scip_var, cname, lb, ub, obj, SCIP_DEPRECATED_VARTYPE_IMPLINT))
|
|
4012
4350
|
else:
|
|
4013
4351
|
raise Warning("unrecognized variable type")
|
|
4014
4352
|
|
|
@@ -4020,11 +4358,7 @@ cdef class Model:
|
|
|
4020
4358
|
else:
|
|
4021
4359
|
PY_SCIP_CALL(SCIPaddVar(self._scip, scip_var))
|
|
4022
4360
|
|
|
4023
|
-
pyVar =
|
|
4024
|
-
|
|
4025
|
-
# store variable in the model to avoid creating new python variable objects in getVars()
|
|
4026
|
-
assert not pyVar.ptr() in self._modelvars
|
|
4027
|
-
self._modelvars[pyVar.ptr()] = pyVar
|
|
4361
|
+
pyVar = self._getOrCreateVar(scip_var)
|
|
4028
4362
|
|
|
4029
4363
|
#setting the variable data
|
|
4030
4364
|
SCIPvarSetData(scip_var, <SCIP_VARDATA*>pyVar)
|
|
@@ -4154,8 +4488,7 @@ cdef class Model:
|
|
|
4154
4488
|
"""
|
|
4155
4489
|
cdef SCIP_VAR* _tvar
|
|
4156
4490
|
PY_SCIP_CALL(SCIPgetTransformedVar(self._scip, var.scip_var, &_tvar))
|
|
4157
|
-
|
|
4158
|
-
return Variable.create(_tvar)
|
|
4491
|
+
return self._getOrCreateVar(_tvar)
|
|
4159
4492
|
|
|
4160
4493
|
def addVarLocks(self, Variable var, int nlocksdown, int nlocksup):
|
|
4161
4494
|
"""
|
|
@@ -4231,11 +4564,72 @@ cdef class Model:
|
|
|
4231
4564
|
|
|
4232
4565
|
"""
|
|
4233
4566
|
cdef SCIP_Bool deleted
|
|
4234
|
-
|
|
4235
|
-
del self._modelvars[var.ptr()]
|
|
4567
|
+
del self._modelvars[var.ptr()]
|
|
4236
4568
|
PY_SCIP_CALL(SCIPdelVar(self._scip, var.scip_var, &deleted))
|
|
4569
|
+
# Invalidate pointer after deletion. See issue #604.
|
|
4570
|
+
var.scip_var = NULL
|
|
4237
4571
|
return deleted
|
|
4238
4572
|
|
|
4573
|
+
def aggregateVars(self, Variable varx, Variable vary, coefx=1.0, coefy=-1.0, rhs=0.0):
|
|
4574
|
+
"""
|
|
4575
|
+
Aggregate two variables by adding an aggregation constraint.
|
|
4576
|
+
|
|
4577
|
+
The aggregation is defined by the linear equation:
|
|
4578
|
+
|
|
4579
|
+
coefx * varx + coefy * vary = rhs
|
|
4580
|
+
|
|
4581
|
+
After aggregation, varx becomes a redundant variable and vary remains active.
|
|
4582
|
+
The aggregation effectively substitutes varx with: (rhs - coefy * vary) / coefx
|
|
4583
|
+
|
|
4584
|
+
This method can only be called during presolving.
|
|
4585
|
+
|
|
4586
|
+
Parameters
|
|
4587
|
+
----------
|
|
4588
|
+
varx : Variable
|
|
4589
|
+
variable to be aggregated (will become redundant)
|
|
4590
|
+
vary : Variable
|
|
4591
|
+
variable to aggregate with (will remain active)
|
|
4592
|
+
coefx : float, optional
|
|
4593
|
+
coefficient for varx in the aggregation equation (default: 1.0)
|
|
4594
|
+
coefy : float, optional
|
|
4595
|
+
coefficient for vary in the aggregation equation (default: -1.0)
|
|
4596
|
+
rhs : float, optional
|
|
4597
|
+
right-hand side of the aggregation equation (default: 0.0)
|
|
4598
|
+
|
|
4599
|
+
Returns
|
|
4600
|
+
-------
|
|
4601
|
+
infeasible : bool
|
|
4602
|
+
whether the aggregation is infeasible (e.g., bounds are incompatible)
|
|
4603
|
+
redundant : bool
|
|
4604
|
+
whether the aggregation makes varx redundant
|
|
4605
|
+
aggregated : bool
|
|
4606
|
+
whether the aggregation was actually performed
|
|
4607
|
+
|
|
4608
|
+
Examples
|
|
4609
|
+
--------
|
|
4610
|
+
To express x = y (i.e., 1*x + (-1)*y = 0):
|
|
4611
|
+
|
|
4612
|
+
infeas, redun, aggr = model.aggregateVars(x, y, 1.0, -1.0, 0.0)
|
|
4613
|
+
|
|
4614
|
+
To express x = 5 - y (i.e., 1*x + 1*y = 5):
|
|
4615
|
+
|
|
4616
|
+
infeas, redun, aggr = model.aggregateVars(x, y, 1.0, 1.0, 5.0)
|
|
4617
|
+
|
|
4618
|
+
"""
|
|
4619
|
+
cdef SCIP_Bool infeasible
|
|
4620
|
+
cdef SCIP_Bool redundant
|
|
4621
|
+
cdef SCIP_Bool aggregated
|
|
4622
|
+
PY_SCIP_CALL(SCIPaggregateVars(self._scip,
|
|
4623
|
+
varx.scip_var,
|
|
4624
|
+
vary.scip_var,
|
|
4625
|
+
coefx,
|
|
4626
|
+
coefy,
|
|
4627
|
+
rhs,
|
|
4628
|
+
&infeasible,
|
|
4629
|
+
&redundant,
|
|
4630
|
+
&aggregated))
|
|
4631
|
+
return infeasible, redundant, aggregated
|
|
4632
|
+
|
|
4239
4633
|
def tightenVarLb(self, Variable var, lb, force=False):
|
|
4240
4634
|
"""
|
|
4241
4635
|
Tighten the lower bound in preprocessing or current node, if the bound is tighter.
|
|
@@ -4456,7 +4850,7 @@ cdef class Model:
|
|
|
4456
4850
|
elif vtype in ['I', 'INTEGER']:
|
|
4457
4851
|
PY_SCIP_CALL(SCIPchgVarType(self._scip, var.scip_var, SCIP_VARTYPE_INTEGER, &infeasible))
|
|
4458
4852
|
elif vtype in ['M', 'IMPLINT']:
|
|
4459
|
-
PY_SCIP_CALL(SCIPchgVarType(self._scip, var.scip_var,
|
|
4853
|
+
PY_SCIP_CALL(SCIPchgVarType(self._scip, var.scip_var, SCIP_DEPRECATED_VARTYPE_IMPLINT, &infeasible))
|
|
4460
4854
|
else:
|
|
4461
4855
|
raise Warning("unrecognized variable type")
|
|
4462
4856
|
if infeasible:
|
|
@@ -4511,17 +4905,7 @@ cdef class Model:
|
|
|
4511
4905
|
nvars = SCIPgetNOrigVars(self._scip)
|
|
4512
4906
|
|
|
4513
4907
|
for i in range(nvars):
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
# check whether the corresponding variable exists already
|
|
4517
|
-
if ptr in self._modelvars:
|
|
4518
|
-
vars.append(self._modelvars[ptr])
|
|
4519
|
-
else:
|
|
4520
|
-
# create a new variable
|
|
4521
|
-
var = Variable.create(_vars[i])
|
|
4522
|
-
assert var.ptr() == ptr
|
|
4523
|
-
self._modelvars[ptr] = var
|
|
4524
|
-
vars.append(var)
|
|
4908
|
+
vars.append(self._getOrCreateVar(_vars[i]))
|
|
4525
4909
|
|
|
4526
4910
|
return vars
|
|
4527
4911
|
|
|
@@ -5795,7 +6179,7 @@ cdef class Model:
|
|
|
5795
6179
|
Parameters
|
|
5796
6180
|
----------
|
|
5797
6181
|
cons : ExprCons
|
|
5798
|
-
|
|
6182
|
+
the constraint expression to add to the model (e.g., x + y <= 5)
|
|
5799
6183
|
name : str, optional
|
|
5800
6184
|
the name of the constraint, generic name if empty (Default value = "")
|
|
5801
6185
|
initial : bool, optional
|
|
@@ -5845,7 +6229,7 @@ cdef class Model:
|
|
|
5845
6229
|
scip_cons = (<Constraint>pycons_initial).scip_cons
|
|
5846
6230
|
|
|
5847
6231
|
PY_SCIP_CALL(SCIPaddCons(self._scip, scip_cons))
|
|
5848
|
-
pycons =
|
|
6232
|
+
pycons = self._getOrCreateCons(scip_cons)
|
|
5849
6233
|
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &scip_cons))
|
|
5850
6234
|
|
|
5851
6235
|
return pycons
|
|
@@ -6167,7 +6551,7 @@ cdef class Model:
|
|
|
6167
6551
|
PY_SCIP_CALL(SCIPaddConsElemDisjunction(self._scip,disj_cons, (<Constraint>pycons).scip_cons))
|
|
6168
6552
|
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &(<Constraint>pycons).scip_cons))
|
|
6169
6553
|
PY_SCIP_CALL(SCIPaddCons(self._scip, disj_cons))
|
|
6170
|
-
PyCons =
|
|
6554
|
+
PyCons = self._getOrCreateCons(disj_cons)
|
|
6171
6555
|
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &disj_cons))
|
|
6172
6556
|
|
|
6173
6557
|
return PyCons
|
|
@@ -6253,20 +6637,11 @@ cdef class Model:
|
|
|
6253
6637
|
|
|
6254
6638
|
vars = []
|
|
6255
6639
|
for i in range(nvars):
|
|
6256
|
-
|
|
6257
|
-
# check whether the corresponding variable exists already
|
|
6258
|
-
if ptr in self._modelvars:
|
|
6259
|
-
vars.append(self._modelvars[ptr])
|
|
6260
|
-
else:
|
|
6261
|
-
# create a new variable
|
|
6262
|
-
var = Variable.create(_vars[i])
|
|
6263
|
-
assert var.ptr() == ptr
|
|
6264
|
-
self._modelvars[ptr] = var
|
|
6265
|
-
vars.append(var)
|
|
6640
|
+
vars.append(self._getOrCreateVar(_vars[i]))
|
|
6266
6641
|
|
|
6267
6642
|
free(_vars)
|
|
6268
6643
|
return vars
|
|
6269
|
-
|
|
6644
|
+
|
|
6270
6645
|
def getConsVals(self, Constraint constraint):
|
|
6271
6646
|
"""
|
|
6272
6647
|
Returns the value array of an arbitrary SCIP constraint that can be represented as a single linear constraint.
|
|
@@ -6342,16 +6717,7 @@ cdef class Model:
|
|
|
6342
6717
|
|
|
6343
6718
|
vars = []
|
|
6344
6719
|
for i in range(nvars):
|
|
6345
|
-
|
|
6346
|
-
# check whether the corresponding variable exists already
|
|
6347
|
-
if ptr in self._modelvars:
|
|
6348
|
-
vars.append(self._modelvars[ptr])
|
|
6349
|
-
else:
|
|
6350
|
-
# create a new variable
|
|
6351
|
-
var = Variable.create(_vars[i])
|
|
6352
|
-
assert var.ptr() == ptr
|
|
6353
|
-
self._modelvars[ptr] = var
|
|
6354
|
-
vars.append(var)
|
|
6720
|
+
vars.append(self._getOrCreateVar(_vars[i]))
|
|
6355
6721
|
|
|
6356
6722
|
return vars
|
|
6357
6723
|
|
|
@@ -6369,22 +6735,10 @@ cdef class Model:
|
|
|
6369
6735
|
Variable
|
|
6370
6736
|
|
|
6371
6737
|
"""
|
|
6372
|
-
|
|
6373
6738
|
cdef SCIP_VAR* _resultant
|
|
6374
6739
|
|
|
6375
6740
|
_resultant = SCIPgetResultantAnd(self._scip, and_cons.scip_cons)
|
|
6376
|
-
|
|
6377
|
-
ptr = <size_t>(_resultant)
|
|
6378
|
-
# check whether the corresponding variable exists already
|
|
6379
|
-
if ptr not in self._modelvars:
|
|
6380
|
-
# create a new variable
|
|
6381
|
-
resultant = Variable.create(_resultant)
|
|
6382
|
-
assert resultant.ptr() == ptr
|
|
6383
|
-
self._modelvars[ptr] = resultant
|
|
6384
|
-
else:
|
|
6385
|
-
resultant = self._modelvars[ptr]
|
|
6386
|
-
|
|
6387
|
-
return resultant
|
|
6741
|
+
return self._getOrCreateVar(_resultant)
|
|
6388
6742
|
|
|
6389
6743
|
def isAndConsSorted(self, Constraint and_cons):
|
|
6390
6744
|
"""
|
|
@@ -6415,38 +6769,6 @@ cdef class Model:
|
|
|
6415
6769
|
"""
|
|
6416
6770
|
|
|
6417
6771
|
PY_SCIP_CALL(SCIPsortAndCons(self._scip, and_cons.scip_cons))
|
|
6418
|
-
|
|
6419
|
-
def chgAndConsCheckFlagWhenUpgr(self, Constraint cons, flag):
|
|
6420
|
-
"""
|
|
6421
|
-
when 'upgrading' the given AND-constraint, should the check flag for the upgraded
|
|
6422
|
-
constraint be set to TRUE, even if the check flag of this AND-constraint is set to FALSE?
|
|
6423
|
-
|
|
6424
|
-
Parameters
|
|
6425
|
-
----------
|
|
6426
|
-
cons : Constraint
|
|
6427
|
-
The AND constraint to change.
|
|
6428
|
-
flag : bool
|
|
6429
|
-
The new value for the check flag.
|
|
6430
|
-
|
|
6431
|
-
"""
|
|
6432
|
-
|
|
6433
|
-
PY_SCIP_CALL(SCIPchgAndConsCheckFlagWhenUpgr(self._scip, cons.scip_cons, flag))
|
|
6434
|
-
|
|
6435
|
-
def chgAndConsRemovableFlagWhenUpgr(self, Constraint cons, flag):
|
|
6436
|
-
"""
|
|
6437
|
-
when 'upgrading' the given AND-constraint, should the removable flag for the upgraded
|
|
6438
|
-
constraint be set to TRUE, even if the removable flag of this AND-constraint is set to FALSE?
|
|
6439
|
-
|
|
6440
|
-
Parameters
|
|
6441
|
-
----------
|
|
6442
|
-
cons : Constraint
|
|
6443
|
-
The AND constraint to change.
|
|
6444
|
-
flag : bool
|
|
6445
|
-
The new value for the removable flag.
|
|
6446
|
-
|
|
6447
|
-
"""
|
|
6448
|
-
|
|
6449
|
-
PY_SCIP_CALL(SCIPchgAndConsRemovableFlagWhenUpgr(self._scip, cons.scip_cons, flag))
|
|
6450
6772
|
|
|
6451
6773
|
def printCons(self, Constraint constraint):
|
|
6452
6774
|
"""
|
|
@@ -6505,7 +6827,10 @@ cdef class Model:
|
|
|
6505
6827
|
else:
|
|
6506
6828
|
raise NotImplementedError("Adding coefficients to %s constraints is not implemented." % constype)
|
|
6507
6829
|
|
|
6508
|
-
def addConsNode(self, Node node,
|
|
6830
|
+
def addConsNode(self, Node node, ExprCons cons, Node validnode=None, name='',
|
|
6831
|
+
initial=True, separate=True, enforce=True, check=True,
|
|
6832
|
+
propagate=True, local=True, dynamic=False, removable=True,
|
|
6833
|
+
stickingatnode=True):
|
|
6509
6834
|
"""
|
|
6510
6835
|
Add a constraint to the given node.
|
|
6511
6836
|
|
|
@@ -6513,35 +6838,120 @@ cdef class Model:
|
|
|
6513
6838
|
----------
|
|
6514
6839
|
node : Node
|
|
6515
6840
|
node at which the constraint will be added
|
|
6516
|
-
cons :
|
|
6517
|
-
the constraint to add to the node
|
|
6841
|
+
cons : ExprCons
|
|
6842
|
+
the constraint expression to add to the node (e.g., x + y <= 5)
|
|
6518
6843
|
validnode : Node or None, optional
|
|
6519
6844
|
more global node where cons is also valid. (Default=None)
|
|
6845
|
+
name : str, optional
|
|
6846
|
+
name of the constraint (Default value = '')
|
|
6847
|
+
initial : bool, optional
|
|
6848
|
+
should the LP relaxation of constraint be in the initial LP? (Default value = True)
|
|
6849
|
+
separate : bool, optional
|
|
6850
|
+
should the constraint be separated during LP processing? (Default value = True)
|
|
6851
|
+
enforce : bool, optional
|
|
6852
|
+
should the constraint be enforced during node processing? (Default value = True)
|
|
6853
|
+
check : bool, optional
|
|
6854
|
+
should the constraint be checked for feasibility? (Default value = True)
|
|
6855
|
+
propagate : bool, optional
|
|
6856
|
+
should the constraint be propagated during node processing? (Default value = True)
|
|
6857
|
+
local : bool, optional
|
|
6858
|
+
is the constraint only valid locally? (Default value = True)
|
|
6859
|
+
dynamic : bool, optional
|
|
6860
|
+
is the constraint subject to aging? (Default value = False)
|
|
6861
|
+
removable : bool, optional
|
|
6862
|
+
should the relaxation be removed from the LP due to aging or cleanup? (Default value = True)
|
|
6863
|
+
stickingatnode : bool, optional
|
|
6864
|
+
should the constraint always be kept at the node where it was added? (Default value = True)
|
|
6865
|
+
|
|
6866
|
+
Returns
|
|
6867
|
+
-------
|
|
6868
|
+
Constraint
|
|
6869
|
+
The added Constraint object.
|
|
6520
6870
|
|
|
6521
6871
|
"""
|
|
6872
|
+
assert isinstance(cons, ExprCons), "given constraint is not ExprCons but %s" % cons.__class__.__name__
|
|
6873
|
+
|
|
6874
|
+
cdef SCIP_CONS* scip_cons
|
|
6875
|
+
|
|
6876
|
+
kwargs = dict(name=name, initial=initial, separate=separate,
|
|
6877
|
+
enforce=enforce, check=check, propagate=propagate,
|
|
6878
|
+
local=local, modifiable=False, dynamic=dynamic,
|
|
6879
|
+
removable=removable, stickingatnode=stickingatnode)
|
|
6880
|
+
pycons_initial = self.createConsFromExpr(cons, **kwargs)
|
|
6881
|
+
scip_cons = (<Constraint>pycons_initial).scip_cons
|
|
6882
|
+
|
|
6522
6883
|
if isinstance(validnode, Node):
|
|
6523
|
-
PY_SCIP_CALL(SCIPaddConsNode(self._scip, node.scip_node,
|
|
6884
|
+
PY_SCIP_CALL(SCIPaddConsNode(self._scip, node.scip_node, scip_cons, validnode.scip_node))
|
|
6524
6885
|
else:
|
|
6525
|
-
PY_SCIP_CALL(SCIPaddConsNode(self._scip, node.scip_node,
|
|
6526
|
-
|
|
6886
|
+
PY_SCIP_CALL(SCIPaddConsNode(self._scip, node.scip_node, scip_cons, NULL))
|
|
6887
|
+
|
|
6888
|
+
pycons = Constraint.create(scip_cons)
|
|
6889
|
+
pycons.data = (<Constraint>pycons_initial).data
|
|
6890
|
+
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &scip_cons))
|
|
6891
|
+
|
|
6892
|
+
return pycons
|
|
6527
6893
|
|
|
6528
|
-
def addConsLocal(self,
|
|
6894
|
+
def addConsLocal(self, ExprCons cons, Node validnode=None, name='',
|
|
6895
|
+
initial=True, separate=True, enforce=True, check=True,
|
|
6896
|
+
propagate=True, local=True, dynamic=False, removable=True,
|
|
6897
|
+
stickingatnode=True):
|
|
6529
6898
|
"""
|
|
6530
6899
|
Add a constraint to the current node.
|
|
6531
6900
|
|
|
6532
6901
|
Parameters
|
|
6533
6902
|
----------
|
|
6534
|
-
cons :
|
|
6535
|
-
the constraint to add to the current node
|
|
6903
|
+
cons : ExprCons
|
|
6904
|
+
the constraint expression to add to the current node (e.g., x + y <= 5)
|
|
6536
6905
|
validnode : Node or None, optional
|
|
6537
6906
|
more global node where cons is also valid. (Default=None)
|
|
6907
|
+
name : str, optional
|
|
6908
|
+
name of the constraint (Default value = '')
|
|
6909
|
+
initial : bool, optional
|
|
6910
|
+
should the LP relaxation of constraint be in the initial LP? (Default value = True)
|
|
6911
|
+
separate : bool, optional
|
|
6912
|
+
should the constraint be separated during LP processing? (Default value = True)
|
|
6913
|
+
enforce : bool, optional
|
|
6914
|
+
should the constraint be enforced during node processing? (Default value = True)
|
|
6915
|
+
check : bool, optional
|
|
6916
|
+
should the constraint be checked for feasibility? (Default value = True)
|
|
6917
|
+
propagate : bool, optional
|
|
6918
|
+
should the constraint be propagated during node processing? (Default value = True)
|
|
6919
|
+
local : bool, optional
|
|
6920
|
+
is the constraint only valid locally? (Default value = True)
|
|
6921
|
+
dynamic : bool, optional
|
|
6922
|
+
is the constraint subject to aging? (Default value = False)
|
|
6923
|
+
removable : bool, optional
|
|
6924
|
+
should the relaxation be removed from the LP due to aging or cleanup? (Default value = True)
|
|
6925
|
+
stickingatnode : bool, optional
|
|
6926
|
+
should the constraint always be kept at the node where it was added? (Default value = True)
|
|
6927
|
+
|
|
6928
|
+
Returns
|
|
6929
|
+
-------
|
|
6930
|
+
Constraint
|
|
6931
|
+
The added Constraint object.
|
|
6538
6932
|
|
|
6539
6933
|
"""
|
|
6934
|
+
assert isinstance(cons, ExprCons), "given constraint is not ExprCons but %s" % cons.__class__.__name__
|
|
6935
|
+
|
|
6936
|
+
cdef SCIP_CONS* scip_cons
|
|
6937
|
+
|
|
6938
|
+
kwargs = dict(name=name, initial=initial, separate=separate,
|
|
6939
|
+
enforce=enforce, check=check, propagate=propagate,
|
|
6940
|
+
local=local, modifiable=False, dynamic=dynamic,
|
|
6941
|
+
removable=removable, stickingatnode=stickingatnode)
|
|
6942
|
+
pycons_initial = self.createConsFromExpr(cons, **kwargs)
|
|
6943
|
+
scip_cons = (<Constraint>pycons_initial).scip_cons
|
|
6944
|
+
|
|
6540
6945
|
if isinstance(validnode, Node):
|
|
6541
|
-
PY_SCIP_CALL(SCIPaddConsLocal(self._scip,
|
|
6946
|
+
PY_SCIP_CALL(SCIPaddConsLocal(self._scip, scip_cons, validnode.scip_node))
|
|
6542
6947
|
else:
|
|
6543
|
-
PY_SCIP_CALL(SCIPaddConsLocal(self._scip,
|
|
6544
|
-
|
|
6948
|
+
PY_SCIP_CALL(SCIPaddConsLocal(self._scip, scip_cons, NULL))
|
|
6949
|
+
|
|
6950
|
+
pycons = Constraint.create(scip_cons)
|
|
6951
|
+
pycons.data = (<Constraint>pycons_initial).data
|
|
6952
|
+
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &scip_cons))
|
|
6953
|
+
|
|
6954
|
+
return pycons
|
|
6545
6955
|
|
|
6546
6956
|
def addConsKnapsack(self, vars, weights, capacity, name="",
|
|
6547
6957
|
initial=True, separate=True, enforce=True, check=True,
|
|
@@ -6608,9 +7018,9 @@ cdef class Model:
|
|
|
6608
7018
|
|
|
6609
7019
|
PY_SCIP_CALL(SCIPaddCons(self._scip, scip_cons))
|
|
6610
7020
|
|
|
6611
|
-
pyCons =
|
|
7021
|
+
pyCons = self._getOrCreateCons(scip_cons)
|
|
6612
7022
|
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &scip_cons))
|
|
6613
|
-
|
|
7023
|
+
|
|
6614
7024
|
return pyCons
|
|
6615
7025
|
|
|
6616
7026
|
def addConsSOS1(self, vars, weights=None, name="",
|
|
@@ -6676,7 +7086,7 @@ cdef class Model:
|
|
|
6676
7086
|
|
|
6677
7087
|
PY_SCIP_CALL(SCIPaddCons(self._scip, scip_cons))
|
|
6678
7088
|
|
|
6679
|
-
return
|
|
7089
|
+
return self._getOrCreateCons(scip_cons)
|
|
6680
7090
|
|
|
6681
7091
|
def addConsSOS2(self, vars, weights=None, name="",
|
|
6682
7092
|
initial=True, separate=True, enforce=True, check=True,
|
|
@@ -6741,7 +7151,7 @@ cdef class Model:
|
|
|
6741
7151
|
|
|
6742
7152
|
PY_SCIP_CALL(SCIPaddCons(self._scip, scip_cons))
|
|
6743
7153
|
|
|
6744
|
-
return
|
|
7154
|
+
return self._getOrCreateCons(scip_cons)
|
|
6745
7155
|
|
|
6746
7156
|
def addConsAnd(self, vars, resvar, name="",
|
|
6747
7157
|
initial=True, separate=True, enforce=True, check=True,
|
|
@@ -6802,7 +7212,7 @@ cdef class Model:
|
|
|
6802
7212
|
initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode))
|
|
6803
7213
|
|
|
6804
7214
|
PY_SCIP_CALL(SCIPaddCons(self._scip, scip_cons))
|
|
6805
|
-
pyCons =
|
|
7215
|
+
pyCons = self._getOrCreateCons(scip_cons)
|
|
6806
7216
|
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &scip_cons))
|
|
6807
7217
|
|
|
6808
7218
|
return pyCons
|
|
@@ -6866,7 +7276,7 @@ cdef class Model:
|
|
|
6866
7276
|
initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode))
|
|
6867
7277
|
|
|
6868
7278
|
PY_SCIP_CALL(SCIPaddCons(self._scip, scip_cons))
|
|
6869
|
-
pyCons =
|
|
7279
|
+
pyCons = self._getOrCreateCons(scip_cons)
|
|
6870
7280
|
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &scip_cons))
|
|
6871
7281
|
|
|
6872
7282
|
return pyCons
|
|
@@ -6929,7 +7339,7 @@ cdef class Model:
|
|
|
6929
7339
|
initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode))
|
|
6930
7340
|
|
|
6931
7341
|
PY_SCIP_CALL(SCIPaddCons(self._scip, scip_cons))
|
|
6932
|
-
pyCons =
|
|
7342
|
+
pyCons = self._getOrCreateCons(scip_cons)
|
|
6933
7343
|
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &scip_cons))
|
|
6934
7344
|
|
|
6935
7345
|
return pyCons
|
|
@@ -7014,7 +7424,7 @@ cdef class Model:
|
|
|
7014
7424
|
PY_SCIP_CALL(SCIPaddVarCardinality(self._scip, scip_cons, scip_var, indvar, <SCIP_Real>weights[i]))
|
|
7015
7425
|
|
|
7016
7426
|
PY_SCIP_CALL(SCIPaddCons(self._scip, scip_cons))
|
|
7017
|
-
pyCons =
|
|
7427
|
+
pyCons = self._getOrCreateCons(scip_cons)
|
|
7018
7428
|
|
|
7019
7429
|
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &scip_cons))
|
|
7020
7430
|
|
|
@@ -7107,7 +7517,7 @@ cdef class Model:
|
|
|
7107
7517
|
PY_SCIP_CALL(SCIPaddVarIndicator(self._scip, scip_cons, wrapper.ptr[0], <SCIP_Real>coeff))
|
|
7108
7518
|
|
|
7109
7519
|
PY_SCIP_CALL(SCIPaddCons(self._scip, scip_cons))
|
|
7110
|
-
pyCons =
|
|
7520
|
+
pyCons = self._getOrCreateCons(scip_cons)
|
|
7111
7521
|
|
|
7112
7522
|
PY_SCIP_CALL(SCIPreleaseCons(self._scip, &scip_cons))
|
|
7113
7523
|
|
|
@@ -7297,7 +7707,7 @@ cdef class Model:
|
|
|
7297
7707
|
cdef SCIP_CONS* lincons = SCIPgetLinearConsIndicator(cons.scip_cons)
|
|
7298
7708
|
if lincons == NULL:
|
|
7299
7709
|
return None
|
|
7300
|
-
return
|
|
7710
|
+
return self._getOrCreateCons(lincons)
|
|
7301
7711
|
|
|
7302
7712
|
def getSlackVarIndicator(self, Constraint cons):
|
|
7303
7713
|
"""
|
|
@@ -7315,7 +7725,7 @@ cdef class Model:
|
|
|
7315
7725
|
|
|
7316
7726
|
"""
|
|
7317
7727
|
cdef SCIP_VAR* var = SCIPgetSlackVarIndicator(cons.scip_cons)
|
|
7318
|
-
return
|
|
7728
|
+
return self._getOrCreateVar(var)
|
|
7319
7729
|
|
|
7320
7730
|
def addPyCons(self, Constraint cons):
|
|
7321
7731
|
"""
|
|
@@ -7759,7 +8169,7 @@ cdef class Model:
|
|
|
7759
8169
|
"""
|
|
7760
8170
|
cdef SCIP_CONS* transcons
|
|
7761
8171
|
PY_SCIP_CALL(SCIPgetTransformedCons(self._scip, cons.scip_cons, &transcons))
|
|
7762
|
-
return
|
|
8172
|
+
return self._getOrCreateCons(transcons)
|
|
7763
8173
|
|
|
7764
8174
|
def isNLPConstructed(self):
|
|
7765
8175
|
"""
|
|
@@ -7899,8 +8309,16 @@ cdef class Model:
|
|
|
7899
8309
|
Returns
|
|
7900
8310
|
-------
|
|
7901
8311
|
bilinterms : list of tuple
|
|
8312
|
+
Triples ``(var1, var2, coef)`` for terms of the form
|
|
8313
|
+
``coef * var1 * var2`` with ``var1 != var2``.
|
|
7902
8314
|
quadterms : list of tuple
|
|
8315
|
+
Triples ``(var, sqrcoef, lincoef)`` for variables that appear in
|
|
8316
|
+
quadratic or bilinear terms. ``sqrcoef`` is the coefficient of
|
|
8317
|
+
``var**2``, and ``lincoef`` is the linear coefficient of ``var``
|
|
8318
|
+
if it also appears linearly.
|
|
7903
8319
|
linterms : list of tuple
|
|
8320
|
+
Pairs ``(var, coef)`` for purely linear variables, i.e.,
|
|
8321
|
+
variables that do not participate in any quadratic or bilinear term.
|
|
7904
8322
|
|
|
7905
8323
|
"""
|
|
7906
8324
|
cdef SCIP_EXPR* expr
|
|
@@ -7919,6 +8337,7 @@ cdef class Model:
|
|
|
7919
8337
|
cdef int nbilinterms
|
|
7920
8338
|
|
|
7921
8339
|
# quadratic terms
|
|
8340
|
+
cdef SCIP_EXPR* quadexpr
|
|
7922
8341
|
cdef SCIP_EXPR* sqrexpr
|
|
7923
8342
|
cdef SCIP_Real sqrcoef
|
|
7924
8343
|
cdef int nquadterms
|
|
@@ -7931,33 +8350,49 @@ cdef class Model:
|
|
|
7931
8350
|
assert self.checkQuadraticNonlinear(cons), "constraint is not quadratic"
|
|
7932
8351
|
|
|
7933
8352
|
expr = SCIPgetExprNonlinear(cons.scip_cons)
|
|
7934
|
-
SCIPexprGetQuadraticData(expr, NULL, &nlinvars, &linexprs, &lincoefs,
|
|
8353
|
+
SCIPexprGetQuadraticData(expr, NULL, &nlinvars, &linexprs, &lincoefs,
|
|
8354
|
+
&nquadterms, &nbilinterms, NULL, NULL)
|
|
7935
8355
|
|
|
7936
8356
|
linterms = []
|
|
7937
8357
|
bilinterms = []
|
|
7938
|
-
quadterms = []
|
|
7939
8358
|
|
|
8359
|
+
# Purely linear terms (variables not in any quadratic/bilinear term)
|
|
7940
8360
|
for termidx in range(nlinvars):
|
|
7941
|
-
var =
|
|
8361
|
+
var = self._getOrCreateVar(SCIPgetVarExprVar(linexprs[termidx]))
|
|
7942
8362
|
linterms.append((var, lincoefs[termidx]))
|
|
7943
8363
|
|
|
8364
|
+
# Collect quadratic terms in a dict so we can merge entries for the same variable.
|
|
8365
|
+
quaddict = {} # var.ptr() -> [var, sqrcoef, lincoef]
|
|
8366
|
+
|
|
7944
8367
|
for termidx in range(nbilinterms):
|
|
7945
8368
|
SCIPexprGetQuadraticBilinTerm(expr, termidx, &bilinterm1, &bilinterm2, &bilincoef, NULL, NULL)
|
|
7946
8369
|
scipvar1 = SCIPgetVarExprVar(bilinterm1)
|
|
7947
8370
|
scipvar2 = SCIPgetVarExprVar(bilinterm2)
|
|
7948
|
-
var1 =
|
|
7949
|
-
var2 =
|
|
8371
|
+
var1 = self._getOrCreateVar(scipvar1)
|
|
8372
|
+
var2 = self._getOrCreateVar(scipvar2)
|
|
7950
8373
|
if scipvar1 != scipvar2:
|
|
7951
|
-
bilinterms.append((var1,var2,bilincoef))
|
|
8374
|
+
bilinterms.append((var1, var2, bilincoef))
|
|
7952
8375
|
else:
|
|
7953
|
-
|
|
7954
|
-
|
|
8376
|
+
# Squared term reported as bilinear var*var
|
|
8377
|
+
key = var1.ptr()
|
|
8378
|
+
if key in quaddict:
|
|
8379
|
+
quaddict[key][1] += bilincoef
|
|
8380
|
+
else: # TODO: SCIP handles expr like x**2 appropriately, but PySCIPOpt requires this. Need to investigate why.
|
|
8381
|
+
quaddict[key] = [var1, bilincoef, 0.0]
|
|
8382
|
+
|
|
8383
|
+
# Also collect linear coefficients from the quadratic terms
|
|
7955
8384
|
for termidx in range(nquadterms):
|
|
7956
|
-
SCIPexprGetQuadraticQuadTerm(expr, termidx,
|
|
7957
|
-
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
8385
|
+
SCIPexprGetQuadraticQuadTerm(expr, termidx, &quadexpr, &lincoef, &sqrcoef, NULL, NULL, &sqrexpr)
|
|
8386
|
+
scipvar1 = SCIPgetVarExprVar(quadexpr)
|
|
8387
|
+
var = self._getOrCreateVar(scipvar1)
|
|
8388
|
+
key = var.ptr()
|
|
8389
|
+
if key in quaddict:
|
|
8390
|
+
quaddict[key][1] += sqrcoef
|
|
8391
|
+
quaddict[key][2] += lincoef
|
|
8392
|
+
else:
|
|
8393
|
+
quaddict[key] = [var, sqrcoef, lincoef]
|
|
8394
|
+
|
|
8395
|
+
quadterms = [tuple(entry) for entry in quaddict.values()]
|
|
7961
8396
|
|
|
7962
8397
|
return (bilinterms, quadterms, linterms)
|
|
7963
8398
|
|
|
@@ -8016,7 +8451,7 @@ cdef class Model:
|
|
|
8016
8451
|
conss = SCIPgetOrigConss(self._scip)
|
|
8017
8452
|
nconss = SCIPgetNOrigConss(self._scip)
|
|
8018
8453
|
|
|
8019
|
-
return [
|
|
8454
|
+
return [self._getOrCreateCons(conss[i]) for i in range(nconss)]
|
|
8020
8455
|
|
|
8021
8456
|
def getNConss(self, transformed=True):
|
|
8022
8457
|
"""
|
|
@@ -8047,7 +8482,10 @@ cdef class Model:
|
|
|
8047
8482
|
constraint to be deleted
|
|
8048
8483
|
|
|
8049
8484
|
"""
|
|
8485
|
+
del self._modelconss[cons.ptr()]
|
|
8050
8486
|
PY_SCIP_CALL(SCIPdelCons(self._scip, cons.scip_cons))
|
|
8487
|
+
# Remove from tracking and invalidate pointer. See issue #604.
|
|
8488
|
+
cons.scip_cons = NULL
|
|
8051
8489
|
|
|
8052
8490
|
def delConsLocal(self, Constraint cons):
|
|
8053
8491
|
"""
|
|
@@ -8647,11 +9085,8 @@ cdef class Model:
|
|
|
8647
9085
|
PY_SCIP_CALL(SCIPgetBendersSubproblemVar(self._scip, _benders, var.scip_var, &_mappedvar, probnumber))
|
|
8648
9086
|
|
|
8649
9087
|
if _mappedvar == NULL:
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
mappedvar = Variable.create(_mappedvar)
|
|
8653
|
-
|
|
8654
|
-
return mappedvar
|
|
9088
|
+
return None
|
|
9089
|
+
return self._getOrCreateVar(_mappedvar)
|
|
8655
9090
|
|
|
8656
9091
|
def getBendersAuxiliaryVar(self, probnumber, Benders benders = None):
|
|
8657
9092
|
"""
|
|
@@ -8678,9 +9113,7 @@ cdef class Model:
|
|
|
8678
9113
|
_benders = benders._benders
|
|
8679
9114
|
|
|
8680
9115
|
_auxvar = SCIPbendersGetAuxiliaryVar(_benders, probnumber)
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
return auxvar
|
|
9116
|
+
return self._getOrCreateVar(_auxvar)
|
|
8684
9117
|
|
|
8685
9118
|
def checkBendersSubproblemOptimality(self, Solution solution, probnumber, Benders benders = None):
|
|
8686
9119
|
"""
|
|
@@ -9154,7 +9587,10 @@ cdef class Model:
|
|
|
9154
9587
|
maxdepth : int, optional
|
|
9155
9588
|
maximal depth level to call heuristic at (Default value = -1)
|
|
9156
9589
|
timingmask : PY_SCIP_HEURTIMING, optional
|
|
9157
|
-
positions in the node
|
|
9590
|
+
positions in the node solvingreturn {
|
|
9591
|
+
'result': SCIP_RESULT.SUCCESS,
|
|
9592
|
+
'lowerbound': 10e4
|
|
9593
|
+
} loop where heuristic should be executed
|
|
9158
9594
|
(Default value = SCIP_HEURTIMING_BEFORENODE)
|
|
9159
9595
|
usessubscip : bool, optional
|
|
9160
9596
|
does the heuristic use a secondary SCIP instance? (Default value = False)
|
|
@@ -9172,6 +9608,72 @@ cdef class Model:
|
|
|
9172
9608
|
heur.model = <Model>weakref.proxy(self)
|
|
9173
9609
|
heur.name = name
|
|
9174
9610
|
Py_INCREF(heur)
|
|
9611
|
+
|
|
9612
|
+
def includeIISfinder(self, IISfinder iisfinder, name, desc, priority=10000, freq=1):
|
|
9613
|
+
"""
|
|
9614
|
+
Include an IIS (Irreducible Infeasible Set) finder handler.
|
|
9615
|
+
|
|
9616
|
+
Parameters
|
|
9617
|
+
----------
|
|
9618
|
+
iisfinder : IISfinder
|
|
9619
|
+
IIS finder
|
|
9620
|
+
name : str
|
|
9621
|
+
name of IIS finder
|
|
9622
|
+
desc : str
|
|
9623
|
+
description of IIS finder
|
|
9624
|
+
priority : int, optional
|
|
9625
|
+
priority of the IISfinder (#todo description)
|
|
9626
|
+
freq : int, optional
|
|
9627
|
+
frequency for calling IIS finder
|
|
9628
|
+
|
|
9629
|
+
"""
|
|
9630
|
+
cdef SCIP_IISFINDER* scip_iisfinder
|
|
9631
|
+
|
|
9632
|
+
nam = str_conversion(name)
|
|
9633
|
+
des = str_conversion(desc)
|
|
9634
|
+
|
|
9635
|
+
iisfinder.iis = IIS()
|
|
9636
|
+
|
|
9637
|
+
PY_SCIP_CALL(SCIPincludeIISfinder(self._scip, nam, des, priority, PyiisfinderCopy, PyiisfinderFree,
|
|
9638
|
+
PyiisfinderExec, <SCIP_IISFINDERDATA*> iisfinder))
|
|
9639
|
+
|
|
9640
|
+
scip_iisfinder = SCIPfindIISfinder(self._scip, nam)
|
|
9641
|
+
iisfinder.name = name
|
|
9642
|
+
Py_INCREF(iisfinder)
|
|
9643
|
+
iisfinder.scip_iisfinder = scip_iisfinder
|
|
9644
|
+
|
|
9645
|
+
def generateIIS(self):
|
|
9646
|
+
"""
|
|
9647
|
+
Generates an Irreducible Infeasible Subsystem (IIS) from the current
|
|
9648
|
+
problem.
|
|
9649
|
+
|
|
9650
|
+
Returns
|
|
9651
|
+
-------
|
|
9652
|
+
IIS
|
|
9653
|
+
|
|
9654
|
+
"""
|
|
9655
|
+
cdef SCIP_IIS* _iis
|
|
9656
|
+
|
|
9657
|
+
PY_SCIP_CALL( SCIPgenerateIIS(self._scip) )
|
|
9658
|
+
|
|
9659
|
+
_iis = SCIPgetIIS(self._scip)
|
|
9660
|
+
return IIS.create(_iis)
|
|
9661
|
+
|
|
9662
|
+
def getIIS(self):
|
|
9663
|
+
"""
|
|
9664
|
+
Get the IIS object.
|
|
9665
|
+
Note: Needs to be called after generateIIS, or after a single execution of the iisfinderExec.
|
|
9666
|
+
|
|
9667
|
+
Returns
|
|
9668
|
+
-------
|
|
9669
|
+
IIS
|
|
9670
|
+
"""
|
|
9671
|
+
cdef SCIP_IIS* _iis
|
|
9672
|
+
|
|
9673
|
+
_iis = SCIPgetIIS(self._scip)
|
|
9674
|
+
assert _iis != NULL, "No IIS exists. You need to first call generateIIS() or run the iisfinderexec method of your custom IISfinder class."
|
|
9675
|
+
|
|
9676
|
+
return IIS.create(_iis)
|
|
9175
9677
|
|
|
9176
9678
|
def includeRelax(self, Relax relax, name, desc, priority=10000, freq=1):
|
|
9177
9679
|
"""
|
|
@@ -9404,7 +9906,7 @@ cdef class Model:
|
|
|
9404
9906
|
PY_SCIP_CALL(SCIPgetLPBranchCands(self._scip, &lpcands, &lpcandssol, &lpcandsfrac,
|
|
9405
9907
|
&nlpcands, &npriolpcands, &nfracimplvars))
|
|
9406
9908
|
|
|
9407
|
-
return ([
|
|
9909
|
+
return ([self._getOrCreateVar(lpcands[i]) for i in range(nlpcands)], [lpcandssol[i] for i in range(nlpcands)],
|
|
9408
9910
|
[lpcandsfrac[i] for i in range(nlpcands)], nlpcands, npriolpcands, nfracimplvars)
|
|
9409
9911
|
|
|
9410
9912
|
def getNLPBranchCands(self):
|
|
@@ -9441,7 +9943,7 @@ cdef class Model:
|
|
|
9441
9943
|
|
|
9442
9944
|
PY_SCIP_CALL(SCIPgetPseudoBranchCands(self._scip, &pseudocands, &npseudocands, &npriopseudocands))
|
|
9443
9945
|
|
|
9444
|
-
return ([
|
|
9946
|
+
return ([self._getOrCreateVar(pseudocands[i]) for i in range(npseudocands)], npseudocands, npriopseudocands)
|
|
9445
9947
|
|
|
9446
9948
|
def branchVar(self, Variable variable):
|
|
9447
9949
|
"""
|
|
@@ -10416,7 +10918,10 @@ cdef class Model:
|
|
|
10416
10918
|
Solution or None
|
|
10417
10919
|
|
|
10418
10920
|
"""
|
|
10419
|
-
|
|
10921
|
+
cdef SCIP_SOL* _sol = SCIPgetBestSol(self._scip)
|
|
10922
|
+
if _sol == NULL:
|
|
10923
|
+
return None
|
|
10924
|
+
self._bestSol = Solution.create(self._scip, _sol)
|
|
10420
10925
|
return self._bestSol
|
|
10421
10926
|
|
|
10422
10927
|
def getSolObjVal(self, Solution sol, original=True):
|
|
@@ -10459,6 +10964,8 @@ cdef class Model:
|
|
|
10459
10964
|
float
|
|
10460
10965
|
|
|
10461
10966
|
"""
|
|
10967
|
+
if sol is None or sol.sol == NULL:
|
|
10968
|
+
raise ValueError("Cannot get solution time: solution is None or NULL")
|
|
10462
10969
|
return SCIPgetSolTime(self._scip, sol.sol)
|
|
10463
10970
|
|
|
10464
10971
|
def getObjVal(self, original=True):
|
|
@@ -10492,20 +10999,26 @@ cdef class Model:
|
|
|
10492
10999
|
|
|
10493
11000
|
return self.getSolObjVal(self._bestSol, original)
|
|
10494
11001
|
|
|
10495
|
-
def getSolVal(
|
|
11002
|
+
def getSolVal(
|
|
11003
|
+
self,
|
|
11004
|
+
Solution sol,
|
|
11005
|
+
expr: Union[Expr, GenExpr, MatrixExpr],
|
|
11006
|
+
) -> Union[float, np.ndarray]:
|
|
10496
11007
|
"""
|
|
10497
|
-
Retrieve value of given variable or expression in the given solution
|
|
10498
|
-
the LP/pseudo solution if sol == None
|
|
11008
|
+
Retrieve value of given variable or expression in the given solution.
|
|
10499
11009
|
|
|
10500
11010
|
Parameters
|
|
10501
11011
|
----------
|
|
10502
11012
|
sol : Solution
|
|
10503
|
-
|
|
10504
|
-
|
|
11013
|
+
Solution to query the value from. If None, the current LP/pseudo solution is
|
|
11014
|
+
used.
|
|
11015
|
+
|
|
11016
|
+
expr : Expr, GenExpr, MatrixExpr
|
|
11017
|
+
Expression to query the value of.
|
|
10505
11018
|
|
|
10506
11019
|
Returns
|
|
10507
11020
|
-------
|
|
10508
|
-
float
|
|
11021
|
+
float or np.ndarray
|
|
10509
11022
|
|
|
10510
11023
|
Notes
|
|
10511
11024
|
-----
|
|
@@ -10513,46 +11026,39 @@ cdef class Model:
|
|
|
10513
11026
|
|
|
10514
11027
|
"""
|
|
10515
11028
|
# no need to create a NULL solution wrapper in case we have a variable
|
|
10516
|
-
|
|
10517
|
-
if sol == None and isinstance(expr, Variable):
|
|
10518
|
-
wrapper = _VarArray(expr)
|
|
10519
|
-
return SCIPgetSolVal(self._scip, NULL, wrapper.ptr[0])
|
|
10520
|
-
if sol == None:
|
|
10521
|
-
sol = Solution.create(self._scip, NULL)
|
|
10522
|
-
return sol[expr]
|
|
11029
|
+
return (sol or Solution.create(self._scip, NULL))[expr]
|
|
10523
11030
|
|
|
10524
|
-
def getVal(self, expr: Union[Expr, MatrixExpr]
|
|
11031
|
+
def getVal(self, expr: Union[Expr, GenExpr, MatrixExpr]) -> Union[float, np.ndarray]:
|
|
10525
11032
|
"""
|
|
10526
11033
|
Retrieve the value of the given variable or expression in the best known solution.
|
|
10527
11034
|
Can only be called after solving is completed.
|
|
10528
11035
|
|
|
10529
11036
|
Parameters
|
|
10530
11037
|
----------
|
|
10531
|
-
expr : Expr
|
|
10532
|
-
|
|
11038
|
+
expr : Expr, GenExpr or MatrixExpr
|
|
11039
|
+
Expression to query the value of.
|
|
10533
11040
|
|
|
10534
11041
|
Returns
|
|
10535
11042
|
-------
|
|
10536
|
-
float
|
|
11043
|
+
float or np.ndarray
|
|
10537
11044
|
|
|
10538
11045
|
Notes
|
|
10539
11046
|
-----
|
|
10540
11047
|
A variable is also an expression.
|
|
10541
11048
|
|
|
10542
11049
|
"""
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
if not stage_check or self._bestSol.sol == NULL and SCIPgetStage(self._scip) != SCIP_STAGE_SOLVING:
|
|
11050
|
+
if SCIPgetStage(self._scip) in {SCIP_STAGE_INIT, SCIP_STAGE_FREE}:
|
|
10546
11051
|
raise Warning("Method cannot be called in stage ", self.getStage())
|
|
10547
11052
|
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
|
|
10551
|
-
|
|
10552
|
-
else:
|
|
10553
|
-
result = self.getSolVal(self._bestSol, expr)
|
|
11053
|
+
# Ensure _bestSol is up-to-date (cheap pointer comparison)
|
|
11054
|
+
cdef SCIP_SOL* current_best_sol = SCIPgetBestSol(self._scip)
|
|
11055
|
+
if self._bestSol is None or self._bestSol.sol != current_best_sol:
|
|
11056
|
+
self._bestSol = Solution.create(self._scip, current_best_sol)
|
|
10554
11057
|
|
|
10555
|
-
|
|
11058
|
+
if self._bestSol.sol == NULL and SCIPgetStage(self._scip) != SCIP_STAGE_SOLVING:
|
|
11059
|
+
raise Warning("No solution available")
|
|
11060
|
+
|
|
11061
|
+
return self._bestSol[expr]
|
|
10556
11062
|
|
|
10557
11063
|
def hasPrimalRay(self):
|
|
10558
11064
|
"""
|
|
@@ -10863,12 +11369,58 @@ cdef class Model:
|
|
|
10863
11369
|
|
|
10864
11370
|
# Statistic Methods
|
|
10865
11371
|
|
|
10866
|
-
def printStatistics(self):
|
|
10867
|
-
"""
|
|
11372
|
+
def printStatistics(self, filename=None):
|
|
11373
|
+
"""
|
|
11374
|
+
Print statistics.
|
|
11375
|
+
|
|
11376
|
+
Parameters
|
|
11377
|
+
----------
|
|
11378
|
+
filename : str, optional
|
|
11379
|
+
name of the output file (Default = None)
|
|
11380
|
+
|
|
11381
|
+
"""
|
|
11382
|
+
|
|
10868
11383
|
user_locale = locale.getlocale(category=locale.LC_NUMERIC)
|
|
10869
11384
|
locale.setlocale(locale.LC_NUMERIC, "C")
|
|
10870
11385
|
|
|
10871
|
-
|
|
11386
|
+
if not filename:
|
|
11387
|
+
PY_SCIP_CALL(SCIPprintStatistics(self._scip, NULL))
|
|
11388
|
+
else:
|
|
11389
|
+
with open(filename, "w") as f:
|
|
11390
|
+
cfile = fdopen(f.fileno(), "w")
|
|
11391
|
+
PY_SCIP_CALL(SCIPprintStatistics(self._scip, cfile))
|
|
11392
|
+
|
|
11393
|
+
locale.setlocale(locale.LC_NUMERIC,user_locale)
|
|
11394
|
+
|
|
11395
|
+
def printStatisticsJson(self, filename=None):
|
|
11396
|
+
"""
|
|
11397
|
+
Print statistics in JSON format.
|
|
11398
|
+
|
|
11399
|
+
Parameters
|
|
11400
|
+
----------
|
|
11401
|
+
filename : str, optional
|
|
11402
|
+
name of the output file (Default = None)
|
|
11403
|
+
|
|
11404
|
+
"""
|
|
11405
|
+
|
|
11406
|
+
user_locale = locale.getlocale(category=locale.LC_NUMERIC)
|
|
11407
|
+
locale.setlocale(locale.LC_NUMERIC, "C")
|
|
11408
|
+
|
|
11409
|
+
if not filename:
|
|
11410
|
+
PY_SCIP_CALL(SCIPprintStatisticsJson(self._scip, NULL))
|
|
11411
|
+
else:
|
|
11412
|
+
with open(filename, "w") as f:
|
|
11413
|
+
cfile = fdopen(f.fileno(), "w")
|
|
11414
|
+
PY_SCIP_CALL(SCIPprintStatisticsJson(self._scip, cfile))
|
|
11415
|
+
|
|
11416
|
+
locale.setlocale(locale.LC_NUMERIC,user_locale)
|
|
11417
|
+
|
|
11418
|
+
def printStatisticsJson(self):
|
|
11419
|
+
"""Print statistics in JSON format."""
|
|
11420
|
+
user_locale = locale.getlocale(category=locale.LC_NUMERIC)
|
|
11421
|
+
locale.setlocale(locale.LC_NUMERIC, "C")
|
|
11422
|
+
|
|
11423
|
+
PY_SCIP_CALL(SCIPprintStatisticsJson(self._scip, NULL))
|
|
10872
11424
|
|
|
10873
11425
|
locale.setlocale(locale.LC_NUMERIC,user_locale)
|
|
10874
11426
|
|
|
@@ -10892,6 +11444,28 @@ cdef class Model:
|
|
|
10892
11444
|
PY_SCIP_CALL(SCIPprintStatistics(self._scip, cfile))
|
|
10893
11445
|
|
|
10894
11446
|
locale.setlocale(locale.LC_NUMERIC,user_locale)
|
|
11447
|
+
|
|
11448
|
+
|
|
11449
|
+
def writeStatisticsJson(self, filename="origprob.stats.json"):
|
|
11450
|
+
"""
|
|
11451
|
+
Write statistics to a JSON file.
|
|
11452
|
+
|
|
11453
|
+
Parameters
|
|
11454
|
+
----------
|
|
11455
|
+
filename : str, optional
|
|
11456
|
+
name of the output file (Default = "origprob.stats.json")
|
|
11457
|
+
|
|
11458
|
+
"""
|
|
11459
|
+
user_locale = locale.getlocale(category=locale.LC_NUMERIC)
|
|
11460
|
+
locale.setlocale(locale.LC_NUMERIC, "C")
|
|
11461
|
+
|
|
11462
|
+
# use this doubled opening pattern to ensure that IOErrors are
|
|
11463
|
+
# triggered early and in Python not in C,Cython or SCIP.
|
|
11464
|
+
with open(filename, "w") as f:
|
|
11465
|
+
cfile = fdopen(f.fileno(), "w")
|
|
11466
|
+
PY_SCIP_CALL(SCIPprintStatisticsJson(self._scip, cfile))
|
|
11467
|
+
|
|
11468
|
+
locale.setlocale(locale.LC_NUMERIC,user_locale)
|
|
10895
11469
|
|
|
10896
11470
|
def getNLPs(self):
|
|
10897
11471
|
"""
|
|
@@ -11300,12 +11874,12 @@ cdef class Model:
|
|
|
11300
11874
|
|
|
11301
11875
|
def chgReoptObjective(self, coeffs, sense = 'minimize'):
|
|
11302
11876
|
"""
|
|
11303
|
-
|
|
11877
|
+
Change the objective function for reoptimization.
|
|
11304
11878
|
|
|
11305
11879
|
Parameters
|
|
11306
11880
|
----------
|
|
11307
|
-
coeffs :
|
|
11308
|
-
the coefficients
|
|
11881
|
+
coeffs : Expr
|
|
11882
|
+
the coefficients as a linear expression
|
|
11309
11883
|
sense : str
|
|
11310
11884
|
the objective sense (Default value = 'minimize')
|
|
11311
11885
|
|
|
@@ -11314,7 +11888,6 @@ cdef class Model:
|
|
|
11314
11888
|
cdef int nvars
|
|
11315
11889
|
cdef SCIP_Real* _coeffs
|
|
11316
11890
|
cdef SCIP_OBJSENSE objsense
|
|
11317
|
-
cdef SCIP_Real coef
|
|
11318
11891
|
cdef int i
|
|
11319
11892
|
cdef _VarArray wrapper
|
|
11320
11893
|
|
|
@@ -11332,24 +11905,27 @@ cdef class Model:
|
|
|
11332
11905
|
if coeffs[CONST] != 0.0:
|
|
11333
11906
|
raise ValueError("Constant offsets in objective are not supported!")
|
|
11334
11907
|
|
|
11335
|
-
|
|
11336
|
-
nvars = SCIPgetNOrigVars(self._scip)
|
|
11337
|
-
_coeffs = <SCIP_Real*> malloc(nvars * sizeof(SCIP_Real))
|
|
11908
|
+
nvars = len(coeffs.terms) - (CONST in coeffs.terms)
|
|
11338
11909
|
|
|
11339
|
-
|
|
11340
|
-
|
|
11910
|
+
if nvars == 0:
|
|
11911
|
+
PY_SCIP_CALL(SCIPchgReoptObjective(self._scip, objsense, NULL, NULL, 0))
|
|
11912
|
+
return
|
|
11913
|
+
|
|
11914
|
+
_coeffs = <SCIP_Real*> malloc(nvars * sizeof(SCIP_Real))
|
|
11915
|
+
vars = <SCIP_VAR**> malloc(nvars * sizeof(SCIP_VAR*))
|
|
11341
11916
|
|
|
11917
|
+
i = 0
|
|
11342
11918
|
for term, coef in coeffs.terms.items():
|
|
11343
11919
|
# avoid CONST term of Expr
|
|
11344
11920
|
if term != CONST:
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
_coeffs[i] = coef
|
|
11921
|
+
wrapper = _VarArray(term[0])
|
|
11922
|
+
vars[i] = wrapper.ptr[0]
|
|
11923
|
+
_coeffs[i] = coef
|
|
11924
|
+
i += 1
|
|
11350
11925
|
|
|
11351
|
-
PY_SCIP_CALL(SCIPchgReoptObjective(self._scip, objsense, vars,
|
|
11926
|
+
PY_SCIP_CALL(SCIPchgReoptObjective(self._scip, objsense, vars, _coeffs, nvars))
|
|
11352
11927
|
|
|
11928
|
+
free(vars)
|
|
11353
11929
|
free(_coeffs)
|
|
11354
11930
|
|
|
11355
11931
|
def chgVarBranchPriority(self, Variable var, priority):
|
|
@@ -11562,6 +12138,65 @@ cdef class Model:
|
|
|
11562
12138
|
"""
|
|
11563
12139
|
return SCIPgetTreesizeEstimation(self._scip)
|
|
11564
12140
|
|
|
12141
|
+
|
|
12142
|
+
# Exact SCIP methods
|
|
12143
|
+
def enableExactSolving(self, SCIP_Bool enable):
|
|
12144
|
+
"""
|
|
12145
|
+
Enables or disables exact solving mode in SCIP.
|
|
12146
|
+
|
|
12147
|
+
Parameters
|
|
12148
|
+
----------
|
|
12149
|
+
enable : SCIP_Bool
|
|
12150
|
+
Whether to enable exact solving mode (True) or disable it (False).
|
|
12151
|
+
"""
|
|
12152
|
+
|
|
12153
|
+
PY_SCIP_CALL(SCIPenableExactSolving(self._scip, enable))
|
|
12154
|
+
|
|
12155
|
+
def isExact(self):
|
|
12156
|
+
"""
|
|
12157
|
+
Returns whether exact solving mode is enabled in SCIP.
|
|
12158
|
+
|
|
12159
|
+
Returns
|
|
12160
|
+
-------
|
|
12161
|
+
bool
|
|
12162
|
+
"""
|
|
12163
|
+
|
|
12164
|
+
return SCIPisExact(self._scip)
|
|
12165
|
+
|
|
12166
|
+
def allowNegSlackExact(self):
|
|
12167
|
+
"""
|
|
12168
|
+
Returns whether negative slack is allowed in exact solving mode.
|
|
12169
|
+
|
|
12170
|
+
Returns
|
|
12171
|
+
-------
|
|
12172
|
+
bool
|
|
12173
|
+
"""
|
|
12174
|
+
|
|
12175
|
+
return SCIPallowNegSlack(self._scip)
|
|
12176
|
+
|
|
12177
|
+
def branchLPExact(self):
|
|
12178
|
+
"""
|
|
12179
|
+
Performs exact LP branching.
|
|
12180
|
+
|
|
12181
|
+
Returns
|
|
12182
|
+
-------
|
|
12183
|
+
SCIP_RESULT
|
|
12184
|
+
"""
|
|
12185
|
+
cdef SCIP_RESULT result
|
|
12186
|
+
PY_SCIP_CALL(SCIPbranchLPExact(self._scip, &result))
|
|
12187
|
+
return result
|
|
12188
|
+
|
|
12189
|
+
def addRowExact(self, RowExact rowexact):
|
|
12190
|
+
"""
|
|
12191
|
+
Adds an exact row to the LP.
|
|
12192
|
+
|
|
12193
|
+
Parameters
|
|
12194
|
+
----------
|
|
12195
|
+
rowexact : RowExact
|
|
12196
|
+
The exact row to add.
|
|
12197
|
+
"""
|
|
12198
|
+
PY_SCIP_CALL(SCIPaddRowExact(self._scip, rowexact.scip_row_exact))
|
|
12199
|
+
|
|
11565
12200
|
def getBipartiteGraphRepresentation(self, prev_col_features=None, prev_edge_features=None, prev_row_features=None,
|
|
11566
12201
|
static_only=False, suppress_warnings=False):
|
|
11567
12202
|
"""
|
|
@@ -11669,7 +12304,7 @@ cdef class Model:
|
|
|
11669
12304
|
col_features[col_i][col_feature_map["integer"]] = 1
|
|
11670
12305
|
elif vtype == SCIP_VARTYPE_CONTINUOUS:
|
|
11671
12306
|
col_features[col_i][col_feature_map["continuous"]] = 1
|
|
11672
|
-
elif vtype ==
|
|
12307
|
+
elif vtype == SCIP_DEPRECATED_VARTYPE_IMPLINT:
|
|
11673
12308
|
col_features[col_i][col_feature_map["implicit_integer"]] = 1
|
|
11674
12309
|
# Objective coefficient
|
|
11675
12310
|
col_features[col_i][col_feature_map["obj_coef"]] = SCIPcolGetObj(cols[i])
|