GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tests/eiquadprog-basic.cpp Lines: 238 238 100.0 %
Date: 2023-11-29 12:38:05 Branches: 622 1244 50.0 %

Line Branch Exec Source
1
//
2
// Copyright (c) 2019 CNRS
3
//
4
// This file is part of eiquadprog.
5
//
6
// eiquadprog is free software: you can redistribute it and/or modify
7
// it under the terms of the GNU Lesser General Public License as published by
8
// the Free Software Foundation, either version 3 of the License, or
9
//(at your option) any later version.
10
11
// eiquadprog is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
// GNU Lesser General Public License for more details.
15
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with eiquadprog.  If not, see <https://www.gnu.org/licenses/>.
18
19
#include <Eigen/Core>
20
#include <boost/test/unit_test.hpp>
21
#include <iostream>
22
23
#include "eiquadprog/eiquadprog.hpp"
24
25
// The problem is in the form:
26
// min 0.5 * x G x + g0 x
27
// s.t.
28
// CE^T x + ce0 = 0
29
// CI^T x + ci0 >= 0
30
// The matrix and vectors dimensions are as follows:
31
// G: n * n
32
// g0: n
33
// CE: n * p
34
// ce0: p
35
// CI: n * m
36
// ci0: m
37
// x: n
38
39
BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
40
41
// min ||x||^2
42
43
















4
BOOST_AUTO_TEST_CASE(test_unbiased) {
44
4
  Eigen::MatrixXd Q(2, 2);
45
2
  Q.setZero();
46
2
  Q(0, 0) = 1.0;
47
2
  Q(1, 1) = 1.0;
48
49
4
  Eigen::VectorXd C(2);
50
2
  C.setZero();
51
52
4
  Eigen::MatrixXd Aeq(2, 0);
53
54
4
  Eigen::VectorXd Beq(0);
55
56
4
  Eigen::MatrixXd Aineq(2, 0);
57
58
4
  Eigen::VectorXd Bineq(0);
59
60
4
  Eigen::VectorXd x(2);
61
4
  Eigen::VectorXi activeSet(0);
62
  size_t activeSetSize;
63
64
4
  Eigen::VectorXd solution(2);
65
2
  solution.setZero();
66
67
2
  double val = 0.0;
68
69
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
70
2
                                                   x, activeSet, activeSetSize);
71
72



2
  BOOST_CHECK_CLOSE(out, val, 1e-6);
73
74



2
  BOOST_CHECK(x.isApprox(solution));
75
2
}
76
77
// min ||x-x_0||^2, x_0 = (1 1)^T
78
79
















4
BOOST_AUTO_TEST_CASE(test_biased) {
80
4
  Eigen::MatrixXd Q(2, 2);
81
2
  Q.setZero();
82
2
  Q(0, 0) = 1.0;
83
2
  Q(1, 1) = 1.0;
84
85
4
  Eigen::VectorXd C(2);
86
2
  C(0) = -1.;
87
2
  C(1) = -1.;
88
89
4
  Eigen::MatrixXd Aeq(2, 0);
90
91
4
  Eigen::VectorXd Beq(0);
92
93
4
  Eigen::MatrixXd Aineq(2, 0);
94
95
4
  Eigen::VectorXd Bineq(0);
96
97
4
  Eigen::VectorXd x(2);
98
4
  Eigen::VectorXi activeSet(0);
99
  size_t activeSetSize;
100
101
4
  Eigen::VectorXd solution(2);
102
2
  solution(0) = 1.;
103
2
  solution(1) = 1.;
104
105
2
  double val = -1.;
106
107
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
108
2
                                                   x, activeSet, activeSetSize);
109
110



2
  BOOST_CHECK_CLOSE(out, val, 1e-6);
111
112



2
  BOOST_CHECK(x.isApprox(solution));
113
2
}
114
115
// min ||x||^2
116
//    s.t.
117
// x[1] = 1 - x[0]
118
119
















