5.7.2. SDP Modeling and Optimization in C

In this chapter, we will use MindOpt C API to model and solve the problem in Examples of semidefinite programming.

5.7.2.1. SDP Example I

Include the header file:

26#include "Mindopt.h"

Step I: Create an optimization model

Create an empty optimization model:

68    /* Create an empty model. */
69    CHECK_RESULT(MDOemptyenv(&env));
70    CHECK_RESULT(MDOstartenv(env));
71    CHECK_RESULT(MDOnewmodel(env, &m, MODEL_NAME, 0, NULL, NULL, NULL, NULL, NULL));

Step II: SDP model input

We set the optimization sense to maximize

77    /* Change to maximization problem. */
78    CHECK_RESULT(MDOsetintattr(m, MODEL_SENSE, MDO_MAXIMIZE));

We utilize MDOaddpsdvar() to create one semidefinite matrix variable and can simultaneously set their corresponding coefficient matrix in the objective function:

  • The first argument is the model,

  • The second argument is the dimension of the matrix variable \(\mathbf{X}\) (in this case, 3),

  • The third argument represents the number of nonzero elements in the coefficient matrix \(\mathbf{C}\),

  • The fourth and fifth arguments represent vectorized indices and values of the nonzero elements in \(\mathbf{X}\), respectively.

79    /* Add matrix variable and corresponding objective coefficients. */
80    CHECK_RESULT(MDOaddpsdvar(m, dim_mat, C_size, C_nnz_indices, C_nnz_values, NULL));

Next, we input the constraints. We use MDOaddpsdconstr() to create constraints with semidefinite matrix variables:

  • The 1st argument is the model.

  • The 2nd argument is the number of linear terms in the constraint. In this case, there is no linear term and the argument is 0.

  • The 3rd argument is the number of matrix terms in the constraint. In this case, there is one matrix term \(\langle \mathbf{A},\mathbf{X} \rangle\) in the constraint, so this argument is 1.

  • The 4th argument represents the total number of nonzero elements in all constraint coefficient matrix. In this case, given the matrix \(\mathbf{A}\) has 5 nonzeros and, owing to its symmetry, only its upper triangular part is considered, this argument becomes 4.

  • The 5th and 6th arguments represent the indices and values of the linear terms in the constraint. In this case, they are both NULL.

  • The 7th argument represents the index of the matrix variable in the constraint. In this case, there is only one matrix variable \(\mathbf{X}\), so its index is 0, making this argument {0}.

  • The 8th argument is an array recording the starting indices of all coefficient matrices in this constraint. Again, in this case, there is only one matrix term so this argument should be {0}. (If there were n matrix terms \(\{\mathbf{A}_i\}_{i=0}^{n-1}\), all matrices should be vectorized and concatenated into a long vector, and this argument should record the starting positions of the n matrices in that long vector.)

  • The 9th and 10th arguments represent the vectorized indices and values of all nonzero elements in all coefficient matrices. Here, we vectorize matrix \(\mathbf{A}\) and use these two arguments to define its non-zero positions and values.

  • The 11th argument represents the type of the constraint, and currently, we only support MDO_EQUAL (‘=’), which represents an equality constraint.

  • The 12th argument represents the right-hand side value of the constraint. In this case, it is 1.

  • The last argument represents the name of the constraint.

82    /* Add Constraints. */
83    CHECK_RESULT(MDOaddpsdconstr(m, 0, num_psd_var, A_size, NULL, NULL, psd_var_indices, psd_coeff_start_indices, A_nnz_indices, A_nnz_values, MDO_EQUAL, 1.0, NULL));

Step III: Solve SDP model

Solve the optimization problem via MDOoptimize().

88    /* Solve the problem. */
89    CHECK_RESULT(MDOoptimize(m));

Step IV: Obtain the solution of SDP problem

We use MDOgetintattr() to obtain the solution status, i.e., the Status attribute; and we use the generic function MDOgetdblattr() to retrieve the optimal objective function value, i.e., the PrimalObjVal attribute.

