test_solver_osqp.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement
4  *
5  * Copyright (c) 2020,
6  * TU Dortmund - Institute of Control Theory and Systems Engineering.
7  * All rights reserved.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  *
22  * Authors: Christoph Rösmann
23  *********************************************************************/
24 
25 #include <corbo-core/console.h>
26 
27 #include "gtest/gtest.h"
28 
29 #ifdef OSQP
30 
33 
34 #include <corbo-core/macros.h>
35 #include <corbo-core/utilities.h>
37 
38 #include <array>
39 #include <functional>
40 #include <memory>
41 
42 // using corbo::SimpleOptimizationProblemWithCallbacks;
43 // using corbo::SolverOsqp;
44 
45 class TestSolverOsqp : public testing::Test
46 {
47  protected:
48  // You can do set-up work for each test here.
49  TestSolverOsqp() {}
50  // You can do clean-up work that doesn't throw exceptions here.
51  virtual ~TestSolverOsqp() {}
52  // If the constructor and destructor are not enough for setting up
53  // and cleaning up each test, you can define the following methods:
54 
55  // Code here will be called immediately after the constructor (right
56  // before each test).
57  void SetUp() override
58  {
59  // configure solver
60  // EXPECT_TRUE(solver.initialize(&optim)); // we need to initialize the sover before setting parameters
61  }
62  // Code here will be called immediately after each test (right
63  // before the destructor).
64  // virtual void TearDown()
65 
66  // SimpleOptimizationProblemWithCallbacks optim;
67 
68  // SolverOsqp solver;
69 };
70 TEST_F(TestSolverOsqp, osqp_demo)
71 {
73 
74  // Load problem data (sparse format)
75  // 0.5*x^T * P * x + q*x s.t. l <= A <= u with P: n x n and A: n x m
76  c_int n = 2;
77  c_int m = 3;
78 
79  c_int P_nnz = 3;
80  Eigen::Vector3d P_x; // value vector
81  P_x << 4, 1, 2;
82  VectorXl P_i(3); // row indices
83  P_i << 0, 0, 1;
84  VectorXl P_p(3); // column pointers
85  P_p << 0, 1, 3;
86  csc* P = csc_matrix(n, n, P_nnz, P_x.data(), P_i.data(), P_p.data());
87 
88  Eigen::Vector2d q(1, 1);
89 
90  c_int A_nnz = 4;
91  Eigen::Vector4d A_x;
92  A_x << 1, 1, 1, 1;
93  VectorXl A_i(4);
94  A_i << 0, 1, 0, 2;
95  VectorXl A_p(3);
96  A_p << 0, 2, 4;
97  csc* A = csc_matrix(m, n, A_nnz, A_x.data(), A_i.data(), A_p.data());
98 
99  Eigen::Vector3d l(1, 0, 0);
100  Eigen::Vector3d u(1, 0.7, 0.7);
101 
102  // Problem settings
103  std::unique_ptr<OSQPSettings> settings = std::unique_ptr<OSQPSettings>(new OSQPSettings);
104 
105  // Populate data
106  std::unique_ptr<OSQPData> data = std::unique_ptr<OSQPData>(new OSQPData);
107  data->n = n;
108  data->m = m;
109  data->P = P;
110  data->q = q.data();
111  data->A = A;
112  data->l = l.data();
113  data->u = u.data();
114 
115  // Define Solver settings as default
116  osqp_set_default_settings(settings.get());
117  settings->verbose = 0;
118  settings->alpha = 1.0; // Change alpha parameter
119 
120  // Setup workspace
121  OSQPWorkspace* work;
122  c_int exitflag = osqp_setup(&work, data.get(), settings.get());
123  EXPECT_EQ(exitflag, 0);
124 
125  // Solve Problem
126  osqp_solve(work);
127 
128  // Access solution
129  const Eigen::Map<const Eigen::VectorXd> x_sol(work->solution->x, n);
130 
131  EXPECT_NEAR(x_sol[0], 0.3, 1e-2);
132  EXPECT_NEAR(x_sol[1], 0.7, 1e-2);
133 
134  // Cleanup
135  osqp_cleanup(work);
136  c_free(A);
137  c_free(P);
138 }
139 
140 TEST_F(TestSolverOsqp, osqp_demo_eigen_sparse_interface)
141 {
143 
144  // Load problem data (sparse format)
145  // 0.5*x^T * P * x + q*x s.t. l <= A <= u with P: n x n and A: n x m
146 
147  c_int n = 2;
148  c_int m = 3;
149 
150  Eigen::MatrixXd P(n, n);
151  P << 4, 1, 1, 2;
152 
153  Eigen::VectorXd q(n);
154  q << 1, 1;
155 
156  Eigen::MatrixXd A(m, n);
157  A << 1, 1, 1, 0, 0, 1;
158 
159  Eigen::VectorXd l(m);
160  l << 1, 0, 0;
161  Eigen::VectorXd u(m);
162  u << 1, 0.7, 0.7;
163 
165  P_sp = P.sparseView();
166  P_sp = P_sp.triangularView<Eigen::Upper>();
167  P_sp.makeCompressed();
168 
170  A_sp = A.sparseView();
171  A_sp.makeCompressed();
172 
173  // just for testing:
174  Eigen::Map<Eigen::VectorXd> P_v(P_sp.valuePtr(), P_sp.nonZeros());
175  EXPECT_EQ(P_v.size(), 3);
176  EXPECT_EQ(P_v[0], 4);
177  EXPECT_EQ(P_v[1], 1);
178  EXPECT_EQ(P_v[2], 2);
179  Eigen::Map<VectorXl> P_i(P_sp.innerIndexPtr(), P_sp.nonZeros());
180  EXPECT_EQ(P_i.size(), 3);
181  EXPECT_EQ(P_i[0], 0);
182  EXPECT_EQ(P_i[1], 0);
183  EXPECT_EQ(P_i[2], 1);
184  Eigen::Map<VectorXl> P_p(P_sp.outerIndexPtr(), P_sp.outerSize() + 1);
185  EXPECT_EQ(P_p.size(), 3);
186  EXPECT_EQ(P_p[0], 0);
187  EXPECT_EQ(P_p[1], 1);
188  EXPECT_EQ(P_p[2], 3);
189 
190  Eigen::Map<Eigen::VectorXd> A_v(A_sp.valuePtr(), A_sp.nonZeros());
191  EXPECT_EQ(A_v.size(), 4);
192  EXPECT_EQ(A_v[0], 1);
193  EXPECT_EQ(A_v[1], 1);
194  EXPECT_EQ(A_v[2], 1);
195  EXPECT_EQ(A_v[3], 1);
196  Eigen::Map<VectorXl> A_i(A_sp.innerIndexPtr(), A_sp.nonZeros());
197  EXPECT_EQ(A_i.size(), 4);
198  EXPECT_EQ(A_i[0], 0);
199  EXPECT_EQ(A_i[1], 1);
200  EXPECT_EQ(A_i[2], 0);
201  EXPECT_EQ(A_i[3], 2);
202  Eigen::Map<VectorXl> A_p(A_sp.outerIndexPtr(), A_sp.outerSize() + 1);
203  EXPECT_EQ(A_p.size(), 3);
204  EXPECT_EQ(A_p[0], 0);
205  EXPECT_EQ(A_p[1], 2);
206  EXPECT_EQ(A_p[2], 4);
207 
208  csc* P_csc = csc_matrix(n, n, P_sp.nonZeros(), P_sp.valuePtr(), P_sp.innerIndexPtr(), P_sp.outerIndexPtr());
209 
210  csc* A_csc = csc_matrix(m, n, A_sp.nonZeros(), A_sp.valuePtr(), A_sp.innerIndexPtr(), A_sp.outerIndexPtr());
211 
212  // Problem settings
213  std::unique_ptr<OSQPSettings> settings = std::unique_ptr<OSQPSettings>(new OSQPSettings);
214 
215  // Populate data
216  std::unique_ptr<OSQPData> data = std::unique_ptr<OSQPData>(new OSQPData);
217  data->n = n;
218  data->m = m;
219  data->P = P_csc;
220  data->q = q.data();
221  data->A = A_csc;
222  data->l = l.data();
223  data->u = u.data();
224 
225  // Define Solver settings as default
226  osqp_set_default_settings(settings.get());
227  settings->verbose = 0;
228  settings->alpha = 1.0; // Change alpha parameter
229 
230  // Setup workspace
231  OSQPWorkspace* work;
232  c_int exitflag = osqp_setup(&work, data.get(), settings.get());
233  EXPECT_EQ(exitflag, 0);
234 
235  // Solve Problem
236  osqp_solve(work);
237 
238  // Access solution
239  const Eigen::Map<const Eigen::VectorXd> x_sol(work->solution->x, n);
240 
241  EXPECT_NEAR(x_sol[0], 0.3, 1e-4);
242  EXPECT_NEAR(x_sol[1], 0.7, 1e-4);
243 
244  // Cleanup
245  osqp_cleanup(work);
246  c_free(P_csc);
247  c_free(A_csc);
248 }
249 
250 #else // OSQP
251 
252 class TestSolverOsqp : public testing::Test
253 {
254  protected:
255  // You can do set-up work for each test here.
256  TestSolverOsqp() {}
257  // You can do clean-up work that doesn't throw exceptions here.
258  virtual ~TestSolverOsqp() {}
259 };
260 
261 TEST_F(TestSolverOsqp, osqp_not_found) { PRINT_WARNING("Skipping OSQP tests, since OSQP is not found."); }
262 
263 #endif // OSQP
Eigen::SparseMatrix
A versatible sparse matrix representation.
Definition: SparseMatrix.h:96
PRINT_WARNING
#define PRINT_WARNING(msg)
Print msg-stream.
Definition: console.h:145
TEST_F
TEST_F(TestSolverOsqp, osqp_not_found)
Definition: test_solver_osqp.cpp:261
simple_optimization_problem.h
TestSolverOsqp::TestSolverOsqp
TestSolverOsqp()
Definition: test_solver_osqp.cpp:278
Eigen::Upper
@ Upper
Definition: Constants.h:206
macros.h
console.h
Eigen::SparseMatrix::nonZeros
Index nonZeros() const
Definition: SparseCompressedBase.h:56
utilities.h
value_comparison.h
Eigen::SparseMatrix::valuePtr
const Scalar * valuePtr() const
Definition: SparseMatrix.h:148
TestSolverOsqp::~TestSolverOsqp
virtual ~TestSolverOsqp()
Definition: test_solver_osqp.cpp:280
Eigen::SparseMatrix::innerIndexPtr
const StorageIndex * innerIndexPtr() const
Definition: SparseMatrix.h:157
Eigen::numext::q
EIGEN_DEVICE_FUNC const Scalar & q
Definition: SpecialFunctionsImpl.h:1520
TestSolverOsqp
Definition: test_solver_osqp.cpp:252
Eigen::SparseMatrix::outerSize
Index outerSize() const
Definition: SparseMatrix.h:143
Eigen::Map
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:94
Eigen::SparseMatrix::outerIndexPtr
const StorageIndex * outerIndexPtr() const
Definition: SparseMatrix.h:166
qp_solver_osqp.h
Eigen::Matrix
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:178
n
PlainMatrixType mat * n
Definition: eigenvalues.cpp:41
A
MatrixType A(a, *n, *n, *lda)
Eigen::SparseMatrix::makeCompressed
void makeCompressed()
Definition: SparseMatrix.h:464


control_box_rst
Author(s): Christoph Rösmann
autogenerated on Wed Mar 2 2022 00:07:06