4
BOOST_AUTO_TEST_CASE(test_equality_constraints) {
120
4
  Eigen::MatrixXd Q(2, 2);
121
2
  Q.setZero();
122
2
  Q(0, 0) = 1.0;
123
2
  Q(1, 1) = 1.0;
124
125
4
  Eigen::VectorXd C(2);
126
2
  C.setZero();
127
128
4
  Eigen::MatrixXd Aeq(2, 1);
129
2
  Aeq(0, 0) = 1.;
130
2
  Aeq(1, 0) = 1.;
131
132
4
  Eigen::VectorXd Beq(1);
133
2
  Beq(0) = -1.;
134
135
4
  Eigen::MatrixXd Aineq(2, 0);
136
137
4
  Eigen::VectorXd Bineq(0);
138
139
4
  Eigen::VectorXd x(2);
140
4
  Eigen::VectorXi activeSet(1);
141
  size_t activeSetSize;
142
143
4
  Eigen::VectorXd solution(2);
144
2
  solution(0) = 0.5;
145
2
  solution(1) = 0.5;
146
147
2
  double val = 0.25;
148
149
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
150
2
                                                   x, activeSet, activeSetSize);
151
152



2
  BOOST_CHECK_CLOSE(out, val, 1e-6);
153
154



2
  BOOST_CHECK(x.isApprox(solution));
155
2
}
156
157
// min ||x||^2
158
//    s.t.
159
// x[i] >= 1
160
161
















4
BOOST_AUTO_TEST_CASE(test_inequality_constraints) {
162
4
  Eigen::MatrixXd Q(2, 2);
163
2
  Q.setZero();
164
2
  Q(0, 0) = 1.0;
165
2
  Q(1, 1) = 1.0;
166
167
4
  Eigen::VectorXd C(2);
168
2
  C.setZero();
169
170
4
  Eigen::MatrixXd Aeq(2, 0);
171
172
4
  Eigen::VectorXd Beq(0);
173
174
4
  Eigen::MatrixXd Aineq(2, 2);
175
2
  Aineq.setZero();
176
2
  Aineq(0, 0) = 1.;
177
2
  Aineq(1, 1) = 1.;
178
179
4
  Eigen::VectorXd Bineq(2);
180
2
  Bineq(0) = -1.;
181
2
  Bineq(1) = -1.;
182
183
4
  Eigen::VectorXd x(2);
184
4
  Eigen::VectorXi activeSet(2);
185
  size_t activeSetSize;
186
187
4
  Eigen::VectorXd solution(2);
188
2
  solution(0) = 1.;
189
2
  solution(1) = 1.;
190
191
2
  double val = 1.;
192
193
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
194
2
                                                   x, activeSet, activeSetSize);
195
196



2
  BOOST_CHECK_CLOSE(out, val, 1e-6);
197
198



2
  BOOST_CHECK(x.isApprox(solution));
199
2
}
200
201
// min ||x-x_0||^2, x_0 = (1 1)^T
202
//    s.t.
203
// x[1] = 5 - x[0]
204
// x[1] >= 3
205
206
















4
BOOST_AUTO_TEST_CASE(test_full) {
207
4
  Eigen::MatrixXd Q(2, 2);
208
2
  Q.setZero();
209
2
  Q(0, 0) = 1.0;
210
2
  Q(1, 1) = 1.0;
211
212
4
  Eigen::VectorXd C(2);
213
2
  C(0) = -1.;
214
2
  C(1) = -1.;
215
216
4
  Eigen::MatrixXd Aeq(2, 1);
217
2
  Aeq(0, 0) = 1.;
218
2
  Aeq(1, 0) = 1.;
219
220
4
  Eigen::VectorXd Beq(1);
221
2
  Beq(0) = -5.;
222
223
4
  Eigen::MatrixXd Aineq(2, 1);
224
2
  Aineq.setZero();
225
2
  Aineq(1, 0) = 1.;
226
227
4
  Eigen::VectorXd Bineq(1);
228
2
  Bineq(0) = -3.;
229
230
4
  Eigen::VectorXd x(2);
231
4
  Eigen::VectorXi activeSet(2);
232
  size_t activeSetSize;
233
234
4
  Eigen::VectorXd solution(2);
235
2
  solution(0) = 2.;
236
2
  solution(1) = 3.;
237
238
2
  double val = 1.5;
239
240
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
241
2
                                                   x, activeSet, activeSetSize);