90    CHECK_RESULT(MDOgetintattr(m, STATUS, &status));
91    if (status == MDO_OPTIMAL)
92    {
93        CHECK_RESULT(MDOgetdblattr(m, OBJ_VAL, &obj));
94        printf("The objective value is %f\n", obj);
95    }
96    else 
97    {
98        printf("No feasible solution exists\n");
99    }

Step V: Release model

We use MDOfreemodel() and MDOfreeenv() to release the model.

30#define RELEASE_MEMORY  \
31    MDOfreemodel(m);    \
32    MDOfreeenv(env);
105    RELEASE_MEMORY;

The complete example code is provided in mdo_sdo_ex1.c :

  1/**
  2 *  Description
  3 *  -----------
  4 *
  5 *  Semidefinite optimization (row-wise input).
  6 *
  7 *  Formulation
  8 *  -----------
  9 *
 10 *  Maximize 
 11 *    obj: tr(C X) 
 12 *  Subject To
 13 *    c0 : tr(A X) = 1
 14 *  Bounds
 15 *    X is p.s.d.
 16 *
 17 *  Matrix
 18 *    C = [ -3  0  1 ]  A = [ 3 0 1 ]
 19 *        [  0 -2  0 ]      [ 0 4 0 ]
 20 *        [  1  0 -3 ]      [ 1 0 5 ]
 21 *  End
 22 */
 23
 24#include <stdio.h>
 25#include <stdlib.h>
 26#include "Mindopt.h"
 27
 28/* Macro to check the return code. */
 29#define CHECK_RESULT(code) { int res = code; if (res != 0) { fprintf(stderr, "Bad code: %d\n", res); exit(res); } }
 30#define RELEASE_MEMORY  \
 31    MDOfreemodel(m);    \
 32    MDOfreeenv(env);
 33#define MODEL_NAME "SDP_01"
 34#define MODEL_SENSE "ModelSense"
 35#define STATUS "Status"
 36#define OBJ_VAL "PrimalObjVal"
 37
 38int main(void)
 39{
 40    /* Variables. */
 41    MDOenv *env;
 42    MDOmodel *m;
 43    double obj;
 44    int status;
 45
 46    /* Model data. */
 47    // Variable dims.
 48    int    num_mats = 1;
 49    int    dim_mat =  3 ;                                
 50
 51    // Objective coefficients. (Only the right upper part in row-major sparse format)
 52    int    C_size = 4;
 53    int    C_nnz_indices[] =  { 0,    2,   4,    8    }; 
 54    double C_nnz_values[]  =  { -3.0, 1.0, -2.0, -3.0 }; 
 55 
 56    // Constraint coefficients. (Only the right upper part in row-major sparse format)
 57    int    num_psd_var               = 1;
 58    int    psd_var_indices[]         = { 0 };            
 59    int    psd_coeff_start_indices[] = { 0 };
 60    
 61    int    A_size = 4;
 62    int    A_nnz_indices[] =  { 0,   2,    4,    8    }; 
 63    double A_nnz_values[]  =  { 3.0, 1.0,  4.0,  5.0  }; 
 64    
 65    /*------------------------------------------------------------------*/
 66    /* Step 1. Create a model and change the parameters.                */
 67    /*------------------------------------------------------------------*/
 68    /* Create an empty model. */
 69    CHECK_RESULT(MDOemptyenv(&env));
 70    CHECK_RESULT(MDOstartenv(env));
 71    CHECK_RESULT(MDOnewmodel(env, &m, MODEL_NAME, 0, NULL, NULL, NULL, NULL, NULL));
 72
 73    /*------------------------------------------------------------------*/
 74    /* Step 2. Input model.                                             */
 75    /*------------------------------------------------------------------*/
 76    /* Change to maximization problem. */
 77    CHECK_RESULT(MDOsetintattr(m, MODEL_SENSE, MDO_MAXIMIZE));
 78
 79    /* Add matrix variable and corresponding objective coefficients. */
 80    CHECK_RESULT(MDOaddpsdvar(m, dim_mat, C_size, C_nnz_indices, C_nnz_values, NULL));
 81
 82    /* Add Constraints. */
 83    CHECK_RESULT(MDOaddpsdconstr(m, 0, num_psd_var, A_size, NULL, NULL, psd_var_indices, psd_coeff_start_indices, A_nnz_indices, A_nnz_values, MDO_EQUAL, 1.0, NULL));
 84  
 85    /*------------------------------------------------------------------*/
 86    /* Step 3. Solve the problem and populate the result.               */
 87    /*------------------------------------------------------------------*/
 88    /* Solve the problem. */
 89    CHECK_RESULT(MDOoptimize(m));
 90    CHECK_RESULT(MDOgetintattr(m, STATUS, &status));
 91    if (status == MDO_OPTIMAL)
 92    {
 93        CHECK_RESULT(MDOgetdblattr(m, OBJ_VAL, &obj));
 94        printf("The objective value is %f\n", obj);
 95    }
 96    else 
 97    {
 98        printf("No feasible solution exists\n");
 99    }
100
101    /*------------------------------------------------------------------*/
102    /* Step 4. Free the model.                                          */
103    /*------------------------------------------------------------------*/
104    /* Free the model. */
105    RELEASE_MEMORY;
106
107    return 0;
108}

