5.5.6. C# 的MIQP建模和优化

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

首先,创建优化模型:

32            // Create model
33            MDOEnv env = new MDOEnv(); 
34            MDOModel model = new MDOModel(env); 
35            model.Set(MDO.StringAttr.ModelName, "MIQP_01");

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

42                // Add variables.
43                MDOVar[] x = new MDOVar[4];
44                x[0] = model.AddVar(0.0,         10.0, 1.0, 'I', "x0");
45                x[1] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'C', "x1");
46                x[2] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'C', "x2");
47                x[3] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'C', "x3");

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

49                // Add constraints.
50                double[][] consV = new double[][]
51                {
52                    new double[] { 1.0, 1.0, 2.0, 3.0},
53                    new double[] { 1.0, 0,  -1.0, 6.0} 
54                };
55
56                MDOLinExpr tempLinExpr1 = new MDOLinExpr();
57                tempLinExpr1.AddTerms(consV[0], x);
58                model.AddConstr(tempLinExpr1, MDO.GREATER_EQUAL, 1.0, "c0");
59
60                MDOLinExpr tempLinExpr2 = new MDOLinExpr();
61                tempLinExpr2.AddTerms(consV[1], x);
62                model.AddConstr(tempLinExpr2, MDO.EQUAL, 1.0, "c1");   

然后,我们创建一个二次表达式 MDOQuadExpr, 再调用 MDOQuadExpr.AddTerms 来设置目标函数线性部分。 obj_idx 表示线性部分的索引,obj_val 表示与 obj_idx 中的索引相对应的非零系数值。

64                // Create a QuadExpr for quadratic objective
65                MDOQuadExpr obj = new MDOQuadExpr();
66
67                // Add objective linear term: 1 x0 + 1 x1 + 1 x2 + 1 x3 
68                int      obj_nnz = 4;
69                MDOVar[] obj_idx = new MDOVar[] { x[0], x[1], x[2], x[3] };
70                double[] obj_val = new double[] { 1.0,  1.0,  1.0,  1.0 };
71                obj.AddTerms(obj_val, obj_idx);

然后,调用 MDOQuadExpr.AddTerms 来设置目标的二次项系数 \(Q\)。 其中,qo_values 表示要添加的二次项的系数,qo_col1qo_col2 表示与qo_values相对应的二次项的第一个变量和第二个变量。

73                // Add quadratic part in objective: 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] 
74                int      qo_nnz    = 5;
75                MDOVar[] qo_col1   = new MDOVar[] { x[0], x[1], x[2], x[3], x[0] };
76                MDOVar[] qo_col2   = new MDOVar[] { x[0], x[1], x[2], x[3], x[1] };
77                double[] qo_values = new double[] { 0.5,  0.5,  0.5,  0.5,  0.5 };
78                obj.AddTerms(qo_values, qo_col1, qo_col2);

最后,我们调用 MDOModel.SetObjective 设定优化目标与方向。

80                model.SetObjective(obj, MDO.MINIMIZE);

问题输入完成后,调用 MDOModel.Optimize 求解优化问题:

83                model.Optimize();

示例 MdoMIQPEx1.cs 提供了完整源代码:

  1/**
  2 *  Description
  3 *  -----------
  4 *  Linear optimization (row-wise input).
  5 *
  6 *  Formulation
  7 *  -----------
  8 *
  9 *  Minimize
 10 *    obj: 1 x0 + 1 x1 + 1 x2 + 1 x3 
 11 *         + 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1]
 12 *  Subject To
 13 *   c0 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
 14 *   c1 : 1 x0 - 1 x2 + 6 x3 = 1
 15 *  Bounds
 16 *    0 <= x0 <= 10
 17 *    0 <= x1
 18 *    0 <= x2
 19 *    0 <= x3
 20  *  x0 Integer
 21 *  End
 22 */
 23
 24using Mindopt;
 25
 26namespace Example
 27{
 28    public class MdoQoEx1
 29    {
 30        public static void Main(string[] args)
 31        {
 32            // Create model
 33            MDOEnv env = new MDOEnv(); 
 34            MDOModel model = new MDOModel(env); 
 35            model.Set(MDO.StringAttr.ModelName, "MIQP_01");
 36
 37            try
 38            {
 39                // Change to minimization problem.
 40                model.Set(MDO.IntAttr.ModelSense, MDO.MINIMIZE);
 41
 42                // Add variables.
 43                MDOVar[] x = new MDOVar[4];
 44                x[0] = model.AddVar(0.0,         10.0, 1.0, 'I', "x0");
 45                x[1] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'C', "x1");
 46                x[2] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'C', "x2");
 47                x[3] = model.AddVar(0.0, MDO.INFINITY, 1.0, 'C', "x3");
 48
 49                // Add constraints.
 50                double[][] consV = new double[][]
 51                {
 52                    new double[] { 1.0, 1.0, 2.0, 3.0},
 53                    new double[] { 1.0, 0,  -1.0, 6.0} 
 54                };
 55
 56                MDOLinExpr tempLinExpr1 = new MDOLinExpr();
 57                tempLinExpr1.AddTerms(consV[0], x);
 58                model.AddConstr(tempLinExpr1, MDO.GREATER_EQUAL, 1.0, "c0");
 59
 60                MDOLinExpr tempLinExpr2 = new MDOLinExpr();
 61                tempLinExpr2.AddTerms(consV[1], x);
 62                model.AddConstr(tempLinExpr2, MDO.EQUAL, 1.0, "c1");   
 63
 64                // Create a QuadExpr for quadratic objective
 65                MDOQuadExpr obj = new MDOQuadExpr();
 66
 67                // Add objective linear term: 1 x0 + 1 x1 + 1 x2 + 1 x3 
 68                int      obj_nnz = 4;
 69                MDOVar[] obj_idx = new MDOVar[] { x[0], x[1], x[2], x[3] };
 70                double[] obj_val = new double[] { 1.0,  1.0,  1.0,  1.0 };
 71                obj.AddTerms(obj_val, obj_idx);
 72
 73                // Add quadratic part in objective: 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] 
 74                int      qo_nnz    = 5;
 75                MDOVar[] qo_col1   = new MDOVar[] { x[0], x[1], x[2], x[3], x[0] };
 76                MDOVar[] qo_col2   = new MDOVar[] { x[0], x[1], x[2], x[3], x[1] };
 77                double[] qo_values = new double[] { 0.5,  0.5,  0.5,  0.5,  0.5 };
 78                obj.AddTerms(qo_values, qo_col1, qo_col2);
 79
 80                model.SetObjective(obj, MDO.MINIMIZE);
 81                
 82                // Solve the problem and populate optimization result.
 83                model.Optimize();
 84
 85                if (model.Get(MDO.IntAttr.Status) == MDO.Status.OPTIMAL)
 86                {
 87                    Console.WriteLine($"Optimal objective value is: {model.Get(MDO.DoubleAttr.ObjVal)}");
 88                    Console.WriteLine("Decision variables: ");
 89                    for (int i = 0; i < 4; i++)
 90                        Console.WriteLine( $"x[{i}] = {x[i].Get(MDO.DoubleAttr.X)}");
 91                }
 92                else
 93                {
 94                    Console.WriteLine("No feasible solution.");
 95                }
 96            }
 97            catch (Exception e)
 98            { 
 99                Console.WriteLine("Exception during optimization");
100                Console.WriteLine(e.Message);
101            }
102            finally
103            { 
104                model.Dispose();
105                env.Dispose();
106            }
107        }
108    }
109}