7.4. PuLP 的建模与优化

Pulp 是基于 Python 开发的第三方开源建模语言,它支持对线性规划、混合整数规划、非线性规划等问题建模和分析,并调用其他商用或开源的求解器进行求解。

目前,MindOpt 可对在 Windows/Linux/macOS 平台上通过 Pulp 建立的 线性规划模型 进行求解。关于 Pulp 的详细内容,请参考 Pulp 官方文档

在本节中,我们将介绍如何使用 PuLP API 来建立 线性规划问题示例 中的优化问题,并调用 MindOpt 求解。

7.4.1. 安装 PuLP

用户首先必须安装 MindOpt。关于 MindOpt 的安装与配置请参考 单机版安装MindOpt 安装后,用户可以通过以下两种方式来安装 PuLP:

  1. pip 命令安装:

pip install pulp
  1. git 命令安装:

pip install -U git+https://github.com/coin-or/pulp

关于 PuLP 的详细安装方式,请参考 PuLP 官方网站PyPi.

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))