PuLP 3.3.0__tar.gz → 3.3.1__tar.gz
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.
- {pulp-3.3.0 → pulp-3.3.1}/PKG-INFO +6 -14
- {pulp-3.3.0 → pulp-3.3.1}/PuLP.egg-info/PKG-INFO +6 -14
- {pulp-3.3.0 → pulp-3.3.1}/PuLP.egg-info/requires.txt +2 -3
- {pulp-3.3.0 → pulp-3.3.1}/README.rst +3 -10
- {pulp-3.3.0 → pulp-3.3.1}/pulp/__init__.py +25 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/coin_api.py +7 -7
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/copt_api.py +10 -10
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/core.py +4 -4
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/cplex_api.py +15 -7
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/cuopt_api.py +5 -5
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/glpk_api.py +7 -8
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/gurobi_api.py +6 -6
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/highs_api.py +9 -6
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/mosek_api.py +7 -7
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/scip_api.py +4 -4
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/xpress_api.py +7 -7
- {pulp-3.3.0 → pulp-3.3.1}/pulp/constants.py +2 -1
- {pulp-3.3.0 → pulp-3.3.1}/pulp/mps_lp.py +6 -6
- {pulp-3.3.0 → pulp-3.3.1}/pulp/pulp.py +410 -74
- {pulp-3.3.0 → pulp-3.3.1}/pulp/tests/bin_packing_problem.py +2 -2
- {pulp-3.3.0 → pulp-3.3.1}/pulp/tests/test_gurobipy_env.py +4 -4
- {pulp-3.3.0 → pulp-3.3.1}/pulp/tests/test_lpdot.py +7 -5
- {pulp-3.3.0 → pulp-3.3.1}/pulp/tests/test_pulp.py +370 -291
- {pulp-3.3.0 → pulp-3.3.1}/pyproject.toml +2 -2
- {pulp-3.3.0 → pulp-3.3.1}/LICENSE +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/PuLP.egg-info/SOURCES.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/PuLP.egg-info/dependency_links.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/PuLP.egg-info/entry_points.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/PuLP.egg-info/top_level.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/__init__.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/choco_api.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/mipcl_api.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/apis/sas_api.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/__init__.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/linux/arm64/__init__.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/linux/arm64/cbc +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/linux/arm64/coin-license.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i32/__init__.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i32/cbc +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i32/coin-license.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i64/__init__.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i64/cbc +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i64/coin-license.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/osx/i64/__init__.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/osx/i64/cbc +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/osx/i64/coin-license.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/win/i32/__init__.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/win/i32/cbc.exe +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/win/i32/coin-license.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/win/i64/__init__.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/win/i64/cbc.exe +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/solverdir/cbc/win/i64/coin-license.txt +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/sparse.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/tests/__init__.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/tests/run_tests.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/tests/test_examples.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/tests/test_sparse.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/pulp/utilities.py +0 -0
- {pulp-3.3.0 → pulp-3.3.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PuLP
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.1
|
|
4
4
|
Summary: PuLP is an LP modeler written in python. PuLP can generate MPS or LP files and call GLPK, COIN CLP/CBC, CPLEX, and GUROBI to solve linear problems.
|
|
5
5
|
Author: J.S. Roy
|
|
6
6
|
Author-email: "S.A. Mitchell" <pulp@stuartmitchell.com>, Franco Peschiera <pchtsp@gmail.com>
|
|
@@ -19,8 +19,7 @@ Requires-Python: >=3.9
|
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE
|
|
21
21
|
Provides-Extra: open-py
|
|
22
|
-
Requires-Dist:
|
|
23
|
-
Requires-Dist: highspy; extra == "open-py"
|
|
22
|
+
Requires-Dist: highspy==1.13; extra == "open-py"
|
|
24
23
|
Requires-Dist: pyscipopt; extra == "open-py"
|
|
25
24
|
Provides-Extra: public-py
|
|
26
25
|
Requires-Dist: gurobipy; extra == "public-py"
|
|
@@ -28,7 +27,7 @@ Requires-Dist: coptpy; extra == "public-py"
|
|
|
28
27
|
Requires-Dist: xpress; extra == "public-py"
|
|
29
28
|
Requires-Dist: cplex; (sys_platform != "darwin" or python_full_version < "3.12") and extra == "public-py"
|
|
30
29
|
Provides-Extra: highs
|
|
31
|
-
Requires-Dist: highspy; extra == "highs"
|
|
30
|
+
Requires-Dist: highspy==1.13; extra == "highs"
|
|
32
31
|
Provides-Extra: scip
|
|
33
32
|
Requires-Dist: pyscipopt; extra == "scip"
|
|
34
33
|
Provides-Extra: gurobi
|
|
@@ -84,7 +83,6 @@ PuLP can use a variety of solvers. The default solver is the COIN-OR CBC solver,
|
|
|
84
83
|
python -m pip install pulp[highs]
|
|
85
84
|
python -m pip install pulp[copt]
|
|
86
85
|
python -m pip install pulp[mosek]
|
|
87
|
-
python -m pip install pulp[cylp]
|
|
88
86
|
|
|
89
87
|
|
|
90
88
|
If you want to install all open source solvers (scip, highs, cylp), you can use the shortcut::
|
|
@@ -95,18 +93,12 @@ For more information on how to install solvers, see the `guide on configuring so
|
|
|
95
93
|
Quickstart
|
|
96
94
|
===============
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
Create a problem first, then add variables with ``add_variable`` (variables are owned by the model). To create a variable ``x`` with 0 ≤ x ≤ 3 and a binary variable ``y``::
|
|
99
97
|
|
|
100
98
|
from pulp import *
|
|
101
|
-
x = LpVariable("x", 0, 3)
|
|
102
|
-
|
|
103
|
-
To create a binary variable, y, with values either 0 or 1::
|
|
104
|
-
|
|
105
|
-
y = LpVariable("y", cat="Binary")
|
|
106
|
-
|
|
107
|
-
Use ``LpProblem`` to create new problems. Create a problem called "myProblem" like so::
|
|
108
|
-
|
|
109
99
|
prob = LpProblem("myProblem", LpMinimize)
|
|
100
|
+
x = prob.add_variable("x", 0, 3)
|
|
101
|
+
y = prob.add_variable("y", cat="Binary")
|
|
110
102
|
|
|
111
103
|
Combine variables in order to create expressions and constraints, and then add them to the problem.::
|
|
112
104
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PuLP
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.1
|
|
4
4
|
Summary: PuLP is an LP modeler written in python. PuLP can generate MPS or LP files and call GLPK, COIN CLP/CBC, CPLEX, and GUROBI to solve linear problems.
|
|
5
5
|
Author: J.S. Roy
|
|
6
6
|
Author-email: "S.A. Mitchell" <pulp@stuartmitchell.com>, Franco Peschiera <pchtsp@gmail.com>
|
|
@@ -19,8 +19,7 @@ Requires-Python: >=3.9
|
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE
|
|
21
21
|
Provides-Extra: open-py
|
|
22
|
-
Requires-Dist:
|
|
23
|
-
Requires-Dist: highspy; extra == "open-py"
|
|
22
|
+
Requires-Dist: highspy==1.13; extra == "open-py"
|
|
24
23
|
Requires-Dist: pyscipopt; extra == "open-py"
|
|
25
24
|
Provides-Extra: public-py
|
|
26
25
|
Requires-Dist: gurobipy; extra == "public-py"
|
|
@@ -28,7 +27,7 @@ Requires-Dist: coptpy; extra == "public-py"
|
|
|
28
27
|
Requires-Dist: xpress; extra == "public-py"
|
|
29
28
|
Requires-Dist: cplex; (sys_platform != "darwin" or python_full_version < "3.12") and extra == "public-py"
|
|
30
29
|
Provides-Extra: highs
|
|
31
|
-
Requires-Dist: highspy; extra == "highs"
|
|
30
|
+
Requires-Dist: highspy==1.13; extra == "highs"
|
|
32
31
|
Provides-Extra: scip
|
|
33
32
|
Requires-Dist: pyscipopt; extra == "scip"
|
|
34
33
|
Provides-Extra: gurobi
|
|
@@ -84,7 +83,6 @@ PuLP can use a variety of solvers. The default solver is the COIN-OR CBC solver,
|
|
|
84
83
|
python -m pip install pulp[highs]
|
|
85
84
|
python -m pip install pulp[copt]
|
|
86
85
|
python -m pip install pulp[mosek]
|
|
87
|
-
python -m pip install pulp[cylp]
|
|
88
86
|
|
|
89
87
|
|
|
90
88
|
If you want to install all open source solvers (scip, highs, cylp), you can use the shortcut::
|
|
@@ -95,18 +93,12 @@ For more information on how to install solvers, see the `guide on configuring so
|
|
|
95
93
|
Quickstart
|
|
96
94
|
===============
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
Create a problem first, then add variables with ``add_variable`` (variables are owned by the model). To create a variable ``x`` with 0 ≤ x ≤ 3 and a binary variable ``y``::
|
|
99
97
|
|
|
100
98
|
from pulp import *
|
|
101
|
-
x = LpVariable("x", 0, 3)
|
|
102
|
-
|
|
103
|
-
To create a binary variable, y, with values either 0 or 1::
|
|
104
|
-
|
|
105
|
-
y = LpVariable("y", cat="Binary")
|
|
106
|
-
|
|
107
|
-
Use ``LpProblem`` to create new problems. Create a problem called "myProblem" like so::
|
|
108
|
-
|
|
109
99
|
prob = LpProblem("myProblem", LpMinimize)
|
|
100
|
+
x = prob.add_variable("x", 0, 3)
|
|
101
|
+
y = prob.add_variable("y", cat="Binary")
|
|
110
102
|
|
|
111
103
|
Combine variables in order to create expressions and constraints, and then add them to the problem.::
|
|
112
104
|
|
|
@@ -39,7 +39,6 @@ PuLP can use a variety of solvers. The default solver is the COIN-OR CBC solver,
|
|
|
39
39
|
python -m pip install pulp[highs]
|
|
40
40
|
python -m pip install pulp[copt]
|
|
41
41
|
python -m pip install pulp[mosek]
|
|
42
|
-
python -m pip install pulp[cylp]
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
If you want to install all open source solvers (scip, highs, cylp), you can use the shortcut::
|
|
@@ -50,18 +49,12 @@ For more information on how to install solvers, see the `guide on configuring so
|
|
|
50
49
|
Quickstart
|
|
51
50
|
===============
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
Create a problem first, then add variables with ``add_variable`` (variables are owned by the model). To create a variable ``x`` with 0 ≤ x ≤ 3 and a binary variable ``y``::
|
|
54
53
|
|
|
55
54
|
from pulp import *
|
|
56
|
-
x = LpVariable("x", 0, 3)
|
|
57
|
-
|
|
58
|
-
To create a binary variable, y, with values either 0 or 1::
|
|
59
|
-
|
|
60
|
-
y = LpVariable("y", cat="Binary")
|
|
61
|
-
|
|
62
|
-
Use ``LpProblem`` to create new problems. Create a problem called "myProblem" like so::
|
|
63
|
-
|
|
64
55
|
prob = LpProblem("myProblem", LpMinimize)
|
|
56
|
+
x = prob.add_variable("x", 0, 3)
|
|
57
|
+
y = prob.add_variable("y", cat="Binary")
|
|
65
58
|
|
|
66
59
|
Combine variables in order to create expressions and constraints, and then add them to the problem.::
|
|
67
60
|
|
|
@@ -29,6 +29,31 @@ Module file that imports all of the pulp functions
|
|
|
29
29
|
|
|
30
30
|
Copyright 2007- Stuart Mitchell (s.mitchell@auckland.ac.nz)
|
|
31
31
|
"""
|
|
32
|
+
|
|
33
|
+
# Pre-load highspy's C extension with RTLD_GLOBAL before any other imports.
|
|
34
|
+
# highspy._core uses C++ exception handling (__cxa_throw etc.) that must be globally
|
|
35
|
+
# visible when pulp._rustcore (a Rust/pyo3 extension) is later loaded into the same
|
|
36
|
+
# process. Without RTLD_GLOBAL, the C++ runtime state gets split across multiple
|
|
37
|
+
# symbol scopes, causing a segfault when highspy.Highs.run() is called.
|
|
38
|
+
# We use find_spec("highspy") (the package) not find_spec("highspy._core") (the
|
|
39
|
+
# submodule) to avoid triggering highspy/__init__.py which would import _core with
|
|
40
|
+
# RTLD_LOCAL before our explicit RTLD_GLOBAL call can take effect.
|
|
41
|
+
try:
|
|
42
|
+
import ctypes as _ctypes
|
|
43
|
+
import glob as _glob
|
|
44
|
+
import importlib.util as _ilu
|
|
45
|
+
|
|
46
|
+
_pkg_spec = _ilu.find_spec("highspy")
|
|
47
|
+
if _pkg_spec is not None and _pkg_spec.submodule_search_locations:
|
|
48
|
+
for _loc in _pkg_spec.submodule_search_locations:
|
|
49
|
+
for _so in _glob.glob(_loc + "/_core*.so"):
|
|
50
|
+
_ctypes.CDLL(_so, _ctypes.RTLD_GLOBAL)
|
|
51
|
+
break
|
|
52
|
+
del _ctypes, _glob, _ilu, _pkg_spec
|
|
53
|
+
except Exception:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
|
|
32
57
|
from .constants import VERSION
|
|
33
58
|
|
|
34
59
|
from .pulp import *
|
|
@@ -167,7 +167,7 @@ class COIN_CMD(LpSolver_CMD):
|
|
|
167
167
|
vs = lp.writeLP(tmpLp)
|
|
168
168
|
# In the Lp we do not create new variable or constraint names:
|
|
169
169
|
variablesNames = {v.name: v.name for v in vs}
|
|
170
|
-
constraintsNames = {c: c for c in lp.
|
|
170
|
+
constraintsNames = {c: c for c in lp._constraints}
|
|
171
171
|
cmds = " " + tmpLp + " "
|
|
172
172
|
if self.optionsDict.get("warmStart", False):
|
|
173
173
|
self.writesol(tmpMst, lp, vs, variablesNames, constraintsNames)
|
|
@@ -323,7 +323,7 @@ class COIN_CMD(LpSolver_CMD):
|
|
|
323
323
|
returns status, values, reducedCosts, shadowPrices, slacks, sol_status
|
|
324
324
|
"""
|
|
325
325
|
variablesNames = {v.name: v.name for v in vs}
|
|
326
|
-
constraintsNames = {c: c for c in lp.
|
|
326
|
+
constraintsNames = {c: c for c in lp._constraints}
|
|
327
327
|
return self.readsol_MPS(filename, lp, vs, variablesNames, constraintsNames)
|
|
328
328
|
|
|
329
329
|
def get_status(self, filename):
|
|
@@ -758,7 +758,7 @@ class YAPOSIB(LpSolver):
|
|
|
758
758
|
var.varValue = var.solverVar.solution
|
|
759
759
|
var.dj = var.solverVar.reducedcost
|
|
760
760
|
# put pi and slack variables against the constraints
|
|
761
|
-
for constr in lp.
|
|
761
|
+
for constr in lp._constraints.values():
|
|
762
762
|
constr.pi = constr.solverConstraint.dual
|
|
763
763
|
constr.slack = -constr.constant - constr.solverConstraint.activity
|
|
764
764
|
if self.msg:
|
|
@@ -817,7 +817,7 @@ class YAPOSIB(LpSolver):
|
|
|
817
817
|
prob.obj[col.index] = lp.objective.get(var, 0.0)
|
|
818
818
|
var.solverVar = col
|
|
819
819
|
log.debug("add the Constraints to the problem")
|
|
820
|
-
for name, constraint in lp.
|
|
820
|
+
for name, constraint in lp._constraints.items():
|
|
821
821
|
row = prob.rows.add(
|
|
822
822
|
yaposib.vec(
|
|
823
823
|
[
|
|
@@ -853,7 +853,7 @@ class YAPOSIB(LpSolver):
|
|
|
853
853
|
solutionStatus = self.findSolutionValues(lp)
|
|
854
854
|
for var in lp.variables():
|
|
855
855
|
var.modified = False
|
|
856
|
-
for constraint in lp.
|
|
856
|
+
for constraint in lp._constraints.values():
|
|
857
857
|
constraint.modified = False
|
|
858
858
|
return solutionStatus
|
|
859
859
|
|
|
@@ -865,7 +865,7 @@ class YAPOSIB(LpSolver):
|
|
|
865
865
|
constraints
|
|
866
866
|
"""
|
|
867
867
|
log.debug("Resolve the model using yaposib")
|
|
868
|
-
for constraint in lp.
|
|
868
|
+
for constraint in lp._constraints.values():
|
|
869
869
|
row = constraint.solverConstraint
|
|
870
870
|
if constraint.modified:
|
|
871
871
|
if constraint.sense == constants.LpConstraintLE:
|
|
@@ -882,7 +882,7 @@ class YAPOSIB(LpSolver):
|
|
|
882
882
|
solutionStatus = self.findSolutionValues(lp)
|
|
883
883
|
for var in lp.variables():
|
|
884
884
|
var.modified = False
|
|
885
|
-
for constraint in lp.
|
|
885
|
+
for constraint in lp._constraints.values():
|
|
886
886
|
constraint.modified = False
|
|
887
887
|
return solutionStatus
|
|
888
888
|
|
|
@@ -471,7 +471,7 @@ class COPT_DLL(LpSolver):
|
|
|
471
471
|
"""
|
|
472
472
|
cols = list(lp.variables())
|
|
473
473
|
ncol = len(cols)
|
|
474
|
-
nrow = len(lp.
|
|
474
|
+
nrow = len(lp._constraints)
|
|
475
475
|
|
|
476
476
|
collb = (ctypes.c_double * ncol)()
|
|
477
477
|
colub = (ctypes.c_double * ncol)()
|
|
@@ -525,9 +525,9 @@ class COPT_DLL(LpSolver):
|
|
|
525
525
|
|
|
526
526
|
# Extract constraint rhs, senses and names
|
|
527
527
|
idx = 0
|
|
528
|
-
for row in lp.
|
|
529
|
-
rowrhs[idx] = -lp.
|
|
530
|
-
rowsense[idx] = coptrsense[lp.
|
|
528
|
+
for row in lp._constraints:
|
|
529
|
+
rowrhs[idx] = -lp._constraints[row].constant
|
|
530
|
+
rowsense[idx] = coptrsense[lp._constraints[row].sense]
|
|
531
531
|
rowname[idx] = coptstr(row)
|
|
532
532
|
|
|
533
533
|
self.c2n[row] = idx
|
|
@@ -946,7 +946,7 @@ class COPT(LpSolver):
|
|
|
946
946
|
if not model.ismip:
|
|
947
947
|
# NOTE: slacks in COPT are activities of rows
|
|
948
948
|
slacks = model.getInfo("Slack", model.getConstrs())
|
|
949
|
-
for constr, value in zip(lp.
|
|
949
|
+
for constr, value in zip(lp._constraints.values(), slacks):
|
|
950
950
|
constr.slack = value
|
|
951
951
|
|
|
952
952
|
redcosts = model.getInfo("RedCost", model.getVars())
|
|
@@ -954,7 +954,7 @@ class COPT(LpSolver):
|
|
|
954
954
|
var.dj = value
|
|
955
955
|
|
|
956
956
|
duals = model.getInfo("Dual", model.getConstrs())
|
|
957
|
-
for constr, value in zip(lp.
|
|
957
|
+
for constr, value in zip(lp._constraints.values(), duals):
|
|
958
958
|
constr.pi = value
|
|
959
959
|
|
|
960
960
|
return status
|
|
@@ -1013,7 +1013,7 @@ class COPT(LpSolver):
|
|
|
1013
1013
|
self.coptmdl.setMipStart(var.solverVar, var.varValue)
|
|
1014
1014
|
self.coptmdl.loadMipStart()
|
|
1015
1015
|
|
|
1016
|
-
for name, constraint in lp.
|
|
1016
|
+
for name, constraint in lp._constraints.items():
|
|
1017
1017
|
expr = coptpy.LinExpr(
|
|
1018
1018
|
[v.solverVar for v in constraint.keys()], list(constraint.values())
|
|
1019
1019
|
)
|
|
@@ -1042,7 +1042,7 @@ class COPT(LpSolver):
|
|
|
1042
1042
|
solutionStatus = self.findSolutionValues(lp)
|
|
1043
1043
|
for var in lp._variables:
|
|
1044
1044
|
var.modified = False
|
|
1045
|
-
for constraint in lp.
|
|
1045
|
+
for constraint in lp._constraints.values():
|
|
1046
1046
|
constraint.modified = False
|
|
1047
1047
|
return solutionStatus
|
|
1048
1048
|
|
|
@@ -1052,7 +1052,7 @@ class COPT(LpSolver):
|
|
|
1052
1052
|
|
|
1053
1053
|
uses the old solver and modifies the rhs of the modified constraints
|
|
1054
1054
|
"""
|
|
1055
|
-
for constraint in lp.
|
|
1055
|
+
for constraint in lp._constraints.values():
|
|
1056
1056
|
if constraint.modified:
|
|
1057
1057
|
if constraint.sense == LpConstraintLE:
|
|
1058
1058
|
constraint.solverConstraint.ub = -constraint.constant
|
|
@@ -1067,6 +1067,6 @@ class COPT(LpSolver):
|
|
|
1067
1067
|
solutionStatus = self.findSolutionValues(lp)
|
|
1068
1068
|
for var in lp._variables:
|
|
1069
1069
|
var.modified = False
|
|
1070
|
-
for constraint in lp.
|
|
1070
|
+
for constraint in lp._constraints.values():
|
|
1071
1071
|
constraint.modified = False
|
|
1072
1072
|
return solutionStatus
|
|
@@ -200,7 +200,7 @@ class LpSolver:
|
|
|
200
200
|
else:
|
|
201
201
|
upperBounds[self.v2n[v]] = infBound
|
|
202
202
|
# values for constraints
|
|
203
|
-
numRows = len(lp.
|
|
203
|
+
numRows = len(lp._constraints)
|
|
204
204
|
NumRowDoubleArray = ctypes.c_double * numRows
|
|
205
205
|
NumRowStrArray = ctypes.c_char_p * numRows
|
|
206
206
|
NumRowCharArray = ctypes.c_char * numRows
|
|
@@ -211,12 +211,12 @@ class LpSolver:
|
|
|
211
211
|
self.c2n = {}
|
|
212
212
|
self.n2c = {}
|
|
213
213
|
i = 0
|
|
214
|
-
for c in lp.
|
|
215
|
-
rhsValues[i] = -lp.
|
|
214
|
+
for c in lp._constraints:
|
|
215
|
+
rhsValues[i] = -lp._constraints[c].constant
|
|
216
216
|
# for ranged constraints a<= constraint >=b
|
|
217
217
|
rangeValues[i] = 0.0
|
|
218
218
|
rowNames[i] = to_string(c)
|
|
219
|
-
rowType[i] = to_string(senseDict[lp.
|
|
219
|
+
rowType[i] = to_string(senseDict[lp._constraints[c].sense])
|
|
220
220
|
self.c2n[c] = i
|
|
221
221
|
self.n2c[i] = c
|
|
222
222
|
i = i + 1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import warnings
|
|
3
|
-
from typing import Iterable, Optional
|
|
3
|
+
from typing import Any, Iterable, Optional
|
|
4
4
|
|
|
5
5
|
from .. import constants
|
|
6
6
|
from .core import LpSolver, LpSolver_CMD, PulpSolverError, clock, log, subprocess
|
|
@@ -277,7 +277,11 @@ class CPLEX_PY(LpSolver):
|
|
|
277
277
|
"""True if the solver is available"""
|
|
278
278
|
return False
|
|
279
279
|
|
|
280
|
-
def actualSolve(
|
|
280
|
+
def actualSolve(
|
|
281
|
+
self,
|
|
282
|
+
lp: Any,
|
|
283
|
+
callback: Optional[Iterable[type[Any]]] = None,
|
|
284
|
+
) -> Any:
|
|
281
285
|
"""Solve a well formulated lp problem"""
|
|
282
286
|
raise PulpSolverError(f"CPLEX_PY: Not Available:\n{self.err}")
|
|
283
287
|
|
|
@@ -330,7 +334,11 @@ class CPLEX_PY(LpSolver):
|
|
|
330
334
|
"""True if the solver is available"""
|
|
331
335
|
return True
|
|
332
336
|
|
|
333
|
-
def actualSolve(
|
|
337
|
+
def actualSolve(
|
|
338
|
+
self,
|
|
339
|
+
lp: Any,
|
|
340
|
+
callback: Optional[Iterable[type[cplex.callbacks.Callback]]] = None,
|
|
341
|
+
) -> Any:
|
|
334
342
|
"""
|
|
335
343
|
Solve a well formulated lp problem
|
|
336
344
|
|
|
@@ -347,7 +355,7 @@ class CPLEX_PY(LpSolver):
|
|
|
347
355
|
solutionStatus = self.findSolutionValues(lp)
|
|
348
356
|
for var in lp._variables:
|
|
349
357
|
var.modified = False
|
|
350
|
-
for constraint in lp.
|
|
358
|
+
for constraint in lp._constraints.values():
|
|
351
359
|
constraint.modified = False
|
|
352
360
|
return solutionStatus
|
|
353
361
|
|
|
@@ -406,8 +414,8 @@ class CPLEX_PY(LpSolver):
|
|
|
406
414
|
rows = []
|
|
407
415
|
senses = []
|
|
408
416
|
rhs = []
|
|
409
|
-
rownames = list(lp.
|
|
410
|
-
for constraint in lp.
|
|
417
|
+
rownames = list(lp._constraints.keys())
|
|
418
|
+
for constraint in lp._constraints.values():
|
|
411
419
|
# build the expression
|
|
412
420
|
if len(constraint) == 0:
|
|
413
421
|
# if the constraint is empty
|
|
@@ -583,7 +591,7 @@ class CPLEX_PY(LpSolver):
|
|
|
583
591
|
sol_status = CplexSolStatus.get(lp.cplex_status)
|
|
584
592
|
lp.assignStatus(status, sol_status)
|
|
585
593
|
var_names = [var.name for var in lp._variables]
|
|
586
|
-
con_names = [con for con in lp.
|
|
594
|
+
con_names = [con for con in lp._constraints]
|
|
587
595
|
try:
|
|
588
596
|
objectiveValue = lp.solverModel.solution.get_objective_value()
|
|
589
597
|
variablevalues = dict(
|
|
@@ -135,7 +135,7 @@ class CUOPT(LpSolver):
|
|
|
135
135
|
var.dj = value
|
|
136
136
|
|
|
137
137
|
duals = solution.get_dual_solution()
|
|
138
|
-
for constr, value in zip(lp.
|
|
138
|
+
for constr, value in zip(lp._constraints.values(), duals):
|
|
139
139
|
constr.pi = value
|
|
140
140
|
|
|
141
141
|
return status
|
|
@@ -214,7 +214,7 @@ class CUOPT(LpSolver):
|
|
|
214
214
|
rhs, sense = [], []
|
|
215
215
|
matrix_data, matrix_indices, matrix_indptr = [], [], [0]
|
|
216
216
|
|
|
217
|
-
for name, constraint in lp.
|
|
217
|
+
for name, constraint in lp._constraints.items():
|
|
218
218
|
row_coeffs = []
|
|
219
219
|
matrix_data.extend(list(constraint.values()))
|
|
220
220
|
matrix_indices.extend([var_dict[v.name] for v in constraint.keys()])
|
|
@@ -247,7 +247,7 @@ class CUOPT(LpSolver):
|
|
|
247
247
|
solutionStatus = self.findSolutionValues(lp, solution)
|
|
248
248
|
for var in lp._variables:
|
|
249
249
|
var.modified = False
|
|
250
|
-
for constraint in lp.
|
|
250
|
+
for constraint in lp._constraints.values():
|
|
251
251
|
constraint.modified = False
|
|
252
252
|
return solutionStatus
|
|
253
253
|
|
|
@@ -260,7 +260,7 @@ class CUOPT(LpSolver):
|
|
|
260
260
|
rhs = lp.solverModel.get_constraint_bounds()
|
|
261
261
|
sense = lp.solverModel.get_row_types()
|
|
262
262
|
|
|
263
|
-
for i, name, constraint in enumerate(lp.
|
|
263
|
+
for i, name, constraint in enumerate(lp._constraints.items()):
|
|
264
264
|
if constraint.modified:
|
|
265
265
|
sense[i] = sense_conv[constraint.sense]
|
|
266
266
|
rhs[i] = -constraint.constant
|
|
@@ -274,6 +274,6 @@ class CUOPT(LpSolver):
|
|
|
274
274
|
solutionStatus = self.findSolutionValues(lp)
|
|
275
275
|
for var in lp._variables:
|
|
276
276
|
var.modified = False
|
|
277
|
-
for constraint in lp.
|
|
277
|
+
for constraint in lp._constraints.values():
|
|
278
278
|
constraint.modified = False
|
|
279
279
|
return solutionStatus
|
|
@@ -188,7 +188,6 @@ class GLPK_CMD(LpSolver_CMD):
|
|
|
188
188
|
|
|
189
189
|
# now actually read column values
|
|
190
190
|
with open(solFile) as f:
|
|
191
|
-
|
|
192
191
|
values = []
|
|
193
192
|
status2 = constants.LpStatusUndefined
|
|
194
193
|
vpos = 2
|
|
@@ -291,7 +290,7 @@ class PYGLPK(LpSolver):
|
|
|
291
290
|
var.varValue = glpk.glp_get_col_prim(prob, var.glpk_index)
|
|
292
291
|
var.dj = glpk.glp_get_col_dual(prob, var.glpk_index)
|
|
293
292
|
# put pi and slack variables against the constraints
|
|
294
|
-
for constr in lp.
|
|
293
|
+
for constr in lp._constraints.values():
|
|
295
294
|
if self.mip and self.hasMIPConstraints(lp.solverModel):
|
|
296
295
|
row_val = glpk.glp_mip_row_val(prob, constr.glpk_index)
|
|
297
296
|
else:
|
|
@@ -337,8 +336,8 @@ class PYGLPK(LpSolver):
|
|
|
337
336
|
if lp.sense == constants.LpMaximize:
|
|
338
337
|
glpk.glp_set_obj_dir(prob, glpk.GLP_MAX)
|
|
339
338
|
log.debug("add the constraints to the problem")
|
|
340
|
-
glpk.glp_add_rows(prob, len(list(lp.
|
|
341
|
-
for i, v in enumerate(lp.
|
|
339
|
+
glpk.glp_add_rows(prob, len(list(lp._constraints.keys())))
|
|
340
|
+
for i, v in enumerate(lp._constraints.items(), start=1):
|
|
342
341
|
name, constraint = v
|
|
343
342
|
glpk.glp_set_row_name(prob, i, name)
|
|
344
343
|
if constraint.sense == constants.LpConstraintLE:
|
|
@@ -385,7 +384,7 @@ class PYGLPK(LpSolver):
|
|
|
385
384
|
if value:
|
|
386
385
|
glpk.glp_set_obj_coef(prob, var.glpk_index, value)
|
|
387
386
|
log.debug("set the problem matrix")
|
|
388
|
-
for constraint in lp.
|
|
387
|
+
for constraint in lp._constraints.values():
|
|
389
388
|
l = len(list(constraint.items()))
|
|
390
389
|
ind = glpk.intArray(l + 1)
|
|
391
390
|
val = glpk.doubleArray(l + 1)
|
|
@@ -412,7 +411,7 @@ class PYGLPK(LpSolver):
|
|
|
412
411
|
solutionStatus = self.findSolutionValues(lp)
|
|
413
412
|
for var in lp.variables():
|
|
414
413
|
var.modified = False
|
|
415
|
-
for constraint in lp.
|
|
414
|
+
for constraint in lp._constraints.values():
|
|
416
415
|
constraint.modified = False
|
|
417
416
|
return solutionStatus
|
|
418
417
|
|
|
@@ -425,7 +424,7 @@ class PYGLPK(LpSolver):
|
|
|
425
424
|
"""
|
|
426
425
|
prob = lp.solverModel
|
|
427
426
|
log.debug("Resolve the Model using glpk")
|
|
428
|
-
for constraint in lp.
|
|
427
|
+
for constraint in lp._constraints.values():
|
|
429
428
|
i = constraint.glpk_index
|
|
430
429
|
if constraint.modified:
|
|
431
430
|
if constraint.sense == constants.LpConstraintLE:
|
|
@@ -451,6 +450,6 @@ class PYGLPK(LpSolver):
|
|
|
451
450
|
solutionStatus = self.findSolutionValues(lp)
|
|
452
451
|
for var in lp.variables():
|
|
453
452
|
var.modified = False
|
|
454
|
-
for constraint in lp.
|
|
453
|
+
for constraint in lp._constraints.values():
|
|
455
454
|
constraint.modified = False
|
|
456
455
|
return solutionStatus
|
|
@@ -215,7 +215,7 @@ class GUROBI(LpSolver):
|
|
|
215
215
|
var.varValue = value
|
|
216
216
|
# populate pulp constraints slack
|
|
217
217
|
for constr, value in zip(
|
|
218
|
-
lp.
|
|
218
|
+
lp._constraints.values(),
|
|
219
219
|
model.getAttr(GRB.Attr.Slack, model.getConstrs()),
|
|
220
220
|
):
|
|
221
221
|
constr.slack = value
|
|
@@ -227,7 +227,7 @@ class GUROBI(LpSolver):
|
|
|
227
227
|
var.dj = value
|
|
228
228
|
|
|
229
229
|
for constr, value in zip(
|
|
230
|
-
lp.
|
|
230
|
+
lp._constraints.values(),
|
|
231
231
|
model.getAttr(GRB.Attr.Pi, model.getConstrs()),
|
|
232
232
|
):
|
|
233
233
|
constr.pi = value
|
|
@@ -316,7 +316,7 @@ class GUROBI(LpSolver):
|
|
|
316
316
|
|
|
317
317
|
lp.solverModel.update()
|
|
318
318
|
log.debug("add the Constraints to the problem")
|
|
319
|
-
for name, constraint in lp.
|
|
319
|
+
for name, constraint in lp._constraints.items():
|
|
320
320
|
# build the expression
|
|
321
321
|
expr = gp.LinExpr(
|
|
322
322
|
list(constraint.values()), [v.solverVar for v in constraint.keys()]
|
|
@@ -352,7 +352,7 @@ class GUROBI(LpSolver):
|
|
|
352
352
|
solutionStatus = self.findSolutionValues(lp)
|
|
353
353
|
for var in lp._variables:
|
|
354
354
|
var.modified = False
|
|
355
|
-
for constraint in lp.
|
|
355
|
+
for constraint in lp._constraints.values():
|
|
356
356
|
constraint.modified = False
|
|
357
357
|
return solutionStatus
|
|
358
358
|
|
|
@@ -363,7 +363,7 @@ class GUROBI(LpSolver):
|
|
|
363
363
|
uses the old solver and modifies the rhs of the modified constraints
|
|
364
364
|
"""
|
|
365
365
|
log.debug("Resolve the Model using gurobi")
|
|
366
|
-
for constraint in lp.
|
|
366
|
+
for constraint in lp._constraints.values():
|
|
367
367
|
if constraint.modified:
|
|
368
368
|
constraint.solverConstraint.setAttr(
|
|
369
369
|
gp.GRB.Attr.RHS, -constraint.constant
|
|
@@ -374,7 +374,7 @@ class GUROBI(LpSolver):
|
|
|
374
374
|
solutionStatus = self.findSolutionValues(lp)
|
|
375
375
|
for var in lp._variables:
|
|
376
376
|
var.modified = False
|
|
377
|
-
for constraint in lp.
|
|
377
|
+
for constraint in lp._constraints.values():
|
|
378
378
|
constraint.modified = False
|
|
379
379
|
return solutionStatus
|
|
380
380
|
|
|
@@ -175,9 +175,12 @@ class HiGHS_CMD(LpSolver_CMD):
|
|
|
175
175
|
if len(model_line) > 0:
|
|
176
176
|
model_status = " ".join(model_line[0][3:]) # Model status: ...
|
|
177
177
|
else:
|
|
178
|
-
# ILP
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
# ILP / MIP logs (format varies; time-limited runs may omit status lines)
|
|
179
|
+
mip_status_lines = [line for line in lines if "Status" in line]
|
|
180
|
+
if mip_status_lines:
|
|
181
|
+
model_status = " ".join(mip_status_lines[0][1:])
|
|
182
|
+
else:
|
|
183
|
+
model_status = ""
|
|
181
184
|
sol_line = [line for line in lines if line[:2] == ["Solution", "status"]]
|
|
182
185
|
sol_line = sol_line[0] if len(sol_line) > 0 else ["Not solved"]
|
|
183
186
|
sol_status = sol_line[-1]
|
|
@@ -382,7 +385,7 @@ class HiGHS(LpSolver):
|
|
|
382
385
|
var.index, highspy.HighsVarType.kInteger
|
|
383
386
|
)
|
|
384
387
|
|
|
385
|
-
for i, constraint in enumerate(lp.
|
|
388
|
+
for i, constraint in enumerate(lp._constraints.values()):
|
|
386
389
|
non_zero_constraint_items = [
|
|
387
390
|
(var.index, coefficient)
|
|
388
391
|
for var, coefficient in constraint.items()
|
|
@@ -492,7 +495,7 @@ class HiGHS(LpSolver):
|
|
|
492
495
|
var.varValue = col_values[var.index]
|
|
493
496
|
var.dj = col_duals[var.index]
|
|
494
497
|
|
|
495
|
-
constraints_list = list(lp.
|
|
498
|
+
constraints_list = list(lp._constraints.values())
|
|
496
499
|
row_values = list(solution.row_value)
|
|
497
500
|
row_duals = list(solution.row_dual)
|
|
498
501
|
for constraint in constraints_list:
|
|
@@ -526,7 +529,7 @@ class HiGHS(LpSolver):
|
|
|
526
529
|
for var in lp.variables():
|
|
527
530
|
var.modified = False
|
|
528
531
|
|
|
529
|
-
for constraint in lp.
|
|
532
|
+
for constraint in lp._constraints.values():
|
|
530
533
|
constraint.modifier = False
|
|
531
534
|
|
|
532
535
|
lp.assignStatus(status, sol_status)
|
|
@@ -115,7 +115,7 @@ class MOSEK(LpSolver):
|
|
|
115
115
|
|
|
116
116
|
def buildSolverModel(self, lp, inf=1e20):
|
|
117
117
|
"""Translate the problem into a Mosek task object."""
|
|
118
|
-
self.cons = lp.
|
|
118
|
+
self.cons = lp._constraints
|
|
119
119
|
self.numcons = len(self.cons)
|
|
120
120
|
self.cons_dict = {}
|
|
121
121
|
i = 0
|
|
@@ -236,8 +236,8 @@ class MOSEK(LpSolver):
|
|
|
236
236
|
try:
|
|
237
237
|
self.xc = [0.0] * self.numcons
|
|
238
238
|
self.task.getxc(self.solution_type, self.xc)
|
|
239
|
-
for con in lp.
|
|
240
|
-
lp.
|
|
239
|
+
for con in lp._constraints:
|
|
240
|
+
lp._constraints[con].slack = -(
|
|
241
241
|
self.cons[con].constant + self.xc[self.cons_dict[con]]
|
|
242
242
|
)
|
|
243
243
|
except mosek.Error:
|
|
@@ -257,8 +257,8 @@ class MOSEK(LpSolver):
|
|
|
257
257
|
try:
|
|
258
258
|
self.y = [0.0] * self.numcons
|
|
259
259
|
self.task.gety(self.solution_type, self.y)
|
|
260
|
-
for con in lp.
|
|
261
|
-
lp.
|
|
260
|
+
for con in lp._constraints:
|
|
261
|
+
lp._constraints[con].pi = self.y[self.cons_dict[con]]
|
|
262
262
|
except mosek.Error:
|
|
263
263
|
pass
|
|
264
264
|
|
|
@@ -306,7 +306,7 @@ class MOSEK(LpSolver):
|
|
|
306
306
|
lp.assignStatus(self.solution_status_dict[self.solsta])
|
|
307
307
|
for var in lp.variables():
|
|
308
308
|
var.modified = False
|
|
309
|
-
for con in lp.
|
|
309
|
+
for con in lp._constraints.values():
|
|
310
310
|
con.modified = False
|
|
311
311
|
return lp.status
|
|
312
312
|
|
|
@@ -340,6 +340,6 @@ class MOSEK(LpSolver):
|
|
|
340
340
|
lp.assignStatus(self.solution_status_dict[self.solsta])
|
|
341
341
|
for var in lp.variables():
|
|
342
342
|
var.modified = False
|
|
343
|
-
for con in lp.
|
|
343
|
+
for con in lp._constraints.values():
|
|
344
344
|
con.modified = False
|
|
345
345
|
return lp.status
|