7.4. PuLP 的建模与优化¶
Pulp 是基于 Python 开发的第三方开源建模语言,它支持对线性规划、混合整数规划、非线性规划等问题建模和分析,并调用其他商用或开源的求解器进行求解。
目前,MindOpt 可对在 Windows/Linux/macOS 平台上通过 Pulp 建立的 线性规划模型 进行求解。关于 Pulp 的详细内容,请参考 Pulp 官方文档。
在本节中,我们将介绍如何使用 PuLP API 来建立 线性规划问题示例 中的优化问题,并调用 MindOpt 求解。
7.4.1. 安装 PuLP¶
用户首先必须安装 MindOpt。关于 MindOpt 的安装与配置请参考 单机版安装。MindOpt 安装后,用户可以通过以下两种方式来安装 PuLP:
pip
命令安装:pip install pulp
git
命令安装:pip install -U git+https://github.com/coin-or/pulp
7.4.2. PuLP 调用接口¶
MindOpt 在 PuLP 接口文件( mindopt_pulp.py
)内定义了 PuLP 调用 MindOpt 所需的相关接口。此接口继承自 PuLP 的 LpSolver
类别,实现细节见安装包内的接口文件:
<MDOHOME>/<VERSION>/<PLATFORM>/lib/pulp/mindopt_pulp.py
用户在使用时需首先将该接口文件移到当前工作目录中,并在 Python 代码中加载该模块中定义的 MINDOPT
类:
25from mindopt_pulp import MINDOPT
接着,我们调用 PuLP API 来建立 线性规划问题示例 中的优化问题。关于 PuLP API 的详细说明,请参考 PuLP 官方文档。
29 # A new LP problem
30 prob = LpProblem("lo_ex1", LpMinimize)
31
32 # Variables
33 # 0 <= x0 <= 10
34 x0 = LpVariable("x0", 0, 10)
35 # 0 <= x1
36 x1 = LpVariable("x1", 0)
37 # 0 <= x2
38 x2 = LpVariable("x2", 0)
39 # 0 <= x3
40 x3 = LpVariable("x3", 0)
41 # Use None for +/- Infinity, i.e. x <= 0 -> LpVariable("x", None, 0)
42
43 # Objective
44 prob += x0 + 1 * x1 + 1 * x2 + 1 * x3, "obj"
45 # (the name at the end is facultative)
46
47 # Constraints
48 """
49 c1 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
50 c2 : 1 x0 - 1 x2 + 6 x3 = 1
51 """
52 prob += x0 + x1 + 2 * x2 + 3 * x3 >= 1, "c1"
53 prob += x0 - x2 + 6 * x3 == 1, "c2"
54 # (the names at the end are facultative)
55
56 # Write the problem as an MPS file
57 prob.writeMPS("lo_ex1.mps")
求解前,我们指定使用 MindOpt 求解器,并对求解的相关参数进行设置(求解器参数数请查阅 参数):
61 options = {
62 "Method": -1,
63 "NumThreads": 0,
64 "Presolve": 1,
65 "Dualization": -1,
66 "SPX/MaxIterations": 2147483647,
67 "SPX/ColumnGeneration": -1,
68 "IPM/MaxIterations": 400,
69 "MaxTime": 1.7976931348623158e+308,
70 "SPX/PrimalTolerance": 1.E-6,
71 "SPX/DualTolerance": 1.E-6,
72 "IPM/PrimalTolerance": 1.E-8,
73 "IPM/DualTolerance": 1.E-8,
74 "IPM/GapTolerance": 1.E-8}
最后,调用 PuLP 的求解函数 solve()
进行求解,并获取相关的结果:
75 prob.solve(MINDOPT(options=options))
7.4.3. 建模示例: mdo_pulp_lo_ex1¶
文件链接 mdo_pulp_lo_ex1.py 中提供了完整代码:
1"""
2/**
3 * Description
4 * -----------
5 *
6 * Linear optimization (row-wise input).
7 *
8 * Formulation
9 * -----------
10 *
11 * Minimize
12 * obj: 1 x0 + 1 x1 + 1 x2 + 1 x3
13 * Subject To
14 * c1 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
15 * c2 : 1 x0 - 1 x2 + 6 x3 = 1
16 * Bounds
17 * 0 <= x0 <= 10
18 * 0 <= x1
19 * 0 <= x2
20 * 0 <= x3
21 * End
22 */
23"""
24from pulp import LpProblem, LpMinimize, LpVariable, LpStatus, value
25from mindopt_pulp import MINDOPT
26
27if __name__ == "__main__":
28
29 # A new LP problem
30 prob = LpProblem("lo_ex1", LpMinimize)
31
32 # Variables
33 # 0 <= x0 <= 10
34 x0 = LpVariable("x0", 0, 10)
35 # 0 <= x1
36 x1 = LpVariable("x1", 0)
37 # 0 <= x2
38 x2 = LpVariable("x2", 0)
39 # 0 <= x3
40 x3 = LpVariable("x3", 0)
41 # Use None for +/- Infinity, i.e. x <= 0 -> LpVariable("x", None, 0)
42
43 # Objective
44 prob += x0 + 1 * x1 + 1 * x2 + 1 * x3, "obj"
45 # (the name at the end is facultative)
46
47 # Constraints
48 """
49 c1 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
50 c2 : 1 x0 - 1 x2 + 6 x3 = 1
51 """
52 prob += x0 + x1 + 2 * x2 + 3 * x3 >= 1, "c1"
53 prob += x0 - x2 + 6 * x3 == 1, "c2"
54 # (the names at the end are facultative)
55
56 # Write the problem as an MPS file
57 prob.writeMPS("lo_ex1.mps")
58
59 # Solve the problem using the MINDOPT solver
60 # prob.solve(MINDOPT()) # use default options
61 options = {
62 "Method": -1,
63 "NumThreads": 0,
64 "Presolve": 1,
65 "Dualization": -1,
66 "SPX/MaxIterations": 2147483647,
67 "SPX/ColumnGeneration": -1,
68 "IPM/MaxIterations": 400,
69 "MaxTime": 1.7976931348623158e+308,
70 "SPX/PrimalTolerance": 1.E-6,
71 "SPX/DualTolerance": 1.E-6,
72 "IPM/PrimalTolerance": 1.E-8,
73 "IPM/DualTolerance": 1.E-8,
74 "IPM/GapTolerance": 1.E-8}
75 prob.solve(MINDOPT(options=options))
76
77 # Print the status of the solved LP
78 print("Status:", LpStatus[prob.status])
79
80 # Print the value of the variables at the optimum
81 for v in prob.variables():
82 print(v.name, "=", v.varValue)
83
84 # Print the value of the objective
85 print("objective=", value(prob.objective))