5.7.2.2. SDP Example II

Include the header file:

32#include "Mindopt.h"

Step I: Create an optimization model

Create an empty optimization model:

94    /* Create an empty model. */
95    CHECK_RESULT(MDOemptyenv(&env));
96    CHECK_RESULT(MDOstartenv(env));
97    CHECK_RESULT(MDOnewmodel(env, &m, MODEL_NAME, 0, NULL, NULL, NULL, NULL, NULL));

Step II: SDP model input

we set the optimization sense to maximize

102    /* Change to maximization problem. */
103    CHECK_RESULT(MDOsetintattr(m, MODEL_SENSE, MDO_MAXIMIZE));

We use MDOaddvar() to create two linear variables \(x_0,x_1\) and set their bounds and coefficients in the objective function.

105    /* Add linear variable and corresponding objective coefficients. */
106    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 0.0, 0.0, MDO_INFINITY, MDO_CONTINUOUS, NULL));
107    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 0.0, 0.0, MDO_INFINITY, MDO_CONTINUOUS, NULL));

We utilize MDOaddpsdvar() to create two semidefinite matrix variables \(\mathbf{X}_0, \mathbf{X}_1\) and can simultaneously set their corresponding coefficient matrix \(\mathbf{C}_0, \mathbf{C}_1\) in the objective function:

  • The first argument is the model,

  • The second argument is the dimension of the matrix variable,

  • The third element represents the number of nonzero elements in the coefficient matrix,

  • The fourth and fifth arguments represent vectorized indices and values of the nonzero elements in the coefficient matrix, respectively.

109    /* Add psd variable and corresponding objective coefficients. */
110    CHECK_RESULT(MDOaddpsdvar(m, dim_mats[0], C0_size, C0_nnz_indices, C0_nnz_values, NULL));
111    CHECK_RESULT(MDOaddpsdvar(m, dim_mats[1], C1_size, C1_nnz_indices, C1_nnz_values, NULL));

Next, we input the constraints. We use MDOaddpsdconstr() to create constraints with semidefinite matrix variables. The arguments of MDOaddpsdconstr() have been explained in SDP Example I. The distinctions in this context are:

  • There are two constraints in Example II.

  • In each constraint, there is a matrix term and a linear term.

The constraints can be added as:

