unittest/cholesky.cpp
Go to the documentation of this file.
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 
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 BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
30 
31 BOOST_AUTO_TEST_CASE(test_cholesky)
32 {
33  using namespace Eigen;
34  using namespace pinocchio;
35 
39 
40  model.lowerPositionLimit.head<3>().fill(-1.);
41  model.upperPositionLimit.head<3>().fill(1.);
42  VectorXd q = randomConfiguration(model);
43  data.M.fill(0); // Only nonzero coeff of M are initialized by CRBA.
45 
47  data.M.triangularView<Eigen::StrictlyLower>() =
48  data.M.triangularView<Eigen::StrictlyUpper>().transpose();
49 
50  const Eigen::MatrixXd & U = data.U;
51  const Eigen::VectorXd & D = data.D;
52  const Eigen::MatrixXd & M = data.M;
53 
54 #ifndef NDEBUG
55  std::cout << "M = [\n" << M << "];" << std::endl;
56  std::cout << "U = [\n" << U << "];" << std::endl;
57  std::cout << "D = [\n" << D.transpose() << "];" << std::endl;
58 #endif
59 
60  BOOST_CHECK(M.isApprox(U * D.asDiagonal() * U.transpose(), 1e-12));
61 
62  Eigen::VectorXd v = Eigen::VectorXd::Random(model.nv);
63  // std::cout << "v = [" << v.transpose() << "]';" << std::endl;
64 
65  Eigen::VectorXd Uv = v;
67  BOOST_CHECK(Uv.isApprox(U * v, 1e-12));
68 
69  Eigen::VectorXd Utv = v;
71  BOOST_CHECK(Utv.isApprox(U.transpose() * v, 1e-12));
72 
73  Eigen::VectorXd Uiv = v;
75  BOOST_CHECK(Uiv.isApprox(U.inverse() * v, 1e-12));
76 
77  Eigen::VectorXd Utiv = v;
79  BOOST_CHECK(Utiv.isApprox(U.transpose().inverse() * v, 1e-12));
80 
81  Eigen::VectorXd Miv = v;
83  BOOST_CHECK(Miv.isApprox(M.inverse() * v, 1e-12));
84 
85  Eigen::VectorXd Mv = v;
87  BOOST_CHECK(Mv.isApprox(M * v, 1e-12));
88  Mv = v;
90  BOOST_CHECK(Mv.isApprox(M * v, 1e-12));
91 }
92 
93 /* The flag triger the following timers:
94  * 000001: sparse UDUt cholesky
95  * 000010: dense Eigen LDLt cholesky (with pivot)
96  * 000100: sparse resolution
97  * 001000: sparse U*v multiplication
98  * 010000: sparse U\v substitution
99  * 100000: sparse M*v multiplication without Cholesky
100  */
101 BOOST_AUTO_TEST_CASE(test_timings)
102 {
103  using namespace Eigen;
104  using namespace pinocchio;
105 
109 
110  model.lowerPositionLimit.head<3>().fill(-1.);
111  model.upperPositionLimit.head<3>().fill(1.);
112  VectorXd q = randomConfiguration(model);
113  data.M.fill(0); // Only nonzero coeff of M are initialized by CRBA.
115 
116  long flag = BOOST_BINARY(1111111);
118 #ifdef NDEBUG
119  #ifdef _INTENSE_TESTING_
120  const size_t NBT = 1000 * 1000;
121  #else
122  const size_t NBT = 10;
123  #endif
124 #else
125  const size_t NBT = 1;
126  std::cout << "(the time score in debug mode is not relevant) ";
127 #endif
128 
129  bool verbose = flag & (flag - 1); // True is two or more binaries of the flag are 1.
130  if (verbose)
131  std::cout << "--" << std::endl;
132 
133  if (flag >> 0 & 1)
134  {
135  timer.tic();
136  SMOOTH(NBT)
137  {
139  }
140  if (verbose)
141  std::cout << "Decompose =\t";
142  timer.toc(std::cout, NBT);
143  }
144 
145  if (flag >> 1 & 1)
146  {
147  timer.tic();
148  Eigen::VectorXd v = Eigen::VectorXd::Random(model.nv);
149  Eigen::VectorXd res(model.nv);
150  SMOOTH(NBT)
151  {
152  Eigen::LDLT<Eigen::MatrixXd> Mchol(data.M);
153  res = Mchol.solve(v);
154  }
155  if (verbose)
156  std::cout << "Eigen::LDLt =\t";
157  timer.toc(std::cout, NBT);
158  }
159 
160  if (flag >> 2 & 31)
161  {
162  std::vector<Eigen::VectorXd> randvec(NBT);
163  for (size_t i = 0; i < NBT; ++i)
164  randvec[i] = Eigen::VectorXd::Random(model.nv);
165  Eigen::VectorXd zero = Eigen::VectorXd::Zero(model.nv);
166  Eigen::VectorXd res(model.nv);
167 
168  if (flag >> 2 & 1)
169  {
170  timer.tic();
171  SMOOTH(NBT)
172  {
173  pinocchio::cholesky::solve(model, data, randvec[_smooth]);
174  }
175  if (verbose)
176  std::cout << "solve =\t\t";
177  timer.toc(std::cout, NBT);
178  }
179 
180  if (flag >> 3 & 1)
181  {
182  timer.tic();
183  SMOOTH(NBT)
184  {
185  pinocchio::cholesky::Uv(model, data, randvec[_smooth]);
186  }
187  if (verbose)
188  std::cout << "Uv =\t\t";
189  timer.toc(std::cout, NBT);
190  }
191 
192  if (flag >> 4 & 1)
193  {
194  timer.tic();
195  SMOOTH(NBT)
196  {
197  pinocchio::cholesky::Uiv(model, data, randvec[_smooth]);
198  }
199  if (verbose)
200  std::cout << "Uiv =\t\t";
201  timer.toc(std::cout, NBT);
202  }
203  if (flag >> 5 & 1)
204  {
205  timer.tic();
206  Eigen::VectorXd res;
207  SMOOTH(NBT)
208  {
209  res = pinocchio::cholesky::Mv(model, data, randvec[_smooth]);
210  }
211  if (verbose)
212  std::cout << "Mv =\t\t";
213  timer.toc(std::cout, NBT);
214  }
215  if (flag >> 6 & 1)
216  {
217  timer.tic();
218  SMOOTH(NBT)
219  {
220  pinocchio::cholesky::UDUtv(model, data, randvec[_smooth]);
221  }
222  if (verbose)
223  std::cout << "UDUtv =\t\t";
224  timer.toc(std::cout, NBT);
225  }
226  }
227 }
228 
229 BOOST_AUTO_TEST_CASE(test_Minv_from_cholesky)
230 {
231  using namespace Eigen;
232  using namespace pinocchio;
233 
237 
238  model.lowerPositionLimit.head<3>().fill(-1.);
239  model.upperPositionLimit.head<3>().fill(1.);
240  VectorXd q = randomConfiguration(model);
242  data.M.triangularView<Eigen::StrictlyLower>() =
243  data.M.triangularView<Eigen::StrictlyUpper>().transpose();
244  MatrixXd Minv_ref(data.M.inverse());
245 
247  VectorXd v_unit(VectorXd::Unit(model.nv, 0));
248 
249  VectorXd Ui_v_unit(model.nv);
250  VectorXd Ui_v_unit_ref(model.nv);
251 
252  for (int k = 0; k < model.nv; ++k)
253  {
254  v_unit = VectorXd::Unit(model.nv, k);
255  Ui_v_unit.setZero();
256  cholesky::internal::Miunit(model, data, k, Ui_v_unit);
257  Ui_v_unit_ref = v_unit;
258  cholesky::Uiv(model, data, Ui_v_unit_ref);
259  Ui_v_unit_ref.array() *= data.Dinv.array();
260  cholesky::Utiv(model, data, Ui_v_unit_ref);
261  BOOST_CHECK(Ui_v_unit.head(k + 1).isApprox(Ui_v_unit_ref.head(k + 1)));
262 
263  Ui_v_unit_ref = v_unit;
264  cholesky::solve(model, data, Ui_v_unit_ref);
265  BOOST_CHECK(Ui_v_unit.head(k + 1).isApprox(Ui_v_unit_ref.head(k + 1)));
266  }
267 
268  MatrixXd Minv(model.nv, model.nv);
269  Minv.setZero();
271 
272  BOOST_CHECK(Minv.isApprox(Minv_ref));
273 
274  // Check second call to cholesky::computeMinv
276  BOOST_CHECK(Minv.isApprox(Minv_ref));
277 
278  // Call the second signature of cholesky::computeMinv
279  Data data_bis(model);
280  crba(model, data_bis, q, Convention::WORLD);
281  cholesky::decompose(model, data_bis);
282  cholesky::computeMinv(model, data_bis);
283  BOOST_CHECK(data_bis.Minv.isApprox(Minv_ref));
284 }
285 
286 BOOST_AUTO_TEST_SUITE_END()
pinocchio::WORLD
@ WORLD
Definition: multibody/fwd.hpp:48
PinocchioTicToc::toc
double toc()
Definition: timer.hpp:88
Eigen
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(test_cholesky)
Definition: unittest/cholesky.cpp:31
pinocchio::DataTpl
Definition: context/generic.hpp:25
pinocchio::cholesky::Uv
Mat & Uv(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< Mat > &v)
Perform the sparse multiplication using the Cholesky decomposition stored in data and acting in plac...
inverse-kinematics.i
int i
Definition: inverse-kinematics.py:17
model.hpp
setup.data
data
Definition: cmake/cython/setup.in.py:48
pinocchio::buildModels::humanoidRandom
void humanoidRandom(ModelTpl< Scalar, Options, JointCollectionTpl > &model, bool usingFF=true)
Create a humanoid kinematic tree with 6-DOF limbs and random joint placements.
pinocchio::crba
const DataTpl< Scalar, Options, JointCollectionTpl >::MatrixXs & crba(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< ConfigVectorType > &q, const Convention convention=Convention::LOCAL)
Computes the upper triangular part of the joint space inertia matrix M by using the Composite Rigid B...
pinocchio::cholesky::UDUtv
Mat & UDUtv(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< Mat > &m)
Performs the multiplication by using the Cholesky decomposition of M stored in data.
pinocchio::randomConfiguration
void randomConfiguration(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const Eigen::MatrixBase< ConfigVectorIn1 > &lowerLimits, const Eigen::MatrixBase< ConfigVectorIn2 > &upperLimits, const Eigen::MatrixBase< ReturnType > &qout)
Generate a configuration vector uniformly sampled among provided limits.
Definition: joint-configuration.hpp:315
timer.hpp
anymal-simulation.model
model
Definition: anymal-simulation.py:8
pinocchio::cholesky::solve
Mat & solve(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< Mat > &y)
Return the solution of using the Cholesky decomposition stored in data given the entry ....
SMOOTH
#define SMOOTH(s)
Definition: timer.hpp:38
res
res
joint-configuration.hpp
se3.hpp
pinocchio::DataTpl::Minv
RowMatrixXs Minv
The inverse of the joint space inertia matrix (a square matrix of dim model.nv).
Definition: multibody/data.hpp:202
cartpole.v
v
Definition: cartpole.py:153
data.hpp
D
D
M
M
pinocchio::cholesky::Uiv
Mat & Uiv(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< Mat > &v)
Perform the pivot inversion using the Cholesky decomposition stored in data and acting in place.
q
q
PinocchioTicToc::US
@ US
Definition: timer.hpp:53
cholesky.hpp
pinocchio::cholesky::decompose
const DataTpl< Scalar, Options, JointCollectionTpl >::MatrixXs & decompose(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data)
Compute the Cholesky decomposition of the joint space inertia matrix M contained in data.
pinocchio::cholesky::computeMinv
Mat & computeMinv(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< Mat > &Minv)
Computes the inverse of the joint space inertia matrix M from its Cholesky factorization.
fill
fill
ocp.U
U
Definition: ocp.py:80
pinocchio::cholesky::Mv
MatRes & Mv(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< Mat > &min, const Eigen::MatrixBase< MatRes > &mout)
Performs the multiplication by using the sparsity pattern of the M matrix.
sample-models.hpp
pinocchio::ModelTpl
Definition: context/generic.hpp:20
verbose
bool verbose
pinocchio.utils.zero
def zero(n)
Definition: bindings/python/pinocchio/utils.py:37
pinocchio::cholesky::Utv
Mat & Utv(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< Mat > &v)
Perform the sparse multiplication using the Cholesky decomposition stored in data and acting in plac...
crba.hpp
pinocchio::cholesky::Utiv
Mat & Utiv(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< Mat > &v)
Perform the pivot inversion using the Cholesky decomposition stored in data and acting in place.
PinocchioTicToc
Definition: timer.hpp:47
pinocchio
Main pinocchio namespace.
Definition: timings.cpp:27
PinocchioTicToc::tic
void tic()
Definition: timer.hpp:82


pinocchio
Author(s):
autogenerated on Fri Nov 1 2024 02:41:39