GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: tests/eiquadprog-fast.cpp Lines: 263 263 100.0 %
Date: 2021-03-10 23:02:29 Branches: 745 1490 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 <iostream>
20
21
#include <Eigen/Core>
22
23
#include <boost/test/unit_test.hpp>
24
25
#include "eiquadprog/eiquadprog-fast.hpp"
26
27
using namespace eiquadprog::solvers;
28
29
/**
30
 * solves the problem
31
 * min. 0.5 * x' Hess x + g0' x
32
 * s.t. CE x + ce0 = 0
33
 *      CI x + ci0 >= 0
34
 */
35
36

1
BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
37
38
// min ||x||^2
39
40


















3
BOOST_AUTO_TEST_CASE(test_unbiased) {
41
2
  EiquadprogFast qp;
42
1
  qp.reset(2, 0, 0);
43
44
2
  Eigen::MatrixXd Q(2, 2);
45
1
  Q.setZero();
46
1
  Q(0, 0) = 1.0;
47
1
  Q(1, 1) = 1.0;
48
49
2
  Eigen::VectorXd C(2);
50
1
  C.setZero();
51
52
2
  Eigen::MatrixXd Aeq(0, 2);
53
54
2
  Eigen::VectorXd Beq(0);
55
56
2
  Eigen::MatrixXd Aineq(0, 2);
57
58
2
  Eigen::VectorXd Bineq(0);
59
60
2
  Eigen::VectorXd x(2);
61
62
2
  Eigen::VectorXd solution(2);
63
1
  solution.setZero();
64
65
1
  double val = 0.0;
66
67
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_OPTIMAL;
68
69
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
70
71



1
  BOOST_CHECK_EQUAL(status, expected);
72
73



1
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
74
75




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


















3
BOOST_AUTO_TEST_CASE(test_biased) {
81
2
  EiquadprogFast qp;
82
1
  qp.reset(2, 0, 0);
83
84
2
  Eigen::MatrixXd Q(2, 2);
85
1
  Q.setZero();
86
1
  Q(0, 0) = 1.0;
87
1
  Q(1, 1) = 1.0;
88
89
2
  Eigen::VectorXd C(2);
90
1
  C(0) = -1.;
91
1
  C(1) = -1.;
92
93
2
  Eigen::MatrixXd Aeq(0, 2);
94
95
2
  Eigen::VectorXd Beq(0);
96
97
2
  Eigen::MatrixXd Aineq(0, 2);
98
99
2
  Eigen::VectorXd Bineq(0);
100
101
2
  Eigen::VectorXd x(2);
102
103
2
  Eigen::VectorXd solution(2);
104
1
  solution(0) = 1.;
105
1
  solution(1) = 1.;
106
107
1
  double val = -1.;
108
109
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_OPTIMAL;
110
111
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
112
113



1
  BOOST_CHECK_EQUAL(status, expected);
114
115



1
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
116
117




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


















3
BOOST_AUTO_TEST_CASE(test_equality_constraints) {
125
2
  EiquadprogFast qp;
126
1
  qp.reset(2, 1, 0);
127
128
2
  Eigen::MatrixXd Q(2, 2);
129
1
  Q.setZero();
130
1
  Q(0, 0) = 1.0;
131
1
  Q(1, 1) = 1.0;
132
133
2
  Eigen::VectorXd C(2);
134
1
  C.setZero();
135
136
2
  Eigen::MatrixXd Aeq(1, 2);
137
1
  Aeq(0, 0) = 1.;
138
1
  Aeq(0, 1) = 1.;
139
140
2
  Eigen::VectorXd Beq(1);
141
1
  Beq(0) = -1.;
142
143
2
  Eigen::MatrixXd Aineq(0, 2);
144
145
2
  Eigen::VectorXd Bineq(0);
146
147
2
  Eigen::VectorXd x(2);
148
149
2
  Eigen::VectorXd solution(2);
150
1
  solution(0) = 0.5;
151
1
  solution(1) = 0.5;
152
153
1
  double val = 0.25;
154
155
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_OPTIMAL;
156
157
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
158
159



1
  BOOST_CHECK_EQUAL(status, expected);
160
161



1
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
162
163




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


















3
BOOST_AUTO_TEST_CASE(test_inequality_constraints) {
171
2
  EiquadprogFast qp;
172
1
  qp.reset(2, 0, 2);
173
174
2
  Eigen::MatrixXd Q(2, 2);
175
1
  Q.setZero();
176
1
  Q(0, 0) = 1.0;
177
1
  Q(1, 1) = 1.0;
178
179
2
  Eigen::VectorXd C(2);
180
1
  C.setZero();
181
182
2
  Eigen::MatrixXd Aeq(0, 2);
183
184
2
  Eigen::VectorXd Beq(0);
185
186
2
  Eigen::MatrixXd Aineq(2, 2);
187
1
  Aineq.setZero();
188
1
  Aineq(0, 0) = 1.;
189
1
  Aineq(1, 1) = 1.;
190
191
2
  Eigen::VectorXd Bineq(2);
192
1
  Bineq(0) = -1.;
193
1
  Bineq(1) = -1.;
194
195
2
  Eigen::VectorXd x(2);
196
197
2
  Eigen::VectorXd solution(2);
198
1
  solution(0) = 1.;
199
1
  solution(1) = 1.;
200
201
1
  double val = 1.;
202
203
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_OPTIMAL;
204
205
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
206
207



1
  BOOST_CHECK_EQUAL(status, expected);
208
209



1
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
210
211




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


















3
BOOST_AUTO_TEST_CASE(test_full) {
220
2
  EiquadprogFast qp;
221
1
  qp.reset(2, 1, 1);
222
223
2
  Eigen::MatrixXd Q(2, 2);
224
1
  Q.setZero();
225
1
  Q(0, 0) = 1.0;
226
1
  Q(1, 1) = 1.0;
227
228
2
  Eigen::VectorXd C(2);
229
1
  C(0) = -1.;
230
1
  C(1) = -1.;
231
232
2
  Eigen::MatrixXd Aeq(1, 2);
233
1
  Aeq(0, 0) = 1.;
234
1
  Aeq(0, 1) = 1.;
235
236
2
  Eigen::VectorXd Beq(1);
237
1
  Beq(0) = -5.;
238
239
2
  Eigen::MatrixXd Aineq(1, 2);
240
1
  Aineq.setZero();
241
1
  Aineq(0, 1) = 1.;
242
243
2
  Eigen::VectorXd Bineq(1);
244
1
  Bineq(0) = -3.;
245
246
2
  Eigen::VectorXd x(2);
247
248
2
  Eigen::VectorXd solution(2);
249
1
  solution(0) = 2.;
250
1
  solution(1) = 3.;
251
252
1
  double val = 1.5;
253
254
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_OPTIMAL;
255
256
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
257
258



1
  BOOST_CHECK_EQUAL(status, expected);
259
260



1
  BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
261
262




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


















3
BOOST_AUTO_TEST_CASE(test_unfeasible_equalities) {
271
2
  EiquadprogFast qp;
272
1
  qp.reset(2, 2, 0);
273
274
2
  Eigen::MatrixXd Q(2, 2);
275
1
  Q.setZero();
276
1
  Q(0, 0) = 1.0;
277
1
  Q(1, 1) = 1.0;
278
279
2
  Eigen::VectorXd C(2);
280
1
  C.setZero();
281
282
2
  Eigen::MatrixXd Aeq(2, 2);
283
1
  Aeq.setZero();
284
1
  Aeq(0, 0) = 1.;
285
1
  Aeq(1, 0) = 1.;
286
287
2
  Eigen::VectorXd Beq(2);
288
1
  Beq(0) = -1.;
289
1
  Beq(1) = 1.;
290
291
2
  Eigen::MatrixXd Aineq(0, 2);
292
293
2
  Eigen::VectorXd Bineq(0);
294
295
2
  Eigen::VectorXd x(2);
296
297
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_REDUNDANT_EQUALITIES;
298
299
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
300
301



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


















3
BOOST_AUTO_TEST_CASE(test_unfeasible_inequalities) {
312
2
  EiquadprogFast qp;
313
1
  qp.reset(2, 0, 2);
314
315
2
  Eigen::MatrixXd Q(2, 2);
316
1
  Q.setZero();
317
1
  Q(0, 0) = 1.0;
318
1
  Q(1, 1) = 1.0;
319
320
2
  Eigen::VectorXd C(2);
321
1
  C.setZero();
322
323
2
  Eigen::MatrixXd Aeq(0, 2);
324
325
2
  Eigen::VectorXd Beq(0);
326
327
2
  Eigen::MatrixXd Aineq(2, 2);
328
1
  Aineq.setZero();
329
1
  Aineq(0, 0) = 1.;
330
1
  Aineq(1, 0) = -1.;
331
332
2
  Eigen::VectorXd Bineq(2);
333
1
  Bineq(0) = -1;
334
1
  Bineq(1) = -1;
335
336
2
  Eigen::VectorXd x(2);
337
338
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_INFEASIBLE;
339
340
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
341
342



1
  BOOST_WARN_EQUAL(status, expected);
343



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


















3
BOOST_AUTO_TEST_CASE(test_unfeasible_constraints) {
355
2
  EiquadprogFast qp;
356
1
  qp.reset(2, 1, 2);
357
358
2
  Eigen::MatrixXd Q(2, 2);
359
1
  Q.setZero();
360
1
  Q(0, 0) = 1.0;
361
1
  Q(1, 1) = 1.0;
362
363
2
  Eigen::VectorXd C(2);
364
1
  C(0) = -1.;
365
1
  C(1) = -1.;
366
367
2
  Eigen::MatrixXd Aeq(1, 2);
368
1
  Aeq(0, 0) = 1.;
369
1
  Aeq(0, 1) = 1.;
370
371
2
  Eigen::VectorXd Beq(1);
372
1
  Beq(0) = -1.;
373
374
2
  Eigen::MatrixXd Aineq(2, 2);
375
1
  Aineq.setZero();
376
1
  Aineq(0, 0) = -1.;
377
1
  Aineq(1, 1) = -1.;
378
379
2
  Eigen::VectorXd Bineq(2);
380
1
  Bineq.setZero();
381
382
2
  Eigen::VectorXd x(2);
383
384
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_INFEASIBLE;
385
386
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
387
388



1
  BOOST_WARN_EQUAL(status, expected);
389



1
  BOOST_CHECK(status != EIQUADPROG_FAST_OPTIMAL);
390
1
}
391
392
// min -||x||^2
393
// DOES NOT WORK!
394
395


















3
BOOST_AUTO_TEST_CASE(test_unbounded) {
396
2
  EiquadprogFast qp;
397
1
  qp.reset(2, 0, 0);
398
399
2
  Eigen::MatrixXd Q(2, 2);
400
1
  Q.setZero();
401
1
  Q(0, 0) = -1.0;
402
1
  Q(1, 1) = -1.0;
403
404
2
  Eigen::VectorXd C(2);
405
1
  C.setZero();
406
407
2
  Eigen::MatrixXd Aeq(0, 2);
408
409
2
  Eigen::VectorXd Beq(0);
410
411
2
  Eigen::MatrixXd Aineq(0, 2);
412
413
2
  Eigen::VectorXd Bineq(0);
414
415
2
  Eigen::VectorXd x(2);
416
417
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_UNBOUNDED;
418
419
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
420
421



1
  BOOST_WARN_EQUAL(status, expected);
422



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


















3
BOOST_AUTO_TEST_CASE(test_nonconvex) {
432
2
  EiquadprogFast qp;
433
1
  qp.reset(2, 0, 4);
434
435
2
  Eigen::MatrixXd Q(2, 2);
436
1
  Q.setZero();
437
1
  Q(0, 0) = -1.0;
438
1
  Q(1, 1) = -1.0;
439
440
2
  Eigen::VectorXd C(2);
441
1
  C.setZero();
442
443
2
  Eigen::MatrixXd Aeq(0, 2);
444
445
2
  Eigen::VectorXd Beq(0);
446
447
2
  Eigen::MatrixXd Aineq(4, 2);
448
1
  Aineq.setZero();
449
1
  Aineq(0, 0) = 1.;
450
1
  Aineq(1, 0) = -1.;
451
1
  Aineq(2, 1) = 1.;
452
1
  Aineq(3, 1) = -1.;
453
454
2
  Eigen::VectorXd Bineq(4);
455
1
  Bineq(0) = 0.;
456
1
  Bineq(1) = 1.;
457
1
  Bineq(2) = 0.;
458
1
  Bineq(3) = 1.;
459
460
2
  Eigen::VectorXd x(2);
461
462
2
  Eigen::VectorXd solution(2);
463
1
  solution(0) = 1.;
464
1
  solution(1) = 1.;
465
466
1
  double val = -1.;
467
468
1
  EiquadprogFast_status expected = EIQUADPROG_FAST_OPTIMAL;
469
470
1
  EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
471
472



1
  BOOST_CHECK_EQUAL(status, expected);
473
474



1
  BOOST_WARN_CLOSE(qp.getObjValue(), val, 1e-6);
475
476




3
  BOOST_WARN(x.isApprox(solution));
477
1
}
478
479

3
BOOST_AUTO_TEST_SUITE_END()