5.4.3. SDP modeling and optimization in C language

In this section, we will use the API of MindOpt C language to model and solve the problem in Examples of SDP Problems.

5.4.3.1. SDP Example 1

First, import the header file:

22#include "Mindopt.h"

Step 1: Create a Model

Create an empty MindOpt model.

67    /*------------------------------------------------------------------*/
68    /* Step 1. Create a model and change the parameters.                */
69    /*------------------------------------------------------------------*/
70    /* Create an empty model. */
71    MDO_CHECK_CALL(Mdo_createMdl(&model));

Step 2: Input SDP Model

Change to maximization problem and add a symmetric matrix variable \(\mathbf{X}\).

73    /*------------------------------------------------------------------*/
74    /* Step 2. Input model.                                             */
75    /*------------------------------------------------------------------*/
76    /* Change to maximization problem. */
77    MDO_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, MDO_NO));
78 
79    /* Add matrix variable. */
80    MDO_CHECK_CALL(Mdo_addSymMat(model, dim_mat, mat_name));

Use Mdo_replaceSymMatObjs() to input the non-zero elements of \(\mathbf{C}\). The first parameter is the model. The second parameter is the index value of the matrix (here is 0). The third parameter represents the number of non-zero elements of the matrix. The fourth and fifth parameters represent the index of the row and column corresponding to the non-zero elements in the matrix. The last parameter is the index of the value of the non-zero elements.

82    /* Input objective coefficients. */
83    MDO_CHECK_CALL(Mdo_replaceSymMatObjs(
84        model, 0, C_size, C_row_indices, C_col_indices, C_values));

Next, write the first constraint. We first write an empty constraint, then use Mdo_replaceSymMatElements() to input non-zero elements of \(\mathbf{A}\). The second and third parameters are the index value of the constraint (here is 0) and the index value of the matrix (here is 0). The fourth parameter represents the number of non-zero elements of the matrix. The fifth and sixth parameters represent the index of the row and column corresponding to the non-zero elements in the matrix. The last parameter is the index of the value of the non-zero element.

86    /* Input first constraint. */
87    MDO_CHECK_CALL(Mdo_addRow(model, 1.0, 1.0, 0, NULL, NULL, "c0"));
88    MDO_CHECK_CALL(Mdo_replaceSymMatElements(model, 0, 0, A_size,
89        A_row_indices_in_cone, A_col_indices_in_cone, A_values_in_cone));

Step 3: Solve the SDP model

When the model is input, use the generic function Mdo_solveProb() to solve the problem and use Mdo_displayResults() to present the solution results.

94    /* Solve the problem. */
95    MDO_CHECK_CALL(Mdo_solveProb(model));
96    Mdo_displayResults(model);

Step 4: Obtain the solutions of the SDP model

Use the function Mdo_getRealAttr() to obtain the optimal objective function value.

104        MDO_CHECK_CALL(Mdo_getRealAttr(model, MDO_REAL_ATTR_PRIMAL_OBJ_VAL, &val));

Finally, use Mdo_getRealAttrSymMat() to obtain \(\mathbf{X}\). The second parameter defines the attribute value (note: Mdo_getRealAttrSymMat() is a generic function, so it is declared with the attribute value and MDO_REAL_ATTR_SYM_MAT_PRIMAL_SOLN defines the purpose to obtain the value of the (symmetric matrix) variable. ) The third parameter is the index value of the matrix (here is 0). The fourth parameter is the size of the matrix, and the return value soln is the index of the corresponding element in the matrix.

107        MDO_CHECK_CALL(Mdo_getRealAttrSymMat(
108            model, MDO_REAL_ATTR_SYM_MAT_PRIMAL_SOLN, 0, dim_mat * dim_mat, NULL, NULL, soln));

