5.3.3. C++ 的QP建模和优化

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

5.3.3.1. 按行输入:MdoQoEx1

首先,引入头文件:

25#include "MindoptCpp.h"

并创建优化模型:

31    /*------------------------------------------------------------------*/
32    /* Step 1. Create a model and change the parameters.                */
33    /*------------------------------------------------------------------*/
34    /* Create an empty model. */
35    MdoModel model;

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

39        /*------------------------------------------------------------------*/
40        /* Step 2. Input model.                                             */
41        /*------------------------------------------------------------------*/
42        /* Change to minimization problem. */
43        model.setIntAttr(MDO_INT_ATTR::MIN_SENSE, MDO_YES);
44
45        /* Add variables. */
46        std::vector<MdoVar> x;
47        x.push_back(model.addVar(0.0, 10.0,         1.0, "x0", MDO_NO));
48        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, "x1", MDO_NO));
49        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, "x2", MDO_NO));
50        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, "x3", MDO_NO));

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

53        model.addCons(1.0, MDO_INFINITY, 1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], "c0");
54        model.addCons(1.0, 1.0,          1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3], "c1");

然后,我们调用 mindopt::MdoModel::setQuadraticElements() 来设置目标的二次项系数 \(Q\)。前两组输入向量分别表示二次项中所有非零项的两个变量的索引,最后一组输入向量是与之相对应的非零系数值。

Note

为了确保 \(Q\) 的对称性,用户只需要输入其下三角形部分,并且在求解器内部会乘以 1/2.

56        /* Add quadratic objective matrix Q.
57         *
58         *  Note.
59         *  1. The objective function is defined as c^Tx + 1/2 x^TQx, where Q is stored with coordinate format.
60         *  2. Q will be scaled by 1/2 internally.
61         *  3. To ensure the symmetricity of Q, user needs to input only the lower triangular part.
62         *
63         * Q = [ 1.0  0.5  0    0   ]
64         *     [ 0.5  1.0  0    0   ]
65         *     [ 0.0  0.0  1.0  0   ]
66         *     [ 0    0    0    1.0 ]
67         */
68        model.setQuadraticElements
69        (
70            { x[0], x[1], x[1], x[2], x[3] },
71            { x[0], x[0], x[1], x[2], x[3] },
72            {  1.0,  0.5,  1.0,  1.0,  1.0 }
73        );

问题输入完成后,再调用 mindopt::MdoModel::solveProb() 求解优化问题,并通过 mindopt::MdoModel::displayResults() 查看优化结果:

75        /*------------------------------------------------------------------*/
76        /* Step 3. Solve the problem and populate the result.               */
77        /*------------------------------------------------------------------*/
78        /* Solve the problem. */
79        model.solveProb();
80        model.displayResults();

文件链接 MdoQoEx1.cpp 提供了完整源代码:

 1/**
 2 *  Description
 3 *  -----------
 4 *
 5 *  Linear optimization (row-wise input).
 6 *
 7 *  Formulation
 8 *  -----------
 9 *
10 *  Minimize
11 *    obj: 1 x0 + 1 x1 + 1 x2 + 1 x3 
12 *         + 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1]
13 *  Subject To
14 *   c0 : 1 x0 + 1 x1 + 2 x2 + 3 x3 >= 1
15 *   c1 : 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#include <iostream>
24#include <vector>
25#include "MindoptCpp.h"
26
27using namespace mindopt;
28
29int main(void)
30{
31    /*------------------------------------------------------------------*/
32    /* Step 1. Create a model and change the parameters.                */
33    /*------------------------------------------------------------------*/
34    /* Create an empty model. */
35    MdoModel model;
36
37    try 
38    {
39        /*------------------------------------------------------------------*/
40        /* Step 2. Input model.                                             */
41        /*------------------------------------------------------------------*/
42        /* Change to minimization problem. */
43        model.setIntAttr(MDO_INT_ATTR::MIN_SENSE, MDO_YES);
44
45        /* Add variables. */
46        std::vector<MdoVar> x;
47        x.push_back(model.addVar(0.0, 10.0,         1.0, "x0", MDO_NO));
48        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, "x1", MDO_NO));
49        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, "x2", MDO_NO));
50        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, "x3", MDO_NO));
51
52        /* Add constraints. */
53        model.addCons(1.0, MDO_INFINITY, 1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], "c0");
54        model.addCons(1.0, 1.0,          1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3], "c1");
55
56        /* Add quadratic objective matrix Q.
57         *
58         *  Note.
59         *  1. The objective function is defined as c^Tx + 1/2 x^TQx, where Q is stored with coordinate format.
60         *  2. Q will be scaled by 1/2 internally.
61         *  3. To ensure the symmetricity of Q, user needs to input only the lower triangular part.
62         *
63         * Q = [ 1.0  0.5  0    0   ]
64         *     [ 0.5  1.0  0    0   ]
65         *     [ 0.0  0.0  1.0  0   ]
66         *     [ 0    0    0    1.0 ]
67         */
68        model.setQuadraticElements
69        (
70            { x[0], x[1], x[1], x[2], x[3] },
71            { x[0], x[0], x[1], x[2], x[3] },
72            {  1.0,  0.5,  1.0,  1.0,  1.0 }
73        );
74
75        /*------------------------------------------------------------------*/
76        /* Step 3. Solve the problem and populate the result.               */
77        /*------------------------------------------------------------------*/
78        /* Solve the problem. */
79        model.solveProb();
80        model.displayResults();
81    }
82    catch (MdoException & e)
83    {
84        std::cerr << "===================================" << std::endl;
85        std::cerr << "Error   : code <" << e.getResult() << ">" << std::endl;
86        std::cerr << "Reason  : " << model.explainResult(e.getResult()) << std::endl;
87        std::cerr << "===================================" << std::endl;
88
89        return static_cast<int>(e.getResult());
90    }
91
92    return static_cast<int>(MDO_OKAY);
93}