242
243



2
  BOOST_CHECK_CLOSE(out, val, 1e-6);
244
245



2
  BOOST_CHECK(x.isApprox(solution));
246
2
}
247
248
// min ||x||^2
249
//    s.t.
250
// x[0] =  1
251
// x[0] = -1
252
// DOES NOT WORK!
253
254
















4
BOOST_AUTO_TEST_CASE(test_unfeasible_equalities) {
255
4
  Eigen::MatrixXd Q(2, 2);
256
2
  Q.setZero();
257
2
  Q(0, 0) = 1.0;
258
2
  Q(1, 1) = 1.0;
259
260
4
  Eigen::VectorXd C(2);
261
2
  C.setZero();
262
263
4
  Eigen::MatrixXd Aeq(2, 2);
264
2
  Aeq.setZero();
265
2
  Aeq(0, 0) = 1.;
266
2
  Aeq(0, 1) = 1.;
267
268
4
  Eigen::VectorXd Beq(2);
269
2
  Beq(0) = -1.;
270
2
  Beq(1) = 1.;
271
272
4
  Eigen::MatrixXd Aineq(2, 0);
273
274
4
  Eigen::VectorXd Bineq(0);
275
276
4
  Eigen::VectorXd x(2);
277
4
  Eigen::VectorXi activeSet(2);
278
  size_t activeSetSize;
279
280
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
281
                                                   x, activeSet, activeSetSize);
282
283
  // DOES NOT WORK!?
284



2
  BOOST_WARN(std::isinf(out));
285
2
}
286
287
// min ||x||^2
288
//    s.t.
289
// x[0] >=  1
290
// x[0] <= -1
291
292
















4
BOOST_AUTO_TEST_CASE(test_unfeasible_inequalities) {
293
4
  Eigen::MatrixXd Q(2, 2);
294
2
  Q.setZero();
295
2
  Q(0, 0) = 1.0;
296
2
  Q(1, 1) = 1.0;
297
298
4
  Eigen::VectorXd C(2);
299
2
  C.setZero();
300
301
4
  Eigen::MatrixXd Aeq(2, 0);
302
303
4
  Eigen::VectorXd Beq(0);
304
305
4
  Eigen::MatrixXd Aineq(2, 2);
306
2
  Aineq.setZero();
307
2
  Aineq(0, 0) = 1.;
308
2
  Aineq(0, 1) = -1.;
309
310
4
  Eigen::VectorXd Bineq(2);
311
2
  Bineq(0) = -1;
312
2
  Bineq(1) = -1;
313
314
4
  Eigen::VectorXd x(2);
315
4
  Eigen::VectorXi activeSet(2);
316
  size_t activeSetSize;
317
318
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
319
                                                   x, activeSet, activeSetSize);
320
321



2
  BOOST_CHECK(std::isinf(out));
322
2
}
323
324
// min ||x-x_0||^2, x_0 = (1 1)^T
325
//    s.t.
326
// x[1] = 1 - x[0]
327
// x[0] <= 0
328
// x[1] <= 0
329
330
















