5.3.2. QP Modeling and Optimization in CΒΆ

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

Include the header file:

27#include "Mindopt.h"

Create an optimization model model:

67    CHECK_RESULT(MDOemptyenv(&env));
68    CHECK_RESULT(MDOstartenv(env));
69    CHECK_RESULT(MDOnewmodel(env, &model, MODEL_NAME, 0, NULL, NULL, NULL, NULL, NULL));

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):

74    /* Change to minimization problem. */
75    CHECK_RESULT(MDOsetintattr(model, MODEL_SENSE, MDO_MINIMIZE));
76
77    /* Add variables. */
78    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0,         10.0, MDO_CONTINUOUS, "x0"));
79    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x1"));
80    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x2"));
81    CHECK_RESULT(MDOaddvar(model, 0, NULL, NULL, 1.0, 0, MDO_INFINITY, MDO_CONTINUOUS, "x3"));

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.

Now we set the constraint matrix \(A\) following the same procedure as in LP. The arrays row1_idx and row2_idx represent positions of the non-zero elements in the first and second rows while row1_val and row2_val represent corresponding values of the non-zero elements.

49    /* Linear part in the first constraint: 1 x0 + 1 x1 + 2 x2 + 3 x3 */
50    int    row1_nnz   = 4;
51    int    row1_idx[] = { 0,   1,   2,   3   };
52    double row1_val[] = { 1.0, 1.0, 2.0, 3.0 };
53    /* Linear part in the second constraint: 1 x0 - 1 x2 + 6 x3 */
54    int    row2_nnz   = 3;
55    int    row2_idx[] = { 0,    2,   3   };
56    double row2_val[] = { 1.0, -1.0, 6.0 };

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

83    /* Add constraints.
84     * Note that the nonzero elements are inputted in a row-wise order here.
85     */
86    CHECK_RESULT(MDOaddconstr(model, row1_nnz, row1_idx, row1_val, MDO_GREATER_EQUAL, 1.0, "c0"));
87    CHECK_RESULT(MDOaddconstr(model, row2_nnz, row2_idx, row2_val, MDO_EQUAL,         1.0, "c1"));

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.

58    /* Quadratic part in objective: 1/2 [ x0^2 + x1^2 + x2^2 + x3^2 + x0 x1] */
59    int    qo_nnz      = 5;
60    int    qo_col1[]   = { 0,   1,   2,   3,   0 };
61    int    qo_col2[]   = { 0,   1,   2,   3,   1 };
62    double qo_values[] = { 0.5, 0.5, 0.5, 0.5, 0.5 };

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

89    /* Add quadratic objective term. */
90    CHECK_RESULT(MDOaddqpterms(model, qo_nnz, qo_col1, qo_col2, qo_values));

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

92    /*------------------------------------------------------------------*/
93    /* Step 3. Solve the problem and populate optimization result.                */
94    /*------------------------------------------------------------------*/
95    /* Solve the problem. */
96    CHECK_RESULT(MDOoptimize(model));

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

 98    CHECK_RESULT(MDOgetintattr(model, STATUS, &status));
 99    if (status == MDO_OPTIMAL) 
100    {
101        CHECK_RESULT(MDOgetdblattr(model, OBJ_VAL, &obj));
102        printf("The optimal objective value is: %f\n", obj);
103        for (int i = 0; i < 4; ++i) 
104        {
105            CHECK_RESULT(MDOgetdblattrelement(model, X, i, &x));
106            printf("x[%d] = %f\n", i, x);
107        }
108    } 
109    else 
110    {
111        printf("No feasible solution.\n");
112    }

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

30#define RELEASE_MEMORY  \
31    MDOfreemodel(model);    \
32    MDOfreeenv(env);
117    RELEASE_MEMORY;

The complete example code is provided in MdoQoEx1.c:

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