CompleteOrthogonalDecomposition.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) 2016 Rasmus Munk Larsen <rmlarsen@google.com>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H
11 #define EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H
12 
13 #include "./InternalHeaderCheck.h"
14 
15 namespace Eigen {
16 
17 namespace internal {
18 template <typename MatrixType_, typename PermutationIndex_>
19 struct traits<CompleteOrthogonalDecomposition<MatrixType_, PermutationIndex_> >
20  : traits<MatrixType_> {
21  typedef MatrixXpr XprKind;
22  typedef SolverStorage StorageKind;
23  typedef PermutationIndex_ PermutationIndex;
24  enum { Flags = 0 };
25 };
26 
27 } // end namespace internal
28 
52 template <typename MatrixType_, typename PermutationIndex_> class CompleteOrthogonalDecomposition
53  : public SolverBase<CompleteOrthogonalDecomposition<MatrixType_, PermutationIndex_> >
54 {
55  public:
56  typedef MatrixType_ MatrixType;
58 
59  template<typename Derived>
60  friend struct internal::solve_assertion;
61  typedef PermutationIndex_ PermutationIndex;
63  enum {
64  MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
65  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
66  };
67  typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
70  typedef typename internal::plain_row_type<MatrixType, Index>::type
72  typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
73  typedef typename internal::plain_row_type<MatrixType, RealScalar>::type
75  typedef HouseholderSequence<
77  typename HCoeffsType::ConjugateReturnType>>
80 
81  public:
90 
99 
116  template <typename InputType>
118  : m_cpqr(matrix.rows(), matrix.cols()),
119  m_zCoeffs((std::min)(matrix.rows(), matrix.cols())),
120  m_temp(matrix.cols())
121  {
122  compute(matrix.derived());
123  }
124 
131  template<typename InputType>
133  : m_cpqr(matrix.derived()),
134  m_zCoeffs((std::min)(matrix.rows(), matrix.cols())),
135  m_temp(matrix.cols())
136  {
137  computeInPlace();
138  }
139 
140  #ifdef EIGEN_PARSED_BY_DOXYGEN
150  template <typename Rhs>
152  const MatrixBase<Rhs>& b) const;
153  #endif
154 
157 
160  MatrixType matrixZ() const {
161  MatrixType Z = MatrixType::Identity(m_cpqr.cols(), m_cpqr.cols());
162  applyZOnTheLeftInPlace<false>(Z);
163  return Z;
164  }
165 
169  const MatrixType& matrixQTZ() const { return m_cpqr.matrixQR(); }
170 
182  const MatrixType& matrixT() const { return m_cpqr.matrixQR(); }
183 
184  template <typename InputType>
186  // Compute the column pivoted QR factorization A P = Q R.
187  m_cpqr.compute(matrix);
188  computeInPlace();
189  return *this;
190  }
191 
194  return m_cpqr.colsPermutation();
195  }
196 
210  typename MatrixType::Scalar determinant() const;
211 
225  typename MatrixType::RealScalar absDeterminant() const;
226 
240  typename MatrixType::RealScalar logAbsDeterminant() const;
241 
249  inline Index rank() const { return m_cpqr.rank(); }
250 
258  inline Index dimensionOfKernel() const { return m_cpqr.dimensionOfKernel(); }
259 
267  inline bool isInjective() const { return m_cpqr.isInjective(); }
268 
276  inline bool isSurjective() const { return m_cpqr.isSurjective(); }
277 
285  inline bool isInvertible() const { return m_cpqr.isInvertible(); }
286 
293  {
294  eigen_assert(m_cpqr.m_isInitialized && "CompleteOrthogonalDecomposition is not initialized.");
296  }
297 
298  inline Index rows() const { return m_cpqr.rows(); }
299  inline Index cols() const { return m_cpqr.cols(); }
300 
306  inline const HCoeffsType& hCoeffs() const { return m_cpqr.hCoeffs(); }
307 
313  const HCoeffsType& zCoeffs() const { return m_zCoeffs; }
314 
336  return *this;
337  }
338 
349  return *this;
350  }
351 
356  RealScalar threshold() const { return m_cpqr.threshold(); }
357 
365  inline Index nonzeroPivots() const { return m_cpqr.nonzeroPivots(); }
366 
370  inline RealScalar maxPivot() const { return m_cpqr.maxPivot(); }
371 
381  eigen_assert(m_cpqr.m_isInitialized && "Decomposition is not initialized.");
382  return Success;
383  }
384 
385 #ifndef EIGEN_PARSED_BY_DOXYGEN
386  template <typename RhsType, typename DstType>
387  void _solve_impl(const RhsType& rhs, DstType& dst) const;
388 
389  template<bool Conjugate, typename RhsType, typename DstType>
390  void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
391 #endif
392 
393  protected:
395 
396  template<bool Transpose_, typename Rhs>
397  void _check_solve_assertion(const Rhs& b) const {
399  eigen_assert(m_cpqr.m_isInitialized && "CompleteOrthogonalDecomposition is not initialized.");
400  eigen_assert((Transpose_?derived().cols():derived().rows())==b.rows() && "CompleteOrthogonalDecomposition::solve(): invalid number of rows of the right hand side matrix b");
401  }
402 
403  void computeInPlace();
404 
409  template <bool Conjugate, typename Rhs>
410  void applyZOnTheLeftInPlace(Rhs& rhs) const;
411 
414  template <typename Rhs>
415  void applyZAdjointOnTheLeftInPlace(Rhs& rhs) const;
416 
420 };
421 
422 template <typename MatrixType, typename PermutationIndex>
423 typename MatrixType::Scalar
425  return m_cpqr.determinant();
426 }
427 
428 template <typename MatrixType, typename PermutationIndex>
429 typename MatrixType::RealScalar
431  return m_cpqr.absDeterminant();
432 }
433 
434 template <typename MatrixType, typename PermutationIndex>
435 typename MatrixType::RealScalar
437  return m_cpqr.logAbsDeterminant();
438 }
439 
447 template <typename MatrixType, typename PermutationIndex>
449 {
451 
452  const Index rank = m_cpqr.rank();
453  const Index cols = m_cpqr.cols();
454  const Index rows = m_cpqr.rows();
455  m_zCoeffs.resize((std::min)(rows, cols));
456  m_temp.resize(cols);
457 
458  if (rank < cols) {
459  // We have reduced the (permuted) matrix to the form
460  // [R11 R12]
461  // [ 0 R22]
462  // where R11 is r-by-r (r = rank) upper triangular, R12 is
463  // r-by-(n-r), and R22 is empty or the norm of R22 is negligible.
464  // We now compute the complete orthogonal decomposition by applying
465  // Householder transformations from the right to the upper trapezoidal
466  // matrix X = [R11 R12] to zero out R12 and obtain the factorization
467  // [R11 R12] = [T11 0] * Z, where T11 is r-by-r upper triangular and
468  // Z = Z(0) * Z(1) ... Z(r-1) is an n-by-n orthogonal matrix.
469  // We store the data representing Z in R12 and m_zCoeffs.
470  for (Index k = rank - 1; k >= 0; --k) {
471  if (k != rank - 1) {
472  // Given the API for Householder reflectors, it is more convenient if
473  // we swap the leading parts of columns k and r-1 (zero-based) to form
474  // the matrix X_k = [X(0:k, k), X(0:k, r:n)]
475  m_cpqr.m_qr.col(k).head(k + 1).swap(
476  m_cpqr.m_qr.col(rank - 1).head(k + 1));
477  }
478  // Construct Householder reflector Z(k) to zero out the last row of X_k,
479  // i.e. choose Z(k) such that
480  // [X(k, k), X(k, r:n)] * Z(k) = [beta, 0, .., 0].
481  RealScalar beta;
482  m_cpqr.m_qr.row(k)
483  .tail(cols - rank + 1)
484  .makeHouseholderInPlace(m_zCoeffs(k), beta);
485  m_cpqr.m_qr(k, rank - 1) = beta;
486  if (k > 0) {
487  // Apply Z(k) to the first k rows of X_k
488  m_cpqr.m_qr.topRightCorner(k, cols - rank + 1)
489  .applyHouseholderOnTheRight(
490  m_cpqr.m_qr.row(k).tail(cols - rank).adjoint(), m_zCoeffs(k),
491  &m_temp(0));
492  }
493  if (k != rank - 1) {
494  // Swap X(0:k,k) back to its proper location.
495  m_cpqr.m_qr.col(k).head(k + 1).swap(
496  m_cpqr.m_qr.col(rank - 1).head(k + 1));
497  }
498  }
499  }
500 }
501 
502 template <typename MatrixType, typename PermutationIndex>
503 template <bool Conjugate, typename Rhs>
505  Rhs& rhs) const {
506  const Index cols = this->cols();
507  const Index nrhs = rhs.cols();
508  const Index rank = this->rank();
510  for (Index k = rank-1; k >= 0; --k) {
511  if (k != rank - 1) {
512  rhs.row(k).swap(rhs.row(rank - 1));
513  }
514  rhs.middleRows(rank - 1, cols - rank + 1)
515  .applyHouseholderOnTheLeft(
516  matrixQTZ().row(k).tail(cols - rank).transpose().template conjugateIf<!Conjugate>(), zCoeffs().template conjugateIf<Conjugate>()(k),
517  &temp(0));
518  if (k != rank - 1) {
519  rhs.row(k).swap(rhs.row(rank - 1));
520  }
521  }
522 }
523 
524 template <typename MatrixType, typename PermutationIndex>
525 template <typename Rhs>
527  Rhs& rhs) const {
528  const Index cols = this->cols();
529  const Index nrhs = rhs.cols();
530  const Index rank = this->rank();
532  for (Index k = 0; k < rank; ++k) {
533  if (k != rank - 1) {
534  rhs.row(k).swap(rhs.row(rank - 1));
535  }
536  rhs.middleRows(rank - 1, cols - rank + 1)
537  .applyHouseholderOnTheLeft(
538  matrixQTZ().row(k).tail(cols - rank).adjoint(), zCoeffs()(k),
539  &temp(0));
540  if (k != rank - 1) {
541  rhs.row(k).swap(rhs.row(rank - 1));
542  }
543  }
544 }
545 
546 #ifndef EIGEN_PARSED_BY_DOXYGEN
547 template <typename MatrixType_, typename PermutationIndex_>
548 template <typename RhsType, typename DstType>
550  const RhsType& rhs, DstType& dst) const {
551  const Index rank = this->rank();
552  if (rank == 0) {
553  dst.setZero();
554  return;
555  }
556 
557  // Compute c = Q^* * rhs
558  typename RhsType::PlainObject c(rhs);
559  c.applyOnTheLeft(matrixQ().setLength(rank).adjoint());
560 
561  // Solve T z = c(1:rank, :)
562  dst.topRows(rank) = matrixT()
563  .topLeftCorner(rank, rank)
564  .template triangularView<Upper>()
565  .solve(c.topRows(rank));
566 
567  const Index cols = this->cols();
568  if (rank < cols) {
569  // Compute y = Z^* * [ z ]
570  // [ 0 ]
571  dst.bottomRows(cols - rank).setZero();
572  applyZAdjointOnTheLeftInPlace(dst);
573  }
574 
575  // Undo permutation to get x = P^{-1} * y.
576  dst = colsPermutation() * dst;
577 }
578 
579 template<typename MatrixType_, typename PermutationIndex_>
580 template<bool Conjugate, typename RhsType, typename DstType>
581 void CompleteOrthogonalDecomposition<MatrixType_, PermutationIndex_>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
582 {
583  const Index rank = this->rank();
584 
585  if (rank == 0) {
586  dst.setZero();
587  return;
588  }
589 
590  typename RhsType::PlainObject c(colsPermutation().transpose()*rhs);
591 
592  if (rank < cols()) {
593  applyZOnTheLeftInPlace<!Conjugate>(c);
594  }
595 
596  matrixT().topLeftCorner(rank, rank)
597  .template triangularView<Upper>()
598  .transpose().template conjugateIf<Conjugate>()
599  .solveInPlace(c.topRows(rank));
600 
601  dst.topRows(rank) = c.topRows(rank);
602  dst.bottomRows(rows()-rank).setZero();
603 
604  dst.applyOnTheLeft(householderQ().setLength(rank).template conjugateIf<!Conjugate>() );
605 }
606 #endif
607 
608 namespace internal {
609 
610 template<typename MatrixType, typename PermutationIndex>
611 struct traits<Inverse<CompleteOrthogonalDecomposition<MatrixType, PermutationIndex> > >
612  : traits<typename Transpose<typename MatrixType::PlainObject>::PlainObject>
613 {
614  enum { Flags = 0 };
615 };
616 
617 template<typename DstXprType, typename MatrixType, typename PermutationIndex>
618 struct Assignment<DstXprType, Inverse<CompleteOrthogonalDecomposition<MatrixType, PermutationIndex> >, internal::assign_op<typename DstXprType::Scalar,typename CompleteOrthogonalDecomposition<MatrixType, PermutationIndex>::Scalar>, Dense2Dense>
619 {
620  typedef CompleteOrthogonalDecomposition<MatrixType, PermutationIndex> CodType;
621  typedef Inverse<CodType> SrcXprType;
622  static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<typename DstXprType::Scalar,typename CodType::Scalar> &)
623  {
624  typedef Matrix<typename CodType::Scalar, CodType::RowsAtCompileTime, CodType::RowsAtCompileTime, 0, CodType::MaxRowsAtCompileTime, CodType::MaxRowsAtCompileTime> IdentityMatrixType;
625  dst = src.nestedExpression().solve(IdentityMatrixType::Identity(src.cols(), src.cols()));
626  }
627 };
628 
629 } // end namespace internal
630 
632 template <typename MatrixType, typename PermutationIndex>
635  return m_cpqr.householderQ();
636 }
637 
642 template <typename Derived>
643 template <typename PermutationIndex>
647 }
648 
649 } // end namespace Eigen
650 
651 #endif // EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H
Array< int, 3, 1 > b
RowXpr row(Index i)
This is the const version of row(). *‍/.
FixedSegmentReturnType<... >::Type tail(NType n)
Array33i c
#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived)
Definition: Macros.h:1149
#define EIGEN_ONLY_USED_FOR_DEBUG(x)
Definition: Macros.h:914
#define eigen_assert(x)
Definition: Macros.h:902
#define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE)
Definition: StaticAssert.h:81
Matrix< float, 1, Dynamic > MatrixType
ColPivHouseholderQR & setThreshold(const RealScalar &threshold)
const HCoeffsType & hCoeffs() const
const PermutationType & colsPermutation() const
HouseholderSequenceType householderQ() const
ColPivHouseholderQR & compute(const EigenBase< InputType > &matrix)
const MatrixType & matrixQR() const
Complete orthogonal decomposition (COD) of a matrix.
internal::plain_diag_type< MatrixType >::type HCoeffsType
HouseholderSequence< MatrixType, internal::remove_all_t< typename HCoeffsType::ConjugateReturnType > > HouseholderSequenceType
CompleteOrthogonalDecomposition & compute(const EigenBase< InputType > &matrix)
PermutationMatrix< ColsAtCompileTime, MaxColsAtCompileTime, PermutationIndex > PermutationType
CompleteOrthogonalDecomposition(const EigenBase< InputType > &matrix)
Constructs a complete orthogonal decomposition from a given matrix.
CompleteOrthogonalDecomposition(Index rows, Index cols)
Default Constructor with memory preallocation.
CompleteOrthogonalDecomposition & setThreshold(const RealScalar &threshold)
const Solve< CompleteOrthogonalDecomposition, Rhs > solve(const MatrixBase< Rhs > &b) const
HouseholderSequenceType householderQ(void) const
ColPivHouseholderQR< MatrixType, PermutationIndex > m_cpqr
ComputationInfo info() const
Reports whether the complete orthogonal decomposition was successful.
internal::plain_row_type< MatrixType >::type RowVectorType
SolverBase< CompleteOrthogonalDecomposition > Base
internal::plain_row_type< MatrixType, Index >::type IntRowVectorType
internal::plain_row_type< MatrixType, RealScalar >::type RealRowVectorType
CompleteOrthogonalDecomposition & setThreshold(Default_t)
const Inverse< CompleteOrthogonalDecomposition > pseudoInverse() const
CompleteOrthogonalDecomposition(EigenBase< InputType > &matrix)
Constructs a complete orthogonal decomposition from a given matrix.
NumTraits< Scalar >::Real RealScalar
Definition: DenseBase.h:68
internal::traits< Derived >::Scalar Scalar
Definition: DenseBase.h:61
Sequence of Householder reflections acting on subspaces with decreasing size.
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 CompleteOrthogonalDecomposition< PlainObject, PermutationIndex > completeOrthogonalDecomposition() 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< CompleteOrthogonalDecomposition< MatrixType_, PermutationIndex_ > >::Scalar Scalar
Definition: SolverBase.h:75
CompleteOrthogonalDecomposition< MatrixType_, PermutationIndex_ > & derived()
Definition: EigenBase.h:48
ComputationInfo
Definition: Constants.h:444
@ Success
Definition: Constants.h:446
bfloat16() max(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:690
bfloat16() min(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:684
typename remove_all< T >::type remove_all_t
Definition: Meta.h:119
: 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
@ Default
Definition: Constants.h:364
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