5.6.11. C# 的 MISOCP 建模和优化¶
在本节中,我们将使用 MindOpt C# API 来建模和求解 MIQCP示例2 中的混合整数二阶锥规划问题。
引入 Mindopt 命名空间:
25 */
26using Mindopt;
创建优化环境和模型:
34 {
35 // Create environment and model.
36 MDOEnv env = new MDOEnv();
37 MDOModel model = new MDOModel(env);
接下来,我们将求解方向设置为 最小化。然后,调用 MDOModel.AddVar 添加五个优化变量。它们的下界、上界、类型、名称以及在目标函数中的线性项系数都将作为参数直接传入。
备注
在调用 MDOModel.AddVar 时,将类型设置为 'I' 代表这个变量是整形变量。
43 // Change to minimization problem.
44 // Add variables. The linear objective coefficients are specified directly.
45 MDOVar[] x = new MDOVar[5];
46 x[0] = model.AddVar(0.0, 10.0, 1.0, 'I', "x0");
47 x[1] = model.AddVar(0.0, MDO.INFINITY, 2.0, 'I', "x1");
48 x[2] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'I', "x2");
49 x[3] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'C', "x3");
备注
由于线性目标系数在创建变量时已直接传入,因此 无需单独调用 MDOModel.SetObjective。
现在,我们添加线性约束。对于 C# 接口,这需要为每个约束创建一个 MDOExpr 对象,并向其添加项。
约束 c0: \(x_0 + x_1 + 2x_2 + 3x_3 \geq 1\)
约束 c1: \(x_0 - x_2 + 6x_3 = 1\)
使用 MDOModel.AddConstr 将它们添加到模型中:
53 // Add linear constraint c0: 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
54 MDOExpr c0 = new MDOExpr();
55 c0.AddTerms(new double[] { 1.0, 1.0, 2.0, 3.0 }, new MDOVar[] { x[0], x[1], x[2], x[3] });
56 model.AddConstr(c0, MDO.GREATER_EQUAL, 1.0, "c0");
57
58 // Add linear constraint c1: 1 x0 - 1 x2 + 6 x3 = 1
59 MDOExpr c1 = new MDOExpr();
60 c1.AddTerms(new double[] { 1.0, -1.0, 6.0 }, new MDOVar[] { x[0], x[2], x[3] });
最后,我们添加二次(二阶锥)约束:
c2: \(x_1^2 + x_2^2 - x_4^2 \leq 0\)
这通过创建一个 MDOQuadExpr 对象并添加二次项来完成。然后使用 MDOModel.AddQConstr 将该约束添加到模型中。
63 // Add second-order cone constraint c2: x_1^2 + x_2^2 - x_4^2 <= 0
64 MDOQuadExpr c2 = new MDOQuadExpr();
65 // This constraint has no linear part. We only add the quadratic terms.
66 c2.AddTerms(
67 new double[] { 1.0, 1.0, -1.0 }, // values
68 new MDOVar[] { x[1], x[2], x[4] }, // first variable indices
69 new MDOVar[] { x[1], x[2], x[4] } // second variable indices
70 );
模型构建完成后,我们调用 MDOModel.Optimize 来求解问题:
74 // Step 2. Solve the problem.
求解后,我们检查求解状态,并获取最优目标值和变量取值。
82 // exist, making it necessary to check the SolCount property.
83 if (model.Get(MDO.IntAttr.Status) == MDO.Status.OPTIMAL || model.Get(MDO.IntAttr.Status) == MDO.Status.SUB_OPTIMAL ||
84 model.Get(MDO.IntAttr.SolCount) > 0)
85 {
86 Console.WriteLine($"Optimal objective value is: {model.Get(MDO.DoubleAttr.ObjVal)}");
87 Console.WriteLine("Decision variables: ");
88 for (int i = 0; i < 5; i++)
89 {
90 Console.WriteLine($"x[{i}] = {x[i].Get(MDO.DoubleAttr.X)}");
91 }
最后,我们释放模型和环境以回收资源。
110 {
111 // Step 4. Free the model.
112 model.Dispose();
示例 MdoMISOCPEx1.cs 提供了完整源代码:
1/**
2 * Description
3 * -----------
4 *
5 * Formulation
6 * -----------
7 *
8 Minimize
9 * obj: 1 x0 + 2 x1 + 1 x2 + 1 x3 + 0.5 x_4
10 *
11 *
12 * Subject To
13 * c0 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
14 * c1 : 1 x0 - 1 x2 + 6 x3 = 1
15 * c2 : x_1^2 + x_2^2 - x_4^2 <= 0
16 * Bounds
17 * 0 <= x0 <= 10
18 * 0 <= x1
19 * 0 <= x2
20 * 0 <= x3
21 * 0 <= x4
22 * Integer
23 * x0, x1, x2
24 * End
25 */
26using Mindopt;
27using System;
28
29namespace Example
30{
31 public class MdoMISOCPEx1
32 {
33 public static void Main(string[] args)
34 {
35 // Create environment and model.
36 MDOEnv env = new MDOEnv();
37 MDOModel model = new MDOModel(env);
38 model.Set(MDO.StringAttr.ModelName, "MISOCPEx1");
39
40 try
41 {
42 // Step 1. Input model.
43 // Change to minimization problem.
44 model.Set(MDO.IntAttr.ModelSense, MDO.MINIMIZE);
45
46 // Add variables. The linear objective coefficients are specified directly.
47 MDOVar[] x = new MDOVar[5];
48 x[0] = model.AddVar(0.0, 10.0, 1.0, 'I', "x0");
49 x[1] = model.AddVar(0.0, MDO.INFINITY, 2.0, 'I', "x1");
50 x[2] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'I', "x2");
51 x[3] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'C', "x3");
52 x[4] = model.AddVar(0.0, MDO.INFINITY, 0.5, 'C', "x4");
53
54 // Add linear constraint c0: 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
55 MDOExpr c0 = new MDOExpr();
56 c0.AddTerms(new double[] { 1.0, 1.0, 2.0, 3.0 }, new MDOVar[] { x[0], x[1], x[2], x[3] });
57 model.AddConstr(c0, MDO.GREATER_EQUAL, 1.0, "c0");
58
59 // Add linear constraint c1: 1 x0 - 1 x2 + 6 x3 = 1
60 MDOExpr c1 = new MDOExpr();
61 c1.AddTerms(new double[] { 1.0, -1.0, 6.0 }, new MDOVar[] { x[0], x[2], x[3] });
62 model.AddConstr(c1, MDO.EQUAL, 1.0, "c1");
63
64 // Add second-order cone constraint c2: x_1^2 + x_2^2 - x_4^2 <= 0
65 MDOQuadExpr c2 = new MDOQuadExpr();
66 // This constraint has no linear part. We only add the quadratic terms.
67 c2.AddTerms(
68 new double[] { 1.0, 1.0, -1.0 }, // values
69 new MDOVar[] { x[1], x[2], x[4] }, // first variable indices
70 new MDOVar[] { x[1], x[2], x[4] } // second variable indices
71 );
72 model.AddQConstr(c2, MDO.LESS_EQUAL, 0.0, "c2");
73
74 // Step 2. Solve the problem.
75 model.Optimize();
76
77 // Step 3. Retrieve model status and solution.
78 // For MIP(MILP,MIQP, MIQCP) problems, if the solving process
79 // terminates early due to reasons such as timeout or interruption,
80 // the model status will indicate termination by timeout (or
81 // interruption, etc.). However, suboptimal solutions may still
82 // exist, making it necessary to check the SolCount property.
83 if (model.Get(MDO.IntAttr.Status) == MDO.Status.OPTIMAL || model.Get(MDO.IntAttr.Status) == MDO.Status.SUB_OPTIMAL ||
84 model.Get(MDO.IntAttr.SolCount) > 0)
85 {
86 Console.WriteLine($"Optimal objective value is: {model.Get(MDO.DoubleAttr.ObjVal)}");
87 Console.WriteLine("Decision variables: ");
88 for (int i = 0; i < 5; i++)
89 {
90 Console.WriteLine($"x[{i}] = {x[i].Get(MDO.DoubleAttr.X)}");
91 }
92 }
93 else
94 {
95 Console.WriteLine("No feasible solution.");
96 }
97 }
98 catch (MDOException e)
99 {
100 Console.WriteLine("Received Mindopt exception.");
101 Console.WriteLine(" - Code : " + e.ErrorCode);
102 Console.WriteLine(" - Reason : " + e.Message);
103 }
104 catch (Exception e)
105 {
106 Console.WriteLine("Received exception.");
107 Console.WriteLine(" - Reason : " + e.Message);
108 }
109 finally
110 {
111 // Step 4. Free the model.
112 model.Dispose();
113 env.Dispose();
114 }
115 }
116 }
117}