PuLP 3.2.2__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.1/LICENSE +22 -0
- {pulp-3.2.2 → pulp-3.3.1}/PKG-INFO +40 -13
- {pulp-3.2.2 → pulp-3.3.1}/PuLP.egg-info/PKG-INFO +40 -13
- {pulp-3.2.2 → pulp-3.3.1}/PuLP.egg-info/SOURCES.txt +1 -0
- pulp-3.3.1/PuLP.egg-info/requires.txt +35 -0
- {pulp-3.2.2 → pulp-3.3.1}/README.rst +20 -8
- {pulp-3.2.2 → pulp-3.3.1}/pulp/__init__.py +25 -1
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/coin_api.py +11 -7
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/copt_api.py +10 -10
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/core.py +4 -4
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/cplex_api.py +37 -10
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/cuopt_api.py +9 -7
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/glpk_api.py +7 -8
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/gurobi_api.py +6 -6
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/highs_api.py +9 -6
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/mosek_api.py +7 -7
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/scip_api.py +4 -4
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/xpress_api.py +138 -40
- {pulp-3.2.2 → pulp-3.3.1}/pulp/constants.py +2 -1
- {pulp-3.2.2 → pulp-3.3.1}/pulp/mps_lp.py +8 -8
- {pulp-3.2.2 → pulp-3.3.1}/pulp/pulp.py +410 -74
- {pulp-3.2.2 → pulp-3.3.1}/pulp/tests/bin_packing_problem.py +2 -2
- {pulp-3.2.2 → pulp-3.3.1}/pulp/tests/test_gurobipy_env.py +4 -4
- {pulp-3.2.2 → pulp-3.3.1}/pulp/tests/test_lpdot.py +7 -5
- {pulp-3.2.2 → pulp-3.3.1}/pulp/tests/test_pulp.py +386 -302
- {pulp-3.2.2 → pulp-3.3.1}/pyproject.toml +22 -8
- pulp-3.2.2/PuLP.egg-info/requires.txt +0 -12
- {pulp-3.2.2 → pulp-3.3.1}/PuLP.egg-info/dependency_links.txt +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/PuLP.egg-info/entry_points.txt +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/PuLP.egg-info/top_level.txt +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/__init__.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/choco_api.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/mipcl_api.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/apis/sas_api.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/__init__.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/linux/arm64/__init__.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/linux/arm64/cbc +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/linux/arm64/coin-license.txt +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i32/__init__.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i32/cbc +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i32/coin-license.txt +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i64/__init__.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i64/cbc +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/linux/i64/coin-license.txt +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/osx/i64/__init__.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/osx/i64/cbc +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/osx/i64/coin-license.txt +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/win/i32/__init__.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/win/i32/cbc.exe +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/win/i32/coin-license.txt +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/win/i64/__init__.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/win/i64/cbc.exe +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/solverdir/cbc/win/i64/coin-license.txt +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/sparse.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/tests/__init__.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/tests/run_tests.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/tests/test_examples.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/tests/test_sparse.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/pulp/utilities.py +0 -0
- {pulp-3.2.2 → pulp-3.3.1}/setup.cfg +0 -0
pulp-3.3.1/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2002-2005, Jean-Sebastien Roy
|
|
2
|
+
Modifications Copyright (c) 2007- Stuart Anthony Mitchell
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
5
|
+
copy of this software and associated documentation files (the
|
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included
|
|
13
|
+
in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
16
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
18
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
19
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
20
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
21
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
@@ -1,31 +1,46 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PuLP
|
|
3
|
-
Version: 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>
|
|
7
7
|
Maintainer-email: Franco Peschiera <pchtsp@gmail.com>
|
|
8
|
-
License: MIT
|
|
8
|
+
License-Expression: MIT
|
|
9
9
|
Project-URL: source, https://github.com/coin-or/pulp
|
|
10
10
|
Project-URL: download, https://github.com/coin-or/pulp/archive/master.zip
|
|
11
11
|
Keywords: Optimization,Linear Programming,Operations Research
|
|
12
12
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
16
15
|
Classifier: Natural Language :: English
|
|
17
16
|
Classifier: Programming Language :: Python
|
|
18
17
|
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
19
18
|
Requires-Python: >=3.9
|
|
20
19
|
Description-Content-Type: text/x-rst
|
|
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"
|
|
27
26
|
Requires-Dist: coptpy; extra == "public-py"
|
|
28
27
|
Requires-Dist: xpress; extra == "public-py"
|
|
28
|
+
Requires-Dist: cplex; (sys_platform != "darwin" or python_full_version < "3.12") and extra == "public-py"
|
|
29
|
+
Provides-Extra: highs
|
|
30
|
+
Requires-Dist: highspy==1.13; extra == "highs"
|
|
31
|
+
Provides-Extra: scip
|
|
32
|
+
Requires-Dist: pyscipopt; extra == "scip"
|
|
33
|
+
Provides-Extra: gurobi
|
|
34
|
+
Requires-Dist: gurobipy; extra == "gurobi"
|
|
35
|
+
Provides-Extra: xpress
|
|
36
|
+
Requires-Dist: xpress; extra == "xpress"
|
|
37
|
+
Provides-Extra: copt
|
|
38
|
+
Requires-Dist: coptpy; extra == "copt"
|
|
39
|
+
Provides-Extra: cplex
|
|
40
|
+
Requires-Dist: cplex; (sys_platform != "darwin" or python_full_version < "3.12") and extra == "cplex"
|
|
41
|
+
Provides-Extra: mosek
|
|
42
|
+
Requires-Dist: mosek; extra == "mosek"
|
|
43
|
+
Dynamic: license-file
|
|
29
44
|
|
|
30
45
|
pulp
|
|
31
46
|
**************************
|
|
@@ -56,22 +71,34 @@ The easiest way to install PuLP is with ``pip``. If ``pip`` is available on your
|
|
|
56
71
|
|
|
57
72
|
Otherwise follow the download instructions on the `PyPi page <https://pypi.python.org/pypi/PuLP>`_.
|
|
58
73
|
|
|
74
|
+
Installing solvers
|
|
75
|
+
----------------------
|
|
59
76
|
|
|
60
|
-
|
|
61
|
-
===============
|
|
77
|
+
PuLP can use a variety of solvers. The default solver is the COIN-OR CBC solver, which is included with PuLP. If you want to use other solvers, PuLP offers a quick way to install most solvers via their pypi package (some require a commercial license for running or for running large models)::
|
|
62
78
|
|
|
63
|
-
|
|
79
|
+
python -m pip install pulp[gurobi]
|
|
80
|
+
python -m pip install pulp[cplex]
|
|
81
|
+
python -m pip install pulp[xpress]
|
|
82
|
+
python -m pip install pulp[scip]
|
|
83
|
+
python -m pip install pulp[highs]
|
|
84
|
+
python -m pip install pulp[copt]
|
|
85
|
+
python -m pip install pulp[mosek]
|
|
64
86
|
|
|
65
|
-
from pulp import *
|
|
66
|
-
x = LpVariable("x", 0, 3)
|
|
67
87
|
|
|
68
|
-
|
|
88
|
+
If you want to install all open source solvers (scip, highs, cylp), you can use the shortcut::
|
|
89
|
+
python -m pip install pulp[open_py]
|
|
69
90
|
|
|
70
|
-
|
|
91
|
+
For more information on how to install solvers, see the `guide on configuring solvers <https://coin-or.github.io/pulp/guides/how_to_configure_solvers.html>`_.
|
|
71
92
|
|
|
72
|
-
|
|
93
|
+
Quickstart
|
|
94
|
+
===============
|
|
95
|
+
|
|
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``::
|
|
73
97
|
|
|
98
|
+
from pulp import *
|
|
74
99
|
prob = LpProblem("myProblem", LpMinimize)
|
|
100
|
+
x = prob.add_variable("x", 0, 3)
|
|
101
|
+
y = prob.add_variable("y", cat="Binary")
|
|
75
102
|
|
|
76
103
|
Combine variables in order to create expressions and constraints, and then add them to the problem.::
|
|
77
104
|
|
|
@@ -1,31 +1,46 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PuLP
|
|
3
|
-
Version: 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>
|
|
7
7
|
Maintainer-email: Franco Peschiera <pchtsp@gmail.com>
|
|
8
|
-
License: MIT
|
|
8
|
+
License-Expression: MIT
|
|
9
9
|
Project-URL: source, https://github.com/coin-or/pulp
|
|
10
10
|
Project-URL: download, https://github.com/coin-or/pulp/archive/master.zip
|
|
11
11
|
Keywords: Optimization,Linear Programming,Operations Research
|
|
12
12
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
16
15
|
Classifier: Natural Language :: English
|
|
17
16
|
Classifier: Programming Language :: Python
|
|
18
17
|
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
19
18
|
Requires-Python: >=3.9
|
|
20
19
|
Description-Content-Type: text/x-rst
|
|
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"
|
|
27
26
|
Requires-Dist: coptpy; extra == "public-py"
|
|
28
27
|
Requires-Dist: xpress; extra == "public-py"
|
|
28
|
+
Requires-Dist: cplex; (sys_platform != "darwin" or python_full_version < "3.12") and extra == "public-py"
|
|
29
|
+
Provides-Extra: highs
|
|
30
|
+
Requires-Dist: highspy==1.13; extra == "highs"
|
|
31
|
+
Provides-Extra: scip
|
|
32
|
+
Requires-Dist: pyscipopt; extra == "scip"
|
|
33
|
+
Provides-Extra: gurobi
|
|
34
|
+
Requires-Dist: gurobipy; extra == "gurobi"
|
|
35
|
+
Provides-Extra: xpress
|
|
36
|
+
Requires-Dist: xpress; extra == "xpress"
|
|
37
|
+
Provides-Extra: copt
|
|
38
|
+
Requires-Dist: coptpy; extra == "copt"
|
|
39
|
+
Provides-Extra: cplex
|
|
40
|
+
Requires-Dist: cplex; (sys_platform != "darwin" or python_full_version < "3.12") and extra == "cplex"
|
|
41
|
+
Provides-Extra: mosek
|
|
42
|
+
Requires-Dist: mosek; extra == "mosek"
|
|
43
|
+
Dynamic: license-file
|
|
29
44
|
|
|
30
45
|
pulp
|
|
31
46
|
**************************
|
|
@@ -56,22 +71,34 @@ The easiest way to install PuLP is with ``pip``. If ``pip`` is available on your
|
|
|
56
71
|
|
|
57
72
|
Otherwise follow the download instructions on the `PyPi page <https://pypi.python.org/pypi/PuLP>`_.
|
|
58
73
|
|
|
74
|
+
Installing solvers
|
|
75
|
+
----------------------
|
|
59
76
|
|
|
60
|
-
|
|
61
|
-
===============
|
|
77
|
+
PuLP can use a variety of solvers. The default solver is the COIN-OR CBC solver, which is included with PuLP. If you want to use other solvers, PuLP offers a quick way to install most solvers via their pypi package (some require a commercial license for running or for running large models)::
|
|
62
78
|
|
|
63
|
-
|
|
79
|
+
python -m pip install pulp[gurobi]
|
|
80
|
+
python -m pip install pulp[cplex]
|
|
81
|
+
python -m pip install pulp[xpress]
|
|
82
|
+
python -m pip install pulp[scip]
|
|
83
|
+
python -m pip install pulp[highs]
|
|
84
|
+
python -m pip install pulp[copt]
|
|
85
|
+
python -m pip install pulp[mosek]
|
|
64
86
|
|
|
65
|
-
from pulp import *
|
|
66
|
-
x = LpVariable("x", 0, 3)
|
|
67
87
|
|
|
68
|
-
|
|
88
|
+
If you want to install all open source solvers (scip, highs, cylp), you can use the shortcut::
|
|
89
|
+
python -m pip install pulp[open_py]
|
|
69
90
|
|
|
70
|
-
|
|
91
|
+
For more information on how to install solvers, see the `guide on configuring solvers <https://coin-or.github.io/pulp/guides/how_to_configure_solvers.html>`_.
|
|
71
92
|
|
|
72
|
-
|
|
93
|
+
Quickstart
|
|
94
|
+
===============
|
|
95
|
+
|
|
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``::
|
|
73
97
|
|
|
98
|
+
from pulp import *
|
|
74
99
|
prob = LpProblem("myProblem", LpMinimize)
|
|
100
|
+
x = prob.add_variable("x", 0, 3)
|
|
101
|
+
y = prob.add_variable("y", cat="Binary")
|
|
75
102
|
|
|
76
103
|
Combine variables in order to create expressions and constraints, and then add them to the problem.::
|
|
77
104
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
[copt]
|
|
3
|
+
coptpy
|
|
4
|
+
|
|
5
|
+
[cplex]
|
|
6
|
+
|
|
7
|
+
[cplex:sys_platform != "darwin" or python_full_version < "3.12"]
|
|
8
|
+
cplex
|
|
9
|
+
|
|
10
|
+
[gurobi]
|
|
11
|
+
gurobipy
|
|
12
|
+
|
|
13
|
+
[highs]
|
|
14
|
+
highspy==1.13
|
|
15
|
+
|
|
16
|
+
[mosek]
|
|
17
|
+
mosek
|
|
18
|
+
|
|
19
|
+
[open_py]
|
|
20
|
+
highspy==1.13
|
|
21
|
+
pyscipopt
|
|
22
|
+
|
|
23
|
+
[public_py]
|
|
24
|
+
gurobipy
|
|
25
|
+
coptpy
|
|
26
|
+
xpress
|
|
27
|
+
|
|
28
|
+
[public_py:sys_platform != "darwin" or python_full_version < "3.12"]
|
|
29
|
+
cplex
|
|
30
|
+
|
|
31
|
+
[scip]
|
|
32
|
+
pyscipopt
|
|
33
|
+
|
|
34
|
+
[xpress]
|
|
35
|
+
xpress
|
|
@@ -27,22 +27,34 @@ The easiest way to install PuLP is with ``pip``. If ``pip`` is available on your
|
|
|
27
27
|
|
|
28
28
|
Otherwise follow the download instructions on the `PyPi page <https://pypi.python.org/pypi/PuLP>`_.
|
|
29
29
|
|
|
30
|
+
Installing solvers
|
|
31
|
+
----------------------
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
===============
|
|
33
|
+
PuLP can use a variety of solvers. The default solver is the COIN-OR CBC solver, which is included with PuLP. If you want to use other solvers, PuLP offers a quick way to install most solvers via their pypi package (some require a commercial license for running or for running large models)::
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
python -m pip install pulp[gurobi]
|
|
36
|
+
python -m pip install pulp[cplex]
|
|
37
|
+
python -m pip install pulp[xpress]
|
|
38
|
+
python -m pip install pulp[scip]
|
|
39
|
+
python -m pip install pulp[highs]
|
|
40
|
+
python -m pip install pulp[copt]
|
|
41
|
+
python -m pip install pulp[mosek]
|
|
35
42
|
|
|
36
|
-
from pulp import *
|
|
37
|
-
x = LpVariable("x", 0, 3)
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
If you want to install all open source solvers (scip, highs, cylp), you can use the shortcut::
|
|
45
|
+
python -m pip install pulp[open_py]
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
For more information on how to install solvers, see the `guide on configuring solvers <https://coin-or.github.io/pulp/guides/how_to_configure_solvers.html>`_.
|
|
42
48
|
|
|
43
|
-
|
|
49
|
+
Quickstart
|
|
50
|
+
===============
|
|
51
|
+
|
|
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``::
|
|
44
53
|
|
|
54
|
+
from pulp import *
|
|
45
55
|
prob = LpProblem("myProblem", LpMinimize)
|
|
56
|
+
x = prob.add_variable("x", 0, 3)
|
|
57
|
+
y = prob.add_variable("y", cat="Binary")
|
|
46
58
|
|
|
47
59
|
Combine variables in order to create expressions and constraints, and then add them to the problem.::
|
|
48
60
|
|
|
@@ -29,13 +29,37 @@ 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 *
|
|
35
60
|
from .apis import *
|
|
36
61
|
from .utilities import *
|
|
37
62
|
from .constants import *
|
|
38
|
-
from .tests import pulpTestAll
|
|
39
63
|
|
|
40
64
|
__doc__ = pulp.__doc__ # type: ignore[name-defined]
|
|
41
65
|
__version__ = VERSION
|
|
@@ -108,6 +108,10 @@ class COIN_CMD(LpSolver_CMD):
|
|
|
108
108
|
:param str timeMode: "elapsed": count wall-time to timeLimit; "cpu": count cpu-time
|
|
109
109
|
:param int maxNodes: max number of nodes during branching. Stops the solving when reached.
|
|
110
110
|
"""
|
|
111
|
+
if warmStart and not keepFiles and operating_system == "win":
|
|
112
|
+
warnings.warn(
|
|
113
|
+
"When using CBC on Windows, warmStart requires keepFiles=True."
|
|
114
|
+
)
|
|
111
115
|
|
|
112
116
|
LpSolver_CMD.__init__(
|
|
113
117
|
self,
|
|
@@ -163,7 +167,7 @@ class COIN_CMD(LpSolver_CMD):
|
|
|
163
167
|
vs = lp.writeLP(tmpLp)
|
|
164
168
|
# In the Lp we do not create new variable or constraint names:
|
|
165
169
|
variablesNames = {v.name: v.name for v in vs}
|
|
166
|
-
constraintsNames = {c: c for c in lp.
|
|
170
|
+
constraintsNames = {c: c for c in lp._constraints}
|
|
167
171
|
cmds = " " + tmpLp + " "
|
|
168
172
|
if self.optionsDict.get("warmStart", False):
|
|
169
173
|
self.writesol(tmpMst, lp, vs, variablesNames, constraintsNames)
|
|
@@ -319,7 +323,7 @@ class COIN_CMD(LpSolver_CMD):
|
|
|
319
323
|
returns status, values, reducedCosts, shadowPrices, slacks, sol_status
|
|
320
324
|
"""
|
|
321
325
|
variablesNames = {v.name: v.name for v in vs}
|
|
322
|
-
constraintsNames = {c: c for c in lp.
|
|
326
|
+
constraintsNames = {c: c for c in lp._constraints}
|
|
323
327
|
return self.readsol_MPS(filename, lp, vs, variablesNames, constraintsNames)
|
|
324
328
|
|
|
325
329
|
def get_status(self, filename):
|
|
@@ -754,7 +758,7 @@ class YAPOSIB(LpSolver):
|
|
|
754
758
|
var.varValue = var.solverVar.solution
|
|
755
759
|
var.dj = var.solverVar.reducedcost
|
|
756
760
|
# put pi and slack variables against the constraints
|
|
757
|
-
for constr in lp.
|
|
761
|
+
for constr in lp._constraints.values():
|
|
758
762
|
constr.pi = constr.solverConstraint.dual
|
|
759
763
|
constr.slack = -constr.constant - constr.solverConstraint.activity
|
|
760
764
|
if self.msg:
|
|
@@ -813,7 +817,7 @@ class YAPOSIB(LpSolver):
|
|
|
813
817
|
prob.obj[col.index] = lp.objective.get(var, 0.0)
|
|
814
818
|
var.solverVar = col
|
|
815
819
|
log.debug("add the Constraints to the problem")
|
|
816
|
-
for name, constraint in lp.
|
|
820
|
+
for name, constraint in lp._constraints.items():
|
|
817
821
|
row = prob.rows.add(
|
|
818
822
|
yaposib.vec(
|
|
819
823
|
[
|
|
@@ -849,7 +853,7 @@ class YAPOSIB(LpSolver):
|
|
|
849
853
|
solutionStatus = self.findSolutionValues(lp)
|
|
850
854
|
for var in lp.variables():
|
|
851
855
|
var.modified = False
|
|
852
|
-
for constraint in lp.
|
|
856
|
+
for constraint in lp._constraints.values():
|
|
853
857
|
constraint.modified = False
|
|
854
858
|
return solutionStatus
|
|
855
859
|
|
|
@@ -861,7 +865,7 @@ class YAPOSIB(LpSolver):
|
|
|
861
865
|
constraints
|
|
862
866
|
"""
|
|
863
867
|
log.debug("Resolve the model using yaposib")
|
|
864
|
-
for constraint in lp.
|
|
868
|
+
for constraint in lp._constraints.values():
|
|
865
869
|
row = constraint.solverConstraint
|
|
866
870
|
if constraint.modified:
|
|
867
871
|
if constraint.sense == constants.LpConstraintLE:
|
|
@@ -878,7 +882,7 @@ class YAPOSIB(LpSolver):
|
|
|
878
882
|
solutionStatus = self.findSolutionValues(lp)
|
|
879
883
|
for var in lp.variables():
|
|
880
884
|
var.modified = False
|
|
881
|
-
for constraint in lp.
|
|
885
|
+
for constraint in lp._constraints.values():
|
|
882
886
|
constraint.modified = False
|
|
883
887
|
return solutionStatus
|
|
884
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
|
|
@@ -240,6 +240,21 @@ class CPLEX_CMD(LpSolver_CMD):
|
|
|
240
240
|
return True
|
|
241
241
|
|
|
242
242
|
|
|
243
|
+
def check_solverModel(func):
|
|
244
|
+
"""
|
|
245
|
+
Decorator that checks if the solverModel is initialized.
|
|
246
|
+
|
|
247
|
+
:raises PulpSolverError: If the ``solverModel`` attribute is not initialized
|
|
248
|
+
"""
|
|
249
|
+
|
|
250
|
+
def wrapper(self, *args, **kwargs):
|
|
251
|
+
if self.solverModel is None:
|
|
252
|
+
raise PulpSolverError("solverModel not initialized")
|
|
253
|
+
return func(self, *args, **kwargs)
|
|
254
|
+
|
|
255
|
+
return wrapper
|
|
256
|
+
|
|
257
|
+
|
|
243
258
|
class CPLEX_PY(LpSolver):
|
|
244
259
|
"""
|
|
245
260
|
The CPLEX LP/MIP solver (via a Python Binding)
|
|
@@ -262,7 +277,11 @@ class CPLEX_PY(LpSolver):
|
|
|
262
277
|
"""True if the solver is available"""
|
|
263
278
|
return False
|
|
264
279
|
|
|
265
|
-
def actualSolve(
|
|
280
|
+
def actualSolve(
|
|
281
|
+
self,
|
|
282
|
+
lp: Any,
|
|
283
|
+
callback: Optional[Iterable[type[Any]]] = None,
|
|
284
|
+
) -> Any:
|
|
266
285
|
"""Solve a well formulated lp problem"""
|
|
267
286
|
raise PulpSolverError(f"CPLEX_PY: Not Available:\n{self.err}")
|
|
268
287
|
|
|
@@ -308,13 +327,18 @@ class CPLEX_PY(LpSolver):
|
|
|
308
327
|
logPath=logPath,
|
|
309
328
|
threads=threads,
|
|
310
329
|
)
|
|
311
|
-
self.
|
|
330
|
+
self.solver_params = solverParams
|
|
331
|
+
self.solverModel = None
|
|
312
332
|
|
|
313
333
|
def available(self):
|
|
314
334
|
"""True if the solver is available"""
|
|
315
335
|
return True
|
|
316
336
|
|
|
317
|
-
def actualSolve(
|
|
337
|
+
def actualSolve(
|
|
338
|
+
self,
|
|
339
|
+
lp: Any,
|
|
340
|
+
callback: Optional[Iterable[type[cplex.callbacks.Callback]]] = None,
|
|
341
|
+
) -> Any:
|
|
318
342
|
"""
|
|
319
343
|
Solve a well formulated lp problem
|
|
320
344
|
|
|
@@ -331,7 +355,7 @@ class CPLEX_PY(LpSolver):
|
|
|
331
355
|
solutionStatus = self.findSolutionValues(lp)
|
|
332
356
|
for var in lp._variables:
|
|
333
357
|
var.modified = False
|
|
334
|
-
for constraint in lp.
|
|
358
|
+
for constraint in lp._constraints.values():
|
|
335
359
|
constraint.modified = False
|
|
336
360
|
return solutionStatus
|
|
337
361
|
|
|
@@ -390,8 +414,8 @@ class CPLEX_PY(LpSolver):
|
|
|
390
414
|
rows = []
|
|
391
415
|
senses = []
|
|
392
416
|
rhs = []
|
|
393
|
-
rownames = list(lp.
|
|
394
|
-
for constraint in lp.
|
|
417
|
+
rownames = list(lp._constraints.keys())
|
|
418
|
+
for constraint in lp._constraints.values():
|
|
395
419
|
# build the expression
|
|
396
420
|
if len(constraint) == 0:
|
|
397
421
|
# if the constraint is empty
|
|
@@ -444,7 +468,7 @@ class CPLEX_PY(LpSolver):
|
|
|
444
468
|
self.solverModel.MIP_starts.add(
|
|
445
469
|
cplex.SparsePair(ind=ind, val=val), effort, "1"
|
|
446
470
|
)
|
|
447
|
-
for param, value in self.
|
|
471
|
+
for param, value in self.solver_params.items():
|
|
448
472
|
self.set_param(param, value)
|
|
449
473
|
|
|
450
474
|
def set_param(self, name: str, value):
|
|
@@ -461,6 +485,7 @@ class CPLEX_PY(LpSolver):
|
|
|
461
485
|
param = self.search_param(name=name)
|
|
462
486
|
return param.get()
|
|
463
487
|
|
|
488
|
+
@check_solverModel
|
|
464
489
|
def search_param(self, name: str):
|
|
465
490
|
"""
|
|
466
491
|
Searches for a solver model parameter by its name and returns the corresponding attribute.
|
|
@@ -474,12 +499,14 @@ class CPLEX_PY(LpSolver):
|
|
|
474
499
|
param = getattr(param, attr)
|
|
475
500
|
return param
|
|
476
501
|
|
|
502
|
+
@check_solverModel
|
|
477
503
|
def get_all_params(self):
|
|
478
504
|
"""
|
|
479
505
|
Returns all parameters from the solver model.
|
|
480
506
|
"""
|
|
481
507
|
return self.solverModel.parameters.get_all()
|
|
482
508
|
|
|
509
|
+
@check_solverModel
|
|
483
510
|
def get_changed_params(self):
|
|
484
511
|
"""
|
|
485
512
|
Returns the parameters that have been changed in the solver model.
|
|
@@ -515,7 +542,7 @@ class CPLEX_PY(LpSolver):
|
|
|
515
542
|
|
|
516
543
|
def callSolver(
|
|
517
544
|
self,
|
|
518
|
-
isMIP,
|
|
545
|
+
isMIP: bool,
|
|
519
546
|
callback: Optional[Iterable[type[cplex.callbacks.Callback]]] = None,
|
|
520
547
|
):
|
|
521
548
|
"""
|
|
@@ -564,7 +591,7 @@ class CPLEX_PY(LpSolver):
|
|
|
564
591
|
sol_status = CplexSolStatus.get(lp.cplex_status)
|
|
565
592
|
lp.assignStatus(status, sol_status)
|
|
566
593
|
var_names = [var.name for var in lp._variables]
|
|
567
|
-
con_names = [con for con in lp.
|
|
594
|
+
con_names = [con for con in lp._constraints]
|
|
568
595
|
try:
|
|
569
596
|
objectiveValue = lp.solverModel.solution.get_objective_value()
|
|
570
597
|
variablevalues = dict(
|