Please refer to the linked file MdoSdoEx1.c for the complete code.

  1/**
  2 *  Description
  3 *  -----------
  4 *
  5 *  Semidefinite optimization (row-wise input).
  6 *
  7 *  Formulation
  8 *  -----------
  9 *
 10 *  Maximize 
 11 *  obj: tr(C X) 
 12 * 
 13 *  Subject To
 14 *    c0 : tr(A X) = 1
 15 *  Matrix
 16 *    C = [ -3  0  1 ]  A = [ 3 0 1 ]
 17 *        [  0 -2  0 ]      [ 0 4 0 ]
 18 *        [  1  0 -3 ]      [ 1 0 5 ]
 19 *  End
 20 */
 21#include <stdio.h>
 22#include "Mindopt.h"
 23
 24/* Macro to check the return code. */
 25#define MDO_CHECK_CALL(MDO_CALL)                                    \
 26    code = MDO_CALL;                                                \
 27    if (code != MDO_OKAY)                                           \
 28    {                                                               \
 29        Mdo_explainResult(model, code, str);                        \
 30        Mdo_freeMdl(&model);                                        \
 31        fprintf(stderr, "===================================\n");   \
 32        fprintf(stderr, "Error   : code <%d>\n", code);             \
 33        fprintf(stderr, "Reason  : %s\n", str);                     \
 34        fprintf(stderr, "===================================\n");   \
 35        return (int)code;                                           \
 36    }
 37
 38int main(void)
 39{
 40    /* Variables. */
 41    char str[1024] = { "\0" };
 42    MdoMdl * model = NULL;
 43    MdoResult code = MDO_OKAY;
 44    MdoStatus status = MDO_UNKNOWN;
 45
 46    /* Input data. */
 47    const int    num_mats = 1;
 48    const int    dim_mat =  3 ; /* Dimension of the matrix variables. */
 49    const char * mat_name = "X";
 50
 51    const int    C_size = 4;
 52    const int    C_row_indices[] =  {  0,   0,    1,    2   }; /* Row index of a matrix variable. */
 53    const int    C_col_indices[] =  {  0,   2,    1,    2   }; /* Column index of a matrix variable. */
 54    const double C_values[]      =  { -3.0, 1.0, -2.0, -3.0 }; /* Values of a matrix variable. */
 55
 56    const int    A_size = 4;
 57    const int    A_mat_idx = 1;
 58    const int    A_row_indices_in_cone[] = { 0, 2, 1, 2 }; /* Row index in a matrix variable. */
 59    const int    A_col_indices_in_cone[] = { 0, 0, 1, 2 }; /* Column index in a matrix variable. */
 60    const double A_values_in_cone[]      = { 3.0, 1.0, 4.0, 5.0 }; /* Values of a matrix variable. */
 61
 62    /* Temp. */
 63    double soln[15];
 64    double val;
 65    int i, j, b;
 66
 67    /*------------------------------------------------------------------*/
 68    /* Step 1. Create a model and change the parameters.                */
 69    /*------------------------------------------------------------------*/
 70    /* Create an empty model. */
 71    MDO_CHECK_CALL(Mdo_createMdl(&model));
 72  
 73    /*------------------------------------------------------------------*/
 74    /* Step 2. Input model.                                             */
 75    /*------------------------------------------------------------------*/
 76    /* Change to maximization problem. */
 77    MDO_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, MDO_NO));
 78 
 79    /* Add matrix variable. */
 80    MDO_CHECK_CALL(Mdo_addSymMat(model, dim_mat, mat_name));
 81
 82    /* Input objective coefficients. */
 83    MDO_CHECK_CALL(Mdo_replaceSymMatObjs(
 84        model, 0, C_size, C_row_indices, C_col_indices, C_values));
 85
 86    /* Input first constraint. */
 87    MDO_CHECK_CALL(Mdo_addRow(model, 1.0, 1.0, 0, NULL, NULL, "c0"));
 88    MDO_CHECK_CALL(Mdo_replaceSymMatElements(model, 0, 0, A_size,
 89        A_row_indices_in_cone, A_col_indices_in_cone, A_values_in_cone));
 90
 91    /*------------------------------------------------------------------*/
 92    /* Step 3. Solve the problem and populate the result.               */
 93    /*------------------------------------------------------------------*/
 94    /* Solve the problem. */
 95    MDO_CHECK_CALL(Mdo_solveProb(model));
 96    Mdo_displayResults(model);
 97
 98    switch (Mdo_getStatus(model))
 99    {
100    case MDO_UNKNOWN:
101        printf("Optimizer terminated with an UNKNOWN status.\n");
102        break;
103    case MDO_OPTIMAL:
104        MDO_CHECK_CALL(Mdo_getRealAttr(model, MDO_REAL_ATTR_PRIMAL_OBJ_VAL, &val));
105        printf("Optimizer terminated with an OPTIMAL status.\n");
106        printf(" - Primal objective : %e.\n", val);
107        MDO_CHECK_CALL(Mdo_getRealAttrSymMat(
108            model, MDO_REAL_ATTR_SYM_MAT_PRIMAL_SOLN, 0, dim_mat * dim_mat, NULL, NULL, soln));
109        printf("X = \n");
110        for (i = 0; i < dim_mat; ++i)
111        {
112            printf("  (");
113            for (j = 0; j < dim_mat; ++j)
114            {
115                printf(" %+8.6e", soln[i * dim_mat + j]);
116            }
117            printf(" )\n");
118        }
119        break;
120    case MDO_INFEASIBLE:
121        printf("Optimizer terminated with an INFEASIBLE status.\n");
122        break;
123    case MDO_UNBOUNDED:
124        printf("Optimizer terminated with an UNBOUNDED status.\n");
125        break;
126    case MDO_INF_OR_UBD:
127        printf("Optimizer terminated with an INFEASIBLE or UNBOUNDED status.\n");
128        break;
129    }
130
131    /*------------------------------------------------------------------*/
132    /* Step 4. Free the model.                                          */
133    /*------------------------------------------------------------------*/
134    /* Free the model. */
135    Mdo_freeMdl(&model);
136
137    return (int)code;
138}

