5.4. Python 的建模与优化

在本节中,我们将使用 MindOpt Python 语言的 API 来建模以及求解 线性规划问题示例 中的问题。

5.4.1. 按行输入: mdo_lo_ex1

首先,引入 Python 包:

24from mindoptpy import *

并创建优化模型:

31    # Step 1. Create a model and change the parameters.
32    model = MdoModel()

接下来,我们通过 mindoptpy.MdoModel.set_int_attr() 将目标函数设置为 最小化 ,并调用 mindoptpy.MdoModel.add_var() 来添加四个优化变量,定义其下界、上界、名称和类型(有关 mindoptpy.MdoModel.set_int_attr()mindoptpy.MdoModel.add_var() 的详细使用方式,请参考 Python 接口函数):

35        # Step 2. Input model.
36        # Change to minimization problem.
37        model.set_int_attr("MinSense", 1)
38        
39        # Add variables.
40        x = []
41        x.append(model.add_var(0.0,         10.0, 1.0, None, "x0", False))
42        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x1", False))
43        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x2", False))
44        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x3", False))

接着,我们开始添加线性约束:

46        # Add constraints.
47        # Note that the nonzero elements are inputted in a row-wise order here.
48        model.add_cons(1.0, MDO_INFINITY, 1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], "c0")
49        model.add_cons(1.0,          1.0, 1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3], "c1")

问题输入完成后,再调用 mindoptpy.MdoModel.solve_prob() 求解优化问题,并用 mindoptpy.MdoModel.display_results() 来查看优化结果:

51        # Step 3. Solve the problem and populate the result.
52        model.solve_prob()
53        model.display_results()

最后,我们调用 mindoptpy.MdoModel.free_mdl() 来释放内存:

63        # Step 4. Free the model.
64        model.free_mdl()

mdo_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 mindoptpy import *
25
26
27if __name__ == "__main__":
28
29    MDO_INFINITY = MdoModel.get_infinity()
30
31    # Step 1. Create a model and change the parameters.
32    model = MdoModel()
33
34    try:
35        # Step 2. Input model.
36        # Change to minimization problem.
37        model.set_int_attr("MinSense", 1)
38        
39        # Add variables.
40        x = []
41        x.append(model.add_var(0.0,         10.0, 1.0, None, "x0", False))
42        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x1", False))
43        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x2", False))
44        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x3", False))
45
46        # Add constraints.
47        # Note that the nonzero elements are inputted in a row-wise order here.
48        model.add_cons(1.0, MDO_INFINITY, 1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], "c0")
49        model.add_cons(1.0,          1.0, 1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3], "c1")
50
51        # Step 3. Solve the problem and populate the result.
52        model.solve_prob()
53        model.display_results()
54
55    except MdoError as e:
56        print("Received Mindopt exception.")
57        print(" - Code          : {}".format(e.code))
58        print(" - Reason        : {}".format(e.message))
59    except Exception as e:
60        print("Received exception.")
61        print(" - Reason        : {}".format(e))
62    finally:
63        # Step 4. Free the model.
64        model.free_mdl()

5.4.2. 按列输入: mdo_lo_ex2

在下面的代码中,我们依然对上述问题进行建模,但改以 按列排列 的方式输入矩阵的非零元。

在时调用 mindoptpy.MdoModel.add_cons() 时,仅输入约束的下界(left-hand-side;LHS)和上界(right-hand-side;RHS),约束矩阵则为空(无非零元素)。待约束输入后,再创建 列对象 mindoptpy.MdoCol() 来保存该列在各约束中相对应的非零元位置(索引)和非零值。最后,调用 mindoptpy.MdoModel.add_var() 创建变量,并输入其相应的目标函数系数、下界和上界、各约束在此列中相对应的非零元、变量名以及变量类型。

此外,我们还调用 mindoptpy.MdoModel.get_status() 来检查求解器的优化状态,并通过 mindoptpy.MdoModel.get_real_attr()mindoptpy.MdoVar.get_real_attr() 来获取目标值和最优解(关于 mindoptpy.MdoModel.get_real_attr()mindoptpy.MdoVar.get_real_attr() 的详细使用方式,请参考 Python 接口函数)。

