5.6.9. Python 的 MISOCP 建模和优化

在本节中,我们将使用 MindOpt Python API 来建模和求解 MIQCP示例2 中的混合整数二阶锥规划问题。

首先,导入 MindOpt Python 工具包:

27"""

创建一个名为 "MISOCPEx1" 的优化模型 model

32    # Step 1. Create a model.

接下来,我们调用 Model.addVar() 添加五个优化变量。它们的下界、上界、类型、名称以及在目标函数中的线性项系数都将作为参数指定。

备注

通过参数 vtype 将类型设置为 'I' 代表这个变量是整形变量。

38        # Add variables. The linear objective coefficients are specified directly.
39        x = []
40        x.append(model.addVar(lb=0.0, ub=10.0, obj=1.0, vtype='I', name="x0"))
41        x.append(model.addVar(lb=0.0, ub=float('inf'), obj=2.0, vtype='I', name="x1"))
42        x.append(model.addVar(lb=0.0, ub=float('inf'), obj=1.0, vtype='I', name="x2"))
43        x.append(model.addVar(lb=0.0, ub=float('inf'), obj=1.0, vtype='C', name="x3"))

然后,将求解方向设置为 最小化

46        # Set the optimization sense.

备注

由于线性目标系数 (1, 2, 1, 1, 0.5) 在创建变量时已通过 obj 参数直接传入,因此 无需单独调用 Model.setObjective()

现在,我们添加约束。对于 Python 接口,可以使用重载的算术运算符自然地构建线性和二次表达式。

  • 约束 c0: \(x_0 + x_1 + 2x_2 + 3x_3 \geq 1\)

  • 约束 c1: \(x_0 - x_2 + 6x_3 = 1\)

  • 二次(SOCP)约束 c2: \(x_1^2 + x_2^2 - x_4^2 \leq 0\)

使用 Model.addConstr() 将它们添加到模型中:

48
49        # Add constraints. Expressions are built using overloaded operators.
50        # c0: 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
51        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3] >= 1.0, "c0")
52
53        # c1: 1 x0 - 1 x2 + 6 x3 = 1
54        model.addConstr(1.0 * x[0] - 1.0 * x[2] + 6.0 * x[3] == 1.0, "c1")
55
56        # c2: x_1^2 + x_2^2 - x_4^2 <= 0

模型构建完成后,我们调用 Model.optimize() 来求解问题:

59        # Step 3. Solve the problem.

我们可以通过属性 Status 检查求解状态,并通过属性 ObjValX 获取最优目标值和解。有关其他属性信息,请参阅 属性

67        # exist, making it necessary to check the SolCount property.
68        if model.status == MDO.OPTIMAL or model.status == MDO.SUB_OPTIMAL or model.solcount > 0:
69            print(f"Optimal objective value is: {model.objval}")
70            print("Decision variables:")
71            for v in model.getVars():

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

84        # Step 5. Free the model.

完整的 Python 代码见 mdo_misocp_ex1.py

 1"""
 2/**
 3 *  Description
 4 *  -----------
 5 *
 6 *  Formulation
 7 *  -----------
 8 *
 9  Minimize
10 *    obj: 1 x0 + 2 x1 + 1 x2 + 1 x3 + 0.5 x_4
11 *
12 *
13 *  Subject To
14 *   c0 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
15 *   c1 : 1 x0 - 1 x2 + 6 x3  = 1
16 *   c2 : x_1^2 + x_2^2 - x_4^2 <= 0
17 *  Bounds
18 *    0 <= x0 <= 10
19 *    0 <= x1
20 *    0 <= x2
21 *    0 <= x3
22 *    0 <= x4
23 *  Integer
24 *  x0, x1, x2
25 *  End
26 */
27"""
28from mindoptpy import *
29
30if __name__ == "__main__":
31
32    # Step 1. Create a model.
33    model = Model("MISOCPEx1")
34
35    try:
36        # Step 2. Input model.
37
38        # Add variables. The linear objective coefficients are specified directly.
39        x = []
40        x.append(model.addVar(lb=0.0, ub=10.0, obj=1.0, vtype='I', name="x0"))
41        x.append(model.addVar(lb=0.0, ub=float('inf'), obj=2.0, vtype='I', name="x1"))
42        x.append(model.addVar(lb=0.0, ub=float('inf'), obj=1.0, vtype='I', name="x2"))
43        x.append(model.addVar(lb=0.0, ub=float('inf'), obj=1.0, vtype='C', name="x3"))
44        x.append(model.addVar(lb=0.0, ub=float('inf'), obj=0.5, vtype='C', name="x4"))
45
46        # Set the optimization sense.
47        model.modelSense = MDO.MINIMIZE
48
49        # Add constraints. Expressions are built using overloaded operators.
50        # c0: 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
51        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3] >= 1.0, "c0")
52
53        # c1: 1 x0 - 1 x2 + 6 x3 = 1
54        model.addConstr(1.0 * x[0] - 1.0 * x[2] + 6.0 * x[3] == 1.0, "c1")
55
56        # c2: x_1^2 + x_2^2 - x_4^2 <= 0
57        model.addConstr(x[1] * x[1] + x[2] * x[2] - x[4] * x[4] <= 0.0, "c2")
58
59        # Step 3. Solve the problem.
60        model.optimize()
61
62        # Step 4. Retrieve model status and solution.
63        # For MIP(MILP, MIQP, MIQCP) problems, if the solving process
64        # terminates early due to reasons such as timeout or interruption,
65        # the model status will indicate termination by timeout (or
66        # interruption, etc.). However, suboptimal solutions may still
67        # exist, making it necessary to check the SolCount property.
68        if model.status == MDO.OPTIMAL or model.status == MDO.SUB_OPTIMAL or model.solcount > 0:
69            print(f"Optimal objective value is: {model.objval}")
70            print("Decision variables:")
71            for v in model.getVars():
72                print(f"{v.VarName} = {v.X}")
73        else:
74            print("No feasible solution.")
75
76    except MindoptError as e:
77        print("Received Mindopt exception.")
78        print(f" - Code          : {e.errno}")
79        print(f" - Reason        : {e.message}")
80    except Exception as e:
81        print("Received other exception.")
82        print(f" - Reason        : {e}")
83    finally:
84        # Step 5. Free the model.
85        model.dispose()