5.4.3.2. SDP Example 2

First, import the header file:

29        Mdo_explainResult(model, code, str);                        \

Step 1: Create a Model

Create an empty MindOpt model.

95    /*------------------------------------------------------------------*/
96    /* Step 1. Create a model and change the parameters.                */
97    /*------------------------------------------------------------------*/
98    /* Create an empty model. */
99    MDO_CHECK_CALL(Mdo_createMdl(&model));

Step 2: Input SDP Model

Change to maximization problem and add two scalar variables \(x_0\)\(x_1\) and two symmetric matrix variables \(\mathbf{X}_0\), \(\mathbf{X}_1\).

101    /*------------------------------------------------------------------*/
102    /* Step 2. Input model.                                             */
103    /*------------------------------------------------------------------*/
104    /* Change to maximization problem. */
105    MDO_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, MDO_NO));
106 
107    /* Add variables. */
108    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 0.0, 0, NULL, NULL, "x0", MDO_NO));
109    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 0.0, 0, NULL, NULL, "x1", MDO_NO));
110
111    /* Add matrix variables. */
112    MDO_CHECK_CALL(Mdo_addSymMats(model, num_mats, dim_mats, mat_names));

Use Mdo_replaceSymMatObjs() to input the non-zero elements of \(\mathbf{C}_0\). The first parameter is the model. The second parameter is the index value of the matrix (here is C0_mat_idx). The third parameter represents the number of non-zero elements of the matrix. The fourth and fifth parameters represent the index of the row and column corresponding to the non-zero elements in the matrix. The last parameter is the index of the value of the non-zero element.

114    /* Input objective coefficients. */
115    MDO_CHECK_CALL(Mdo_replaceSymMatObjs(
116        model, C0_mat_idx, C0_size, C0_row_indices, C0_col_indices, C0_values));

Similarly, we then input the non-zero elements of \(\mathbf{C}_1\) in the objective function.

117    MDO_CHECK_CALL(Mdo_replaceSymMatObjs(
118        model, C1_mat_idx, C1_size, C1_row_indices, C1_col_indices, C1_values));

Next, write the first constraint. We first write an empty constraint, then use Mdo_replaceSymMatElements() to input non-zero elements of \(\mathbf{A}_{00}\). The second and third parameters are the index value of the constraint (here is 0) and the index value of the matrix (here is A00_mat_idx). The fourth parameter represents the number of non-zero elements of the matrix. The fifth and sixth parameters represent the index of the row and column corresponding to the non-zero elements in the matrix. The last parameter is the index of the value of the non-zero element.

