pinocchio  3.3.1
A fast and flexible implementation of Rigid Body Dynamics algorithms and their analytical derivatives
tridiagonal-matrix.hpp
1 //
2 // Copyright (c) 2024 INRIA
3 //
4 
5 #ifndef __pinocchio_math_tridiagonal_matrix_hpp__
6 #define __pinocchio_math_tridiagonal_matrix_hpp__
7 
8 #include "pinocchio/fwd.hpp"
9 #include <Eigen/Dense>
10 
11 namespace pinocchio
12 {
13  template<typename Scalar, int Options = 0>
14  struct TridiagonalSymmetricMatrixTpl;
15 
16  template<typename _Scalar, int _Options>
17  struct traits<TridiagonalSymmetricMatrixTpl<_Scalar, _Options>>
18  {
19  typedef _Scalar Scalar;
20  enum
21  {
22  Options = _Options
23  };
24  typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Options> PlainMatrixType;
25  };
26 
27  template<typename TridiagonalSymmetricMatrix, typename MatrixDerived>
29 
30  template<typename TridiagonalSymmetricMatrix, typename MatrixDerived>
31  struct traits<
32  TridiagonalSymmetricMatrixApplyOnTheRightReturnType<TridiagonalSymmetricMatrix, MatrixDerived>>
33  : public traits<TridiagonalSymmetricMatrix>
34  {
35  };
36 
37  template<typename MatrixDerived, typename TridiagonalSymmetricMatrix>
39 
40  template<typename MatrixDerived, typename TridiagonalSymmetricMatrix>
41  struct traits<
42  TridiagonalSymmetricMatrixApplyOnTheLeftReturnType<MatrixDerived, TridiagonalSymmetricMatrix>>
43  : public traits<TridiagonalSymmetricMatrix>
44  {
45  };
46 
47  template<typename TridiagonalSymmetricMatrix>
49 
50  template<typename TridiagonalSymmetricMatrix>
51  struct traits<TridiagonalSymmetricMatrixInverse<TridiagonalSymmetricMatrix>>
52  : public traits<TridiagonalSymmetricMatrix>
53  {
54  };
55 
56  template<typename TridiagonalSymmetricMatrixInverse, typename MatrixDerived>
58 
59  template<typename TridiagonalSymmetricMatrixInverse, typename MatrixDerived>
62  MatrixDerived>> : public traits<TridiagonalSymmetricMatrixInverse>
63  {
64  };
65 } // namespace pinocchio
66 
67 namespace Eigen
68 {
69  namespace internal
70  {
71 
72  template<typename Scalar, int Options>
73  struct traits<pinocchio::TridiagonalSymmetricMatrixTpl<Scalar, Options>>
74  : public traits<typename pinocchio::traits<
75  pinocchio::TridiagonalSymmetricMatrixTpl<Scalar, Options>>::PlainMatrixType>
76  {
78  typedef typename Base::PlainMatrixType ReturnType;
79  enum
80  {
81  Flags = 0
82  };
83  };
84 
85  template<typename TridiagonalSymmetricMatrix, typename MatrixDerived>
86  struct traits<pinocchio::TridiagonalSymmetricMatrixApplyOnTheRightReturnType<
87  TridiagonalSymmetricMatrix,
88  MatrixDerived>>
89  : public traits<
90  typename pinocchio::traits<pinocchio::TridiagonalSymmetricMatrixApplyOnTheRightReturnType<
91  TridiagonalSymmetricMatrix,
92  MatrixDerived>>::PlainMatrixType>
93  {
95  TridiagonalSymmetricMatrix,
96  MatrixDerived>>
97  Base;
98  typedef typename Base::PlainMatrixType ReturnType;
99  enum
100  {
101  Flags = 0
102  };
103  };
104 
105  template<typename MatrixDerived, typename TridiagonalSymmetricMatrix>
106  struct traits<pinocchio::TridiagonalSymmetricMatrixApplyOnTheLeftReturnType<
107  MatrixDerived,
108  TridiagonalSymmetricMatrix>>
109  : public traits<
110  typename pinocchio::traits<pinocchio::TridiagonalSymmetricMatrixApplyOnTheLeftReturnType<
111  MatrixDerived,
112  TridiagonalSymmetricMatrix>>::PlainMatrixType>
113  {
115  MatrixDerived,
116  TridiagonalSymmetricMatrix>>
117  Base;
118  typedef typename Base::PlainMatrixType ReturnType;
119  enum
120  {
121  Flags = 0
122  };
123  };
124 
125  template<typename TridiagonalSymmetricMatrix>
126  struct traits<pinocchio::TridiagonalSymmetricMatrixInverse<TridiagonalSymmetricMatrix>>
127  : public traits<TridiagonalSymmetricMatrix>
128  {
129  };
130 
131  template<typename TridiagonalSymmetricMatrixInverse, typename MatrixDerived>
132  struct traits<pinocchio::TridiagonalSymmetricMatrixInverseApplyOnTheRightReturnType<
133  TridiagonalSymmetricMatrixInverse,
134  MatrixDerived>>
135  : public traits<typename pinocchio::traits<
136  pinocchio::TridiagonalSymmetricMatrixInverseApplyOnTheRightReturnType<
137  TridiagonalSymmetricMatrixInverse,
138  MatrixDerived>>::PlainMatrixType>
139  {
140  typedef pinocchio::traits<
142  TridiagonalSymmetricMatrixInverse,
143  MatrixDerived>>
144  Base;
145  typedef typename Base::PlainMatrixType ReturnType;
146  enum
147  {
148  Flags = 0
149  };
150  };
151 
152  } // namespace internal
153 } // namespace Eigen
154 
155 namespace pinocchio
156 {
157 
160  template<typename _Scalar, int _Options>
162  : public Eigen::ReturnByValue<TridiagonalSymmetricMatrixTpl<_Scalar, _Options>>
163  {
164  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
166  typedef _Scalar Scalar;
167  enum
168  {
169  Options = _Options
170  };
171 
172  typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Options> CoeffVectorType;
173  typedef typename traits<Self>::PlainMatrixType PlainMatrixType;
174 
176  explicit TridiagonalSymmetricMatrixTpl(const Eigen::DenseIndex size)
177  : m_size(size)
178  , m_diagonal(size)
179  , m_sub_diagonal(size - 1)
180  {
181  assert(size > 0 && "size should be greater than 0.");
182  }
183 
184  bool operator==(const TridiagonalSymmetricMatrixTpl & other) const
185  {
186  if (this == &other)
187  return true;
188  return diagonal() == other.diagonal() && subDiagonal() == other.subDiagonal();
189  }
190 
191  bool operator!=(const TridiagonalSymmetricMatrixTpl & other) const
192  {
193  return !(*this == other);
194  }
195 
196  TridiagonalSymmetricMatrixInverse<Self> inverse() const
197  {
198  return TridiagonalSymmetricMatrixInverse<Self>(*this);
199  }
200 
201  CoeffVectorType & diagonal()
202  {
203  return m_diagonal;
204  }
205  const CoeffVectorType & diagonal() const
206  {
207  return m_diagonal;
208  }
209  CoeffVectorType & subDiagonal()
210  {
211  return m_sub_diagonal;
212  }
213  const CoeffVectorType & subDiagonal() const
214  {
215  return m_sub_diagonal;
216  }
217 
218  void setIdentity()
219  {
220  diagonal().setOnes();
221  subDiagonal().setZero();
222  }
223 
224  bool isIdentity(const Scalar prec = Eigen::NumTraits<Scalar>::dummy_precision()) const
225  {
226  return subDiagonal().isZero(prec) && diagonal().isOnes(prec);
227  }
228 
229  void setZero()
230  {
231  diagonal().setZero();
232  subDiagonal().setZero();
233  }
234 
235  bool isZero(const Scalar prec = Eigen::NumTraits<Scalar>::dummy_precision()) const
236  {
237  return subDiagonal().isZero(prec) && diagonal().isZero(prec);
238  }
239 
240  void setRandom()
241  {
242  diagonal().setRandom();
243  subDiagonal().setRandom();
244  }
245 
246  bool isDiagonal(const Scalar prec = Eigen::NumTraits<Scalar>::dummy_precision()) const
247  {
248  return subDiagonal().isZero(prec);
249  }
250 
251  template<typename VectorCoeffType>
252  void setDiagonal(const Eigen::MatrixBase<VectorCoeffType> & diagonal_coefficients)
253  {
254  PINOCCHIO_CHECK_ARGUMENT_SIZE(diagonal_coefficients.size(), cols());
255  static_assert(
256  VectorCoeffType::IsVectorAtCompileTime,
257  "VectorCoeffType should be a vector type at compile time");
258 
259  diagonal() = diagonal_coefficients;
260  subDiagonal().setZero();
261  }
262 
263  EIGEN_CONSTEXPR Eigen::Index rows() const EIGEN_NOEXCEPT
264  {
265  return m_size;
266  }
267  EIGEN_CONSTEXPR Eigen::Index cols() const EIGEN_NOEXCEPT
268  {
269  return m_size;
270  }
271 
272  PlainMatrixType matrix() const
273  {
274  return PlainMatrixType(*this);
275  }
276 
277  template<typename ResultType>
278  inline void evalTo(ResultType & result) const
279  {
280  result.setZero();
281  result.template diagonal<1>() = subDiagonal().conjugate();
282  result.diagonal() = diagonal();
283  result.template diagonal<-1>() = subDiagonal();
284  }
285 
286  template<typename MatrixDerived>
287  TridiagonalSymmetricMatrixApplyOnTheRightReturnType<Self, MatrixDerived>
288  applyOnTheRight(const Eigen::MatrixBase<MatrixDerived> & mat) const
289  {
290  typedef TridiagonalSymmetricMatrixApplyOnTheRightReturnType<Self, MatrixDerived> ReturnType;
291  return ReturnType(*this, mat.derived());
292  }
293 
294  template<typename MatrixDerived>
295  TridiagonalSymmetricMatrixApplyOnTheLeftReturnType<MatrixDerived, Self>
296  applyOnTheLeft(const Eigen::MatrixBase<MatrixDerived> & mat) const
297  {
298  typedef TridiagonalSymmetricMatrixApplyOnTheLeftReturnType<MatrixDerived, Self> ReturnType;
299  return ReturnType(mat.derived(), *this);
300  }
301 
302  template<typename MatrixDerived>
303  inline TridiagonalSymmetricMatrixApplyOnTheRightReturnType<Self, MatrixDerived>
304  operator*(const Eigen::MatrixBase<MatrixDerived> & mat) const
305  {
306  return this->applyOnTheRight(mat.derived());
307  }
308 
309  protected:
310  Eigen::DenseIndex m_size;
311  CoeffVectorType m_diagonal;
312  CoeffVectorType m_sub_diagonal;
313  };
314 
315  template<typename LhsMatrixType, typename S, int O>
316  TridiagonalSymmetricMatrixApplyOnTheLeftReturnType<
317  LhsMatrixType,
318  TridiagonalSymmetricMatrixTpl<S, O>>
319  operator*(
320  const Eigen::MatrixBase<LhsMatrixType> & lhs, const TridiagonalSymmetricMatrixTpl<S, O> & rhs)
321  {
322  return rhs.applyOnTheLeft(lhs);
323  }
324 
325  template<typename TridiagonalSymmetricMatrix, typename RhsMatrixType>
327  : public Eigen::ReturnByValue<TridiagonalSymmetricMatrixApplyOnTheRightReturnType<
328  TridiagonalSymmetricMatrix,
329  RhsMatrixType>>
330  {
332  typedef typename traits<Self>::PlainMatrixType PlainMatrixType;
333 
335  const TridiagonalSymmetricMatrix & lhs, const RhsMatrixType & rhs)
336  : m_lhs(lhs)
337  , m_rhs(rhs)
338  {
339  }
340 
341  template<typename ResultType>
342  inline void evalTo(ResultType & result) const
343  {
344  PINOCCHIO_CHECK_ARGUMENT_SIZE(result.rows(), rows());
345  PINOCCHIO_CHECK_ARGUMENT_SIZE(result.cols(), cols());
346 
347  assert(cols() >= 1);
348  assert(rows() >= 1);
349 
350  const Eigen::DenseIndex reduced_size = cols() - 1;
351  // Main diagonal
352  result.noalias() = m_lhs.diagonal().asDiagonal() * m_rhs;
353  // Upper diagonal
354  result.topRows(reduced_size).noalias() +=
355  m_lhs.subDiagonal().conjugate().asDiagonal() * m_rhs.bottomRows(reduced_size);
356  // Sub diagonal
357  result.bottomRows(reduced_size).noalias() +=
358  m_lhs.subDiagonal().asDiagonal() * m_rhs.topRows(reduced_size);
359  }
360 
361  EIGEN_CONSTEXPR Eigen::Index rows() const EIGEN_NOEXCEPT
362  {
363  return m_lhs.rows();
364  }
365  EIGEN_CONSTEXPR Eigen::Index cols() const EIGEN_NOEXCEPT
366  {
367  return m_rhs.cols();
368  }
369 
370  protected:
371  const TridiagonalSymmetricMatrix & m_lhs;
372  const RhsMatrixType & m_rhs;
373  };
374 
375  template<typename LhsMatrixType, typename TridiagonalSymmetricMatrix>
377  : public Eigen::ReturnByValue<
378  TridiagonalSymmetricMatrixApplyOnTheLeftReturnType<LhsMatrixType, TridiagonalSymmetricMatrix>>
379  {
381  typedef typename traits<Self>::PlainMatrixType PlainMatrixType;
382 
384  const LhsMatrixType & lhs, const TridiagonalSymmetricMatrix & rhs)
385  : m_lhs(lhs)
386  , m_rhs(rhs)
387  {
388  }
389 
390  template<typename ResultType>
391  inline void evalTo(ResultType & result) const
392  {
393  PINOCCHIO_CHECK_ARGUMENT_SIZE(result.rows(), rows());
394  PINOCCHIO_CHECK_ARGUMENT_SIZE(result.cols(), cols());
395 
396  assert(cols() >= 1);
397  assert(rows() >= 1);
398 
399  const Eigen::DenseIndex reduced_size = cols() - 1;
400  // Main diagonal
401  result.noalias() = m_lhs * m_rhs.diagonal().asDiagonal();
402  // Upper diagonal
403  result.rightCols(reduced_size).noalias() +=
404  m_lhs.leftCols(reduced_size) * m_rhs.subDiagonal().conjugate().asDiagonal();
405  // Sub diagonal
406  result.leftCols(reduced_size).noalias() +=
407  m_lhs.rightCols(reduced_size) * m_rhs.subDiagonal().asDiagonal();
408  }
409 
410  EIGEN_CONSTEXPR Eigen::Index rows() const EIGEN_NOEXCEPT
411  {
412  return m_lhs.rows();
413  }
414  EIGEN_CONSTEXPR Eigen::Index cols() const EIGEN_NOEXCEPT
415  {
416  return m_rhs.cols();
417  }
418 
419  protected:
420  const LhsMatrixType & m_lhs;
421  const TridiagonalSymmetricMatrix & m_rhs;
422  };
423 
424  template<typename _TridiagonalSymmetricMatrix>
426  : public Eigen::ReturnByValue<TridiagonalSymmetricMatrixInverse<_TridiagonalSymmetricMatrix>>
427  {
428  typedef _TridiagonalSymmetricMatrix TridiagonalSymmetricMatrix;
430  typedef typename TridiagonalSymmetricMatrix::Scalar Scalar;
431  enum
432  {
433  Options = TridiagonalSymmetricMatrix::Options
434  };
435 
436  typedef typename TridiagonalSymmetricMatrix::CoeffVectorType CoeffVectorType;
437  typedef typename traits<Self>::PlainMatrixType PlainMatrixType;
438 
440  const TridiagonalSymmetricMatrix & tridiagonal_matrix)
441  : tridiagonal_matrix(tridiagonal_matrix)
442  , m_size(tridiagonal_matrix.rows())
443  , m_diagonal(m_size)
444  , m_sub_diagonal(m_size - 1)
445  {
446  eval();
447  }
448 
449  const TridiagonalSymmetricMatrix & inverse() const
450  {
451  return tridiagonal_matrix;
452  }
453 
454  template<typename MatrixDerived>
456  applyOnTheRight(const Eigen::MatrixBase<MatrixDerived> & mat) const
457  {
459  ReturnType;
460  return ReturnType(*this, mat.derived());
461  }
462 
463  template<typename MatrixDerived>
465  operator*(const Eigen::MatrixBase<MatrixDerived> & mat) const
466  {
467  return this->applyOnTheRight(mat.derived());
468  }
469 
470  template<typename ResultType>
471  inline void evalTo(ResultType & result) const
472  {
473  PINOCCHIO_CHECK_ARGUMENT_SIZE(result.rows(), rows());
474  PINOCCHIO_CHECK_ARGUMENT_SIZE(result.cols(), cols());
475 
476  assert(cols() >= 1);
477  assert(rows() >= 1);
478 
479  const auto & b = m_diagonal;
480  const auto & c = tridiagonal_matrix.subDiagonal();
481  const auto & w = m_sub_diagonal;
482 
483  // Forward sweep
484  result.setIdentity();
485  for (Eigen::DenseIndex i = 1; i < m_size; ++i)
486  {
487  result.row(i).head(i) -= w[i - 1] * result.row(i - 1).head(i);
488  }
489 
490  // Backward sweep
491  result.row(m_size - 1) /= b[m_size - 1];
492  for (Eigen::DenseIndex i = m_size - 2; i >= 0; --i)
493  {
494  result.row(i) -= c[i] * result.row(i + 1);
495  result.row(i) /= b[i];
496  }
497  }
498 
499  EIGEN_CONSTEXPR Eigen::Index rows() const EIGEN_NOEXCEPT
500  {
501  return m_size;
502  }
503  EIGEN_CONSTEXPR Eigen::Index cols() const EIGEN_NOEXCEPT
504  {
505  return m_size;
506  }
507 
508  protected:
509  template<typename T, typename MatrixDerived>
511 
513  void eval()
514  {
515  m_diagonal = tridiagonal_matrix.diagonal();
516  m_sub_diagonal = tridiagonal_matrix.subDiagonal();
517  auto & w = m_sub_diagonal;
518  auto & b = m_diagonal;
519  const auto & c = tridiagonal_matrix.subDiagonal();
520  for (Eigen::DenseIndex i = 1; i < m_size; ++i)
521  {
522  w.coeffRef(i - 1) /= b[i - 1];
523  m_diagonal.coeffRef(i) -= w[i - 1] * c[i - 1];
524  }
525  }
526 
527  const TridiagonalSymmetricMatrix & tridiagonal_matrix;
528  Eigen::DenseIndex m_size;
529  CoeffVectorType m_diagonal;
530  CoeffVectorType m_sub_diagonal;
531  };
532 
533  template<typename TridiagonalSymmetricMatrixInverse, typename RhsMatrixType>
535  : public Eigen::ReturnByValue<TridiagonalSymmetricMatrixInverseApplyOnTheRightReturnType<
536  TridiagonalSymmetricMatrixInverse,
537  RhsMatrixType>>
538  {
540  typedef typename traits<Self>::PlainMatrixType PlainMatrixType;
541 
543  const TridiagonalSymmetricMatrixInverse & lhs, const RhsMatrixType & rhs)
544  : m_lhs(lhs)
545  , m_rhs(rhs)
546  {
547  }
548 
549  template<typename ResultType>
550  inline void evalTo(ResultType & result) const
551  {
552  PINOCCHIO_CHECK_ARGUMENT_SIZE(result.rows(), rows());
553  PINOCCHIO_CHECK_ARGUMENT_SIZE(result.cols(), cols());
554 
555  assert(cols() >= 1);
556  assert(rows() >= 1);
557 
558  const Eigen::DenseIndex size = m_lhs.rows();
559  const auto & b = m_lhs.m_diagonal;
560  const auto & c = m_lhs.tridiagonal_matrix.subDiagonal();
561  const auto & w = m_lhs.m_sub_diagonal;
562 
563  // Forward sweep
564  result = m_rhs;
565  for (Eigen::DenseIndex i = 1; i < size; ++i)
566  {
567  result.row(i) -= w[i - 1] * result.row(i - 1);
568  }
569 
570  // Backward sweep
571  result.row(size - 1) /= b[size - 1];
572  for (Eigen::DenseIndex i = size - 2; i >= 0; --i)
573  {
574  result.row(i) -= c[i] * result.row(i + 1);
575  result.row(i) /= b[i];
576  }
577  }
578 
579  EIGEN_CONSTEXPR Eigen::Index rows() const EIGEN_NOEXCEPT
580  {
581  return m_lhs.rows();
582  }
583  EIGEN_CONSTEXPR Eigen::Index cols() const EIGEN_NOEXCEPT
584  {
585  return m_rhs.cols();
586  }
587 
588  protected:
589  const TridiagonalSymmetricMatrixInverse & m_lhs;
590  const RhsMatrixType & m_rhs;
591  };
592 } // namespace pinocchio
593 
594 #endif // #ifndef __pinocchio_math_tridiagonal_matrix_hpp__
Main pinocchio namespace.
Definition: treeview.dox:11
void eval()
Forward sweep of https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm.
Dynamic size Tridiagonal symmetric matrix type This class is in practice used in Lanczos decompositio...
TridiagonalSymmetricMatrixTpl(const Eigen::DenseIndex size)
Default constructor from a given size.
Common traits structure to fully define base classes for CRTP.
Definition: fwd.hpp:72