GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
// |
||
2 |
// Copyright (c) 2015-2019 CNRS INRIA |
||
3 |
// |
||
4 |
|||
5 |
/* |
||
6 |
* Validate the sparse Cholesky decomposition of the mass matrix. The code |
||
7 |
* tests both the numerical value and the computation time. For a strong |
||
8 |
* computation benchmark, see benchmark/timings. |
||
9 |
* |
||
10 |
*/ |
||
11 |
|||
12 |
#include "pinocchio/spatial/se3.hpp" |
||
13 |
#include "pinocchio/multibody/model.hpp" |
||
14 |
#include "pinocchio/multibody/data.hpp" |
||
15 |
#include "pinocchio/algorithm/crba.hpp" |
||
16 |
#include "pinocchio/algorithm/cholesky.hpp" |
||
17 |
#include "pinocchio/parsers/sample-models.hpp" |
||
18 |
#include "pinocchio/utils/timer.hpp" |
||
19 |
#include "pinocchio/algorithm/joint-configuration.hpp" |
||
20 |
|||
21 |
#include <iostream> |
||
22 |
#ifdef NDEBUG |
||
23 |
# include <Eigen/Cholesky> |
||
24 |
#endif |
||
25 |
|||
26 |
#include <boost/test/unit_test.hpp> |
||
27 |
#include <boost/utility/binary.hpp> |
||
28 |
|||
29 |
|||
30 |
BOOST_AUTO_TEST_SUITE ( BOOST_TEST_MODULE ) |
||
31 |
|||
32 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗ |
4 |
BOOST_AUTO_TEST_CASE ( test_cholesky ) |
33 |
{ |
||
34 |
using namespace Eigen; |
||
35 |
using namespace pinocchio; |
||
36 |
|||
37 |
✓✗ | 4 |
pinocchio::Model model; |
38 |
✓✗ | 2 |
pinocchio::buildModels::humanoidRandom(model,true); |
39 |
✓✗ | 4 |
pinocchio::Data data(model); |
40 |
|||
41 |
✓✗✓✗ |
2 |
model.lowerPositionLimit.head<3>().fill(-1.); |
42 |
✓✗✓✗ |
2 |
model.upperPositionLimit.head<3>().fill(1.); |
43 |
✓✗ | 4 |
VectorXd q = randomConfiguration(model); |
44 |
✓✗ | 2 |
data.M.fill(0); // Only nonzero coeff of M are initialized by CRBA. |
45 |
✓✗ | 2 |
crba(model,data,q); |
46 |
|||
47 |
✓✗ | 2 |
pinocchio::cholesky::decompose(model,data); |
48 |
✓✗ | 2 |
data.M.triangularView<Eigen::StrictlyLower>() = |
49 |
✓✗✓✗ ✓✗ |
4 |
data.M.triangularView<Eigen::StrictlyUpper>().transpose(); |
50 |
|||
51 |
2 |
const Eigen::MatrixXd & U = data.U; |
|
52 |
2 |
const Eigen::VectorXd & D = data.D; |
|
53 |
2 |
const Eigen::MatrixXd & M = data.M; |
|
54 |
|||
55 |
#ifndef NDEBUG |
||
56 |
✓✗✓✗ ✓✗✓✗ |
2 |
std::cout << "M = [\n" << M << "];" << std::endl; |
57 |
✓✗✓✗ ✓✗✓✗ |
2 |
std::cout << "U = [\n" << U << "];" << std::endl; |
58 |
✓✗✓✗ ✓✗✓✗ ✓✗ |
2 |
std::cout << "D = [\n" << D.transpose() << "];" << std::endl; |
59 |
#endif |
||
60 |
|||
61 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
2 |
BOOST_CHECK(M.isApprox(U*D.asDiagonal()*U.transpose() , 1e-12)); |
62 |
|||
63 |
✓✗✓✗ |
4 |
Eigen::VectorXd v = Eigen::VectorXd::Random(model.nv); |
64 |
// std::cout << "v = [" << v.transpose() << "]';" << std::endl; |
||
65 |
|||
66 |
✓✗✓✗ |
4 |
Eigen::VectorXd Uv = v; pinocchio::cholesky::Uv(model,data,Uv); |
67 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
2 |
BOOST_CHECK(Uv.isApprox(U*v, 1e-12)); |
68 |
|||
69 |
✓✗✓✗ |
4 |
Eigen::VectorXd Utv = v; pinocchio::cholesky::Utv(model,data,Utv); |
70 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
2 |
BOOST_CHECK(Utv.isApprox(U.transpose()*v, 1e-12)); |
71 |
|||
72 |
✓✗✓✗ |
4 |
Eigen::VectorXd Uiv = v; pinocchio::cholesky::Uiv(model,data,Uiv); |
73 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
2 |
BOOST_CHECK(Uiv.isApprox(U.inverse()*v, 1e-12)); |
74 |
|||
75 |
|||
76 |
✓✗✓✗ |
4 |
Eigen::VectorXd Utiv = v; pinocchio::cholesky::Utiv(model,data,Utiv); |
77 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
2 |
BOOST_CHECK(Utiv.isApprox(U.transpose().inverse()*v, 1e-12)); |
78 |
|||
79 |
✓✗✓✗ |
4 |
Eigen::VectorXd Miv = v; pinocchio::cholesky::solve(model,data,Miv); |
80 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
2 |
BOOST_CHECK(Miv.isApprox(M.inverse()*v, 1e-12)); |
81 |
|||
82 |
✓✗✓✗ |
4 |
Eigen::VectorXd Mv = v; Mv = pinocchio::cholesky::Mv(model,data,Mv); |
83 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
2 |
BOOST_CHECK(Mv.isApprox(M*v, 1e-12)); |
84 |
✓✗✓✗ |
2 |
Mv = v; pinocchio::cholesky::UDUtv(model,data,Mv); |
85 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
2 |
BOOST_CHECK(Mv.isApprox(M*v, 1e-12)); |
86 |
2 |
} |
|
87 |
|||
88 |
|||
89 |
/* The flag triger the following timers: |
||
90 |
* 000001: sparse UDUt cholesky |
||
91 |
* 000010: dense Eigen LDLt cholesky (with pivot) |
||
92 |
* 000100: sparse resolution |
||
93 |
* 001000: sparse U*v multiplication |
||
94 |
* 010000: sparse U\v substitution |
||
95 |
* 100000: sparse M*v multiplication without Cholesky |
||
96 |
*/ |
||
97 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗ |
4 |
BOOST_AUTO_TEST_CASE ( test_timings ) |
98 |
{ |
||
99 |
using namespace Eigen; |
||
100 |
using namespace pinocchio; |
||
101 |
|||
102 |
✓✗ | 4 |
pinocchio::Model model; |
103 |
✓✗ | 2 |
pinocchio::buildModels::humanoidRandom(model,true); |
104 |
✓✗ | 4 |
pinocchio::Data data(model); |
105 |
|||
106 |
✓✗✓✗ |
2 |
model.lowerPositionLimit.head<3>().fill(-1.); |
107 |
✓✗✓✗ |
2 |
model.upperPositionLimit.head<3>().fill(1.); |
108 |
✓✗ | 4 |
VectorXd q = randomConfiguration(model); |
109 |
✓✗ | 2 |
data.M.fill(0); // Only nonzero coeff of M are initialized by CRBA. |
110 |
✓✗ | 2 |
crba(model,data,q); |
111 |
|||
112 |
|||
113 |
2 |
long flag = BOOST_BINARY(1111111); |
|
114 |
✓✗ | 4 |
PinocchioTicToc timer(PinocchioTicToc::US); |
115 |
#ifdef NDEBUG |
||
116 |
#ifdef _INTENSE_TESTING_ |
||
117 |
const size_t NBT = 1000*1000; |
||
118 |
#else |
||
119 |
const size_t NBT = 10; |
||
120 |
#endif |
||
121 |
#else |
||
122 |
2 |
const size_t NBT = 1; |
|
123 |
✓✗ | 2 |
std::cout << "(the time score in debug mode is not relevant) " ; |
124 |
#endif |
||
125 |
|||
126 |
2 |
bool verbose = flag & (flag-1) ; // True is two or more binaries of the flag are 1. |
|
127 |
✓✗✓✗ ✓✗ |
2 |
if(verbose) std::cout <<"--" << std::endl; |
128 |
|||
129 |
✓✗ | 2 |
if( flag >> 0 & 1 ) |
130 |
{ |
||
131 |
✓✗ | 2 |
timer.tic(); |
132 |
✓✓ | 4 |
SMOOTH(NBT) |
133 |
{ |
||
134 |
✓✗ | 2 |
pinocchio::cholesky::decompose(model,data); |
135 |
} |
||
136 |
✓✗✓✗ |
2 |
if(verbose) std::cout << "Decompose =\t"; |
137 |
✓✗ | 2 |
timer.toc(std::cout,NBT); |
138 |
} |
||
139 |
|||
140 |
✓✗ | 2 |
if( flag >> 1 & 1 ) |
141 |
{ |
||
142 |
✓✗ | 2 |
timer.tic(); |
143 |
✓✗✓✗ |
4 |
Eigen::VectorXd v = Eigen::VectorXd::Random(model.nv); |
144 |
✓✗ | 4 |
Eigen::VectorXd res(model.nv); |
145 |
✓✓ | 4 |
SMOOTH(NBT) |
146 |
{ |
||
147 |
✓✗ | 2 |
Eigen::LDLT <Eigen::MatrixXd> Mchol(data.M); |
148 |
✓✗✓✗ |
2 |
res = Mchol.solve(v); |
149 |
} |
||
150 |
✓✗✓✗ |
2 |
if(verbose) std::cout << "Eigen::LDLt =\t"; |
151 |
✓✗ | 2 |
timer.toc(std::cout,NBT); |
152 |
} |
||
153 |
|||
154 |
✓✗ | 2 |
if( flag >> 2 & 31 ) |
155 |
{ |
||
156 |
✓✗ | 4 |
std::vector<Eigen::VectorXd> randvec(NBT); |
157 |
✓✓✓✗ ✓✗ |
4 |
for(size_t i=0;i<NBT;++i ) randvec[i] = Eigen::VectorXd::Random(model.nv); |
158 |
✓✗✓✗ |
4 |
Eigen::VectorXd zero = Eigen::VectorXd::Zero(model.nv); |
159 |
✓✗ | 4 |
Eigen::VectorXd res (model.nv); |
160 |
|||
161 |
|||
162 |
✓✗ | 2 |
if( flag >> 2 & 1 ) |
163 |
{ |
||
164 |
✓✗ | 2 |
timer.tic(); |
165 |
✓✓ | 4 |
SMOOTH(NBT) |
166 |
{ |
||
167 |
✓✗ | 2 |
pinocchio::cholesky::solve(model,data,randvec[_smooth]); |
168 |
} |
||
169 |
✓✗✓✗ |
2 |
if(verbose) std::cout << "solve =\t\t"; |
170 |
✓✗ | 2 |
timer.toc(std::cout,NBT); |
171 |
} |
||
172 |
|||
173 |
✓✗ | 2 |
if( flag >> 3 & 1 ) |
174 |
{ |
||
175 |
✓✗ | 2 |
timer.tic(); |
176 |
✓✓ | 4 |
SMOOTH(NBT) |
177 |
{ |
||
178 |
✓✗ | 2 |
pinocchio::cholesky::Uv(model,data,randvec[_smooth]); |
179 |
} |
||
180 |
✓✗✓✗ |
2 |
if(verbose) std::cout << "Uv =\t\t"; |
181 |
✓✗ | 2 |
timer.toc(std::cout,NBT); |
182 |
} |
||
183 |
|||
184 |
✓✗ | 2 |
if( flag >> 4 & 1 ) |
185 |
{ |
||
186 |
✓✗ | 2 |
timer.tic(); |
187 |
✓✓ | 4 |
SMOOTH(NBT) |
188 |
{ |
||
189 |
✓✗ | 2 |
pinocchio::cholesky::Uiv(model,data,randvec[_smooth]); |
190 |
} |
||
191 |
✓✗✓✗ |
2 |
if(verbose) std::cout << "Uiv =\t\t"; |
192 |
✓✗ | 2 |
timer.toc(std::cout,NBT); |
193 |
} |
||
194 |
✓✗ | 2 |
if( flag >> 5 & 1 ) |
195 |
{ |
||
196 |
✓✗ | 2 |
timer.tic(); |
197 |
✓✗ | 4 |
Eigen::VectorXd res; |
198 |
✓✓ | 4 |
SMOOTH(NBT) |
199 |
{ |
||
200 |
✓✗ | 2 |
res = pinocchio::cholesky::Mv(model,data,randvec[_smooth]); |
201 |
} |
||
202 |
✓✗✓✗ |
2 |
if(verbose) std::cout << "Mv =\t\t"; |
203 |
✓✗ | 2 |
timer.toc(std::cout,NBT); |
204 |
} |
||
205 |
✓✗ | 2 |
if( flag >> 6 & 1 ) |
206 |
{ |
||
207 |
✓✗ | 2 |
timer.tic(); |
208 |
✓✓ | 4 |
SMOOTH(NBT) |
209 |
{ |
||
210 |
✓✗ | 2 |
pinocchio::cholesky::UDUtv(model,data,randvec[_smooth]); |
211 |
} |
||
212 |
✓✗✓✗ |
2 |
if(verbose) std::cout << "UDUtv =\t\t"; |
213 |
✓✗ | 2 |
timer.toc(std::cout,NBT); |
214 |
} |
||
215 |
} |
||
216 |
2 |
} |
|
217 |
|||
218 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗ |
4 |
BOOST_AUTO_TEST_CASE(test_Minv_from_cholesky) |
219 |
{ |
||
220 |
using namespace Eigen; |
||
221 |
using namespace pinocchio; |
||
222 |
|||
223 |
✓✗ | 4 |
pinocchio::Model model; |
224 |
✓✗ | 2 |
pinocchio::buildModels::humanoidRandom(model,true); |
225 |
✓✗ | 4 |
pinocchio::Data data(model); |
226 |
|||
227 |
✓✗✓✗ |
2 |
model.lowerPositionLimit.head<3>().fill(-1.); |
228 |
✓✗✓✗ |
2 |
model.upperPositionLimit.head<3>().fill(1.); |
229 |
✓✗ | 4 |
VectorXd q = randomConfiguration(model); |
230 |
✓✗ | 2 |
crba(model,data,q); |
231 |
✓✗ | 2 |
data.M.triangularView<Eigen::StrictlyLower>() = |
232 |
✓✗✓✗ ✓✗ |
4 |
data.M.triangularView<Eigen::StrictlyUpper>().transpose(); |
233 |
✓✗✓✗ |
4 |
MatrixXd Minv_ref(data.M.inverse()); |
234 |
|||
235 |
✓✗ | 2 |
cholesky::decompose(model,data); |
236 |
✓✗✓✗ |
4 |
VectorXd v_unit(VectorXd::Unit(model.nv,0)); |
237 |
|||
238 |
✓✗ | 4 |
VectorXd Ui_v_unit(model.nv); |
239 |
✓✗ | 4 |
VectorXd Ui_v_unit_ref(model.nv); |
240 |
|||
241 |
✓✓ | 66 |
for(int k = 0; k < model.nv; ++k) |
242 |
{ |
||
243 |
✓✗✓✗ |
64 |
v_unit = VectorXd::Unit(model.nv,k); |
244 |
✓✗ | 64 |
Ui_v_unit.setZero(); |
245 |
✓✗ | 64 |
cholesky::internal::Miunit(model,data,k,Ui_v_unit); |
246 |
✓✗ | 64 |
Ui_v_unit_ref = v_unit; |
247 |
✓✗ | 64 |
cholesky::Uiv(model,data,Ui_v_unit_ref); |
248 |
✓✗✓✗ ✓✗ |
64 |
Ui_v_unit_ref.array() *= data.Dinv.array(); |
249 |
✓✗ | 64 |
cholesky::Utiv(model,data,Ui_v_unit_ref); |
250 |
|||
251 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
64 |
BOOST_CHECK(Ui_v_unit.isApprox(Ui_v_unit_ref)); |
252 |
|||
253 |
✓✗ | 64 |
Ui_v_unit_ref = v_unit; |
254 |
✓✗ | 64 |
cholesky::solve(model,data,Ui_v_unit_ref); |
255 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
64 |
BOOST_CHECK(Ui_v_unit.isApprox(Ui_v_unit_ref)); |
256 |
|||
257 |
// std::cout << "Ui_v_unit : " << Ui_v_unit.transpose() << std::endl; |
||
258 |
// std::cout << "Ui_v_unit_ref : " << Ui_v_unit_ref.transpose() << std::endl << std::endl; |
||
259 |
} |
||
260 |
|||
261 |
✓✗ | 4 |
MatrixXd Minv(model.nv,model.nv); |
262 |
✓✗ | 2 |
Minv.setZero(); |
263 |
✓✗ | 2 |
cholesky::computeMinv(model,data,Minv); |
264 |
|||
265 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
2 |
BOOST_CHECK(Minv.isApprox(Minv_ref)); |
266 |
|||
267 |
// Check second call to cholesky::computeMinv |
||
268 |
✓✗ | 2 |
cholesky::computeMinv(model,data,Minv); |
269 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
2 |
BOOST_CHECK(Minv.isApprox(Minv_ref)); |
270 |
|||
271 |
// Call the second signature of cholesky::computeMinv |
||
272 |
✓✗ | 4 |
Data data_bis(model); |
273 |
✓✗ | 2 |
crba(model,data_bis,q); |
274 |
✓✗ | 2 |
cholesky::decompose(model,data_bis); |
275 |
✓✗ | 2 |
cholesky::computeMinv(model,data_bis); |
276 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
2 |
BOOST_CHECK(data_bis.Minv.isApprox(Minv_ref)); |
277 |
2 |
} |
|
278 |
|||
279 |
BOOST_AUTO_TEST_SUITE_END () |
Generated by: GCOVR (Version 4.2) |