113    /* Add constraints coefficients. */
114    CHECK_RESULT(MDOaddpsdconstr(m, row0_size, num_psd_var[0], A0_size, row0_idx, row0_val, A0_psd_var_indices, A0_psd_coeff_start_indices, A0_nnz_indices, A0_nnz_values, MDO_EQUAL, 1.0, NULL));
115    CHECK_RESULT(MDOaddpsdconstr(m, row1_size, num_psd_var[1], A1_size, row1_idx, row1_val, A1_psd_var_indices, A1_psd_coeff_start_indices, A1_nnz_indices, A1_nnz_values, MDO_EQUAL, 2.0, NULL));

Step III: Solve SDP model

Solve the optimization problem via MDOoptimize().

120    /* Solve the problem. */
121    CHECK_RESULT(MDOoptimize(m));

Step IV: Obtain the solution of SDP problem

We use MDOgetintattr() to obtain the solution status, i.e., the Status attribute; and we use the generic function MDOgetdblattr() to retrieve the optimal objective function value, i.e., the PrimalObjVal attribute.

122    CHECK_RESULT(MDOgetintattr(m, STATUS, &status));
123    if (status == MDO_OPTIMAL)
124    {
125        CHECK_RESULT(MDOgetdblattr(m, OBJ_VAL, &obj));
126        printf("The objective value is %f\n", obj);
127    }
128    else 
129    {
130        printf("No feasible solution exists\n");
131    }

Step V: Release model

We use MDOfreemodel() and MDOfreeenv() to release the model.

36#define RELEASE_MEMORY  \
37    MDOfreemodel(m);    \
38    MDOfreeenv(env);
137    RELEASE_MEMORY;

