5.6.2. MIQCP Modeling and Optimization in CΒΆ

In this chapter, we will use MindOpt C API to model and solve the problem in Example of Mixed Integer Quadratically Constrained Programming.

Include the header file:

27#include <stdio.h>

Create an optimization model model:

78    /* Step 1. Create environment and model.                            */
79    /*------------------------------------------------------------------*/
80    CHECK_RESULT(MDOemptyenv(&env));

Next, we set the optimization sense to minimization via MDOsetIntAttr() and four variables are added by calling MDOaddvar(). Their lower bounds, upper bounds, names, types and linear objective coefficients are defined as follows (for more details on how to use MDOsetIntAttr() and MDOaddvar(), please refer to Attributes):

86    /* Step 2. Input model.                                             */
87    /*------------------------------------------------------------------*/
88    /* Change to minimization problem. */
89    CHECK_RESULT(MDOsetintattr(model, MODEL_SENSE, MDO_MINIMIZE));
90
91    /* Add variables. */
92    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0,         10.0, MDO_INTEGER, "x0"));
93    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x1"));

Note

The non-zero elements of the matrix \(A\) will be inputted later. After adding the four aforementioned variables, certain parameters of the constraint matrix, specifically size, indices, and value, are set to 0, NULL, and NULL, respectively. This means that, as of now, model has no constraints.

Next, we will introduce the quadratic terms in the objective. Three arrays are utilized for this purpose. Specifically, qo_col1, qo_col2, and qo_values record the row indices, column indices, and values of all the non-zero quadratic terms.

49    /* Prepare model data. */
50    /* Quadratic part in objective: 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] */
51    int    qo_nnz      = 5;
52    int    qo_col1[]   = { 0,   1,   2,   3,   0 };

We call MDOaddqpterms() to set the quadratic terms of the objective.

95    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x3"));

Now we start to add quadratic constraints to the model. The linear part is constructed in the same way as in the objective.

55    double qo_values[] = { 0.5, 0.5, 0.5, 0.5, 0.5 };
56
57    /* Linear part in the first constraint: 1 x0 + 1 x1 + 2 x2 + 3 x3 */
58    int    row1_nnz   = 4;
65    double qc1_values[] = { -0.5, -0.5, -0.5, -0.5, -0.5 };
66
67    /* Linear part in the second constraint: 1 x0 - 1 x2 + 6 x3 */
68    int    row2_nnz   = 3;

The quadratic part is constructed in the same way as it is in the objective as well.

59    int    row1_idx[] = { 0,   1,   2,   3   };
60    double row1_val[] = { 1.0, 1.0, 2.0, 3.0 };
61    /* Quadratic part in the first constraint: - 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] */
62    int    qc1_nnz      = 5;
63    int    qc1_col1[]   = { 0,    1,    2,    3,    0 };
69    int    row2_idx[] = { 0,    2,   3   };
70    double row2_val[] = { 1.0, -1.0, 6.0 };
71    /* Quadratic part in the second constraint: 1/2 [x1^2] */
72    int    qc2_nnz      = 1;
73    int    qc2_col1[]   = { 1 };

We call MDOaddqconstr() to input the linear constraints into model:

 98    CHECK_RESULT(MDOaddqpterms(model, qo_nnz, qo_col1, qo_col2, qo_values));
 99
100    /* Add quadratic constraints. */

Once the model is constructed, we call MDOoptimize() to solve the problem:

105    /* Step 3. Solve the problem and populate optimization result.                */
106    /*------------------------------------------------------------------*/

We can retrieive the optimal objective value and solutions via getting attributes:

