FullPivHouseholderQR.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
5 // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11 #ifndef EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
12 #define EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
13 
14 #include "./InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
18 namespace internal {
19 
20 template<typename MatrixType_, typename PermutationIndex_> struct traits<FullPivHouseholderQR<MatrixType_, PermutationIndex_> >
21  : traits<MatrixType_>
22 {
23  typedef MatrixXpr XprKind;
24  typedef SolverStorage StorageKind;
25  typedef PermutationIndex_ PermutationIndex;
26  enum { Flags = 0 };
27 };
28 
29 template<typename MatrixType, typename PermutationIndex> struct FullPivHouseholderQRMatrixQReturnType;
30 
31 template<typename MatrixType, typename PermutationIndex>
32 struct traits<FullPivHouseholderQRMatrixQReturnType<MatrixType, PermutationIndex> >
33 {
34  typedef typename MatrixType::PlainObject ReturnType;
35 };
36 
37 } // end namespace internal
38 
62 template<typename MatrixType_, typename PermutationIndex_> class FullPivHouseholderQR
63  : public SolverBase<FullPivHouseholderQR<MatrixType_, PermutationIndex_> >
64 {
65  public:
66 
67  typedef MatrixType_ MatrixType;
69  friend class SolverBase<FullPivHouseholderQR>;
70  typedef PermutationIndex_ PermutationIndex;
72 
73  enum {
74  MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
75  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
76  };
77  typedef internal::FullPivHouseholderQRMatrixQReturnType<MatrixType, PermutationIndex> MatrixQReturnType;
78  typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
79  typedef Matrix<PermutationIndex, 1,
83  typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
84  typedef typename internal::plain_col_type<MatrixType>::type ColVectorType;
86 
93  : m_qr(),
94  m_hCoeffs(),
98  m_temp(),
99  m_isInitialized(false),
100  m_usePrescribedThreshold(false) {}
101 
109  : m_qr(rows, cols),
110  m_hCoeffs((std::min)(rows,cols)),
114  m_temp(cols),
115  m_isInitialized(false),
116  m_usePrescribedThreshold(false) {}
117 
130  template<typename InputType>
132  : m_qr(matrix.rows(), matrix.cols()),
133  m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
134  m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())),
135  m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())),
136  m_cols_permutation(matrix.cols()),
137  m_temp(matrix.cols()),
138  m_isInitialized(false),
140  {
141  compute(matrix.derived());
142  }
143 
150  template<typename InputType>
152  : m_qr(matrix.derived()),
153  m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
154  m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())),
155  m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())),
156  m_cols_permutation(matrix.cols()),
157  m_temp(matrix.cols()),
158  m_isInitialized(false),
160  {
161  computeInPlace();
162  }
163 
164  #ifdef EIGEN_PARSED_BY_DOXYGEN
180  template<typename Rhs>
182  solve(const MatrixBase<Rhs>& b) const;
183  #endif
184 
187  MatrixQReturnType matrixQ(void) const;
188 
191  const MatrixType& matrixQR() const
192  {
193  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
194  return m_qr;
195  }
196 
197  template<typename InputType>
199 
202  {
203  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
204  return m_cols_permutation;
205  }
206 
209  {
210  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
211  return m_rows_transpositions;
212  }
213 
227  typename MatrixType::Scalar determinant() const;
228 
242  typename MatrixType::RealScalar absDeterminant() const;
243 
256  typename MatrixType::RealScalar logAbsDeterminant() const;
257 
264  inline Index rank() const
265  {
266  using std::abs;
267  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
268  RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold();
269  Index result = 0;
270  for(Index i = 0; i < m_nonzero_pivots; ++i)
271  result += (abs(m_qr.coeff(i,i)) > premultiplied_threshold);
272  return result;
273  }
274 
281  inline Index dimensionOfKernel() const
282  {
283  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
284  return cols() - rank();
285  }
286 
294  inline bool isInjective() const
295  {
296  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
297  return rank() == cols();
298  }
299 
307  inline bool isSurjective() const
308  {
309  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
310  return rank() == rows();
311  }
312 
319  inline bool isInvertible() const
320  {
321  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
322  return isInjective() && isSurjective();
323  }
324 
331  {
332  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
333  return Inverse<FullPivHouseholderQR>(*this);
334  }
335 
336  inline Index rows() const { return m_qr.rows(); }
337  inline Index cols() const { return m_qr.cols(); }
338 
343  const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
344 
363  {
366  return *this;
367  }
368 
378  {
379  m_usePrescribedThreshold = false;
380  return *this;
381  }
382 
387  RealScalar threshold() const
388  {
391  // this formula comes from experimenting (see "LU precision tuning" thread on the list)
392  // and turns out to be identical to Higham's formula used already in LDLt.
393  : NumTraits<Scalar>::epsilon() * RealScalar(m_qr.diagonalSize());
394  }
395 
403  inline Index nonzeroPivots() const
404  {
405  eigen_assert(m_isInitialized && "LU is not initialized.");
406  return m_nonzero_pivots;
407  }
408 
412  RealScalar maxPivot() const { return m_maxpivot; }
413 
414  #ifndef EIGEN_PARSED_BY_DOXYGEN
415  template<typename RhsType, typename DstType>
416  void _solve_impl(const RhsType &rhs, DstType &dst) const;
417 
418  template<bool Conjugate, typename RhsType, typename DstType>
419  void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
420  #endif
421 
422  protected:
423 
425 
426  void computeInPlace();
427 
437  RealScalar m_precision;
439 };
440 
441 template<typename MatrixType, typename PermutationIndex>
443 {
444  eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
445  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
446  Scalar detQ;
447  internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ);
448  return m_qr.diagonal().prod() * detQ * Scalar(m_det_p);
449 }
450 
451 template<typename MatrixType, typename PermutationIndex>
453 {
454  using std::abs;
455  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
456  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
457  return abs(m_qr.diagonal().prod());
458 }
459 
460 template<typename MatrixType, typename PermutationIndex>
462 {
463  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
464  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
465  return m_qr.diagonal().cwiseAbs().array().log().sum();
466 }
467 
474 template<typename MatrixType, typename PermutationIndex>
475 template<typename InputType>
477 {
478  m_qr = matrix.derived();
479  computeInPlace();
480  return *this;
481 }
482 
483 template<typename MatrixType, typename PermutationIndex>
485 {
487  using std::abs;
488  Index rows = m_qr.rows();
489  Index cols = m_qr.cols();
490  Index size = (std::min)(rows,cols);
491 
492 
493  m_hCoeffs.resize(size);
494 
495  m_temp.resize(cols);
496 
497  m_precision = NumTraits<Scalar>::epsilon() * RealScalar(size);
498 
499  m_rows_transpositions.resize(size);
500  m_cols_transpositions.resize(size);
501  Index number_of_transpositions = 0;
502 
503  RealScalar biggest(0);
504 
505  m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
506  m_maxpivot = RealScalar(0);
507 
508  for (Index k = 0; k < size; ++k)
509  {
510  Index row_of_biggest_in_corner, col_of_biggest_in_corner;
511  typedef internal::scalar_score_coeff_op<Scalar> Scoring;
512  typedef typename Scoring::result_type Score;
513 
514  Score score = m_qr.bottomRightCorner(rows-k, cols-k)
515  .unaryExpr(Scoring())
516  .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
517  row_of_biggest_in_corner += k;
518  col_of_biggest_in_corner += k;
519  RealScalar biggest_in_corner = internal::abs_knowing_score<Scalar>()(m_qr(row_of_biggest_in_corner, col_of_biggest_in_corner), score);
520  if(k==0) biggest = biggest_in_corner;
521 
522  // if the corner is negligible, then we have less than full rank, and we can finish early
523  if(internal::isMuchSmallerThan(biggest_in_corner, biggest, m_precision))
524  {
525  m_nonzero_pivots = k;
526  for(Index i = k; i < size; i++)
527  {
528  m_rows_transpositions.coeffRef(i) = internal::convert_index<PermutationIndex>(i);
529  m_cols_transpositions.coeffRef(i) = internal::convert_index<PermutationIndex>(i);
530  m_hCoeffs.coeffRef(i) = Scalar(0);
531  }
532  break;
533  }
534 
535  m_rows_transpositions.coeffRef(k) = internal::convert_index<PermutationIndex>(row_of_biggest_in_corner);
536  m_cols_transpositions.coeffRef(k) = internal::convert_index<PermutationIndex>(col_of_biggest_in_corner);
537  if(k != row_of_biggest_in_corner) {
538  m_qr.row(k).tail(cols-k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols-k));
539  ++number_of_transpositions;
540  }
541  if(k != col_of_biggest_in_corner) {
542  m_qr.col(k).swap(m_qr.col(col_of_biggest_in_corner));
543  ++number_of_transpositions;
544  }
545 
546  RealScalar beta;
547  m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
548  m_qr.coeffRef(k,k) = beta;
549 
550  // remember the maximum absolute value of diagonal coefficients
551  if(abs(beta) > m_maxpivot) m_maxpivot = abs(beta);
552 
553  m_qr.bottomRightCorner(rows-k, cols-k-1)
554  .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
555  }
556 
557  m_cols_permutation.setIdentity(cols);
558  for(Index k = 0; k < size; ++k)
559  m_cols_permutation.applyTranspositionOnTheRight(k, m_cols_transpositions.coeff(k));
560 
561  m_det_p = (number_of_transpositions%2) ? -1 : 1;
562  m_isInitialized = true;
563 }
564 
565 #ifndef EIGEN_PARSED_BY_DOXYGEN
566 template<typename MatrixType_, typename PermutationIndex_>
567 template<typename RhsType, typename DstType>
568 void FullPivHouseholderQR<MatrixType_, PermutationIndex_>::_solve_impl(const RhsType &rhs, DstType &dst) const
569 {
570  const Index l_rank = rank();
571 
572  // FIXME introduce nonzeroPivots() and use it here. and more generally,
573  // make the same improvements in this dec as in FullPivLU.
574  if(l_rank==0)
575  {
576  dst.setZero();
577  return;
578  }
579 
580  typename RhsType::PlainObject c(rhs);
581 
582  Matrix<typename RhsType::Scalar,1,RhsType::ColsAtCompileTime> temp(rhs.cols());
583  for (Index k = 0; k < l_rank; ++k)
584  {
585  Index remainingSize = rows()-k;
586  c.row(k).swap(c.row(m_rows_transpositions.coeff(k)));
587  c.bottomRightCorner(remainingSize, rhs.cols())
588  .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize-1),
589  m_hCoeffs.coeff(k), &temp.coeffRef(0));
590  }
591 
592  m_qr.topLeftCorner(l_rank, l_rank)
593  .template triangularView<Upper>()
594  .solveInPlace(c.topRows(l_rank));
595 
596  for(Index i = 0; i < l_rank; ++i) dst.row(m_cols_permutation.indices().coeff(i)) = c.row(i);
597  for(Index i = l_rank; i < cols(); ++i) dst.row(m_cols_permutation.indices().coeff(i)).setZero();
598 }
599 
600 template<typename MatrixType_, typename PermutationIndex_>
601 template<bool Conjugate, typename RhsType, typename DstType>
602 void FullPivHouseholderQR<MatrixType_, PermutationIndex_>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
603 {
604  const Index l_rank = rank();
605 
606  if(l_rank == 0)
607  {
608  dst.setZero();
609  return;
610  }
611 
612  typename RhsType::PlainObject c(m_cols_permutation.transpose()*rhs);
613 
614  m_qr.topLeftCorner(l_rank, l_rank)
615  .template triangularView<Upper>()
616  .transpose().template conjugateIf<Conjugate>()
617  .solveInPlace(c.topRows(l_rank));
618 
619  dst.topRows(l_rank) = c.topRows(l_rank);
620  dst.bottomRows(rows()-l_rank).setZero();
621 
622  Matrix<Scalar, 1, DstType::ColsAtCompileTime> temp(dst.cols());
623  const Index size = (std::min)(rows(), cols());
624  for (Index k = size-1; k >= 0; --k)
625  {
626  Index remainingSize = rows()-k;
627 
628  dst.bottomRightCorner(remainingSize, dst.cols())
629  .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize-1).template conjugateIf<!Conjugate>(),
630  m_hCoeffs.template conjugateIf<Conjugate>().coeff(k), &temp.coeffRef(0));
631 
632  dst.row(k).swap(dst.row(m_rows_transpositions.coeff(k)));
633  }
634 }
635 #endif
636 
637 namespace internal {
638 
639 template<typename DstXprType, typename MatrixType, typename PermutationIndex>
640 struct Assignment<DstXprType, Inverse<FullPivHouseholderQR<MatrixType, PermutationIndex> >, internal::assign_op<typename DstXprType::Scalar,typename FullPivHouseholderQR<MatrixType, PermutationIndex>::Scalar>, Dense2Dense>
641 {
642  typedef FullPivHouseholderQR<MatrixType, PermutationIndex> QrType;
643  typedef Inverse<QrType> SrcXprType;
644  static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<typename DstXprType::Scalar,typename QrType::Scalar> &)
645  {
646  dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols()));
647  }
648 };
649 
656 template<typename MatrixType, typename PermutationIndex> struct FullPivHouseholderQRMatrixQReturnType
657  : public ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType, PermutationIndex> >
658 {
659 public:
661  typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
662  typedef Matrix<typename MatrixType::Scalar, 1, MatrixType::RowsAtCompileTime, RowMajor, 1,
663  MatrixType::MaxRowsAtCompileTime> WorkVectorType;
664 
665  FullPivHouseholderQRMatrixQReturnType(const MatrixType& qr,
666  const HCoeffsType& hCoeffs,
667  const IntDiagSizeVectorType& rowsTranspositions)
668  : m_qr(qr),
669  m_hCoeffs(hCoeffs),
670  m_rowsTranspositions(rowsTranspositions)
671  {}
672 
673  template <typename ResultType>
674  void evalTo(ResultType& result) const
675  {
676  const Index rows = m_qr.rows();
677  WorkVectorType workspace(rows);
678  evalTo(result, workspace);
679  }
680 
681  template <typename ResultType>
682  void evalTo(ResultType& result, WorkVectorType& workspace) const
683  {
684  using numext::conj;
685  // compute the product H'_0 H'_1 ... H'_n-1,
686  // where H_k is the k-th Householder transformation I - h_k v_k v_k'
687  // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...]
688  const Index rows = m_qr.rows();
689  const Index cols = m_qr.cols();
690  const Index size = (std::min)(rows, cols);
691  workspace.resize(rows);
692  result.setIdentity(rows, rows);
693  for (Index k = size-1; k >= 0; k--)
694  {
695  result.block(k, k, rows-k, rows-k)
696  .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), conj(m_hCoeffs.coeff(k)), &workspace.coeffRef(k));
697  result.row(k).swap(result.row(m_rowsTranspositions.coeff(k)));
698  }
699  }
700 
701  Index rows() const { return m_qr.rows(); }
702  Index cols() const { return m_qr.rows(); }
703 
704 protected:
705  typename MatrixType::Nested m_qr;
706  typename HCoeffsType::Nested m_hCoeffs;
707  typename IntDiagSizeVectorType::Nested m_rowsTranspositions;
708 };
709 
710 // template<typename MatrixType>
711 // struct evaluator<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
712 // : public evaluator<ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> > >
713 // {};
714 
715 } // end namespace internal
716 
717 template<typename MatrixType, typename PermutationIndex>
719 {
720  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
721  return MatrixQReturnType(m_qr, m_hCoeffs, m_rows_transpositions);
722 }
723 
728 template<typename Derived>
729 template<typename PermutationIndex>
732 {
734 }
735 
736 } // end namespace Eigen
737 
738 #endif // EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
const AbsReturnType abs() const
Array< int, 3, 1 > b
Array33i c
HouseholderQR< MatrixXf > qr(A)
#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived)
Definition: Macros.h:1149
#define eigen_assert(x)
Definition: Macros.h:902
v setZero(3)
#define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE)
Definition: StaticAssert.h:81
Matrix< float, 1, Dynamic > MatrixType
NumTraits< Scalar >::Real RealScalar
Definition: DenseBase.h:68
internal::traits< Derived >::Scalar Scalar
Definition: DenseBase.h:61
void swap(const DenseBase< OtherDerived > &other)
Definition: DenseBase.h:418
Householder rank-revealing QR decomposition of a matrix with full pivoting.
IntDiagSizeVectorType m_rows_transpositions
const MatrixType & matrixQR() const
const IntDiagSizeVectorType & rowsTranspositions() const
FullPivHouseholderQR & compute(const EigenBase< InputType > &matrix)
const PermutationType & colsPermutation() const
internal::plain_col_type< MatrixType >::type ColVectorType
IntDiagSizeVectorType m_cols_transpositions
MatrixQReturnType matrixQ(void) const
const HCoeffsType & hCoeffs() const
MatrixType::RealScalar logAbsDeterminant() const
PermutationMatrix< ColsAtCompileTime, MaxColsAtCompileTime, PermutationIndex > PermutationType
internal::plain_diag_type< MatrixType >::type HCoeffsType
Matrix< PermutationIndex, 1, internal::min_size_prefer_dynamic(ColsAtCompileTime, RowsAtCompileTime), RowMajor, 1, internal::min_size_prefer_fixed(MaxColsAtCompileTime, MaxRowsAtCompileTime)> IntDiagSizeVectorType
internal::FullPivHouseholderQRMatrixQReturnType< MatrixType, PermutationIndex > MatrixQReturnType
MatrixType::Scalar determinant() const
FullPivHouseholderQR()
Default Constructor.
MatrixType::PlainObject PlainObject
MatrixType::RealScalar absDeterminant() const
FullPivHouseholderQR(Index rows, Index cols)
Default Constructor with memory preallocation.
const Inverse< FullPivHouseholderQR > inverse() const
const Solve< FullPivHouseholderQR, Rhs > solve(const MatrixBase< Rhs > &b) const
FullPivHouseholderQR(const EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
SolverBase< FullPivHouseholderQR > Base
FullPivHouseholderQR & setThreshold(const RealScalar &threshold)
FullPivHouseholderQR(EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
internal::plain_row_type< MatrixType >::type RowVectorType
FullPivHouseholderQR & setThreshold(Default_t)
Expression of the inverse of another expression.
Definition: Inverse.h:46
Base class for all dense matrices, vectors, and expressions.
Definition: MatrixBase.h:52
const FullPivHouseholderQR< PlainObject, PermutationIndex > fullPivHouseholderQr() const
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:182
Base::PlainObject PlainObject
Definition: Matrix.h:194
Derived & setZero(Index size)
Pseudo expression representing a solving operation.
Definition: Solve.h:65
A base class for matrix decomposition and solvers.
Definition: SolverBase.h:71
internal::traits< FullPivHouseholderQR< MatrixType_, PermutationIndex_ > >::Scalar Scalar
Definition: SolverBase.h:75
FullPivHouseholderQR< MatrixType_, PermutationIndex_ > & derived()
Definition: EigenBase.h:48
@ RowMajor
Definition: Constants.h:323
bfloat16() min(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:684
constexpr int min_size_prefer_fixed(A a, B b)
Definition: Meta.h:553
bool isMuchSmallerThan(const Scalar &x, const OtherScalar &y, const typename NumTraits< Scalar >::Real &precision=NumTraits< Scalar >::dummy_precision())
constexpr int min_size_prefer_dynamic(A a, B b)
Definition: Meta.h:537
: InteropHeaders
Definition: Core:139
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
Default_t
Definition: Constants.h:364
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_conjugate_op< typename Derived::Scalar >, const Derived > conj(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
Definition: BFloat16.h:222
Derived & derived()
Definition: EigenBase.h:48
Eigen::Index Index
The interface type of indices.
Definition: EigenBase.h:41
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition: NumTraits.h:231