GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tests/eiquadprog-rt.cpp Lines: 251 251 100.0 %
Date: 2023-11-29 12:38:05 Branches: 666 1332 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 "eiquadprog/eiquadprog-rt.hpp"
20
21
#include <Eigen/Core>
22
#include <boost/test/unit_test.hpp>
23
#include <iostream>
24
25
using namespace eiquadprog::solvers;
26
27
/**
28
 * solves the problem
29
 * min. 0.5 * x' Hess x + g0' x
30
 * s.t. CE x + ce0 = 0
31
 *      CI x + ci0 >= 0
32
 */
33
34
BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
35
36
// min ||x||^2
37
38
















4
BOOST_AUTO_TEST_CASE(test_unbiased) {
39
4
  RtEiquadprog<2, 0, 0> qp;
40
41
2
  RtMatrixX<2, 2>::d Q;
42
2
  Q.setZero();
43
2
  Q(0, 0) = 1.0;
44
2
  Q(1, 1) = 1.0;
45
46
2
  RtVectorX<2>::d C;
47
2
  C.setZero();
48
49
2
  RtMatrixX<0, 2>::d Aeq;
50
51
2
  RtVectorX<0>::d Beq;
52
53
2
  RtMatrixX<0, 2>::d Aineq;
54
55
2
  RtVectorX<0>::d Bineq;
56
57
2
  RtVectorX<2>::d x;
58
59
2
  RtVectorX<2>::d solution;
60
2
  solution.setZero();
61
62
2
  double val = 0.0;
63
64
2
  RtEiquadprog_status expected = RT_EIQUADPROG_OPTIMAL;
65
66
  RtEiquadprog_status status =
67
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
68
69


2
  BOOST_CHECK_EQUAL(status, expected);
70
71



2
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
72
73



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
















4
BOOST_AUTO_TEST_CASE(test_biased) {
79
4
  RtEiquadprog<2, 0, 0> qp;
80
81
2
  RtMatrixX<2, 2>::d Q;
82
2
  Q.setZero();
83
2
  Q(0, 0) = 1.0;
84
2
  Q(1, 1) = 1.0;
85
86
2
  RtVectorX<2>::d C;
87
2
  C(0) = -1.;
88
2
  C(1) = -1.;
89
90
2
  RtMatrixX<0, 2>::d Aeq;
91
92
2
  RtVectorX<0>::d Beq;
93
94
2
  RtMatrixX<0, 2>::d Aineq;
95
96
2
  RtVectorX<0>::d Bineq;
97
98
2
  RtVectorX<2>::d x;
99
100
2
  RtVectorX<2>::d solution;
101
2
  solution(0) = 1.;
102
2
  solution(1) = 1.;
103
104
2
  double val = -1.;
105
106
2
  RtEiquadprog_status expected = RT_EIQUADPROG_OPTIMAL;
107
108
  RtEiquadprog_status status =
109
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
110
111


2
  BOOST_CHECK_EQUAL(status, expected);
112
113



2
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
114
115



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
















4
BOOST_AUTO_TEST_CASE(test_equality_constraints) {
123
4
  RtEiquadprog<2, 1, 0> qp;
124
125
2
  RtMatrixX<2, 2>::d Q;
126
2
  Q.setZero();
127
2
  Q(0, 0) = 1.0;
128
2
  Q(1, 1) = 1.0;
129
130
2
  RtVectorX<2>::d C;
131
2
  C.setZero();
132
133
2
  RtMatrixX<1, 2>::d Aeq;
134
2
  Aeq(0, 0) = 1.;
135
2
  Aeq(0, 1) = 1.;
136
137
2
  RtVectorX<1>::d Beq;
138
2
  Beq(0) = -1.;
139
140
2
  RtMatrixX<0, 2>::d Aineq;
141
142
2
  RtVectorX<0>::d Bineq;
143
144
2
  RtVectorX<2>::d x;
145
146
2
  RtVectorX<2>::d solution;
147
2
  solution(0) = 0.5;
148
2
  solution(1) = 0.5;
149
150
2
  double val = 0.25;
151
152
2
  RtEiquadprog_status expected = RT_EIQUADPROG_OPTIMAL;
153
154
  RtEiquadprog_status status =
155
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
156
157


2
  BOOST_CHECK_EQUAL(status, expected);
158
159



2
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
160
161



2
  BOOST_CHECK(x.isApprox(solution));
162
2
}
163
164
// min ||x||^2
165
//    s.t.
166
// x[i] >= 1
167
168
















4
BOOST_AUTO_TEST_CASE(test_inequality_constraints) {
169
4
  RtEiquadprog<2, 0, 2> qp;
170
171
2
  RtMatrixX<2, 2>::d Q;
172
2
  Q.setZero();
173
2
  Q(0, 0) = 1.0;
174
2
  Q(1, 1) = 1.0;
175
176
2
  RtVectorX<2>::d C;
177
2
  C.setZero();
178
179
2
  RtMatrixX<0, 2>::d Aeq;
180
181
2
  RtVectorX<0>::d Beq(0);
182
183
2
  RtMatrixX<2, 2>::d Aineq;
184
2
  Aineq.setZero();
185
2
  Aineq(0, 0) = 1.;
186
2
  Aineq(1, 1) = 1.;
187
188
2
  RtVectorX<2>::d Bineq;
189
2
  Bineq(0) = -1.;
190
2
  Bineq(1) = -1.;
191
192
2
  RtVectorX<2>::d x;
193
194
2
  RtVectorX<2>::d solution;
195
2
  solution(0) = 1.;
196
2
  solution(1) = 1.;
197
198
2
  double val = 1.;
199
200
2
  RtEiquadprog_status expected = RT_EIQUADPROG_OPTIMAL;
201
202
  RtEiquadprog_status status =
203
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
204
205


2
  BOOST_CHECK_EQUAL(status, expected);
206
207



2
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
208
209



2
  BOOST_CHECK(x.isApprox(solution));
210
2
}
211
212
// min ||x-x_0||^2, x_0 = (1 1)^T
213
//    s.t.
214
// x[1] = 5 - x[0]
215
// x[1] >= 3
216
217
















4
BOOST_AUTO_TEST_CASE(test_full) {
218
4
  RtEiquadprog<2, 1, 1> qp;
219
220
2
  RtMatrixX<2, 2>::d Q;
221
2
  Q.setZero();
222
2
  Q(0, 0) = 1.0;
223
2
  Q(1, 1) = 1.0;
224
225
2
  RtVectorX<2>::d C;
226
2
  C(0) = -1.;
227
2
  C(1) = -1.;
228
229
2
  RtMatrixX<1, 2>::d Aeq;
230
2
  Aeq(0, 0) = 1.;
231
2
  Aeq(0, 1) = 1.;
232
233
2
  RtVectorX<1>::d Beq;
234
2
  Beq(0) = -5.;
235
236
2
  RtMatrixX<1, 2>::d Aineq;
237
2
  Aineq.setZero();
238
2
  Aineq(0, 1) = 1.;
239
240
2
  RtVectorX<1>::d Bineq;
241
2
  Bineq(0) = -3.;
242
243
2
  RtVectorX<2>::d x;
244
245
2
  RtVectorX<2>::d solution;
246
2
  solution(0) = 2.;
247
2
  solution(1) = 3.;
248
249
2
  double val = 1.5;
250
251
2
  RtEiquadprog_status expected = RT_EIQUADPROG_OPTIMAL;
252
253
  RtEiquadprog_status status =
254
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
255
256


2
  BOOST_CHECK_EQUAL(status, expected);
257
258



2
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
259
260



2
  BOOST_CHECK(x.isApprox(solution));
261
2
}
262
263
// min ||x||^2
264
//    s.t.
265
// x[0] =  1
266
// x[0] = -1
267
268
















4
BOOST_AUTO_TEST_CASE(test_unfeasible_equalities) {
269
4
  RtEiquadprog<2, 2, 0> qp;
270
271
2
  RtMatrixX<2, 2>::d Q;
272
2
  Q.setZero();
273
2
  Q(0, 0) = 1.0;
274
2
  Q(1, 1) = 1.0;
275
276
2
  RtVectorX<2>::d C;
277
2
  C.setZero();
278
279
2
  RtMatrixX<2, 2>::d Aeq;
280
2
  Aeq.setZero();
281
2
  Aeq(0, 0) = 1.;
282
2
  Aeq(1, 0) = 1.;
283
284
2
  RtVectorX<2>::d Beq;
285
2
  Beq(0) = -1.;
286
2
  Beq(1) = 1.;
287
288
2
  RtMatrixX<0, 2>::d Aineq;
289
290
2
  RtVectorX<0>::d Bineq;
291
292
2
  RtVectorX<2>::d x;
293
294
2
  RtEiquadprog_status expected = RT_EIQUADPROG_REDUNDANT_EQUALITIES;
295
296
  RtEiquadprog_status status =
297
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
298
299


2
  BOOST_CHECK_EQUAL(status, expected);
300
2
}
301
302
// min ||x||^2
303
//    s.t.
304
// x[0] >=  1
305
// x[0] <= -1
306
//
307
// correctly fails, but returns wrong error code
308
309
















4
BOOST_AUTO_TEST_CASE(test_unfeasible_inequalities) {
310
4
  RtEiquadprog<2, 0, 2> qp;
311
312
2
  RtMatrixX<2, 2>::d Q;
313
2
  Q.setZero();
314
2
  Q(0, 0) = 1.0;
315
2
  Q(1, 1) = 1.0;
316
317
2
  RtVectorX<2>::d C;
318
2
  C.setZero();
319
320
2
  RtMatrixX<0, 2>::d Aeq;
321
322
2
  RtVectorX<0>::d Beq;
323
324
2
  RtMatrixX<2, 2>::d Aineq;
325
2
  Aineq.setZero();
326
2
  Aineq(0, 0) = 1.;
327
2
  Aineq(1, 0) = -1.;
328
329
2
  RtVectorX<2>::d Bineq;
330
2
  Bineq(0) = -1;
331
2
  Bineq(1) = -1;
332
333
2
  RtVectorX<2>::d x;
334
335
2
  RtEiquadprog_status expected = RT_EIQUADPROG_INFEASIBLE;
336
337
  RtEiquadprog_status status =
338
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
339
340


2
  BOOST_WARN_EQUAL(status, expected);
341



2
  BOOST_CHECK(status != RT_EIQUADPROG_OPTIMAL);
342
2
}
343
344
// min ||x-x_0||^2, x_0 = (1 1)^T
345
//    s.t.
346
// x[1] = 1 - x[0]
347
// x[0] <= 0
348
// x[1] <= 0
349
//
350
// correctly fails, but returns wrong error code
351
352
















4
BOOST_AUTO_TEST_CASE(test_unfeasible_constraints) {
353
4
  RtEiquadprog<2, 1, 2> qp;
354
355
2
  RtMatrixX<2, 2>::d Q;
356
2
  Q.setZero();
357
2
  Q(0, 0) = 1.0;
358
2
  Q(1, 1) = 1.0;
359
360
2
  RtVectorX<2>::d C;
361
2
  C(0) = -1.;
362
2
  C(1) = -1.;
363
364
2
  RtMatrixX<1, 2>::d Aeq;
365
2
  Aeq(0, 0) = 1.;
366
2
  Aeq(0, 1) = 1.;
367
368
2
  RtVectorX<1>::d Beq;
369
2
  Beq(0) = -1.;
370
371
2
  RtMatrixX<2, 2>::d Aineq;
372
2
  Aineq.setZero();
373
2
  Aineq(0, 0) = -1.;
374
2
  Aineq(1, 1) = -1.;
375
376
2
  RtVectorX<2>::d Bineq;
377
2
  Bineq.setZero();
378
379
2
  RtVectorX<2>::d x;
380
381
2
  RtEiquadprog_status expected = RT_EIQUADPROG_INFEASIBLE;
382
383
  RtEiquadprog_status status =
384
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
385
386


2
  BOOST_WARN_EQUAL(status, expected);
387



2
  BOOST_CHECK(status != RT_EIQUADPROG_OPTIMAL);
388
2
}
389
390
// min -||x||^2
391
// DOES NOT WORK!
392
393
















4
BOOST_AUTO_TEST_CASE(test_unbounded) {
394
4
  RtEiquadprog<2, 0, 0> qp;
395
396
2
  RtMatrixX<2, 2>::d Q;
397
2
  Q.setZero();
398
2
  Q(0, 0) = -1.0;
399
2
  Q(1, 1) = -1.0;
400
401
2
  RtVectorX<2>::d C;
402
2
  C.setZero();
403
404
2
  RtMatrixX<0, 2>::d Aeq;
405
406
2
  RtVectorX<0>::d Beq;
407
408
2
  RtMatrixX<0, 2>::d Aineq;
409
410
2
  RtVectorX<0>::d Bineq;
411
412
2
  RtVectorX<2>::d x;
413
414
2
  RtEiquadprog_status expected = RT_EIQUADPROG_UNBOUNDED;
415
416
  RtEiquadprog_status status =
417
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
418
419


2
  BOOST_WARN_EQUAL(status, expected);
420



2
  BOOST_WARN(status != RT_EIQUADPROG_OPTIMAL);  // SHOULD pass!
421
2
}
422
423
// min -||x||^2
424
//    s.t.
425
// 0<= x[0] <= 1
426
// 0<= x[1] <= 1
427
// DOES NOT WORK!
428
429
















4
BOOST_AUTO_TEST_CASE(test_nonconvex) {
430
4
  RtEiquadprog<2, 0, 4> qp;
431
432
2
  RtMatrixX<2, 2>::d Q;
433
2
  Q.setZero();
434
2
  Q(0, 0) = -1.0;
435
2
  Q(1, 1) = -1.0;
436
437
2
  RtVectorX<2>::d C;
438
2
  C.setZero();
439
440
2
  RtMatrixX<0, 2>::d Aeq;
441
442
2
  RtVectorX<0>::d Beq;
443
444
2
  RtMatrixX<4, 2>::d Aineq(4, 2);
445
2
  Aineq.setZero();
446
2
  Aineq(0, 0) = 1.;
447
2
  Aineq(1, 0) = -1.;
448
2
  Aineq(2, 1) = 1.;
449
2
  Aineq(3, 1) = -1.;
450
451
2
  RtVectorX<4>::d Bineq;
452
2
  Bineq(0) = 0.;
453
2
  Bineq(1) = 1.;
454
2
  Bineq(2) = 0.;
455
2
  Bineq(3) = 1.;
456
457
2
  RtVectorX<2>::d x;
458
459
2
  RtVectorX<2>::d solution;
460
2
  solution(0) = 1.;
461
2
  solution(1) = 1.;
462
463
2
  double val = -1.;
464
465
2
  RtEiquadprog_status expected = RT_EIQUADPROG_OPTIMAL;
466
467
  RtEiquadprog_status status =
468
2
      qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
469
470


2
  BOOST_CHECK_EQUAL(status, expected);
471
472



2
  BOOST_WARN_CLOSE(qp.getObjValue(), val, 1e-6);
473
474



2
  BOOST_WARN(x.isApprox(solution));
475
2
}
476
477
BOOST_AUTO_TEST_SUITE_END()