120    /* Input first constraint. */
121    MDO_CHECK_CALL(Mdo_addRow(model, 1.0, 1.0, row0_size, row0_idx, row0_val, "c0"));
122    MDO_CHECK_CALL(Mdo_replaceSymMatElements(model, 0, A00_mat_idx, A00_size,
123        A00_row_indices_in_cone, A00_col_indices_in_cone, A00_values_in_cone));

In the same way, write the second constraint.

125    /* Input second constraint. */
126    MDO_CHECK_CALL(Mdo_addRow(model, 2.0, 2.0, row1_size, row1_idx, row1_val, "c1"));
127    MDO_CHECK_CALL(Mdo_replaceSymMatElements(model, 1, A11_mat_idx, A11_size,
128        A11_row_indices_in_cone, A11_col_indices_in_cone, A11_values_in_cone));

Step3: Solve the SDP model

When the model is input, use the generic function Mdo_solveProb() to solve the problem and use the function Mdo_displayResults() to present the solution results.

130    /*------------------------------------------------------------------*/
131    /* Step 3. Solve the problem and populate the result.               */
132    /*------------------------------------------------------------------*/
133    /* Solve the problem. */
134    MDO_CHECK_CALL(Mdo_solveProb(model));
135    Mdo_displayResults(model);

Step 4: Obtain the solutions of the SDP model

We use the function Mdo_getRealAttr() to get the optimal objective function value and the function Mdo_getRealAttrArray() to obtain the variables \(x_0\)\(x_1\). The second parameter is the attribute value (note: Mdo_getRealAttrArray() is a generic function, so it is declared with the attribute value and MDO_REAL_ATTR_PRIMAL_SOLN defines the purpose to obtain the values of scalar variables. ) ) The third and the fourth parameters represent the first index and the last index plus 1, that is, \(x_j\), \(0 \leq j < 2\).

143        MDO_CHECK_CALL(Mdo_getRealAttr(model, MDO_REAL_ATTR_PRIMAL_OBJ_VAL, &val));
144        printf("Optimizer terminated with an OPTIMAL status.\n");
145        printf(" - Primal objective : %e.\n", val);
146        MDO_CHECK_CALL(Mdo_getRealAttrArray(model, MDO_REAL_ATTR_PRIMAL_SOLN, 0, 2, soln));

Finally, use Mdo_getRealAttrSymMat() to obtain \(\mathbf{X}_0\) and \(\mathbf{X}_1\). The second parameter defines the attribute value (note: Mdo_getRealAttrSymMat() is a generic function, so it is declared with the attribute value and MDO_REAL_ATTR_SYM_MAT_PRIMAL_SOLN defines the purpose to obtain the value of the (symmetric matrix) variable. ) The third parameter is the index value of the matrix (here is b). The fourth parameter is the size of the matrix, and the return value soln is the index of the corresponding element in the matrix.

153            MDO_CHECK_CALL(Mdo_getRealAttrSymMat(
154                model, MDO_REAL_ATTR_SYM_MAT_PRIMAL_SOLN, b, dim_mats[b] * dim_mats[b], NULL, NULL, soln));

