Skip to content

Commit 1b32975

Browse files
olivier-stasseOlivier Stasse
authored andcommitted
Fix and test the inclusion problem of both fast and rt.
Add a unittest showing the problem with classical use of the library.
1 parent b08d57d commit 1b32975

File tree

8 files changed

+282
-32
lines changed

8 files changed

+282
-32
lines changed

include/eiquadprog/eiquadprog-fast.hxx

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,7 @@
2222
namespace eiquadprog {
2323
namespace solvers {
2424

25-
/// Compute sqrt(a^2 + b^2)
26-
template <typename Scalar>
27-
inline Scalar distance(Scalar a, Scalar b) {
28-
Scalar a1, b1, t;
29-
a1 = std::abs(a);
30-
b1 = std::abs(b);
31-
if (a1 > b1) {
32-
t = (b1 / a1);
33-
return a1 * std::sqrt(1.0 + t * t);
34-
} else if (b1 > a1) {
35-
t = (a1 / b1);
36-
return b1 * std::sqrt(1.0 + t * t);
37-
}
38-
return a1 * std::sqrt(2.0);
39-
}
25+
#include "eiquadprog/eiquadprog-utils.hxx"
4026

4127
EiquadprogFast::EiquadprogFast() {
4228
m_maxIter = DEFAULT_MAX_ITER;
@@ -216,14 +202,6 @@ void EiquadprogFast::delete_constraint(MatrixXd& R, MatrixXd& J, VectorXi& A, Ve
216202
}
217203
}
218204

219-
template <class Derived>
220-
void print_vector(const char* name, Eigen::MatrixBase<Derived>& x, int n) {
221-
// std::cerr << name << x.transpose() << std::endl;
222-
}
223-
template <class Derived>
224-
void print_matrix(const char* name, Eigen::MatrixBase<Derived>& x, int n) {
225-
// std::cerr << name << std::endl << x << std::endl;
226-
}
227205

228206
EiquadprogFast_status EiquadprogFast::solve_quadprog(const MatrixXd& Hess, const VectorXd& g0, const MatrixXd& CE,
229207
const VectorXd& ce0, const MatrixXd& CI, const VectorXd& ci0,
@@ -634,4 +612,5 @@ l2a: /* Step 2a: determine step direction */
634612
} /* namespace solvers */
635613
} /* namespace eiquadprog */
636614

615+
637616
#endif /* EIQUADPROGFAST_HXX_ */

include/eiquadprog/eiquadprog-rt.hxx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#ifndef __eiquadprog_rt_hxx__
2020
#define __eiquadprog_rt_hxx__
2121

22+
#include "eiquadprog/eiquadprog-utils.hxx"
23+
2224
namespace eiquadprog {
2325

2426
namespace solvers {
@@ -182,15 +184,6 @@ void RtEiquadprog<nVars, nEqCon, nIneqCon>::delete_constraint(typename RtMatrixX
182184
}
183185
}
184186

185-
template <class Derived>
186-
void print_vector(const char* name, Eigen::MatrixBase<Derived>& x, int n) {
187-
// std::cerr << name << x.transpose() << std::endl;
188-
}
189-
template <class Derived>
190-
void print_matrix(const char* name, Eigen::MatrixBase<Derived>& x, int n) {
191-
// std::cerr << name << std::endl << x << std::endl;
192-
}
193-
194187
template <int nVars, int nEqCon, int nIneqCon>
195188
RtEiquadprog_status RtEiquadprog<nVars, nEqCon, nIneqCon>::solve_quadprog(
196189
const typename RtMatrixX<nVars, nVars>::d& Hess, const typename RtVectorX<nVars>::d& g0,
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef EIQUADPROG_UTILS_HPP_
2+
#define EIQUADPROG_UTILS_HPP_
3+
4+
/// Compute sqrt(a^2 + b^2)
5+
template <typename Scalar>
6+
inline Scalar distance(Scalar a, Scalar b) {
7+
Scalar a1, b1, t;
8+
a1 = std::abs(a);
9+
b1 = std::abs(b);
10+
if (a1 > b1) {
11+
t = (b1 / a1);
12+
return a1 * std::sqrt(1.0 + t * t);
13+
} else if (b1 > a1) {
14+
t = (a1 / b1);
15+
return b1 * std::sqrt(1.0 + t * t);
16+
}
17+
return a1 * std::sqrt(2.0);
18+
}
19+
20+
template <class Derived>
21+
void print_vector(const char* name, Eigen::MatrixBase<Derived>& x, int n) {
22+
// std::cerr << name << x.transpose() << std::endl;
23+
}
24+
template <class Derived>
25+
void print_matrix(const char* name, Eigen::MatrixBase<Derived>& x, int n) {
26+
// std::cerr << name << std::endl << x << std::endl;
27+
}
28+
29+
#endif

tests/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,16 @@ SET(TESTS
2222
eiquadprog-basic
2323
eiquadprog-fast
2424
eiquadprog-rt
25+
eiquadprog-both
2526
)
2627

2728
FOREACH(test ${TESTS})
2829
ADD_UNIT_TEST(${test} ${test}.cpp)
2930
TARGET_LINK_LIBRARIES(${test} ${PROJECT_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
3031
ENDFOREACH(test ${TESTS})
32+
33+
ADD_LIBRARY(testab SHARED TestA.cpp TestB.cpp)
34+
TARGET_INCLUDE_DIRECTORIES(testab SYSTEM PRIVATE ${EIGEN3_INCLUDE_DIR})
35+
36+
#ADD_UNIT_TEST(test-integration test-integration.cpp )
37+
#TARGET_LINK_LIBRARIES(test-integration ${PROJECT_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} testab)

tests/TestA.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <iostream>
2+
3+
#include <Eigen/Core>
4+
5+
#include <boost/test/unit_test.hpp>
6+
7+
#include "TestA.hpp"
8+
9+
using namespace eiquadprog::solvers;
10+
using namespace eiquadprog::tests;
11+
12+
A::A():
13+
Q_(2, 2),
14+
C_(2),
15+
Aeq_(0,2),
16+
Beq_(0),
17+
Aineq_(0,2),
18+
Bineq_(0),
19+
solution_(2),
20+
QP_()
21+
{
22+
23+
QP_.reset(2, 0, 0);
24+
25+
Q_.setZero();
26+
Q_(0, 0) = 1.0;
27+
Q_(1, 1) = 1.0;
28+
29+
30+
C_.setZero();
31+
32+
solution_.setZero();
33+
34+
expected_ = EIQUADPROG_FAST_OPTIMAL;
35+
36+
}
37+
38+
EiquadprogFast_status A::solve(Eigen::VectorXd &x)
39+
{
40+
return QP_.solve_quadprog(Q_, C_, Aeq_, Beq_, Aineq_, Bineq_, x);
41+
}

tests/TestB.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <iostream>
2+
3+
#include <Eigen/Core>
4+
5+
#include <boost/test/unit_test.hpp>
6+
7+
#include "TestB.hpp"
8+
using namespace eiquadprog::solvers;
9+
using namespace eiquadprog::tests;
10+
11+
B::B()
12+
{
13+
}
14+
15+
bool B::do_something()
16+
{
17+
18+
}

tests/eiquadprog-both.cpp

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
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+
#include "eiquadprog/eiquadprog-rt.hpp"
27+
28+
using namespace eiquadprog::solvers;
29+
30+
/**
31+
* solves the problem
32+
* min. 0.5 * x' Hess x + g0' x
33+
* s.t. CE x + ce0 = 0
34+
* CI x + ci0 >= 0
35+
*/
36+
37+
BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
38+
39+
// min ||x||^2
40+
41+
BOOST_AUTO_TEST_CASE(test_unbiased) {
42+
EiquadprogFast qp;
43+
qp.reset(2, 0, 0);
44+
45+
Eigen::MatrixXd Q(2, 2);
46+
Q.setZero();
47+
Q(0, 0) = 1.0;
48+
Q(1, 1) = 1.0;
49+
50+
Eigen::VectorXd C(2);
51+
C.setZero();
52+
53+
Eigen::MatrixXd Aeq(0, 2);
54+
55+
Eigen::VectorXd Beq(0);
56+
57+
Eigen::MatrixXd Aineq(0, 2);
58+
59+
Eigen::VectorXd Bineq(0);
60+
61+
Eigen::VectorXd x(2);
62+
63+
Eigen::VectorXd solution(2);
64+
solution.setZero();
65+
66+
double val = 0.0;
67+
68+
EiquadprogFast_status expected = EIQUADPROG_FAST_OPTIMAL;
69+
70+
EiquadprogFast_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
71+
72+
BOOST_CHECK_EQUAL(status, expected);
73+
74+
BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
75+
76+
BOOST_CHECK(x.isApprox(solution));
77+
}
78+
79+
// min ||x-x_0||^2, x_0 = (1 1)^T
80+
81+
BOOST_AUTO_TEST_CASE(test_biased) {
82+
RtEiquadprog<2, 0, 0> qp;
83+
84+
RtMatrixX<2, 2>::d Q;
85+
Q.setZero();
86+
Q(0, 0) = 1.0;
87+
Q(1, 1) = 1.0;
88+
89+
RtVectorX<2>::d C;
90+
C(0) = -1.;
91+
C(1) = -1.;
92+
93+
RtMatrixX<0, 2>::d Aeq;
94+
95+
RtVectorX<0>::d Beq;
96+
97+
RtMatrixX<0, 2>::d Aineq;
98+
99+
RtVectorX<0>::d Bineq;
100+
101+
RtVectorX<2>::d x;
102+
103+
RtVectorX<2>::d solution;
104+
solution(0) = 1.;
105+
solution(1) = 1.;
106+
107+
double val = -1.;
108+
109+
RtEiquadprog_status expected = RT_EIQUADPROG_OPTIMAL;
110+
111+
RtEiquadprog_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
112+
113+
BOOST_CHECK_EQUAL(status, expected);
114+
115+
BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
116+
117+
BOOST_CHECK(x.isApprox(solution));
118+
}
119+
120+
// min ||x||^2
121+
// s.t.
122+
// x[1] = 1 - x[0]
123+
124+
BOOST_AUTO_TEST_CASE(test_equality_constraints) {
125+
RtEiquadprog<2, 1, 0> qp;
126+
127+
RtMatrixX<2, 2>::d Q;
128+
Q.setZero();
129+
Q(0, 0) = 1.0;
130+
Q(1, 1) = 1.0;
131+
132+
RtVectorX<2>::d C;
133+
C.setZero();
134+
135+
RtMatrixX<1, 2>::d Aeq;
136+
Aeq(0, 0) = 1.;
137+
Aeq(0, 1) = 1.;
138+
139+
RtVectorX<1>::d Beq;
140+
Beq(0) = -1.;
141+
142+
RtMatrixX<0, 2>::d Aineq;
143+
144+
RtVectorX<0>::d Bineq;
145+
146+
RtVectorX<2>::d x;
147+
148+
RtVectorX<2>::d solution;
149+
solution(0) = 0.5;
150+
solution(1) = 0.5;
151+
152+
double val = 0.25;
153+
154+
RtEiquadprog_status expected = RT_EIQUADPROG_OPTIMAL;
155+
156+
RtEiquadprog_status status = qp.solve_quadprog(Q, C, Aeq, Beq, Aineq, Bineq, x);
157+
158+
BOOST_CHECK_EQUAL(status, expected);
159+
160+
BOOST_CHECK_CLOSE(qp.getObjValue(), val, 1e-6);
161+
162+
BOOST_CHECK(x.isApprox(solution));
163+
}
164+
165+
BOOST_AUTO_TEST_SUITE_END()

tests/test-integration.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <iostream>
2+
3+
#include <Eigen/Core>
4+
5+
#include <boost/test/unit_test.hpp>
6+
7+
#include "TestA.hpp"
8+
#include "TestB.hpp"
9+
10+
BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
11+
12+
BOOST_AUTO_TEST_CASE(test_class_A_and_class_B) {
13+
eiquadprog::tests::B aB;
14+
15+
BOOST_CHECK(aB.do_something());
16+
}
17+
18+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)