mdo_lo_ex2.py 提供了完整源代码:

 1"""
 2/**
 3 *  Description
 4 *  -----------
 5 *
 6 *  Linear optimization (column-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 mindoptpy import *
25
26
27if __name__ == "__main__":
28
29    MDO_INFINITY = MdoModel.get_infinity()
30
31    # Step 1. Create a model and change the parameters.
32    model = MdoModel()
33
34    try:
35        # Step 2. Input model.
36        # Change to minimization problem.
37        model.set_int_attr("MinSense", 1)
38
39        # Add empty constraints. 
40        cons = []
41        cons.append(model.add_cons(1.0, MDO_INFINITY, None, "c0"))
42        cons.append(model.add_cons(1.0, 1.0,          None, "c1"))
43        
44        # Input columns. 
45        col = []
46        for j in range(4):
47            col.append(MdoCol())
48        col[0].add_term(cons[0], 1.0)
49        col[0].add_term(cons[1], 1.0)
50        col[1].add_term(cons[0], 1.0)
51        col[2].add_term(cons[0], 2.0)
52        col[2].add_term(cons[1], -1.0)
53        col[3].add_term(cons[0], 3.0)
54        col[3].add_term(cons[1], 6.0)
55
56        # Add variables.
57        # Note that the nonzero elements are inputted in a column-wise order here.
58        x = []
59        x.append(model.add_var(0.0,         10.0, 1.0, col[0], "x0", False))
60        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, col[1], "x1", False))
61        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, col[2], "x2", False))
62        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, col[3], "x3", False))
63
64        # Step 3. Solve the problem and populate the result.
65        model.solve_prob()
66        model.display_results()
67
68        status_code, status_msg = model.get_status()
69        if status_msg == "OPTIMAL":
70            print("Optimizer terminated with an OPTIMAL status (code {0}).".format(status_code))
71            print("Primal objective : {0}".format(round(model.get_real_attr("PrimalObjVal"), 2)))
72            for curr_x in x:
73                print(" - x[{0}]          : {1}".format(curr_x.get_index(), round(curr_x.get_real_attr("PrimalSoln"), 2)))
74        else:
75            print("Optimizer terminated with a(n) {0} status (code {1}).".format(status_msg, status_code))
76
77    except MdoError as e:
78        print("Received Mindopt exception.")
79        print(" - Code          : {}".format(e.code))
80        print(" - Reason        : {}".format(e.message))
81    except Exception as e:
82        print("Received exception.")
83        print(" - Explanation   : {}".format(e))
84    finally:
85        # Step 4. Free the model.
86        model.free_mdl()

5.4.3. 进阶使用示例:mdo_lo_ex3

在下面的代码中,我们展示了其他进阶 API 使用方式,如:输入模型、修改模型、获取基解、热启动的例子;关于 API 的完整使用方法,请参考 接口的定义与调用规范

mdo_lo_ex3.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 mindoptpy import *
 25
 26
 27if __name__ == "__main__":
 28
 29    MDO_INFINITY = MdoModel.get_infinity()
 30    WRITE_LP = True
 31
 32    # Step 1. Create a model and change the parameters.
 33    model = MdoModel()
 34
 35    try:
 36        # Step 2. Input model.
 37        print("\nStep 2. Input model.\n")        
 38        # Change to minimization problem.
 39        model.set_int_attr("MinSense", 1)
 40        
 41        # Add variables.
 42        xs = model.add_vars(4, lb=0, ub=MDO_INFINITY, obj=1.0, name="x")
 43        x = [ value for key, value in xs.items() ]
 44        x[0].set_real_attr("UB", 10.0)
 45
 46        # Add constraints.
 47        # Note that the nonzero elements are inputted in a row-wise order here.
 48        conss = []
 49        conss.append(model.add_cons(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3] >= 1.0, "c0"))
 50        conss.append(model.add_cons(1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3] == 1.0, "c1"))
 51
 52        # Step 3. Solve the problem and populate the result.
 53        print("\nStep 3. Solve the problem and populate the result.\n")        
 54        model.solve_prob()
 55        model.display_results()
 56        if WRITE_LP:
 57            model.write_prob("Step3.lp");
 58
 59        # Step 4. Add another two variables and then resolve the problem. 
 60        print("\nStep 4. Add another two variables and then resolve the problem.\n")        
 61        # Input columns. 
 62        cols = [ MdoCol() for i in range(2) ]
 63        cols[0].add_terms(conss, [ 1.0, 2.0 ])
 64        cols[1].add_terms(conss, [ 3.4, 4.0 ])
 65        y = []
 66        y.append(model.add_var( 0.0, MDO_INFINITY,  1.0, cols[0], "y0", False))
 67        y.append(model.add_var(-2.0, MDO_INFINITY, -1.0, cols[1], "y1", False))
 68
 69        # Solve the problem. 
 70        model.solve_prob()
 71        model.display_results()
 72        if WRITE_LP:
 73            model.write_prob("Step4.lp");
 74
 75        # Step 5. Add another two constraints and then resolve the problem.     
 76        print("\nStep 5. Add another two constraints and then resolve the problem.\n")
 77        bgn2 = [ 0, 3, 6 ]
 78        indices2 = [
 79            0,   1,        3,
 80            0,        2,   3  
 81        ]
 82        values2 = [
 83            1.0, 1.0,      -2.0,
 84            1.0,      -2.0, 6.0
 85        ]    
 86
 87        lhss2 = [ 0, 1            ]
 88        rhss2 = [ 2, MDO_INFINITY ]
 89
 90        expr = [ MdoExprLinear() for i in range(2) ]
 91        for i in range(2):
 92            for e in range(bgn2[i], bgn2[i + 1]):
 93                expr[i] += values2[e] * x[indices2[e]]
 94                
 95        c2 = model.add_conss( [ expr[i] == [lhss2[i], rhss2[i]] for i in range(2) ] )
 96        for key, value in c2.items():
 97            conss.append(value)
 98
 99        # Solve the problem. 
100        model.solve_prob()
101        model.display_results()
102        if WRITE_LP:
103            model.write_prob("Step5.lp");
104
105        # Step 6. Obtain optimal basis.     
106        print("\nStep 6. Obtain optimal basis.\n")
107        
108        # isFree = 0,
109        # basic = 1,
110        # atUpperBound = 2,
111        # atLowerBound = 3,
112        # superBasic = 4,
113        # isFixed = 5,
114        col_basis = []
115        row_basis = []
116        for var in x:
117            print("Basis status of variable {0} is {1}".format(var.get_index(), var.get_int_attr("ColBasis")))
118            col_basis.append(var.get_int_attr("ColBasis"))
119        for var in y:
120            print("Basis status of variable {0} is {1}".format(var.get_index(), var.get_int_attr("ColBasis")))
121            col_basis.append(var.get_int_attr("ColBasis"))
122        for cons in conss:
123            print("Basis status of constraint {0} is {1}".format(cons.get_index(), cons.get_int_attr("RowBasis")))
124            row_basis.append(cons.get_int_attr("RowBasis"))
125
126        if WRITE_LP:
127            model.write_prob("Step6.lp");
128            model.write_soln("Step6.bas");
129
130        # Step 7. Warm-start Simplex.    
131        print("\nStep 7. Warm-start Simplex.\n")
132
133        # Change the objective coefficients. 
134        x[1].set_real_attr("Obj", 3.0);
135        x[2].set_real_attr("Obj", -3.0);
136
137        # Load the basis. 
138        model.set_int_attr_array("RowBasis", 0, row_basis);
139        model.set_int_attr_array("ColBasis", 0, col_basis);
140
141        # Solve the problem. 
142        model.solve_prob()
143        model.display_results()
144        if WRITE_LP:
145            model.write_prob("Step7.lp");
146
147        # Step 8. Model query.     
148        print("\nStep 8. Model query.\n")
149
150        # Query 1: Retrieve first constraint. 
151        print("Query 1: Retrieve first constraint.")
152        
153        temp_expr = model.get_expr_linear(conss[0])
154        print(temp_expr)
155        
156        # Query 2: Retrieve second column. 
157        print("Query 2: Retrieve second column.")
158        
159        temp_col = model.get_col(x[1]);
160        print(temp_col)
161
162    except MdoError as e:
163        print("Received Mindopt exception.")
164        print(" - Code          : {}".format(e.code))
165        print(" - Reason        : {}".format(e.message))
166    except Exception as e:
167        print("Received exception.")
168        print(" - Reason        : {}".format(e))
169    finally:
170        # Step 4. Free the model.
171        model.free_mdl()