The complete example code is provided in mdo_sdo_ex2.c :

  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 *  Subject To
 13 *    c0 : tr(A00 X0)                +  1 x0        = 1
 14 *    c1 :               tr(A11 X1)          + 1 x1 = 2
 15 *  Bounds
 16 *    0 <= x0
 17 *    0 <= x1
 18 *    X0, X1 are p.s.d.
 19 *
 20 *  Matrix
 21 *    C0 =  [ 2 1 ]   A00 = [ 3 1 ]
 22 *          [ 1 2 ]         [ 1 3 ]
 23 *
 24 *    C1 = [ 3 0 1 ]  A11 = [ 3 0 1 ]
 25 *         [ 0 2 0 ]        [ 0 4 0 ]
 26 *         [ 1 0 3 ]        [ 1 0 5 ]
 27 *  End
 28 */
 29
 30#include <stdio.h>
 31#include <stdlib.h>
 32#include "Mindopt.h"
 33
 34/* Macro to check the return code. */
 35#define CHECK_RESULT(code) { int res = code; if (res != 0) { fprintf(stderr, "Bad code: %d\n", res); exit(res); } }
 36#define RELEASE_MEMORY  \
 37    MDOfreemodel(m);    \
 38    MDOfreeenv(env);
 39#define MODEL_NAME "SDP_02"
 40#define MODEL_SENSE "ModelSense"
 41#define STATUS "Status"
 42#define OBJ_VAL "PrimalObjVal"
 43
 44int main(void)
 45{
 46    /* Variables. */
 47    MDOenv *env;
 48    MDOmodel *m;
 49    double obj;
 50    int status;
 51
 52    /* Model data. */
 53    // linear variables.
 54    int     num_cols = 2;    
 55
 56    // psd variables.
 57    int    num_mats    = 2;
 58    int    dim_mats[]  = { 2, 3 };
 59    
 60    // Objective coefficients.  (Only the right upper part in row-major sparse format)
 61    int    C0_size = 3;
 62    int    C0_nnz_indices[] =  { 0,    1,   3   }; 
 63    double C0_nnz_values[]  =  { 2.0,  1.0, 2.0 }; 
 64
 65    int    C1_size = 4;
 66    int    C1_nnz_indices[] =  { 0,    2,   4,    8   }; 
 67    double C1_nnz_values[]  =  { 3.0,  1.0, 2.0,  3.0 };  
 68    
 69    // Constraints (linear).
 70    int    row0_size  = 1;
 71    int    row0_idx[] = { 0 };
 72    double row0_val[] = { 1.0 };
 73    int    row1_size  = 1;
 74    int    row1_idx[] = { 1 };
 75    double row1_val[] = { 1.0 };
 76
 77    // Constraints (psd).  (Only the right upper part in row-major sparse format)
 78    int    num_psd_var[]                = { 1, 1 };
 79    int    A0_psd_var_indices[]         = { 0 }; 
 80    int    A0_psd_coeff_start_indices[] = { 0 };
 81    int    A0_size                      = 3;
 82    int    A0_nnz_indices[]             = { 0,   1,    3   }; 
 83    double A0_nnz_values[]              = { 3.0, 1.0,  3.0 };
 84
 85    int    A1_psd_var_indices[]         = { 1 };
 86    int    A1_psd_coeff_start_indices[] = { 0 }; 
 87    int    A1_size                      = 4;
 88    int    A1_nnz_indices[]             = { 0,   2,    4,    8   };
 89    double A1_nnz_values[]              = { 3.0, 1.0,  4.0,  5.0 }; 
 90 
 91    /*------------------------------------------------------------------*/
 92    /* Step 1. Create a model and change the parameters.                */
 93    /*------------------------------------------------------------------*/
 94    /* Create an empty model. */
 95    CHECK_RESULT(MDOemptyenv(&env));
 96    CHECK_RESULT(MDOstartenv(env));
 97    CHECK_RESULT(MDOnewmodel(env, &m, MODEL_NAME, 0, NULL, NULL, NULL, NULL, NULL));
 98    
 99    /*------------------------------------------------------------------*/
100    /* Step 2. Input model.                                             */
101    /*------------------------------------------------------------------*/
102    /* Change to maximization problem. */
103    CHECK_RESULT(MDOsetintattr(m, MODEL_SENSE, MDO_MAXIMIZE));
104    
105    /* Add linear variable and corresponding objective coefficients. */
106    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 0.0, 0.0, MDO_INFINITY, MDO_CONTINUOUS, NULL));
107    CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, 0.0, 0.0, MDO_INFINITY, MDO_CONTINUOUS, NULL));
108
109    /* Add psd variable and corresponding objective coefficients. */
110    CHECK_RESULT(MDOaddpsdvar(m, dim_mats[0], C0_size, C0_nnz_indices, C0_nnz_values, NULL));
111    CHECK_RESULT(MDOaddpsdvar(m, dim_mats[1], C1_size, C1_nnz_indices, C1_nnz_values, NULL));
112
113    /* Add constraints coefficients. */
114    CHECK_RESULT(MDOaddpsdconstr(m, row0_size, num_psd_var[0], A0_size, row0_idx, row0_val, A0_psd_var_indices, A0_psd_coeff_start_indices, A0_nnz_indices, A0_nnz_values, MDO_EQUAL, 1.0, NULL));
115    CHECK_RESULT(MDOaddpsdconstr(m, row1_size, num_psd_var[1], A1_size, row1_idx, row1_val, A1_psd_var_indices, A1_psd_coeff_start_indices, A1_nnz_indices, A1_nnz_values, MDO_EQUAL, 2.0, NULL));
116  
117    /*------------------------------------------------------------------*/
118    /* Step 3. Solve the problem and populate the result.               */
119    /*------------------------------------------------------------------*/
120    /* Solve the problem. */
121    CHECK_RESULT(MDOoptimize(m));
122    CHECK_RESULT(MDOgetintattr(m, STATUS, &status));
123    if (status == MDO_OPTIMAL)
124    {
125        CHECK_RESULT(MDOgetdblattr(m, OBJ_VAL, &obj));
126        printf("The objective value is %f\n", obj);
127    }
128    else 
129    {
130        printf("No feasible solution exists\n");
131    }
132
133    /*------------------------------------------------------------------*/
134    /* Step 4. Free the model.                                          */
135    /*------------------------------------------------------------------*/
136    /* Free the model. */
137    RELEASE_MEMORY;
138
139    return 0;
140}