5.6.8. MISOCP Modeling and Optimization in C++

In this chapter, we will use MindOpt C++ API to model and solve the problem in MIQCP Example II.

Include the header file:

26#include <iostream>

Create an optimization model model:

32int main(void)
33{
34    /*------------------------------------------------------------------*/
35    /* Step 1. Create environment and model.                            */
36    /*------------------------------------------------------------------*/
37    MDOEnv env = MDOEnv();

Note

To mark a variable as integer, set the value of vtype as MDO_INTEGER in MDOModel::addVar().

Next, we set the optimization sense to minimization via MDOModel::set(). Then, we call MDOModel::addVar() to add five variables, specifying their lower bounds, upper bounds, objective coefficients, types, and names.

43        /* Step 2. Input model.                                             */
44        /*------------------------------------------------------------------*/
45        /* Change to minimization problem. */
46        model.set(MDO_IntAttr_ModelSense, MDO_MINIMIZE);
47
48        /* Add variables. */
49        std::vector<MDOVar> x;
50        x.push_back(model.addVar(0.0, 10.0,         1.0, MDO_INTEGER, "x0"));
51        x.push_back(model.addVar(0.0, MDO_INFINITY, 2.0, MDO_INTEGER, "x1"));
52        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, MDO_INTEGER, "x2"));
53        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, MDO_CONTINUOUS, "x3"));

Note

The linear objective coefficients (1, 2, 1, 1, 0.5) are passed directly during variable creation via the third argument of addVar(). Therefore, there is no separate call to setObjective(), and the objective is purely linear.

We now add the linear constraints.

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

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

These are added using overloaded arithmetic operators to build linear expressions:

61        model.addConstr(1.0 * x[0] - 1.0 * x[2] + 6.0 * x[3], MDO_EQUAL, 1.0, "c1");
62
63        /* second order cone constraint */
64        int    qc2_nnz      = 3;
65        MDOVar qc2_col1[]   = { x[1], x[2], x[4]};

Finally, we add the quadratic (second-order cone) constraint:

  • c2: \(x_1^2 + x_2^2 - x_4^2 \leq 0\)

This is modeled as a quadratic constraint using MDOQuadExpr. We define the quadratic terms by specifying variable pairs and coefficients:

67        double qc2_values[] = { 1.0, 1.0, -1.0};
68
69        /* Add the second order cone constraint. c2*/
70        MDOQuadExpr c2 = MDOQuadExpr(0.0);
71        c2.addTerms(qc2_values, qc2_col1, qc2_col2, qc2_nnz);

Then, the quadratic expression is added to the model as a constraint:

74        /*------------------------------------------------------------------*/
75        /* Step 3. Solve the problem.                                       */
76        /*------------------------------------------------------------------*/
77        /* Solve the problem. */

Once the model is fully constructed, we solve it by calling:

81        /* Step 4. Retrive model status and objective.                      */
82        /* For MIP(MILP,MIQP, MIQCP) problems, if the solving process       */

After solving, we check the solution status and retrieve the optimal objective value and variable values:

 92            cout << "Decision variables:" << endl;
 93            int i = 0;
 94            for (auto v : x)
 95            {
 96                cout << "x[" << i++ << "] = " << v.get(MDO_DoubleAttr_X) << endl;
 97            }
 98        }
 99        else
100        {
101            cout<< "No feasible solution." << endl;
102        }
103        
104    }
105    catch (MDOException& e) 
106    { 

The complete example code is shown in MdoMISOCPEx1.cpp :

  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 */
 26#include <iostream>
 27#include "MindoptCpp.h"
 28#include <vector>
 29
 30using namespace std;
 31
 32int main(void)
 33{
 34    /*------------------------------------------------------------------*/
 35    /* Step 1. Create environment and model.                            */
 36    /*------------------------------------------------------------------*/
 37    MDOEnv env = MDOEnv();
 38    MDOModel model = MDOModel(env);
 39    
 40    try 
 41    {
 42        /*------------------------------------------------------------------*/
 43        /* Step 2. Input model.                                             */
 44        /*------------------------------------------------------------------*/
 45        /* Change to minimization problem. */
 46        model.set(MDO_IntAttr_ModelSense, MDO_MINIMIZE);
 47
 48        /* Add variables. */
 49        std::vector<MDOVar> x;
 50        x.push_back(model.addVar(0.0, 10.0,         1.0, MDO_INTEGER, "x0"));
 51        x.push_back(model.addVar(0.0, MDO_INFINITY, 2.0, MDO_INTEGER, "x1"));
 52        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, MDO_INTEGER, "x2"));
 53        x.push_back(model.addVar(0.0, MDO_INFINITY, 1.0, MDO_CONTINUOUS, "x3"));
 54        x.push_back(model.addVar(0.0, MDO_INFINITY, 0.5, MDO_CONTINUOUS, "x4"));
 55
 56        /* Prepare model data. */
 57        /* add c0 */
 58        model.addConstr(1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], MDO_GREATER_EQUAL, 1.0, "c0");
 59
 60        /* add c1 */
 61        model.addConstr(1.0 * x[0] - 1.0 * x[2] + 6.0 * x[3], MDO_EQUAL, 1.0, "c1");
 62
 63        /* second order cone constraint */
 64        int    qc2_nnz      = 3;
 65        MDOVar qc2_col1[]   = { x[1], x[2], x[4]};
 66        MDOVar qc2_col2[]   = { x[1], x[2], x[4]};
 67        double qc2_values[] = { 1.0, 1.0, -1.0};
 68
 69        /* Add the second order cone constraint. c2*/
 70        MDOQuadExpr c2 = MDOQuadExpr(0.0);
 71        c2.addTerms(qc2_values, qc2_col1, qc2_col2, qc2_nnz);
 72        model.addQConstr(c2, MDO_LESS_EQUAL, 0.0, "c2");
 73
 74        /*------------------------------------------------------------------*/
 75        /* Step 3. Solve the problem.                                       */
 76        /*------------------------------------------------------------------*/
 77        /* Solve the problem. */
 78        model.optimize();
 79
 80        /*------------------------------------------------------------------*/
 81        /* Step 4. Retrive model status and objective.                      */
 82        /* For MIP(MILP,MIQP, MIQCP) problems, if the solving process       */
 83        /* terminates early due to reasons such as timeout or interruption, */
 84        /* the model status will indicate termination by timeout (or        */
 85        /* interruption, etc.). However, suboptimal solutions may still     */
 86        /* exist, making it necessary to check the SolCount property.       */
 87        /*------------------------------------------------------------------*/
 88        if (model.get(MDO_IntAttr_Status) == MDO_OPTIMAL || model.get(MDO_IntAttr_Status) == MDO_SUB_OPTIMAL ||
 89            model.get(MDO_IntAttr_SolCount) != 0)
 90        {
 91            cout << "Optimal objective value is: " << model.get(MDO_DoubleAttr_ObjVal) << endl;
 92            cout << "Decision variables:" << endl;
 93            int i = 0;
 94            for (auto v : x)
 95            {
 96                cout << "x[" << i++ << "] = " << v.get(MDO_DoubleAttr_X) << endl;
 97            }
 98        }
 99        else
100        {
101            cout<< "No feasible solution." << endl;
102        }
103        
104    }
105    catch (MDOException& e) 
106    { 
107        std::cout << "Error code = " << e.getErrorCode() << std::endl;
108        std::cout << e.getMessage() << std::endl;
109    } 
110    catch (...) 
111    { 
112        std::cout << "Error during optimization." << std::endl;
113    }
114    
115    return static_cast<int>(MDO_OKAY);
116}