5.7.3. 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.3.1. SDP Example I¶
Include the header file:
25#include "MindoptCpp.h"
Step I: Create an optimization model
Create an empty optimization model:
46 MDOEnv env = MDOEnv();
47 MDOModel m = MDOModel(env);
Step II: SDP model input
We use MDOModel::addPsdVar()
to create a new semidefinite matrix variable representing \(\mathbf{X}\) in our example and simultaneously set its corresponding coefficient matrix \(\mathbf{C}\) in the objective function.
The first argument is the coefficient matrix, which is an instance of the
MDOMatrix
created using theMDOMatrix::coo()
method. Note that the dimensions of the coefficient matrix should match the matrix variables.The second argument is the name of the variable.
54 /* Add variables. */
55 MDOPsdVar psd_var = m.addPsdVar(MDOMatrix::coo(dim_mat, dim_mat, C_nnz, C_nz_indices, C_nz_values), "X0");
Next, we input the first constraint. We use MDOModel::addPsdConstr()
to establish a constraint with a semidefinite matrix variable.
The first argument is the semidefinite expression in the constraint, i.e., \(\langle \mathbf{A},\mathbf{X} \rangle\). We create it using the initialization method
MDOPsdExpr::MDOPsdExpr()
.The second argument is the type of the constraint, and currently, we only support MDO_EQUAL (‘=’), which represents an equality constraint.
The third argument is the right-hand side value of the constraint (in this case, 1.0). The last argument is the name of the constraint.
57 /* Add constraints. */
58 m.addPsdConstr(MDOPsdExpr(psd_var, MDOMatrix::coo(dim_mat, dim_mat, A_nnz, A_nz_indices, A_nz_values)), MDO_EQUAL, 1.0, "C0");
Finally, we use MDOModel::setObjective()
to set the linear part of the objective function (in this case, 0), and change the optimization direction to maximization (-1).
60 /* Set objective function. */
61 MDOLinExpr objective = 0;
62 m.setObjective(objective, MDO.MAXIMIZE);
Step III: Solve SDP model
Solve the optimization problem via MDOModel::optimize()
.
67 // Optimize the model
68 m.optimize();
Step IV: Obtain the solution of SDP problem
We use the generic function MDOModel::get()
to retrieve the optimal objective function value, i.e., the PrimalObjVal attribute.
69 if (m.get(MDO_IntAttr_Status) == MDO_OPTIMAL)
70 {
71 cout << "Primal objective val: " << m.get(MDO_DoubleAttr_PrimalObjVal) << endl;
72 }
73 else
74 {
75 cout << "No feasible solution." << endl;
76 }
The complete example code is provided in MdoSdoEx1.cpp :
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 * 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 <iostream>
25#include "MindoptCpp.h"
26
27using namespace std;
28
29int main(void)
30{
31 /* Model data. */
32 int num_mats = 1;
33 int dim_mat = 3; /* Dimension of the matrix variables. */
34
35 int C_nnz = 4;
36 int C_nz_indices[] = { 0, 2, 4, 8 }; /* Nonzero vectorized index of obj coeff. */
37 double C_nz_values[] = { -3.0, 1.0, -2.0, -3.0 }; /* Nonzero values of obj coeff. */
38
39 int A_nnz = 4;
40 int A_nz_indices[] = { 0, 2, 4, 8 }; /* Nonzero vectorized index of constr coeff. */
41 double A_nz_values[] = { 3.0, 1.0, 4.0, 5.0 }; /* Nonzero values of constr coeff. */
42
43 /*------------------------------------------------------------------*/
44 /* Step 1. Create environment and model. */
45 /*------------------------------------------------------------------*/
46 MDOEnv env = MDOEnv();
47 MDOModel m = MDOModel(env);
48
49 try
50 {
51 /*------------------------------------------------------------------*/
52 /* Step 2. Input model. */
53 /*------------------------------------------------------------------*/
54 /* Add variables. */
55 MDOPsdVar psd_var = m.addPsdVar(MDOMatrix::coo(dim_mat, dim_mat, C_nnz, C_nz_indices, C_nz_values), "X0");
56
57 /* Add constraints. */
58 m.addPsdConstr(MDOPsdExpr(psd_var, MDOMatrix::coo(dim_mat, dim_mat, A_nnz, A_nz_indices, A_nz_values)), MDO_EQUAL, 1.0, "C0");
59
60 /* Set objective function. */
61 MDOLinExpr objective = 0;
62 m.setObjective(objective, MDO.MAXIMIZE);
63
64 /*------------------------------------------------------------------*/
65 /* Step 3. Solve the problem and populate optimization result. */
66 /*------------------------------------------------------------------*/
67 // Optimize the model
68 m.optimize();
69 if (m.get(MDO_IntAttr_Status) == MDO_OPTIMAL)
70 {
71 cout << "Primal objective val: " << m.get(MDO_DoubleAttr_PrimalObjVal) << endl;
72 }
73 else
74 {
75 cout << "No feasible solution." << endl;
76 }
77 }
78 catch (MDOException &e)
79 {
80 cout << "Error code = " << e.getErrorCode() << endl;
81 cout << e.getMessage() << endl;
82 }
83 catch (...)
84 {
85 cout << "Error during optimization." << endl;
86 }
87
88 return static_cast<int>(MDO_OKAY);
89}
5.7.3.2. SDP Example II¶
Include the header file:
32#include "MindoptCpp.h"
Step I: Create an optimization model
Create an empty optimization model:
64 MDOEnv env = MDOEnv();
65 MDOModel m = MDOModel(env);
Step II: SDP model input
We use MDOModel::addPsdVar()
to create two new semidefinite matrix variables (in this case, \(\mathbf{X}_0, \mathbf{X}_1\)) and simultaneously set their corresponding coefficient matrices (in this case, \(\mathbf{C}_0, \mathbf{C}_1\)) in the objective function.
73 MDOPsdVar psd_var0 = m.addPsdVar(MDOMatrix::coo(dim_mat[0], dim_mat[0], C0_nnz, C0_nz_indices, C0_nz_values), "X0");
74 MDOPsdVar psd_var1 = m.addPsdVar(MDOMatrix::coo(dim_mat[1], dim_mat[1], C1_nnz, C1_nz_indices, C1_nz_values), "X1");
We then use MDOModel::addVar()
to create two linear variables representing \(x_0,x_1\) in this example.
The first and second arguments are the lower and upper bounds of the variables.
The third argument is the coefficient of the variable in the objective function.
The fourth argument is the type of the variable, which is continuous variable type (‘C’) in this case. The last argument is the name of the variable.
75 MDOVar var0 = m.addVar(0.0, MDO_INFINITY, 0.0, 'C', "x0");
76 MDOVar var1 = m.addVar(0.0, MDO_INFINITY, 0.0, 'C', "x1");
Next, we create constraints. We use MDOModel::addPsdConstr()
to establish constraints with semidefinite matrix variables.
The first argument is the semidefinite expression in the constraint. Since the constraint in this example contains both semidefinite variables and linear variables, we construct the semidefinite expression in two steps.
Firstly, we create the semidefinite term using the initialization method
MDOPsdExpr::MDOPsdExpr()
.Then, we add the remaining linear term using the
MDOPsdExpr::addTerms()
method to obtain the final semidefinite expression for the constraint.The second argument is the type of the constraint, and currently, we only support MDO_EQUAL (‘=’), which represents an equality constraint.
The third argument is the right-hand side value of the constraint (in this case, 1.0).
The last argument is the name of the constraint.
78 /* Add constraints. */
79 MDOPsdExpr psd_expr0 = MDOPsdExpr(psd_var0, MDOMatrix::coo(dim_mat[0], dim_mat[0], A0_nnz, A0_nz_indices, A0_nz_values));
80 const MDOVar row0_vars[] = { var0 };
81 psd_expr0.addTerms(row0_values, row0_vars, 1);
82 m.addPsdConstr(psd_expr0, MDO_EQUAL, 1.0, "C0");
83
84 MDOPsdExpr psd_expr1 = MDOPsdExpr(psd_var1, MDOMatrix::coo(dim_mat[1], dim_mat[1], A1_nnz, A1_nz_indices, A1_nz_values));
85 const MDOVar row1_vars[] = { var1 };
86 psd_expr1.addTerms(row1_values, row1_vars, 1);
87 m.addPsdConstr(psd_expr1, MDO_EQUAL, 2.0, "C1");
Finally, we use MDOModel::setObjective()
to set the linear part of the objective function (in this case, 0), and change the optimization direction to maximization (-1).
89 /* Set objective function. */
90 MDOLinExpr objective = 0;
91 m.setObjective(objective, MDO.MAXIMIZE);
Step III: Solve SDP model
Solve the optimization problem via MDOModel::optimize()
.
96 // Optimize the model
97 m.optimize();
Step IV: Obtain the solution of SDP problem
We use the generic function MDOModel::get()
to retrieve the optimal objective function value, i.e., the PrimalObjVal attribute.
98 if (m.get(MDO_IntAttr_Status) == MDO_OPTIMAL)
99 {
100 cout << "Primal objective val: " << m.get(MDO_DoubleAttr_PrimalObjVal) << endl;
101 }
102 else
103 {
104 cout << "No feasible solution." << endl;
105 }
The complete example code is provided in MdoSdoEx2.cpp :
1/**
2 * Description
3 * -----------
4 *
5 * Semidefinite optimization (row-wise input).
6 *
7 * Formulation
8 * -----------
9 *
10 * Maximize
11 * obj:
12 * tr(C0 X0) + tr(C1 X1) + 0 x0 + 0 x1
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 * X0,X1 are p.s.d.
20 *
21 * Matrix
22 * C0 = [ 2 1 ] A00 = [ 3 1 ]
23 * [ 1 2 ] [ 1 3 ]
24 *
25 * C1 = [ 3 0 1 ] A11 = [ 3 0 1 ]
26 * [ 0 2 0 ] [ 0 4 0 ]
27 * [ 1 0 3 ] [ 1 0 5 ]
28 * End
29 */
30
31#include <iostream>
32#include "MindoptCpp.h"
33
34using namespace std;
35
36int main(void)
37{
38 /* Model data. */
39 int num_mats = 1;
40 int dim_mat[] = { 2, 3 }; /* Dimension of the matrix variables. */
41
42 int C0_nnz = 3;
43 int C0_nz_indices[] = { 0, 1, 3 }; /* Nonzero vectorized index of obj coeff. */
44 double C0_nz_values[] = { 2.0, 1.0, 2.0 }; /* Nonzero values of obj coeff. */
45
46 int C1_nnz = 4;
47 int C1_nz_indices[] = { 0, 2, 4, 8 }; /* Nonzero vectorized index of obj coeff. */
48 double C1_nz_values[] = { 3.0, 1.0, 2.0, 3.0 }; /* Nonzero values of obj coeff. */
49
50 int A0_nnz = 3;
51 int A0_nz_indices[] = { 0, 1, 3 }; /* Nonzero vectorized index of constr coeff. */
52 double A0_nz_values[] = { 3.0, 1.0, 3.0 }; /* Nonzero values of constr coeff. */
53
54 int A1_nnz = 4;
55 int A1_nz_indices[] = { 0, 2, 4, 8 }; /* Nonzero vectorized index of constr coeff. */
56 double A1_nz_values[] = { 3.0, 1.0, 4.0, 5.0 }; /* Nonzero values of constr coeff. */
57
58 const double row0_values[] = { 1.0 };
59 const double row1_values[] = { 1.0 };
60
61 /*------------------------------------------------------------------*/
62 /* Step 1. Create environment and model. */
63 /*------------------------------------------------------------------*/
64 MDOEnv env = MDOEnv();
65 MDOModel m = MDOModel(env);
66
67 try
68 {
69 /*------------------------------------------------------------------*/
70 /* Step 2. Input model. */
71 /*------------------------------------------------------------------*/
72 /* Add variables. */
73 MDOPsdVar psd_var0 = m.addPsdVar(MDOMatrix::coo(dim_mat[0], dim_mat[0], C0_nnz, C0_nz_indices, C0_nz_values), "X0");
74 MDOPsdVar psd_var1 = m.addPsdVar(MDOMatrix::coo(dim_mat[1], dim_mat[1], C1_nnz, C1_nz_indices, C1_nz_values), "X1");
75 MDOVar var0 = m.addVar(0.0, MDO_INFINITY, 0.0, 'C', "x0");
76 MDOVar var1 = m.addVar(0.0, MDO_INFINITY, 0.0, 'C', "x1");
77
78 /* Add constraints. */
79 MDOPsdExpr psd_expr0 = MDOPsdExpr(psd_var0, MDOMatrix::coo(dim_mat[0], dim_mat[0], A0_nnz, A0_nz_indices, A0_nz_values));
80 const MDOVar row0_vars[] = { var0 };
81 psd_expr0.addTerms(row0_values, row0_vars, 1);
82 m.addPsdConstr(psd_expr0, MDO_EQUAL, 1.0, "C0");
83
84 MDOPsdExpr psd_expr1 = MDOPsdExpr(psd_var1, MDOMatrix::coo(dim_mat[1], dim_mat[1], A1_nnz, A1_nz_indices, A1_nz_values));
85 const MDOVar row1_vars[] = { var1 };
86 psd_expr1.addTerms(row1_values, row1_vars, 1);
87 m.addPsdConstr(psd_expr1, MDO_EQUAL, 2.0, "C1");
88
89 /* Set objective function. */
90 MDOLinExpr objective = 0;
91 m.setObjective(objective, MDO.MAXIMIZE);
92
93 /*------------------------------------------------------------------*/
94 /* Step 3. Solve the problem and populate optimization result. */
95 /*------------------------------------------------------------------*/
96 // Optimize the model
97 m.optimize();
98 if (m.get(MDO_IntAttr_Status) == MDO_OPTIMAL)
99 {
100 cout << "Primal objective val: " << m.get(MDO_DoubleAttr_PrimalObjVal) << endl;
101 }
102 else
103 {
104 cout << "No feasible solution." << endl;
105 }
106 }
107 catch (MDOException &e)
108 {
109 cout << "Error code = " << e.getErrorCode() << endl;
110 cout << e.getMessage() << endl;
111 }
112 catch (...)
113 {
114 cout << "Error during optimization." << endl;
115 }
116
117 return static_cast<int>(MDO_OKAY);
118}