6.3. PuLP 的建模与优化

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

目前,MindOpt 支持在 Windows/Linux/OSX 系统中,通过 Pulp 建立 线性规划模型 并调用 MindOpt 来求解。关于 Pulp 的详细内容,请参考 Pulp 官方文档

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

6.3.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 官方网站

6.3.2. 调用 PuLP 接口

MindOpt 的 PuLP 接口文件( mindopt_pulp.py )定义了 PuLP 调用 MindOpt 所需的相关接口。此接口文件继承自 PuLP 的 LpSolver 类别,实现代码则在安装包中:

<MDOHOME>\<VERSION>\<PLATFORM>\lib\pulp\mindopt_pulp.py

用户首先将该接口文件移到当前使用目录中,并在 Python 代码中导入该文件:

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

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