5.5.3. C++ 的MIQP建模和优化

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

首先,引入头文件:

27#include "MindoptCpp.h"

并创建优化模型:

36    MDOEnv env = MDOEnv();
37    MDOModel model = MDOModel(env);

接下来,我们通过 MDOModel::set() 将目标函数设置为 最小化,并调用 MDOModel::addVar() 来添加四个优化变量(有关模型属性内容及其设置可参考 属性, 其他API请参考 C++ API):

44        /* Add variables. */
45        std::vector<MDOVar> x;
46        x.push_back(model.addVar(0.0, 10.0,         0.0, MDO_INTEGER, "x0"));
47        x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, MDO_CONTINUOUS, "x1"));
48        x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, MDO_CONTINUOUS, "x2"));
49        x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, MDO_CONTINUOUS, "x3"));

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

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

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

56        MDOQuadExpr obj = MDOQuadExpr(0.0);
57
58        /* Add objective linear term.*/
59        const MDOVar obj_idx[] = { x[0], x[1], x[2], x[3]};
60        const double obj_val[] = { 1.0, 1.0, 1.0, 1.0};
61        obj.addTerms(obj_val, obj_idx, 4);
62
63       /* Add objective quadratic term: 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] */

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

64        int    qo_nnz      = 5;
65        MDOVar qo_col1[]   = { x[0], x[1], x[2], x[3], x[0] };
66        MDOVar qo_col2[]   = { x[0], x[1], x[2], x[3], x[1] };
67        double qo_values[] = { 0.5,  0.5,  0.5,  0.5,  0.5 };
68        obj.addTerms(qo_values, qo_col1, qo_col2, qo_nnz);

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

72        model.setObjective(obj, MDO_MINIMIZE);

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

78        model.optimize();

示例 MdoMIQPEx1.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 *  Integers
 22 *  x0 
 23 *  End
 24 */
 25
 26#include <iostream>
 27#include "MindoptCpp.h"
 28#include <vector>
 29using namespace std;
 30
 31int main(void)
 32{
 33    /*------------------------------------------------------------------*/
 34    /* Step 1. Create environment and model.                            */
 35    /*------------------------------------------------------------------*/
 36    MDOEnv env = MDOEnv();
 37    MDOModel model = MDOModel(env);
 38    
 39    try 
 40    {
 41        /*------------------------------------------------------------------*/
 42        model.set(MDO_IntAttr_ModelSense, MDO_MINIMIZE);
 43
 44        /* Add variables. */
 45        std::vector<MDOVar> x;
 46        x.push_back(model.addVar(0.0, 10.0,         0.0, MDO_INTEGER, "x0"));
 47        x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, MDO_CONTINUOUS, "x1"));
 48        x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, MDO_CONTINUOUS, "x2"));
 49        x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, MDO_CONTINUOUS, "x3"));
 50
 51        /* Add constraints. */
 52        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], MDO_GREATER_EQUAL, 1.0, "c0");
 53        model.addConstr(1.0 * x[0] - 1.0 * x[2] + 6.0 * x[3], MDO_EQUAL, 1.0, "c1");
 54        
 55        /*Create a QuadExpr. */
 56        MDOQuadExpr obj = MDOQuadExpr(0.0);
 57
 58        /* Add objective linear term.*/
 59        const MDOVar obj_idx[] = { x[0], x[1], x[2], x[3]};
 60        const double obj_val[] = { 1.0, 1.0, 1.0, 1.0};
 61        obj.addTerms(obj_val, obj_idx, 4);
 62
 63       /* Add objective quadratic term: 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] */
 64        int    qo_nnz      = 5;
 65        MDOVar qo_col1[]   = { x[0], x[1], x[2], x[3], x[0] };
 66        MDOVar qo_col2[]   = { x[0], x[1], x[2], x[3], x[1] };
 67        double qo_values[] = { 0.5,  0.5,  0.5,  0.5,  0.5 };
 68        obj.addTerms(qo_values, qo_col1, qo_col2, qo_nnz);
 69
 70
 71
 72        model.setObjective(obj, MDO_MINIMIZE);
 73
 74        /*------------------------------------------------------------------*/
 75        /* Step 3. Solve the problem and populate optimization result.                */
 76        /*------------------------------------------------------------------*/
 77        /* Solve the problem. */
 78        model.optimize();
 79
 80        if(model.get(MDO_IntAttr_Status) == MDO_OPTIMAL)
 81        {
 82            cout << "Optimal objective value is: " << model.get(MDO_DoubleAttr_ObjVal) << endl;
 83            cout << "Decision variables:" << endl;
 84            int i = 0;
 85            for (auto v : x)
 86            {
 87                cout << "x[" << i++ << "] = " << v.get(MDO_DoubleAttr_X) << endl;
 88            }
 89        }
 90        else
 91        {
 92            cout<< "No feasible solution." << endl;
 93        }
 94        
 95    }
 96    catch (MDOException& e) 
 97    { 
 98        std::cout << "Error code = " << e.getErrorCode() << std::endl;
 99        std::cout << e.getMessage() << std::endl;
100    } 
101    catch (...) 
102    { 
103        std::cout << "Error during optimization." << std::endl;
104    }
105    
106    return static_cast<int>(MDO_OKAY);
107}