Please refer to the linked file MdoSdoEx2.c for the complete code.

  1/**
  2 *  Description
  3 *  -----------
  4 *
  5 *  Semidefinite optimization (row-wise input).
  6 *
  7 *  Formulation
  8 *  -----------
  9 *
 10 *  Maximize
 11 *  obj: tr(C0 X0)   + tr(C1 X1)    + 0 x0 + 0 x1
 12 *
 13 *  Subject To
 14 *   c0 : tr(A00 X0)                + 1 x0        = 1
 15 *   c1 :              tr(A11 X1)          + 1 x1 = 2
 16 *  Bounds
 17 *    0 <= x0
 18 *    0 <= x1
 19 *  Matrix
 20 *    C0 =  [ 2 1 ]   A00 = [ 3 1 ]
 21 *          [ 1 2 ]         [ 1 3 ]
 22 *
 23 *    C1 = [ 3 0 1 ]  A11 = [ 3 0 1 ]
 24 *         [ 0 2 0 ]        [ 0 4 0 ]
 25 *         [ 1 0 3 ]        [ 1 0 5 ]
 26 *  End
 27 */
 28#include <stdio.h>
 29#include "Mindopt.h"
 30
 31/* Macro to check the return code. */
 32#define MDO_CHECK_CALL(MDO_CALL)                                    \
 33    code = MDO_CALL;                                                \
 34    if (code != MDO_OKAY)                                           \
 35    {                                                               \
 36        Mdo_explainResult(model, code, str);                        \
 37        Mdo_freeMdl(&model);                                        \
 38        fprintf(stderr, "===================================\n");   \
 39        fprintf(stderr, "Error   : code <%d>\n", code);             \
 40        fprintf(stderr, "Reason  : %s\n", str);                     \
 41        fprintf(stderr, "===================================\n");   \
 42        return (int)code;                                           \
 43    }
 44
 45int main(void)
 46{
 47    /* Variables. */
 48    char str[1024] = { "\0" };
 49    MdoMdl * model = NULL;
 50    MdoResult code = MDO_OKAY;
 51    MdoStatus status = MDO_UNKNOWN;
 52
 53    /* Input data. */
 54    const int    num_cols = 2;
 55    const int    num_mats = 2;
 56    const int    dim_mats[] = { 2, 3 }; /* Dimension of the matrix variables. */
 57    const char * mat_names[] = { "X0", "X1" };
 58
 59    const int    row0_size = 1;
 60    const int    row0_idx[] = { 0 };
 61    const double row0_val[] = { 1.0 };
 62    const int    row1_size = 1;
 63    const int    row1_idx[] = { 1 };
 64    const double row1_val[] = { 1.0 };
 65
 66    const int    C0_size = 3;
 67    const int    C0_mat_idx = 0;
 68    const int    C0_row_indices[] =  { 0,   1,   1   }; /* Row index of a matrix variable. */
 69    const int    C0_col_indices[] =  { 0,   0,   1   }; /* Column index of a matrix variable. */
 70    const double C0_values[]      =  { 2.0, 1.0, 2.0 }; /* Values of a matrix variable. */
 71
 72    const int    C1_size = 4;
 73    const int    C1_mat_idx = 1;
 74    const int    C1_row_indices[] =  { 0,   0,   1,   2   }; /* Row index of a matrix variable. */
 75    const int    C1_col_indices[] =  { 0,   2,   1,   2   }; /* Column index of a matrix variable. */
 76    const double C1_values[]      =  { 3.0, 1.0, 2.0, 3.0 }; /* Values of a matrix variable. */
 77
 78    const int    A00_size = 3;
 79    const int    A00_mat_idx = 0;
 80    const int    A00_row_indices_in_cone[] = { 0, 1, 1 }; /* Row index in a matrix variable. */
 81    const int    A00_col_indices_in_cone[] = { 0, 0, 1 }; /* Column index in a matrix variable. */
 82    const double A00_values_in_cone[]      = { 3.0, 1.0, 3.0 }; /* Values of a matrix variable. */
 83
 84    const int    A11_size = 4;
 85    const int    A11_mat_idx = 1;
 86    const int    A11_row_indices_in_cone[] = { 0, 2, 1, 2 }; /* Row index in a matrix variable. */
 87    const int    A11_col_indices_in_cone[] = { 0, 0, 1, 2 }; /* Column index in a matrix variable. */
 88    const double A11_values_in_cone[]      = { 3.0, 1.0, 4.0, 5.0 }; /* Values of a matrix variable. */
 89     
 90    /* Temp. */
 91    double soln[15];
 92    double val;
 93    int i, j, b;
 94
 95    /*------------------------------------------------------------------*/
 96    /* Step 1. Create a model and change the parameters.                */
 97    /*------------------------------------------------------------------*/
 98    /* Create an empty model. */
 99    MDO_CHECK_CALL(Mdo_createMdl(&model));
100 
101    /*------------------------------------------------------------------*/
102    /* Step 2. Input model.                                             */
103    /*------------------------------------------------------------------*/
104    /* Change to maximization problem. */
105    MDO_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, MDO_NO));
106 
107    /* Add variables. */
108    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 0.0, 0, NULL, NULL, "x0", MDO_NO));
109    MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 0.0, 0, NULL, NULL, "x1", MDO_NO));
110
111    /* Add matrix variables. */
112    MDO_CHECK_CALL(Mdo_addSymMats(model, num_mats, dim_mats, mat_names));
113
114    /* Input objective coefficients. */
115    MDO_CHECK_CALL(Mdo_replaceSymMatObjs(
116        model, C0_mat_idx, C0_size, C0_row_indices, C0_col_indices, C0_values));
117    MDO_CHECK_CALL(Mdo_replaceSymMatObjs(
118        model, C1_mat_idx, C1_size, C1_row_indices, C1_col_indices, C1_values));
119
120    /* Input first constraint. */
121    MDO_CHECK_CALL(Mdo_addRow(model, 1.0, 1.0, row0_size, row0_idx, row0_val, "c0"));
122    MDO_CHECK_CALL(Mdo_replaceSymMatElements(model, 0, A00_mat_idx, A00_size,
123        A00_row_indices_in_cone, A00_col_indices_in_cone, A00_values_in_cone));
124
125    /* Input second constraint. */
126    MDO_CHECK_CALL(Mdo_addRow(model, 2.0, 2.0, row1_size, row1_idx, row1_val, "c1"));
127    MDO_CHECK_CALL(Mdo_replaceSymMatElements(model, 1, A11_mat_idx, A11_size,
128        A11_row_indices_in_cone, A11_col_indices_in_cone, A11_values_in_cone));
129
130    /*------------------------------------------------------------------*/
131    /* Step 3. Solve the problem and populate the result.               */
132    /*------------------------------------------------------------------*/
133    /* Solve the problem. */
134    MDO_CHECK_CALL(Mdo_solveProb(model));
135    Mdo_displayResults(model);
136
137    switch (Mdo_getStatus(model))
138    {
139    case MDO_UNKNOWN:
140        printf("Optimizer terminated with an UNKNOWN status.\n");
141        break;
142    case MDO_OPTIMAL:
143        MDO_CHECK_CALL(Mdo_getRealAttr(model, MDO_REAL_ATTR_PRIMAL_OBJ_VAL, &val));
144        printf("Optimizer terminated with an OPTIMAL status.\n");
145        printf(" - Primal objective : %e.\n", val);
146        MDO_CHECK_CALL(Mdo_getRealAttrArray(model, MDO_REAL_ATTR_PRIMAL_SOLN, 0, 2, soln));
147        for (j = 0; j < 2; ++j)
148        {
149            printf("x[%d] = %+8.6e\n", j, soln[j]);
150        }
151        for (b = 0; b < num_mats; ++b)
152        {
153            MDO_CHECK_CALL(Mdo_getRealAttrSymMat(
154                model, MDO_REAL_ATTR_SYM_MAT_PRIMAL_SOLN, b, dim_mats[b] * dim_mats[b], NULL, NULL, soln));
155            printf("X[%d] = \n", b);
156            for (i = 0; i < dim_mats[b]; ++i)
157            {
158                printf("  (");
159                for (j = 0; j < dim_mats[b]; ++j)
160                {
161                    printf(" %+8.6e", soln[i * dim_mats[b] + j]);
162                }
163                printf(" )\n");
164            }
165        }
166        break;
167    case MDO_INFEASIBLE:
168        printf("Optimizer terminated with an INFEASIBLE status.\n");
169        break;
170    case MDO_UNBOUNDED:
171        printf("Optimizer terminated with an UNBOUNDED status.\n");
172        break;
173    case MDO_INF_OR_UBD:
174        printf("Optimizer terminated with an INFEASIBLE or UNBOUNDED status.\n");
175        break;
176    }
177
178    /*------------------------------------------------------------------*/
179    /* Step 4. Free the model.                                          */
180    /*------------------------------------------------------------------*/
181    /* Free the model. */
182    Mdo_freeMdl(&model);
183
184    return (int)code;
185}