• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 namespace Eigen {
14 
15 namespace internal {
16 template <typename _MatrixType>
17 struct traits<CompleteOrthogonalDecomposition<_MatrixType> >
18     : traits<_MatrixType> {
19   enum { Flags = 0 };
20 };
21 
22 }  // end namespace internal
23 
24 /** \ingroup QR_Module
25   *
26   * \class CompleteOrthogonalDecomposition
27   *
28   * \brief Complete orthogonal decomposition (COD) of a matrix.
29   *
30   * \param MatrixType the type of the matrix of which we are computing the COD.
31   *
32   * This class performs a rank-revealing complete orthogonal decomposition of a
33   * matrix  \b A into matrices \b P, \b Q, \b T, and \b Z such that
34   * \f[
35   *  \mathbf{A} \, \mathbf{P} = \mathbf{Q} \,
36   *                     \begin{bmatrix} \mathbf{T} &  \mathbf{0} \\
37   *                                     \mathbf{0} & \mathbf{0} \end{bmatrix} \, \mathbf{Z}
38   * \f]
39   * by using Householder transformations. Here, \b P is a permutation matrix,
40   * \b Q and \b Z are unitary matrices and \b T an upper triangular matrix of
41   * size rank-by-rank. \b A may be rank deficient.
42   *
43   * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism.
44   *
45   * \sa MatrixBase::completeOrthogonalDecomposition()
46   */
47 template <typename _MatrixType>
48 class CompleteOrthogonalDecomposition {
49  public:
50   typedef _MatrixType MatrixType;
51   enum {
52     RowsAtCompileTime = MatrixType::RowsAtCompileTime,
53     ColsAtCompileTime = MatrixType::ColsAtCompileTime,
54     MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
55     MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
56   };
57   typedef typename MatrixType::Scalar Scalar;
58   typedef typename MatrixType::RealScalar RealScalar;
59   typedef typename MatrixType::StorageIndex StorageIndex;
60   typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
61   typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime>
62       PermutationType;
63   typedef typename internal::plain_row_type<MatrixType, Index>::type
64       IntRowVectorType;
65   typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
66   typedef typename internal::plain_row_type<MatrixType, RealScalar>::type
67       RealRowVectorType;
68   typedef HouseholderSequence<
69       MatrixType, typename internal::remove_all<
70                       typename HCoeffsType::ConjugateReturnType>::type>
71       HouseholderSequenceType;
72   typedef typename MatrixType::PlainObject PlainObject;
73 
74  private:
75   typedef typename PermutationType::Index PermIndexType;
76 
77  public:
78   /**
79    * \brief Default Constructor.
80    *
81    * The default constructor is useful in cases in which the user intends to
82    * perform decompositions via
83    * \c CompleteOrthogonalDecomposition::compute(const* MatrixType&).
84    */
85   CompleteOrthogonalDecomposition() : m_cpqr(), m_zCoeffs(), m_temp() {}
86 
87   /** \brief Default Constructor with memory preallocation
88    *
89    * Like the default constructor but with preallocation of the internal data
90    * according to the specified problem \a size.
91    * \sa CompleteOrthogonalDecomposition()
92    */
93   CompleteOrthogonalDecomposition(Index rows, Index cols)
94       : m_cpqr(rows, cols), m_zCoeffs((std::min)(rows, cols)), m_temp(cols) {}
95 
96   /** \brief Constructs a complete orthogonal decomposition from a given
97    * matrix.
98    *
99    * This constructor computes the complete orthogonal decomposition of the
100    * matrix \a matrix by calling the method compute(). The default
101    * threshold for rank determination will be used. It is a short cut for:
102    *
103    * \code
104    * CompleteOrthogonalDecomposition<MatrixType> cod(matrix.rows(),
105    *                                                 matrix.cols());
106    * cod.setThreshold(Default);
107    * cod.compute(matrix);
108    * \endcode
109    *
110    * \sa compute()
111    */
112   template <typename InputType>
113   explicit CompleteOrthogonalDecomposition(const EigenBase<InputType>& matrix)
114       : m_cpqr(matrix.rows(), matrix.cols()),
115         m_zCoeffs((std::min)(matrix.rows(), matrix.cols())),
116         m_temp(matrix.cols())
117   {
118     compute(matrix.derived());
119   }
120 
121   /** \brief Constructs a complete orthogonal decomposition from a given matrix
122     *
123     * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when \c MatrixType is a Eigen::Ref.
124     *
125     * \sa CompleteOrthogonalDecomposition(const EigenBase&)
126     */
127   template<typename InputType>
128   explicit CompleteOrthogonalDecomposition(EigenBase<InputType>& matrix)
129     : m_cpqr(matrix.derived()),
130       m_zCoeffs((std::min)(matrix.rows(), matrix.cols())),
131       m_temp(matrix.cols())
132   {
133     computeInPlace();
134   }
135 
136 
137   /** This method computes the minimum-norm solution X to a least squares
138    * problem \f[\mathrm{minimize} \|A X - B\|, \f] where \b A is the matrix of
139    * which \c *this is the complete orthogonal decomposition.
140    *
141    * \param b the right-hand sides of the problem to solve.
142    *
143    * \returns a solution.
144    *
145    */
146   template <typename Rhs>
147   inline const Solve<CompleteOrthogonalDecomposition, Rhs> solve(
148       const MatrixBase<Rhs>& b) const {
149     eigen_assert(m_cpqr.m_isInitialized &&
150                  "CompleteOrthogonalDecomposition is not initialized.");
151     return Solve<CompleteOrthogonalDecomposition, Rhs>(*this, b.derived());
152   }
153 
154   HouseholderSequenceType householderQ(void) const;
155   HouseholderSequenceType matrixQ(void) const { return m_cpqr.householderQ(); }
156 
157   /** \returns the matrix \b Z.
158    */
159   MatrixType matrixZ() const {
160     MatrixType Z = MatrixType::Identity(m_cpqr.cols(), m_cpqr.cols());
161     applyZAdjointOnTheLeftInPlace(Z);
162     return Z.adjoint();
163   }
164 
165   /** \returns a reference to the matrix where the complete orthogonal
166    * decomposition is stored
167    */
168   const MatrixType& matrixQTZ() const { return m_cpqr.matrixQR(); }
169 
170   /** \returns a reference to the matrix where the complete orthogonal
171    * decomposition is stored.
172    * \warning The strict lower part and \code cols() - rank() \endcode right
173    * columns of this matrix contains internal values.
174    * Only the upper triangular part should be referenced. To get it, use
175    * \code matrixT().template triangularView<Upper>() \endcode
176    * For rank-deficient matrices, use
177    * \code
178    * matrixR().topLeftCorner(rank(), rank()).template triangularView<Upper>()
179    * \endcode
180    */
181   const MatrixType& matrixT() const { return m_cpqr.matrixQR(); }
182 
183   template <typename InputType>
184   CompleteOrthogonalDecomposition& compute(const EigenBase<InputType>& matrix) {
185     // Compute the column pivoted QR factorization A P = Q R.
186     m_cpqr.compute(matrix);
187     computeInPlace();
188     return *this;
189   }
190 
191   /** \returns a const reference to the column permutation matrix */
192   const PermutationType& colsPermutation() const {
193     return m_cpqr.colsPermutation();
194   }
195 
196   /** \returns the absolute value of the determinant of the matrix of which
197    * *this is the complete orthogonal decomposition. It has only linear
198    * complexity (that is, O(n) where n is the dimension of the square matrix)
199    * as the complete orthogonal decomposition has already been computed.
200    *
201    * \note This is only for square matrices.
202    *
203    * \warning a determinant can be very big or small, so for matrices
204    * of large enough dimension, there is a risk of overflow/underflow.
205    * One way to work around that is to use logAbsDeterminant() instead.
206    *
207    * \sa logAbsDeterminant(), MatrixBase::determinant()
208    */
209   typename MatrixType::RealScalar absDeterminant() const;
210 
211   /** \returns the natural log of the absolute value of the determinant of the
212    * matrix of which *this is the complete orthogonal decomposition. It has
213    * only linear complexity (that is, O(n) where n is the dimension of the
214    * square matrix) as the complete orthogonal decomposition has already been
215    * computed.
216    *
217    * \note This is only for square matrices.
218    *
219    * \note This method is useful to work around the risk of overflow/underflow
220    * that's inherent to determinant computation.
221    *
222    * \sa absDeterminant(), MatrixBase::determinant()
223    */
224   typename MatrixType::RealScalar logAbsDeterminant() const;
225 
226   /** \returns the rank of the matrix of which *this is the complete orthogonal
227    * decomposition.
228    *
229    * \note This method has to determine which pivots should be considered
230    * nonzero. For that, it uses the threshold value that you can control by
231    * calling setThreshold(const RealScalar&).
232    */
233   inline Index rank() const { return m_cpqr.rank(); }
234 
235   /** \returns the dimension of the kernel of the matrix of which *this is the
236    * complete orthogonal decomposition.
237    *
238    * \note This method has to determine which pivots should be considered
239    * nonzero. For that, it uses the threshold value that you can control by
240    * calling setThreshold(const RealScalar&).
241    */
242   inline Index dimensionOfKernel() const { return m_cpqr.dimensionOfKernel(); }
243 
244   /** \returns true if the matrix of which *this is the decomposition represents
245    * an injective linear map, i.e. has trivial kernel; false otherwise.
246    *
247    * \note This method has to determine which pivots should be considered
248    * nonzero. For that, it uses the threshold value that you can control by
249    * calling setThreshold(const RealScalar&).
250    */
251   inline bool isInjective() const { return m_cpqr.isInjective(); }
252 
253   /** \returns true if the matrix of which *this is the decomposition represents
254    * a surjective linear map; false otherwise.
255    *
256    * \note This method has to determine which pivots should be considered
257    * nonzero. For that, it uses the threshold value that you can control by
258    * calling setThreshold(const RealScalar&).
259    */
260   inline bool isSurjective() const { return m_cpqr.isSurjective(); }
261 
262   /** \returns true if the matrix of which *this is the complete orthogonal
263    * decomposition is invertible.
264    *
265    * \note This method has to determine which pivots should be considered
266    * nonzero. For that, it uses the threshold value that you can control by
267    * calling setThreshold(const RealScalar&).
268    */
269   inline bool isInvertible() const { return m_cpqr.isInvertible(); }
270 
271   /** \returns the pseudo-inverse of the matrix of which *this is the complete
272    * orthogonal decomposition.
273    * \warning: Do not compute \c this->pseudoInverse()*rhs to solve a linear systems.
274    * It is more efficient and numerically stable to call \c this->solve(rhs).
275    */
276   inline const Inverse<CompleteOrthogonalDecomposition> pseudoInverse() const
277   {
278     return Inverse<CompleteOrthogonalDecomposition>(*this);
279   }
280 
281   inline Index rows() const { return m_cpqr.rows(); }
282   inline Index cols() const { return m_cpqr.cols(); }
283 
284   /** \returns a const reference to the vector of Householder coefficients used
285    * to represent the factor \c Q.
286    *
287    * For advanced uses only.
288    */
289   inline const HCoeffsType& hCoeffs() const { return m_cpqr.hCoeffs(); }
290 
291   /** \returns a const reference to the vector of Householder coefficients
292    * used to represent the factor \c Z.
293    *
294    * For advanced uses only.
295    */
296   const HCoeffsType& zCoeffs() const { return m_zCoeffs; }
297 
298   /** Allows to prescribe a threshold to be used by certain methods, such as
299    * rank(), who need to determine when pivots are to be considered nonzero.
300    * Most be called before calling compute().
301    *
302    * When it needs to get the threshold value, Eigen calls threshold(). By
303    * default, this uses a formula to automatically determine a reasonable
304    * threshold. Once you have called the present method
305    * setThreshold(const RealScalar&), your value is used instead.
306    *
307    * \param threshold The new value to use as the threshold.
308    *
309    * A pivot will be considered nonzero if its absolute value is strictly
310    * greater than
311    *  \f$ \vert pivot \vert \leqslant threshold \times \vert maxpivot \vert \f$
312    * where maxpivot is the biggest pivot.
313    *
314    * If you want to come back to the default behavior, call
315    * setThreshold(Default_t)
316    */
317   CompleteOrthogonalDecomposition& setThreshold(const RealScalar& threshold) {
318     m_cpqr.setThreshold(threshold);
319     return *this;
320   }
321 
322   /** Allows to come back to the default behavior, letting Eigen use its default
323    * formula for determining the threshold.
324    *
325    * You should pass the special object Eigen::Default as parameter here.
326    * \code qr.setThreshold(Eigen::Default); \endcode
327    *
328    * See the documentation of setThreshold(const RealScalar&).
329    */
330   CompleteOrthogonalDecomposition& setThreshold(Default_t) {
331     m_cpqr.setThreshold(Default);
332     return *this;
333   }
334 
335   /** Returns the threshold that will be used by certain methods such as rank().
336    *
337    * See the documentation of setThreshold(const RealScalar&).
338    */
339   RealScalar threshold() const { return m_cpqr.threshold(); }
340 
341   /** \returns the number of nonzero pivots in the complete orthogonal
342    * decomposition. Here nonzero is meant in the exact sense, not in a
343    * fuzzy sense. So that notion isn't really intrinsically interesting,
344    * but it is still useful when implementing algorithms.
345    *
346    * \sa rank()
347    */
348   inline Index nonzeroPivots() const { return m_cpqr.nonzeroPivots(); }
349 
350   /** \returns the absolute value of the biggest pivot, i.e. the biggest
351    *          diagonal coefficient of R.
352    */
353   inline RealScalar maxPivot() const { return m_cpqr.maxPivot(); }
354 
355   /** \brief Reports whether the complete orthogonal decomposition was
356    * succesful.
357    *
358    * \note This function always returns \c Success. It is provided for
359    * compatibility
360    * with other factorization routines.
361    * \returns \c Success
362    */
363   ComputationInfo info() const {
364     eigen_assert(m_cpqr.m_isInitialized && "Decomposition is not initialized.");
365     return Success;
366   }
367 
368 #ifndef EIGEN_PARSED_BY_DOXYGEN
369   template <typename RhsType, typename DstType>
370   EIGEN_DEVICE_FUNC void _solve_impl(const RhsType& rhs, DstType& dst) const;
371 #endif
372 
373  protected:
374   static void check_template_parameters() {
375     EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
376   }
377 
378   void computeInPlace();
379 
380   /** Overwrites \b rhs with \f$ \mathbf{Z}^* * \mathbf{rhs} \f$.
381    */
382   template <typename Rhs>
383   void applyZAdjointOnTheLeftInPlace(Rhs& rhs) const;
384 
385   ColPivHouseholderQR<MatrixType> m_cpqr;
386   HCoeffsType m_zCoeffs;
387   RowVectorType m_temp;
388 };
389 
390 template <typename MatrixType>
391 typename MatrixType::RealScalar
392 CompleteOrthogonalDecomposition<MatrixType>::absDeterminant() const {
393   return m_cpqr.absDeterminant();
394 }
395 
396 template <typename MatrixType>
397 typename MatrixType::RealScalar
398 CompleteOrthogonalDecomposition<MatrixType>::logAbsDeterminant() const {
399   return m_cpqr.logAbsDeterminant();
400 }
401 
402 /** Performs the complete orthogonal decomposition of the given matrix \a
403  * matrix. The result of the factorization is stored into \c *this, and a
404  * reference to \c *this is returned.
405  *
406  * \sa class CompleteOrthogonalDecomposition,
407  * CompleteOrthogonalDecomposition(const MatrixType&)
408  */
409 template <typename MatrixType>
410 void CompleteOrthogonalDecomposition<MatrixType>::computeInPlace()
411 {
412   check_template_parameters();
413 
414   // the column permutation is stored as int indices, so just to be sure:
415   eigen_assert(m_cpqr.cols() <= NumTraits<int>::highest());
416 
417   const Index rank = m_cpqr.rank();
418   const Index cols = m_cpqr.cols();
419   const Index rows = m_cpqr.rows();
420   m_zCoeffs.resize((std::min)(rows, cols));
421   m_temp.resize(cols);
422 
423   if (rank < cols) {
424     // We have reduced the (permuted) matrix to the form
425     //   [R11 R12]
426     //   [ 0  R22]
427     // where R11 is r-by-r (r = rank) upper triangular, R12 is
428     // r-by-(n-r), and R22 is empty or the norm of R22 is negligible.
429     // We now compute the complete orthogonal decomposition by applying
430     // Householder transformations from the right to the upper trapezoidal
431     // matrix X = [R11 R12] to zero out R12 and obtain the factorization
432     // [R11 R12] = [T11 0] * Z, where T11 is r-by-r upper triangular and
433     // Z = Z(0) * Z(1) ... Z(r-1) is an n-by-n orthogonal matrix.
434     // We store the data representing Z in R12 and m_zCoeffs.
435     for (Index k = rank - 1; k >= 0; --k) {
436       if (k != rank - 1) {
437         // Given the API for Householder reflectors, it is more convenient if
438         // we swap the leading parts of columns k and r-1 (zero-based) to form
439         // the matrix X_k = [X(0:k, k), X(0:k, r:n)]
440         m_cpqr.m_qr.col(k).head(k + 1).swap(
441             m_cpqr.m_qr.col(rank - 1).head(k + 1));
442       }
443       // Construct Householder reflector Z(k) to zero out the last row of X_k,
444       // i.e. choose Z(k) such that
445       // [X(k, k), X(k, r:n)] * Z(k) = [beta, 0, .., 0].
446       RealScalar beta;
447       m_cpqr.m_qr.row(k)
448           .tail(cols - rank + 1)
449           .makeHouseholderInPlace(m_zCoeffs(k), beta);
450       m_cpqr.m_qr(k, rank - 1) = beta;
451       if (k > 0) {
452         // Apply Z(k) to the first k rows of X_k
453         m_cpqr.m_qr.topRightCorner(k, cols - rank + 1)
454             .applyHouseholderOnTheRight(
455                 m_cpqr.m_qr.row(k).tail(cols - rank).transpose(), m_zCoeffs(k),
456                 &m_temp(0));
457       }
458       if (k != rank - 1) {
459         // Swap X(0:k,k) back to its proper location.
460         m_cpqr.m_qr.col(k).head(k + 1).swap(
461             m_cpqr.m_qr.col(rank - 1).head(k + 1));
462       }
463     }
464   }
465 }
466 
467 template <typename MatrixType>
468 template <typename Rhs>
469 void CompleteOrthogonalDecomposition<MatrixType>::applyZAdjointOnTheLeftInPlace(
470     Rhs& rhs) const {
471   const Index cols = this->cols();
472   const Index nrhs = rhs.cols();
473   const Index rank = this->rank();
474   Matrix<typename MatrixType::Scalar, Dynamic, 1> temp((std::max)(cols, nrhs));
475   for (Index k = 0; k < rank; ++k) {
476     if (k != rank - 1) {
477       rhs.row(k).swap(rhs.row(rank - 1));
478     }
479     rhs.middleRows(rank - 1, cols - rank + 1)
480         .applyHouseholderOnTheLeft(
481             matrixQTZ().row(k).tail(cols - rank).adjoint(), zCoeffs()(k),
482             &temp(0));
483     if (k != rank - 1) {
484       rhs.row(k).swap(rhs.row(rank - 1));
485     }
486   }
487 }
488 
489 #ifndef EIGEN_PARSED_BY_DOXYGEN
490 template <typename _MatrixType>
491 template <typename RhsType, typename DstType>
492 void CompleteOrthogonalDecomposition<_MatrixType>::_solve_impl(
493     const RhsType& rhs, DstType& dst) const {
494   eigen_assert(rhs.rows() == this->rows());
495 
496   const Index rank = this->rank();
497   if (rank == 0) {
498     dst.setZero();
499     return;
500   }
501 
502   // Compute c = Q^* * rhs
503   // Note that the matrix Q = H_0^* H_1^*... so its inverse is
504   // Q^* = (H_0 H_1 ...)^T
505   typename RhsType::PlainObject c(rhs);
506   c.applyOnTheLeft(
507       householderSequence(matrixQTZ(), hCoeffs()).setLength(rank).transpose());
508 
509   // Solve T z = c(1:rank, :)
510   dst.topRows(rank) = matrixT()
511                           .topLeftCorner(rank, rank)
512                           .template triangularView<Upper>()
513                           .solve(c.topRows(rank));
514 
515   const Index cols = this->cols();
516   if (rank < cols) {
517     // Compute y = Z^* * [ z ]
518     //                   [ 0 ]
519     dst.bottomRows(cols - rank).setZero();
520     applyZAdjointOnTheLeftInPlace(dst);
521   }
522 
523   // Undo permutation to get x = P^{-1} * y.
524   dst = colsPermutation() * dst;
525 }
526 #endif
527 
528 namespace internal {
529 
530 template<typename DstXprType, typename MatrixType>
531 struct Assignment<DstXprType, Inverse<CompleteOrthogonalDecomposition<MatrixType> >, internal::assign_op<typename DstXprType::Scalar,typename CompleteOrthogonalDecomposition<MatrixType>::Scalar>, Dense2Dense>
532 {
533   typedef CompleteOrthogonalDecomposition<MatrixType> CodType;
534   typedef Inverse<CodType> SrcXprType;
535   static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<typename DstXprType::Scalar,typename CodType::Scalar> &)
536   {
537     dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.rows()));
538   }
539 };
540 
541 } // end namespace internal
542 
543 /** \returns the matrix Q as a sequence of householder transformations */
544 template <typename MatrixType>
545 typename CompleteOrthogonalDecomposition<MatrixType>::HouseholderSequenceType
546 CompleteOrthogonalDecomposition<MatrixType>::householderQ() const {
547   return m_cpqr.householderQ();
548 }
549 
550 /** \return the complete orthogonal decomposition of \c *this.
551   *
552   * \sa class CompleteOrthogonalDecomposition
553   */
554 template <typename Derived>
555 const CompleteOrthogonalDecomposition<typename MatrixBase<Derived>::PlainObject>
556 MatrixBase<Derived>::completeOrthogonalDecomposition() const {
557   return CompleteOrthogonalDecomposition<PlainObject>(eval());
558 }
559 
560 }  // end namespace Eigen
561 
562 #endif  // EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H
563