108    CHECK_RESULT(MDOoptimize(model));
109        
110    CHECK_RESULT(MDOgetintattr(model, STATUS, &status));
111    if (status == MDO_OPTIMAL) 
112    {
113        CHECK_RESULT(MDOgetdblattr(model, OBJ_VAL, &obj));
114        printf("The optimal objective value is: %f\n", obj);
115        for (int i = 0; i < 4; ++i) 
116        {
117            CHECK_RESULT(MDOgetdblattrelement(model, X, i, &x));
118            printf("x[%d] = %f\n", i, x);
119        }
120    } 
121    else 
122    {

Finally, we call MDOfreemodel() and MDOfreeenv() to free the model:

30/* Macro to check the return code */
31#define RELEASE_MEMORY  \
127    /* Step 4. Free the model.                                          */

The complete example code is provided in MdoMIQCPEx1.c:

  1/**
  2 *  Description
  3 *  -----------
  4 *
  5 *  Mixed Integer Quadratically constrained quadratic 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 *
 14 *  Subject To
 15 *   c0 : 1 x0 + 1 x1 + 2 x2 + 3 x3 - 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] >= 1
 16 *   c1 : 1 x0 - 1 x2 + 6 x3 + 1/2 [x1^2] <= 1
 17 *  Bounds
 18 *    0 <= x0 <= 10
 19 *    0 <= x1
 20 *    0 <= x2
 21 *    0 <= x3
 22 *  Integer
 23 *  x0 
 24 *  End
 25 */
 26
 27#include <stdio.h>
 28#include <stdlib.h>
 29#include "Mindopt.h"
 30
 31/* Macro to check the return code */
 32#define RELEASE_MEMORY  \
 33    MDOfreemodel(model);    \
 34    MDOfreeenv(env);
 35#define CHECK_RESULT(code) { int res = code; if (res != 0) { fprintf(stderr, "Bad code: %d\n", res);  RELEASE_MEMORY; return (res); } }
 36#define MODEL_NAME  "QCP_01"
 37#define MODEL_SENSE "ModelSense"
 38#define STATUS      "Status"
 39#define OBJ_VAL     "ObjVal"
 40#define X           "X"
 41
 42int main(void)
 43{
 44    /* Variables. */
 45    MDOenv *env;
 46    MDOmodel *model;
 47    double obj, x;
 48    int status, i;
 49
 50    /* Prepare model data. */
 51    /* Quadratic part in objective: 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] */
 52    int    qo_nnz      = 5;
 53    int    qo_col1[]   = { 0,   1,   2,   3,   0 };
 54    int    qo_col2[]   = { 0,   1,   2,   3,   1 };
 55    double qo_values[] = { 0.5, 0.5, 0.5, 0.5, 0.5 };
 56
 57    /* Linear part in the first constraint: 1 x0 + 1 x1 + 2 x2 + 3 x3 */
 58    int    row1_nnz   = 4;
 59    int    row1_idx[] = { 0,   1,   2,   3   };
 60    double row1_val[] = { 1.0, 1.0, 2.0, 3.0 };
 61    /* Quadratic part in the first constraint: - 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] */
 62    int    qc1_nnz      = 5;
 63    int    qc1_col1[]   = { 0,    1,    2,    3,    0 };
 64    int    qc1_col2[]   = { 0,    1,    2,    3,    1 };
 65    double qc1_values[] = { -0.5, -0.5, -0.5, -0.5, -0.5 };
 66
 67    /* Linear part in the second constraint: 1 x0 - 1 x2 + 6 x3 */
 68    int    row2_nnz   = 3;
 69    int    row2_idx[] = { 0,    2,   3   };
 70    double row2_val[] = { 1.0, -1.0, 6.0 };
 71    /* Quadratic part in the second constraint: 1/2 [x1^2] */
 72    int    qc2_nnz      = 1;
 73    int    qc2_col1[]   = { 1 };
 74    int    qc2_col2[]   = { 1 };
 75    double qc2_values[] = { 0.5 };
 76
 77     /*------------------------------------------------------------------*/
 78    /* Step 1. Create environment and model.                            */
 79    /*------------------------------------------------------------------*/
 80    CHECK_RESULT(MDOemptyenv(&env));
 81    CHECK_RESULT(MDOstartenv(env));
 82    CHECK_RESULT(MDOnewmodel(env, &model, MODEL_NAME, 0, NULL, NULL, NULL, NULL, NULL));
 83
 84
 85    /*------------------------------------------------------------------*/
 86    /* Step 2. Input model.                                             */
 87    /*------------------------------------------------------------------*/
 88    /* Change to minimization problem. */
 89    CHECK_RESULT(MDOsetintattr(model, MODEL_SENSE, MDO_MINIMIZE));
 90
 91    /* Add variables. */
 92    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0,         10.0, MDO_INTEGER, "x0"));
 93    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x1"));
 94    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x2"));
 95    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x3"));
 96
 97    /* Add quadratic objective term. */
 98    CHECK_RESULT(MDOaddqpterms(model, qo_nnz, qo_col1, qo_col2, qo_values));
 99
100    /* Add quadratic constraints. */
101    CHECK_RESULT(MDOaddqconstr(model, row1_nnz, row1_idx, row1_val, qc1_nnz, qc1_col1, qc1_col2, qc1_values, MDO_GREATER_EQUAL, 1.0, "c0"));
102    CHECK_RESULT(MDOaddqconstr(model, row2_nnz, row2_idx, row2_val, qc2_nnz, qc2_col1, qc2_col2, qc2_values, MDO_LESS_EQUAL,    1.0, "c1"));
103    
104    /*------------------------------------------------------------------*/
105    /* Step 3. Solve the problem and populate optimization result.                */
106    /*------------------------------------------------------------------*/
107    /* Solve the problem. */
108    CHECK_RESULT(MDOoptimize(model));
109        
110    CHECK_RESULT(MDOgetintattr(model, STATUS, &status));
111    if (status == MDO_OPTIMAL) 
112    {
113        CHECK_RESULT(MDOgetdblattr(model, OBJ_VAL, &obj));
114        printf("The optimal objective value is: %f\n", obj);
115        for (int i = 0; i < 4; ++i) 
116        {
117            CHECK_RESULT(MDOgetdblattrelement(model, X, i, &x));
118            printf("x[%d] = %f\n", i, x);
119        }
120    } 
121    else 
122    {
123        printf("No feasible solution.\n");
124    }
125 
126    /*------------------------------------------------------------------*/
127    /* Step 4. Free the model.                                          */
128    /*------------------------------------------------------------------*/
129    RELEASE_MEMORY;
130       
131    return 0;
132}