4
BOOST_AUTO_TEST_CASE(test_unfeasible_constraints) {
331
4
  Eigen::MatrixXd Q(2, 2);
332
2
  Q.setZero();
333
2
  Q(0, 0) = 1.0;
334
2
  Q(1, 1) = 1.0;
335
336
4
  Eigen::VectorXd C(2);
337
2
  C(0) = -1.;
338
2
  C(1) = -1.;
339
340
4
  Eigen::MatrixXd Aeq(2, 1);
341
2
  Aeq(0, 0) = 1.;
342
2
  Aeq(1, 0) = 1.;
343
344
4
  Eigen::VectorXd Beq(1);
345
2
  Beq(0) = -1.;
346
347
4
  Eigen::MatrixXd Aineq(2, 2);
348
2
  Aineq.setZero();
349
2
  Aineq(0, 0) = -1.;
350
2
  Aineq(1, 1) = -1.;
351
352
4
  Eigen::VectorXd Bineq(2);
353
2
  Bineq.setZero();
354
355
4
  Eigen::VectorXd x(2);
356
4
  Eigen::VectorXi activeSet(3);
357
  size_t activeSetSize;
358
359
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
360
                                                   x, activeSet, activeSetSize);
361
362



2
  BOOST_CHECK(std::isinf(out));
363
2
}
364
365
// min -||x||^2
366
// DOES NOT WORK!
367
368
















4
BOOST_AUTO_TEST_CASE(test_unbounded) {
369
4
  Eigen::MatrixXd Q(2, 2);
370
2
  Q.setZero();
371
2
  Q(0, 0) = -1.0;
372
2
  Q(1, 1) = -1.0;
373
374
4
  Eigen::VectorXd C(2);
375
2
  C.setZero();
376
377
4
  Eigen::MatrixXd Aeq(2, 0);
378
379
4
  Eigen::VectorXd Beq(0);
380
381
4
  Eigen::MatrixXd Aineq(2, 0);
382
383
4
  Eigen::VectorXd Bineq(0);
384
385
4
  Eigen::VectorXd x(2);
386
4
  Eigen::VectorXi activeSet(0);
387
  size_t activeSetSize;
388
389
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
390
                                                   x, activeSet, activeSetSize);
391
392
  // DOES NOT WORK!?
393



2
  BOOST_WARN(std::isinf(out));
394
2
}
395
396
// min -||x||^2
397
//    s.t.
398
// 0<= x[0] <= 1
399
// 0<= x[1] <= 1
400
// DOES NOT WORK!
401
402
















4
BOOST_AUTO_TEST_CASE(test_nonconvex) {
403
4
  Eigen::MatrixXd Q(2, 2);
404
2
  Q.setZero();
405
2
  Q(0, 0) = -1.0;
406
2
  Q(1, 1) = -1.0;
407
408
4
  Eigen::VectorXd C(2);
409
2
  C.setZero();
410
411
4
  Eigen::MatrixXd Aeq(2, 0);
412
413
4
  Eigen::VectorXd Beq(0);
414
415
4
  Eigen::MatrixXd Aineq(2, 4);
416
2
  Aineq.setZero();
417
2
  Aineq(0, 0) = 1.;
418
2
  Aineq(0, 1) = -1.;
419
2
  Aineq(1, 2) = 1.;
420
2
  Aineq(1, 3) = -1.;
421
422
4
  Eigen::VectorXd Bineq(4);
423
2
  Bineq(0) = 0.;
424
2
  Bineq(1) = 1.;
425
2
  Bineq(2) = 0.;
426
2
  Bineq(3) = 1.;
427
428
4
  Eigen::VectorXd x(2);
429
4
  Eigen::VectorXi activeSet(4);
430
  size_t activeSetSize;
431
432
4
  Eigen::VectorXd solution(2);
433
2
  solution(0) = 1.;
434
2
  solution(1) = 1.;
435
436
2
  double val = -1.;
437
438
2
  double out = eiquadprog::solvers::solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq,
439
2
                                                   x, activeSet, activeSetSize);
440
441
  // DOES NOT WORK!?
442



2
  BOOST_WARN_CLOSE(out, val, 1e-6);
443
444



2
  BOOST_WARN(x.isApprox(solution));
445
2
}
446
447
BOOST_AUTO_TEST_SUITE_END()