5.5.4. Python 的MIQP建模与优化

在本节中,我们将使用 MindOpt Python API,以按行输入的形式来建模以及求解 MIQP题示例 中的问题。

首先,引入 Python 包:

27from mindoptpy import *

创建优化模型,并赋予一个名称:

33    model = Model("MIQP_01")

调用 Model.addVar() 来添加四个优化变量,定义其下界、上界、名称和类型(有关函数的详细使用方式,请参考 Python API):

36        # Add variables.
37        x = []
38        x.append(model.addVar(0.0,         10.0, 0.0, 'I', "x0")) 
39        x.append(model.addVar(0.0, float('inf'), 0.0, 'C', "x1"))
40        x.append(model.addVar(0.0, float('inf'), 0.0, 'C', "x2"))
41        x.append(model.addVar(0.0, float('inf'), 0.0, 'C', "x3"))

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

43        # Add constraints.
44        # Note that the nonzero elements are inputted in a row-wise order here.
45        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3] >= 1, "c0")
46        model.addConstr(1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3] == 1, "c1")

然后,我们来设置目标函数。首先使用类 QuadExpr 创建一个二次表达式,然后有两种方式来构建: 第一种是利用 QuadExpr 中的方法 QuadExpr.addTerms() 分别输入线性部分和二次部分; 第二种是直接输入一个二次表达式。 最后再用 Model.setObjective() 来设置目标函数并将问题设置为 最小化

47        # Add objective: 1 x0 + 1 x1 + 1 x2 + 1 x3 + 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1]
48        obj = QuadExpr()
49
50        #option-I
51        obj.addTerms([1.0, 1.0, 1.0, 1.0], [x[0], x[1], x[2], x[3]])
52        obj.addTerms([0.5, 0.5, 0.5, 0.5, 0.5], [x[0], x[1], x[2], x[3], x[0]], [x[0], x[1], x[2], x[3], x[1]])
53        
54        #option II
55        # obj = 1*x[0] + 1*x[1] + 1*x[2] + 1*x[3] + 0.5 * x[0]*x[0] + 0.5 * x[1]*x[1] + 0.5 * x[2]*x[2] + 0.5 * x[3]*x[3] + 0.5*x[0]*x[1]
56        
57        # Set objective and change to minimization problem.
58        model.setObjective(obj, MDO.MINIMIZE)

问题输入完成后,再调用 Model.optimize() 求解优化问题:

62        model.optimize()

然后,通过属性 Status 和属性 ObjVal 来查看优化结果和最优目标值,并通过属性 X 来查看变量的取值。 其他的属性值请查看 属性 章节。

64        if model.status == MDO.OPTIMAL:
65            print(f"Optimal objective value is: {model.objval}")
66            print("Decision variables:")
67            for v in x:
68                print(f"x[{v.VarName}] = {v.X}")
69        else:
70            print("No feasible solution.")

最后,我们调用 Model.dispose() 来释放模型:

80        model.dispose()

示例 mdo_miqp_ex1.py 提供了完整源代码:

 1"""
 2/**
 3 *  Description
 4 *  -----------
 5 *
 6 *  Mixed Integer Quadratic optimization (row-wise input).
 7 *
 8 *  Formulation
 9 *  -----------
10 *
11 *  Minimize
12 *    obj: 1 x0 + 1 x1 + 1 x2 + 1 x3
13 *         + 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1]
14 *  Subject To
15 *   c1 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
16 *   c2 : 1 x0 - 1 x2 + 6 x3 = 1
17 *  Bounds
18 *    0 <= x0 <= 10
19 *    0 <= x1
20 *    0 <= x2
21 *    0 <= x3
22 *  Integers
23 *    x0 
24 *  End
25 */
26"""
27from mindoptpy import *
28
29
30if __name__ == "__main__":
31
32    # Step 1. Create model.
33    model = Model("MIQP_01")
34    try:
35        # Step 2. Input model.
36        # Add variables.
37        x = []
38        x.append(model.addVar(0.0,         10.0, 0.0, 'I', "x0")) 
39        x.append(model.addVar(0.0, float('inf'), 0.0, 'C', "x1"))
40        x.append(model.addVar(0.0, float('inf'), 0.0, 'C', "x2"))
41        x.append(model.addVar(0.0, float('inf'), 0.0, 'C', "x3"))
42
43        # Add constraints.
44        # Note that the nonzero elements are inputted in a row-wise order here.
45        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3] >= 1, "c0")
46        model.addConstr(1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3] == 1, "c1")
47
48        # Add objective: 1 x0 + 1 x1 + 1 x2 + 1 x3 + 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1]
49        obj = QuadExpr()
50
51        #option-I
52        obj.addTerms([1.0, 1.0, 1.0, 1.0], [x[0], x[1], x[2], x[3]])
53        obj.addTerms([0.5, 0.5, 0.5, 0.5, 0.5], [x[0], x[1], x[2], x[3], x[0]], [x[0], x[1], x[2], x[3], x[1]])
54        
55        #option II
56        # obj = 1*x[0] + 1*x[1] + 1*x[2] + 1*x[3] + 0.5 * x[0]*x[0] + 0.5 * x[1]*x[1] + 0.5 * x[2]*x[2] + 0.5 * x[3]*x[3] + 0.5*x[0]*x[1]
57        
58        # Set objective and change to minimization problem.
59        model.setObjective(obj, MDO.MINIMIZE)
60
61        # Step 3. Solve the problem and populate optimization result.
62        model.optimize()
63
64        if model.status == MDO.OPTIMAL:
65            print(f"Optimal objective value is: {model.objval}")
66            print("Decision variables:")
67            for v in x:
68                print(f"x[{v.VarName}] = {v.X}")
69        else:
70            print("No feasible solution.")
71    except MindoptError as e:
72        print("Received Mindopt exception.")
73        print(" - Code          : {}".format(e.errno))
74        print(" - Reason        : {}".format(e.message))
75    except Exception as e:
76        print("Received other exception.")
77        print(" - Reason        : {}".format(e))
78    finally:
79        # Step 4. Free the model.
80        model.dispose()