PageRenderTime 77ms CodeModel.GetById 19ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Geometry_Eigen/Eigen/src/QR/ColPivHouseholderQR.h

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