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_COLPIVOTINGHOUSEHOLDERQR_H
12 #define EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
13
14 namespace Eigen {
15
16 /** \ingroup QR_Module
17 *
18 * \class ColPivHouseholderQR
19 *
20 * \brief Householder rank-revealing QR decomposition of a matrix with column-pivoting
21 *
22 * \param MatrixType the type of the matrix of which we are computing the QR decomposition
23 *
24 * This class performs a rank-revealing QR decomposition of a matrix \b A into matrices \b P, \b Q and \b R
25 * such that
26 * \f[
27 * \mathbf{A} \, \mathbf{P} = \mathbf{Q} \, \mathbf{R}
28 * \f]
29 * by using Householder transformations. Here, \b P is a permutation matrix, \b Q a unitary matrix and \b R an
30 * upper triangular matrix.
31 *
32 * This decomposition performs column pivoting in order to be rank-revealing and improve
33 * numerical stability. It is slower than HouseholderQR, and faster than FullPivHouseholderQR.
34 *
35 * \sa MatrixBase::colPivHouseholderQr()
36 */
37 template<typename _MatrixType> class ColPivHouseholderQR
38 {
39 public:
40
41 typedef _MatrixType MatrixType;
42 enum {
43 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
44 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
45 Options = MatrixType::Options,
46 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
47 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
48 };
49 typedef typename MatrixType::Scalar Scalar;
50 typedef typename MatrixType::RealScalar RealScalar;
51 typedef typename MatrixType::Index Index;
52 typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, Options, MaxRowsAtCompileTime, MaxRowsAtCompileTime> MatrixQType;
53 typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
54 typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
55 typedef typename internal::plain_row_type<MatrixType, Index>::type IntRowVectorType;
56 typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
57 typedef typename internal::plain_row_type<MatrixType, RealScalar>::type RealRowVectorType;
58 typedef typename HouseholderSequence<MatrixType,HCoeffsType>::ConjugateReturnType HouseholderSequenceType;
59
60 /**
61 * \brief Default Constructor.
62 *
63 * The default constructor is useful in cases in which the user intends to
64 * perform decompositions via ColPivHouseholderQR::compute(const MatrixType&).
65 */
ColPivHouseholderQR()66 ColPivHouseholderQR()
67 : m_qr(),
68 m_hCoeffs(),
69 m_colsPermutation(),
70 m_colsTranspositions(),
71 m_temp(),
72 m_colSqNorms(),
73 m_isInitialized(false) {}
74
75 /** \brief Default Constructor with memory preallocation
76 *
77 * Like the default constructor but with preallocation of the internal data
78 * according to the specified problem \a size.
79 * \sa ColPivHouseholderQR()
80 */
ColPivHouseholderQR(Index rows,Index cols)81 ColPivHouseholderQR(Index rows, Index cols)
82 : m_qr(rows, cols),
83 m_hCoeffs((std::min)(rows,cols)),
84 m_colsPermutation(cols),
85 m_colsTranspositions(cols),
86 m_temp(cols),
87 m_colSqNorms(cols),
88 m_isInitialized(false),
89 m_usePrescribedThreshold(false) {}
90
ColPivHouseholderQR(const MatrixType & matrix)91 ColPivHouseholderQR(const MatrixType& matrix)
92 : m_qr(matrix.rows(), matrix.cols()),
93 m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
94 m_colsPermutation(matrix.cols()),
95 m_colsTranspositions(matrix.cols()),
96 m_temp(matrix.cols()),
97 m_colSqNorms(matrix.cols()),
98 m_isInitialized(false),
99 m_usePrescribedThreshold(false)
100 {
101 compute(matrix);
102 }
103
104 /** This method finds a solution x to the equation Ax=b, where A is the matrix of which
105 * *this is the QR decomposition, if any exists.
106 *
107 * \param b the right-hand-side of the equation to solve.
108 *
109 * \returns a solution.
110 *
111 * \note The case where b is a matrix is not yet implemented. Also, this
112 * code is space inefficient.
113 *
114 * \note_about_checking_solutions
115 *
116 * \note_about_arbitrary_choice_of_solution
117 *
118 * Example: \include ColPivHouseholderQR_solve.cpp
119 * Output: \verbinclude ColPivHouseholderQR_solve.out
120 */
121 template<typename Rhs>
122 inline const internal::solve_retval<ColPivHouseholderQR, Rhs>
solve(const MatrixBase<Rhs> & b)123 solve(const MatrixBase<Rhs>& b) const
124 {
125 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
126 return internal::solve_retval<ColPivHouseholderQR, Rhs>(*this, b.derived());
127 }
128
129 HouseholderSequenceType householderQ(void) const;
130
131 /** \returns a reference to the matrix where the Householder QR decomposition is stored
132 */
matrixQR()133 const MatrixType& matrixQR() const
134 {
135 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
136 return m_qr;
137 }
138
139 ColPivHouseholderQR& compute(const MatrixType& matrix);
140
colsPermutation()141 const PermutationType& colsPermutation() const
142 {
143 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
144 return m_colsPermutation;
145 }
146
147 /** \returns the absolute value of the determinant of the matrix of which
148 * *this is the QR decomposition. It has only linear complexity
149 * (that is, O(n) where n is the dimension of the square matrix)
150 * as the QR decomposition has already been computed.
151 *
152 * \note This is only for square matrices.
153 *
154 * \warning a determinant can be very big or small, so for matrices
155 * of large enough dimension, there is a risk of overflow/underflow.
156 * One way to work around that is to use logAbsDeterminant() instead.
157 *
158 * \sa logAbsDeterminant(), MatrixBase::determinant()
159 */
160 typename MatrixType::RealScalar absDeterminant() const;
161
162 /** \returns the natural log of the absolute value of the determinant of the matrix of which
163 * *this is the QR decomposition. It has only linear complexity
164 * (that is, O(n) where n is the dimension of the square matrix)
165 * as the QR decomposition has already been computed.
166 *
167 * \note This is only for square matrices.
168 *
169 * \note This method is useful to work around the risk of overflow/underflow that's inherent
170 * to determinant computation.
171 *
172 * \sa absDeterminant(), MatrixBase::determinant()
173 */
174 typename MatrixType::RealScalar logAbsDeterminant() const;
175
176 /** \returns the rank of the matrix of which *this is the QR decomposition.
177 *
178 * \note This method has to determine which pivots should be considered nonzero.
179 * For that, it uses the threshold value that you can control by calling
180 * setThreshold(const RealScalar&).
181 */
rank()182 inline Index rank() const
183 {
184 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
185 RealScalar premultiplied_threshold = internal::abs(m_maxpivot) * threshold();
186 Index result = 0;
187 for(Index i = 0; i < m_nonzero_pivots; ++i)
188 result += (internal::abs(m_qr.coeff(i,i)) > premultiplied_threshold);
189 return result;
190 }
191
192 /** \returns the dimension of the kernel of the matrix of which *this is the QR decomposition.
193 *
194 * \note This method has to determine which pivots should be considered nonzero.
195 * For that, it uses the threshold value that you can control by calling
196 * setThreshold(const RealScalar&).
197 */
dimensionOfKernel()198 inline Index dimensionOfKernel() const
199 {
200 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
201 return cols() - rank();
202 }
203
204 /** \returns true if the matrix of which *this is the QR decomposition represents an injective
205 * linear map, i.e. has trivial kernel; false otherwise.
206 *
207 * \note This method has to determine which pivots should be considered nonzero.
208 * For that, it uses the threshold value that you can control by calling
209 * setThreshold(const RealScalar&).
210 */
isInjective()211 inline bool isInjective() const
212 {
213 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
214 return rank() == cols();
215 }
216
217 /** \returns true if the matrix of which *this is the QR decomposition represents a surjective
218 * linear map; false otherwise.
219 *
220 * \note This method has to determine which pivots should be considered nonzero.
221 * For that, it uses the threshold value that you can control by calling
222 * setThreshold(const RealScalar&).
223 */
isSurjective()224 inline bool isSurjective() const
225 {
226 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
227 return rank() == rows();
228 }
229
230 /** \returns true if the matrix of which *this is the QR decomposition is invertible.
231 *
232 * \note This method has to determine which pivots should be considered nonzero.
233 * For that, it uses the threshold value that you can control by calling
234 * setThreshold(const RealScalar&).
235 */
isInvertible()236 inline bool isInvertible() const
237 {
238 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
239 return isInjective() && isSurjective();
240 }
241
242 /** \returns the inverse of the matrix of which *this is the QR decomposition.
243 *
244 * \note If this matrix is not invertible, the returned matrix has undefined coefficients.
245 * Use isInvertible() to first determine whether this matrix is invertible.
246 */
247 inline const
248 internal::solve_retval<ColPivHouseholderQR, typename MatrixType::IdentityReturnType>
inverse()249 inverse() const
250 {
251 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
252 return internal::solve_retval<ColPivHouseholderQR,typename MatrixType::IdentityReturnType>
253 (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols()));
254 }
255
rows()256 inline Index rows() const { return m_qr.rows(); }
cols()257 inline Index cols() const { return m_qr.cols(); }
hCoeffs()258 const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
259
260 /** Allows to prescribe a threshold to be used by certain methods, such as rank(),
261 * who need to determine when pivots are to be considered nonzero. This is not used for the
262 * QR decomposition itself.
263 *
264 * When it needs to get the threshold value, Eigen calls threshold(). By default, this
265 * uses a formula to automatically determine a reasonable threshold.
266 * Once you have called the present method setThreshold(const RealScalar&),
267 * your value is used instead.
268 *
269 * \param threshold The new value to use as the threshold.
270 *
271 * A pivot will be considered nonzero if its absolute value is strictly greater than
272 * \f$ \vert pivot \vert \leqslant threshold \times \vert maxpivot \vert \f$
273 * where maxpivot is the biggest pivot.
274 *
275 * If you want to come back to the default behavior, call setThreshold(Default_t)
276 */
setThreshold(const RealScalar & threshold)277 ColPivHouseholderQR& setThreshold(const RealScalar& threshold)
278 {
279 m_usePrescribedThreshold = true;
280 m_prescribedThreshold = threshold;
281 return *this;
282 }
283
284 /** Allows to come back to the default behavior, letting Eigen use its default formula for
285 * determining the threshold.
286 *
287 * You should pass the special object Eigen::Default as parameter here.
288 * \code qr.setThreshold(Eigen::Default); \endcode
289 *
290 * See the documentation of setThreshold(const RealScalar&).
291 */
setThreshold(Default_t)292 ColPivHouseholderQR& setThreshold(Default_t)
293 {
294 m_usePrescribedThreshold = false;
295 return *this;
296 }
297
298 /** Returns the threshold that will be used by certain methods such as rank().
299 *
300 * See the documentation of setThreshold(const RealScalar&).
301 */
threshold()302 RealScalar threshold() const
303 {
304 eigen_assert(m_isInitialized || m_usePrescribedThreshold);
305 return m_usePrescribedThreshold ? m_prescribedThreshold
306 // this formula comes from experimenting (see "LU precision tuning" thread on the list)
307 // and turns out to be identical to Higham's formula used already in LDLt.
308 : NumTraits<Scalar>::epsilon() * m_qr.diagonalSize();
309 }
310
311 /** \returns the number of nonzero pivots in the QR decomposition.
312 * Here nonzero is meant in the exact sense, not in a fuzzy sense.
313 * So that notion isn't really intrinsically interesting, but it is
314 * still useful when implementing algorithms.
315 *
316 * \sa rank()
317 */
nonzeroPivots()318 inline Index nonzeroPivots() const
319 {
320 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
321 return m_nonzero_pivots;
322 }
323
324 /** \returns the absolute value of the biggest pivot, i.e. the biggest
325 * diagonal coefficient of R.
326 */
maxPivot()327 RealScalar maxPivot() const { return m_maxpivot; }
328
329 protected:
330 MatrixType m_qr;
331 HCoeffsType m_hCoeffs;
332 PermutationType m_colsPermutation;
333 IntRowVectorType m_colsTranspositions;
334 RowVectorType m_temp;
335 RealRowVectorType m_colSqNorms;
336 bool m_isInitialized, m_usePrescribedThreshold;
337 RealScalar m_prescribedThreshold, m_maxpivot;
338 Index m_nonzero_pivots;
339 Index m_det_pq;
340 };
341
342 template<typename MatrixType>
absDeterminant()343 typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::absDeterminant() const
344 {
345 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
346 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
347 return internal::abs(m_qr.diagonal().prod());
348 }
349
350 template<typename MatrixType>
logAbsDeterminant()351 typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::logAbsDeterminant() const
352 {
353 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
354 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
355 return m_qr.diagonal().cwiseAbs().array().log().sum();
356 }
357
358 template<typename MatrixType>
compute(const MatrixType & matrix)359 ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix)
360 {
361 Index rows = matrix.rows();
362 Index cols = matrix.cols();
363 Index size = matrix.diagonalSize();
364
365 m_qr = matrix;
366 m_hCoeffs.resize(size);
367
368 m_temp.resize(cols);
369
370 m_colsTranspositions.resize(matrix.cols());
371 Index number_of_transpositions = 0;
372
373 m_colSqNorms.resize(cols);
374 for(Index k = 0; k < cols; ++k)
375 m_colSqNorms.coeffRef(k) = m_qr.col(k).squaredNorm();
376
377 RealScalar threshold_helper = m_colSqNorms.maxCoeff() * internal::abs2(NumTraits<Scalar>::epsilon()) / RealScalar(rows);
378
379 m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
380 m_maxpivot = RealScalar(0);
381
382 for(Index k = 0; k < size; ++k)
383 {
384 // first, we look up in our table m_colSqNorms which column has the biggest squared norm
385 Index biggest_col_index;
386 RealScalar biggest_col_sq_norm = m_colSqNorms.tail(cols-k).maxCoeff(&biggest_col_index);
387 biggest_col_index += k;
388
389 // since our table m_colSqNorms accumulates imprecision at every step, we must now recompute
390 // the actual squared norm of the selected column.
391 // Note that not doing so does result in solve() sometimes returning inf/nan values
392 // when running the unit test with 1000 repetitions.
393 biggest_col_sq_norm = m_qr.col(biggest_col_index).tail(rows-k).squaredNorm();
394
395 // we store that back into our table: it can't hurt to correct our table.
396 m_colSqNorms.coeffRef(biggest_col_index) = biggest_col_sq_norm;
397
398 // if the current biggest column is smaller than epsilon times the initial biggest column,
399 // terminate to avoid generating nan/inf values.
400 // Note that here, if we test instead for "biggest == 0", we get a failure every 1000 (or so)
401 // repetitions of the unit test, with the result of solve() filled with large values of the order
402 // of 1/(size*epsilon).
403 if(biggest_col_sq_norm < threshold_helper * RealScalar(rows-k))
404 {
405 m_nonzero_pivots = k;
406 m_hCoeffs.tail(size-k).setZero();
407 m_qr.bottomRightCorner(rows-k,cols-k)
408 .template triangularView<StrictlyLower>()
409 .setZero();
410 break;
411 }
412
413 // apply the transposition to the columns
414 m_colsTranspositions.coeffRef(k) = biggest_col_index;
415 if(k != biggest_col_index) {
416 m_qr.col(k).swap(m_qr.col(biggest_col_index));
417 std::swap(m_colSqNorms.coeffRef(k), m_colSqNorms.coeffRef(biggest_col_index));
418 ++number_of_transpositions;
419 }
420
421 // generate the householder vector, store it below the diagonal
422 RealScalar beta;
423 m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
424
425 // apply the householder transformation to the diagonal coefficient
426 m_qr.coeffRef(k,k) = beta;
427
428 // remember the maximum absolute value of diagonal coefficients
429 if(internal::abs(beta) > m_maxpivot) m_maxpivot = internal::abs(beta);
430
431 // apply the householder transformation
432 m_qr.bottomRightCorner(rows-k, cols-k-1)
433 .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
434
435 // update our table of squared norms of the columns
436 m_colSqNorms.tail(cols-k-1) -= m_qr.row(k).tail(cols-k-1).cwiseAbs2();
437 }
438
439 m_colsPermutation.setIdentity(cols);
440 for(Index k = 0; k < m_nonzero_pivots; ++k)
441 m_colsPermutation.applyTranspositionOnTheRight(k, m_colsTranspositions.coeff(k));
442
443 m_det_pq = (number_of_transpositions%2) ? -1 : 1;
444 m_isInitialized = true;
445
446 return *this;
447 }
448
449 namespace internal {
450
451 template<typename _MatrixType, typename Rhs>
452 struct solve_retval<ColPivHouseholderQR<_MatrixType>, Rhs>
453 : solve_retval_base<ColPivHouseholderQR<_MatrixType>, Rhs>
454 {
455 EIGEN_MAKE_SOLVE_HELPERS(ColPivHouseholderQR<_MatrixType>,Rhs)
456
457 template<typename Dest> void evalTo(Dest& dst) const
458 {
459 eigen_assert(rhs().rows() == dec().rows());
460
461 const int cols = dec().cols(),
462 nonzero_pivots = dec().nonzeroPivots();
463
464 if(nonzero_pivots == 0)
465 {
466 dst.setZero();
467 return;
468 }
469
470 typename Rhs::PlainObject c(rhs());
471
472 // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T
473 c.applyOnTheLeft(householderSequence(dec().matrixQR(), dec().hCoeffs())
474 .setLength(dec().nonzeroPivots())
475 .transpose()
476 );
477
478 dec().matrixQR()
479 .topLeftCorner(nonzero_pivots, nonzero_pivots)
480 .template triangularView<Upper>()
481 .solveInPlace(c.topRows(nonzero_pivots));
482
483
484 typename Rhs::PlainObject d(c);
485 d.topRows(nonzero_pivots)
486 = dec().matrixQR()
487 .topLeftCorner(nonzero_pivots, nonzero_pivots)
488 .template triangularView<Upper>()
489 * c.topRows(nonzero_pivots);
490
491 for(Index i = 0; i < nonzero_pivots; ++i) dst.row(dec().colsPermutation().indices().coeff(i)) = c.row(i);
492 for(Index i = nonzero_pivots; i < cols; ++i) dst.row(dec().colsPermutation().indices().coeff(i)).setZero();
493 }
494 };
495
496 } // end namespace internal
497
498 /** \returns the matrix Q as a sequence of householder transformations */
499 template<typename MatrixType>
500 typename ColPivHouseholderQR<MatrixType>::HouseholderSequenceType ColPivHouseholderQR<MatrixType>
501 ::householderQ() const
502 {
503 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
504 return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()).setLength(m_nonzero_pivots);
505 }
506
507 /** \return the column-pivoting Householder QR decomposition of \c *this.
508 *
509 * \sa class ColPivHouseholderQR
510 */
511 template<typename Derived>
512 const ColPivHouseholderQR<typename MatrixBase<Derived>::PlainObject>
513 MatrixBase<Derived>::colPivHouseholderQr() const
514 {
515 return ColPivHouseholderQR<PlainObject>(eval());
516 }
517
518 } // end namespace Eigen
519
520 #endif // EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
521