5.4.4. 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.4.1. SDP Example 1¶
First, import the header file:
23#include "MindoptCpp.h"
Step 1: Create a Model
Create an empty MindOpt model.
47 MdoModel model;
Step 2: Input SDP Model
Change to maximization problem and add a symmetric matrix variable \(\mathbf{X}\).
51 /*------------------------------------------------------------------*/
52 /* Step 2. Input model. */
53 /*------------------------------------------------------------------*/
54 /* Change to maximization problem. */
55 model.setIntAttr(MDO_INT_ATTR::MIN_SENSE, MDO_NO);
56
57 /* Add matrix variable. */
58 model.addSymMat(dim_mat, mat_name);
Use mindopt::MdoModel::replaceSymMatObjs()
to input the non-zero elements of \(\mathbf{C}\).
The first parameter is the index value of the matrix (here is 0). The second parameter represents the number of non-zero elements of the matrix.
The third and fourth 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.
60 /* Input objective coefficients. */
61 model.replaceSymMatObjs(0, C_size, C_row_indices, C_col_indices, C_values);
Next, write the first constraint. We first write an empty constraint, then use mindopt::MdoModel::replaceSymMatElements()
to input non-zero elements of \(\mathbf{A}\).
The first and the second parameters are the index value of the constraint (here is 0) and 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 element.
63 /* Input first constraint. */
64 model.addCons(1.0, 1.0, "c0");
65 model.replaceSymMatElements(
66 0, 0, A_size, 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 mindopt::MdoModel::solveProb()
to solve the problem and use Mdo_displayResults()
to present the solution results.
71 /* Solve the problem. */
72 model.solveProb();
73 model.displayResults();
第四步: 取得SDP模型的解
Use the function mindopt::MdoModel::getRealAttr()
to obtain the optimal objective function value.
82 std::cout << "Optimizer terminated with an OPTIMAL status" << std::endl;
83 std::cout << std::setprecision(6) << std::cout.width(8) << std::fixed << std::scientific <<
84 " - Primal objective : " << model.getRealAttr(MDO_REAL_ATTR::PRIMAL_OBJ_VAL) << std::endl;
Finally, use mindopt::MdoModel::getRealAttrSymMat()
to obtain \(\mathbf{X}\). The first parameter defines the attribute value (note: mindopt::MdoModel::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 second parameter is the index value of the matrix (here is 0). The third parameter is the size of the matrix.
85 auto soln = model.getRealAttrSymMat(
86 MDO_REAL_ATTR::SYM_MAT_PRIMAL_SOLN, 0, dim_mat * dim_mat, NULL, NULL);
Please refer to the linked file MdoSdoEx1.cpp 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 <iostream>
22#include <iomanip>
23#include "MindoptCpp.h"
24
25using namespace mindopt;
26
27int main(void)
28{
29 const std::string mat_name = "X";
30 const int num_mats = 1;
31 const int dim_mat = 3; /* Dimension of the matrix variables. */
32
33 const int C_size = 4;
34 const int C_row_indices[] = { 0, 0, 1, 2 }; /* Row index of a matrix variable. */
35 const int C_col_indices[] = { 0, 2, 1, 2 }; /* Column index of a matrix variable. */
36 const double C_values[] = { -3.0, 1.0, -2.0, -3.0 }; /* Values of a matrix variable. */
37
38 const int A_size = 4;
39 const int A_row_indices_in_cone[] = { 0, 2, 1, 2 }; /* Row index in a matrix variable. */
40 const int A_col_indices_in_cone[] = { 0, 0, 1, 2 }; /* Column index in a matrix variable. */
41 const double A_values_in_cone[] = { 3.0, 1.0, 4.0, 5.0 }; /* Values of a matrix variable. */
42
43 /*------------------------------------------------------------------*/
44 /* Step 1. Create a model and change the parameters. */
45 /*------------------------------------------------------------------*/
46 /* Create an empty model. */
47 MdoModel model;
48
49 try
50 {
51 /*------------------------------------------------------------------*/
52 /* Step 2. Input model. */
53 /*------------------------------------------------------------------*/
54 /* Change to maximization problem. */
55 model.setIntAttr(MDO_INT_ATTR::MIN_SENSE, MDO_NO);
56
57 /* Add matrix variable. */
58 model.addSymMat(dim_mat, mat_name);
59
60 /* Input objective coefficients. */
61 model.replaceSymMatObjs(0, C_size, C_row_indices, C_col_indices, C_values);
62
63 /* Input first constraint. */
64 model.addCons(1.0, 1.0, "c0");
65 model.replaceSymMatElements(
66 0, 0, A_size, A_row_indices_in_cone, A_col_indices_in_cone, A_values_in_cone);
67
68 /*------------------------------------------------------------------*/
69 /* Step 3. Solve the problem and populate the result. */
70 /*------------------------------------------------------------------*/
71 /* Solve the problem. */
72 model.solveProb();
73 model.displayResults();
74
75 switch (model.getStatus())
76 {
77 case MDO_UNKNOWN:
78 std::cout <<"Optimizer terminated with an UNKNOWN status." << std::endl;
79 break;
80 case MDO_OPTIMAL:
81 {
82 std::cout << "Optimizer terminated with an OPTIMAL status" << std::endl;
83 std::cout << std::setprecision(6) << std::cout.width(8) << std::fixed << std::scientific <<
84 " - Primal objective : " << model.getRealAttr(MDO_REAL_ATTR::PRIMAL_OBJ_VAL) << std::endl;
85 auto soln = model.getRealAttrSymMat(
86 MDO_REAL_ATTR::SYM_MAT_PRIMAL_SOLN, 0, dim_mat * dim_mat, NULL, NULL);
87 std::cout << "X = " << std::endl;
88 for (auto i = 0; i < dim_mat; ++i)
89 {
90 std::cout << " (";
91 for (auto j = 0; j < dim_mat; ++j)
92 {
93 std::cout << " " << soln[i * dim_mat + j];
94 }
95 std::cout << " )" << std::endl;
96 }
97 break;
98 }
99 case MDO_INFEASIBLE:
100 std::cout << "Optimizer terminated with an INFEASIBLE status." << std::endl;
101 break;
102 case MDO_UNBOUNDED:
103 std::cout << "Optimizer terminated with an UNBOUNDED status." << std::endl;
104 break;
105 case MDO_INF_OR_UBD:
106 std::cout << "Optimizer terminated with an INFEASIBLE or UNBOUNDED status." << std::endl;
107 break;
108 }
109 }
110 catch (MdoException & e)
111 {
112 std::cerr << "===================================" << std::endl;
113 std::cerr << "Error : code <" << e.getResult() << ">" << std::endl;
114 std::cerr << "Reason : " << model.explainResult(e.getResult()) << std::endl;
115 std::cerr << "===================================" << std::endl;
116
117 return static_cast<int>(e.getResult());
118 }
119
120 return static_cast<int>(MDO_OKAY);
121}
5.4.4.2. SDP Example 2¶
First, import the header file:
30#include "MindoptCpp.h"
Step 1: Create a Model
Create an empty MindOpt model.
67 /* Create an empty model. */
68 MdoModel 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\).
72 /*------------------------------------------------------------------*/
73 /* Step 2. Input model. */
74 /*------------------------------------------------------------------*/
75 /* Change to maximization problem. */
76 model.setIntAttr(MDO_INT_ATTR::MIN_SENSE, MDO_NO);
77
78 /* Add variables. */
79 std::vector<MdoVar> x;
80 x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, "x0", MDO_NO));
81 x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, "x1", MDO_NO));
82
83 /* Add matrix variables. */
84 model.addSymMats(num_mats, dim_mats, mat_names);
Use mindopt::MdoModel::replaceSymMatObjs()
to input the non-zero elements of \(\mathbf{C}_0\).
The first parameter is the index value of the matrix (here is C0_mat_idx). The second parameter represents the number of non-zero elements of the matrix.
The third and fourth 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 objective coefficients. */
87 model.replaceSymMatObjs(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.
88 model.replaceSymMatObjs(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 mindopt::MdoModel::replaceSymMatElements()
to input non-zero elements of \(\mathbf{A}_{00}\).
The first and second parameters are the index value of the constraint (here is 0) and the index value of the matrix (here is A00_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.
90 /* Input first constraint. */
91 model.addCons(1.0 * x[0] == 1.0, "c0");
92 model.replaceSymMatElements(
93 0, A00_mat_idx, A00_size, A00_row_indices_in_cone, A00_col_indices_in_cone, A00_values_in_cone);
In the same way, write the second constraint.
95 /* Input second constraint. */
96 model.addCons(1.0 * x[1] == 2.0, "c1");
97 model.replaceSymMatElements(
98 1, A11_mat_idx, A11_size, 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 mindopt::MdoModel::solveProb()
to solve the problem and use the function mindopt::MdoModel::displayResults()
to present the solution results.
100 /*------------------------------------------------------------------*/
101 /* Step 3. Solve the problem and populate the result. */
102 /*------------------------------------------------------------------*/
103 /* Solve the problem. */
104 model.solveProb();
105 model.displayResults();
Step 4: Obtain the solutions of the SDP model
We use the function mindopt::MdoModel::getRealAttr()
to get the optimal objective function value and the function mindopt::MdoModel::getRealAttrArray()
to obtain the variables \(x_0\) 和 \(x_1\). The first parameter is the attribute value (note: mindopt::MdoModel::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 second and third parameters represent the first index and the last index plus 1, that is, \(x_j\), \(0 \leq j < 2\).
115 std::cout << std::setprecision(6) << std::cout.width(8) << std::fixed << std::scientific <<
116 " - Primal objective : " << model.getRealAttr(MDO_REAL_ATTR::PRIMAL_OBJ_VAL) << std::endl;
Finally, use mindopt::MdoModel::getRealAttrSymMat()
to obtain \(\mathbf{X}_0\) and \(\mathbf{X}_1\). The first
parameter defines the attribute value (note: mindopt::MdoModel::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 second parameter is the index value of the matrix (here is b). The third
parameter is the size of the matrix.
124 auto soln = model.getRealAttrSymMat(
125 MDO_REAL_ATTR::SYM_MAT_PRIMAL_SOLN, b, dim_mats[b] * dim_mats[b], NULL, NULL);
Please refer to the linked file`MdoSdoEx2.cpp <../../codes/MdoSdoEx2.cpp>`_ 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(C0 X1) + 0 x0 + 0 x1
12 *
13 * Subject To
14 * c0 : tr(A00 X0) + 1 x0 = 1
15 * c1 : tr(A00 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 * C0 = [ 3 0 1 ] A00 = [ 3 0 1 ]
24 * [ 0 2 0 ] [ 0 4 0 ]
25 * [ 1 0 3 ] [ 1 0 5 ]
26 * End
27 */
28#include <iostream>
29#include <iomanip>
30#include "MindoptCpp.h"
31
32using namespace mindopt;
33
34int main(void)
35{
36 const int num_mats = 2;
37 const int dim_mats[] = { 2, 3 }; /* Dimension of the matrix variables. */
38 const std::string mat_names[] = { "X0", "X1" };
39
40 const int C0_size = 3;
41 const int C0_mat_idx = 0;
42 const int C0_row_indices[] = { 0, 1, 1 }; /* Row index of a matrix variable. */
43 const int C0_col_indices[] = { 0, 0, 1 }; /* Column index of a matrix variable. */
44 const double C0_values[] = { 2.0, 1.0, 2.0 }; /* Values of a matrix variable. */
45
46 const int C1_size = 4;
47 const int C1_mat_idx = 1;
48 const int C1_row_indices[] = { 0, 0, 1, 2 }; /* Row index of a matrix variable. */
49 const int C1_col_indices[] = { 0, 2, 1, 2 }; /* Column index of a matrix variable. */
50 const double C1_values[] = { 3.0, 1.0, 2.0, 3.0 }; /* Values of a matrix variable. */
51
52 const int A00_size = 3;
53 const int A00_mat_idx = 0;
54 const int A00_row_indices_in_cone[] = { 0, 1, 1 }; /* Row index in a matrix variable. */
55 const int A00_col_indices_in_cone[] = { 0, 0, 1 }; /* Column index in a matrix variable. */
56 const double A00_values_in_cone[] = { 3.0, 1.0, 3.0 }; /* Values of a matrix variable. */
57
58 const int A11_size = 4;
59 const int A11_mat_idx = 1;
60 const int A11_row_indices_in_cone[] = { 0, 2, 1, 2 }; /* Row index in a matrix variable. */
61 const int A11_col_indices_in_cone[] = { 0, 0, 1, 2 }; /* Column index in a matrix variable. */
62 const double A11_values_in_cone[] = { 3.0, 1.0, 4.0, 5.0 }; /* Values of a matrix variable. */
63
64 /*------------------------------------------------------------------*/
65 /* Step 1. Create a model and change the parameters. */
66 /*------------------------------------------------------------------*/
67 /* Create an empty model. */
68 MdoModel model;
69
70 try
71 {
72 /*------------------------------------------------------------------*/
73 /* Step 2. Input model. */
74 /*------------------------------------------------------------------*/
75 /* Change to maximization problem. */
76 model.setIntAttr(MDO_INT_ATTR::MIN_SENSE, MDO_NO);
77
78 /* Add variables. */
79 std::vector<MdoVar> x;
80 x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, "x0", MDO_NO));
81 x.push_back(model.addVar(0.0, MDO_INFINITY, 0.0, "x1", MDO_NO));
82
83 /* Add matrix variables. */
84 model.addSymMats(num_mats, dim_mats, mat_names);
85
86 /* Input objective coefficients. */
87 model.replaceSymMatObjs(C0_mat_idx, C0_size, C0_row_indices, C0_col_indices, C0_values);
88 model.replaceSymMatObjs(C1_mat_idx, C1_size, C1_row_indices, C1_col_indices, C1_values);
89
90 /* Input first constraint. */
91 model.addCons(1.0 * x[0] == 1.0, "c0");
92 model.replaceSymMatElements(
93 0, A00_mat_idx, A00_size, A00_row_indices_in_cone, A00_col_indices_in_cone, A00_values_in_cone);
94
95 /* Input second constraint. */
96 model.addCons(1.0 * x[1] == 2.0, "c1");
97 model.replaceSymMatElements(
98 1, A11_mat_idx, A11_size, A11_row_indices_in_cone, A11_col_indices_in_cone, A11_values_in_cone);
99
100 /*------------------------------------------------------------------*/
101 /* Step 3. Solve the problem and populate the result. */
102 /*------------------------------------------------------------------*/
103 /* Solve the problem. */
104 model.solveProb();
105 model.displayResults();
106
107 switch (model.getStatus())
108 {
109 case MDO_UNKNOWN:
110 std::cout <<"Optimizer terminated with an UNKNOWN status." << std::endl;
111 break;
112 case MDO_OPTIMAL:
113 {
114 std::cout << "Optimizer terminated with an OPTIMAL status" << std::endl;
115 std::cout << std::setprecision(6) << std::cout.width(8) << std::fixed << std::scientific <<
116 " - Primal objective : " << model.getRealAttr(MDO_REAL_ATTR::PRIMAL_OBJ_VAL) << std::endl;
117 auto soln = model.getRealAttrArray(MDO_REAL_ATTR::PRIMAL_SOLN, 0, 2);
118 for (auto j = 0; j < 2; ++j)
119 {
120 std::cout << "x[" << j << "] = " << soln[j] << std::endl;
121 }
122 for (auto b = 0; b < num_mats; ++b)
123 {
124 auto soln = model.getRealAttrSymMat(
125 MDO_REAL_ATTR::SYM_MAT_PRIMAL_SOLN, b, dim_mats[b] * dim_mats[b], NULL, NULL);
126 std::cout << "X[" << b<< "] = " << std::endl;
127 for (auto i = 0; i < dim_mats[b]; ++i)
128 {
129 std::cout << " (";
130 for (auto j = 0; j < dim_mats[b]; ++j)
131 {
132 std::cout << " " << soln[i * dim_mats[b] + j];
133 }
134 std::cout << " )" << std::endl;
135 }
136 }
137 break;
138 }
139 case MDO_INFEASIBLE:
140 std::cout << "Optimizer terminated with an INFEASIBLE status." << std::endl;
141 break;
142 case MDO_UNBOUNDED:
143 std::cout << "Optimizer terminated with an UNBOUNDED status." << std::endl;
144 break;
145 case MDO_INF_OR_UBD:
146 std::cout << "Optimizer terminated with an INFEASIBLE or UNBOUNDED status." << std::endl;
147 break;
148 }
149 }
150 catch (MdoException & e)
151 {
152 std::cerr << "===================================" << std::endl;
153 std::cerr << "Error : code <" << e.getResult() << ">" << std::endl;
154 std::cerr << "Reason : " << model.explainResult(e.getResult()) << std::endl;
155 std::cerr << "===================================" << std::endl;
156
157 return static_cast<int>(e.getResult());
158 }
159
160 return static_cast<int>(MDO_OKAY);
161}