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}