FullPivHouseholderQR.h 24.9 KB
Newer Older
LM's avatar
LM committed
1 2 3 4 5 6
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
//
Don Gagne's avatar
Don Gagne committed
7 8 9
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
LM's avatar
LM committed
10 11 12 13

#ifndef EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
#define EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H

Don Gagne's avatar
Don Gagne committed
14 15 16 17
namespace Eigen { 

namespace internal {

18 19 20 21 22 23
template<typename _MatrixType> struct traits<FullPivHouseholderQR<_MatrixType> >
 : traits<_MatrixType>
{
  enum { Flags = 0 };
};

Don Gagne's avatar
Don Gagne committed
24 25 26 27 28 29 30 31
template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType;

template<typename MatrixType>
struct traits<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
{
  typedef typename MatrixType::PlainObject ReturnType;
};

32
} // end namespace internal
Don Gagne's avatar
Don Gagne committed
33

LM's avatar
LM committed
34 35 36 37 38 39
/** \ingroup QR_Module
  *
  * \class FullPivHouseholderQR
  *
  * \brief Householder rank-revealing QR decomposition of a matrix with full pivoting
  *
40
  * \tparam _MatrixType the type of the matrix of which we are computing the QR decomposition
LM's avatar
LM committed
41
  *
42
  * This class performs a rank-revealing QR decomposition of a matrix \b A into matrices \b P, \b P', \b Q and \b R
LM's avatar
LM committed
43 44
  * such that 
  * \f[
45
  *  \mathbf{P} \, \mathbf{A} \, \mathbf{P}' = \mathbf{Q} \, \mathbf{R}
LM's avatar
LM committed
46
  * \f]
47 48
  * by using Householder transformations. Here, \b P and \b P' are permutation matrices, \b Q a unitary matrix 
  * and \b R an upper triangular matrix.
LM's avatar
LM committed
49 50 51 52
  *
  * This decomposition performs a very prudent full pivoting in order to be rank-revealing and achieve optimal
  * numerical stability. The trade-off is that it is slower than HouseholderQR and ColPivHouseholderQR.
  *
53 54
  * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism.
  * 
LM's avatar
LM committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
  * \sa MatrixBase::fullPivHouseholderQr()
  */
template<typename _MatrixType> class FullPivHouseholderQR
{
  public:

    typedef _MatrixType MatrixType;
    enum {
      RowsAtCompileTime = MatrixType::RowsAtCompileTime,
      ColsAtCompileTime = MatrixType::ColsAtCompileTime,
      MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
      MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
    };
    typedef typename MatrixType::Scalar Scalar;
    typedef typename MatrixType::RealScalar RealScalar;
70 71
    // FIXME should be int
    typedef typename MatrixType::StorageIndex StorageIndex;
Don Gagne's avatar
Don Gagne committed
72
    typedef internal::FullPivHouseholderQRMatrixQReturnType<MatrixType> MatrixQReturnType;
LM's avatar
LM committed
73
    typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
74
    typedef Matrix<StorageIndex, 1,
75 76
                   EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime,RowsAtCompileTime), RowMajor, 1,
                   EIGEN_SIZE_MIN_PREFER_FIXED(MaxColsAtCompileTime,MaxRowsAtCompileTime)> IntDiagSizeVectorType;
LM's avatar
LM committed
77 78 79
    typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
    typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
    typedef typename internal::plain_col_type<MatrixType>::type ColVectorType;
80
    typedef typename MatrixType::PlainObject PlainObject;
LM's avatar
LM committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

    /** \brief Default Constructor.
      *
      * The default constructor is useful in cases in which the user intends to
      * perform decompositions via FullPivHouseholderQR::compute(const MatrixType&).
      */
    FullPivHouseholderQR()
      : m_qr(),
        m_hCoeffs(),
        m_rows_transpositions(),
        m_cols_transpositions(),
        m_cols_permutation(),
        m_temp(),
        m_isInitialized(false),
        m_usePrescribedThreshold(false) {}

    /** \brief Default Constructor with memory preallocation
      *
      * Like the default constructor but with preallocation of the internal data
      * according to the specified problem \a size.
      * \sa FullPivHouseholderQR()
      */
    FullPivHouseholderQR(Index rows, Index cols)
      : m_qr(rows, cols),
Don Gagne's avatar
Don Gagne committed
105
        m_hCoeffs((std::min)(rows,cols)),
106 107
        m_rows_transpositions((std::min)(rows,cols)),
        m_cols_transpositions((std::min)(rows,cols)),
LM's avatar
LM committed
108
        m_cols_permutation(cols),
109
        m_temp(cols),
LM's avatar
LM committed
110 111 112
        m_isInitialized(false),
        m_usePrescribedThreshold(false) {}

Don Gagne's avatar
Don Gagne committed
113 114 115 116 117 118 119 120 121 122 123 124
    /** \brief Constructs a QR factorization from a given matrix
      *
      * This constructor computes the QR factorization of the matrix \a matrix by calling
      * the method compute(). It is a short cut for:
      * 
      * \code
      * FullPivHouseholderQR<MatrixType> qr(matrix.rows(), matrix.cols());
      * qr.compute(matrix);
      * \endcode
      * 
      * \sa compute()
      */
125 126
    template<typename InputType>
    explicit FullPivHouseholderQR(const EigenBase<InputType>& matrix)
LM's avatar
LM committed
127
      : m_qr(matrix.rows(), matrix.cols()),
Don Gagne's avatar
Don Gagne committed
128
        m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
129 130
        m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())),
        m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())),
LM's avatar
LM committed
131
        m_cols_permutation(matrix.cols()),
132
        m_temp(matrix.cols()),
LM's avatar
LM committed
133 134 135
        m_isInitialized(false),
        m_usePrescribedThreshold(false)
    {
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
      compute(matrix.derived());
    }

    /** \brief Constructs a QR factorization from a given matrix
      *
      * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when \c MatrixType is a Eigen::Ref.
      *
      * \sa FullPivHouseholderQR(const EigenBase&)
      */
    template<typename InputType>
    explicit FullPivHouseholderQR(EigenBase<InputType>& matrix)
      : m_qr(matrix.derived()),
        m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
        m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())),
        m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())),
        m_cols_permutation(matrix.cols()),
        m_temp(matrix.cols()),
        m_isInitialized(false),
        m_usePrescribedThreshold(false)
    {
      computeInPlace();
LM's avatar
LM committed
157 158 159
    }

    /** This method finds a solution x to the equation Ax=b, where A is the matrix of which
160
      * \c *this is the QR decomposition.
LM's avatar
LM committed
161 162 163
      *
      * \param b the right-hand-side of the equation to solve.
      *
164 165
      * \returns the exact or least-square solution if the rank is greater or equal to the number of columns of A,
      * and an arbitrary solution otherwise.
LM's avatar
LM committed
166 167 168 169 170 171 172 173 174
      *
      * \note_about_checking_solutions
      *
      * \note_about_arbitrary_choice_of_solution
      *
      * Example: \include FullPivHouseholderQR_solve.cpp
      * Output: \verbinclude FullPivHouseholderQR_solve.out
      */
    template<typename Rhs>
175
    inline const Solve<FullPivHouseholderQR, Rhs>
LM's avatar
LM committed
176 177 178
    solve(const MatrixBase<Rhs>& b) const
    {
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
179
      return Solve<FullPivHouseholderQR, Rhs>(*this, b.derived());
LM's avatar
LM committed
180 181
    }

Don Gagne's avatar
Don Gagne committed
182 183 184
    /** \returns Expression object representing the matrix Q
      */
    MatrixQReturnType matrixQ(void) const;
LM's avatar
LM committed
185 186 187 188 189 190 191 192 193

    /** \returns a reference to the matrix where the Householder QR decomposition is stored
      */
    const MatrixType& matrixQR() const
    {
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
      return m_qr;
    }

194 195
    template<typename InputType>
    FullPivHouseholderQR& compute(const EigenBase<InputType>& matrix);
LM's avatar
LM committed
196

Don Gagne's avatar
Don Gagne committed
197
    /** \returns a const reference to the column permutation matrix */
LM's avatar
LM committed
198 199 200 201 202 203
    const PermutationType& colsPermutation() const
    {
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
      return m_cols_permutation;
    }

Don Gagne's avatar
Don Gagne committed
204
    /** \returns a const reference to the vector of indices representing the rows transpositions */
205
    const IntDiagSizeVectorType& rowsTranspositions() const
LM's avatar
LM committed
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    {
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
      return m_rows_transpositions;
    }

    /** \returns the absolute value of the determinant of the matrix of which
      * *this is the QR decomposition. It has only linear complexity
      * (that is, O(n) where n is the dimension of the square matrix)
      * as the QR decomposition has already been computed.
      *
      * \note This is only for square matrices.
      *
      * \warning a determinant can be very big or small, so for matrices
      * of large enough dimension, there is a risk of overflow/underflow.
      * One way to work around that is to use logAbsDeterminant() instead.
      *
      * \sa logAbsDeterminant(), MatrixBase::determinant()
      */
    typename MatrixType::RealScalar absDeterminant() const;

    /** \returns the natural log of the absolute value of the determinant of the matrix of which
      * *this is the QR decomposition. It has only linear complexity
      * (that is, O(n) where n is the dimension of the square matrix)
      * as the QR decomposition has already been computed.
      *
      * \note This is only for square matrices.
      *
      * \note This method is useful to work around the risk of overflow/underflow that's inherent
      * to determinant computation.
      *
      * \sa absDeterminant(), MatrixBase::determinant()
      */
    typename MatrixType::RealScalar logAbsDeterminant() const;

    /** \returns the rank of the matrix of which *this is the QR decomposition.
      *
      * \note This method has to determine which pivots should be considered nonzero.
      *       For that, it uses the threshold value that you can control by calling
      *       setThreshold(const RealScalar&).
      */
    inline Index rank() const
    {
Don Gagne's avatar
Don Gagne committed
248
      using std::abs;
LM's avatar
LM committed
249
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
Don Gagne's avatar
Don Gagne committed
250
      RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold();
LM's avatar
LM committed
251 252
      Index result = 0;
      for(Index i = 0; i < m_nonzero_pivots; ++i)
Don Gagne's avatar
Don Gagne committed
253
        result += (abs(m_qr.coeff(i,i)) > premultiplied_threshold);
LM's avatar
LM committed
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
      return result;
    }

    /** \returns the dimension of the kernel of the matrix of which *this is the QR decomposition.
      *
      * \note This method has to determine which pivots should be considered nonzero.
      *       For that, it uses the threshold value that you can control by calling
      *       setThreshold(const RealScalar&).
      */
    inline Index dimensionOfKernel() const
    {
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
      return cols() - rank();
    }

    /** \returns true if the matrix of which *this is the QR decomposition represents an injective
      *          linear map, i.e. has trivial kernel; false otherwise.
      *
      * \note This method has to determine which pivots should be considered nonzero.
      *       For that, it uses the threshold value that you can control by calling
      *       setThreshold(const RealScalar&).
      */
    inline bool isInjective() const
    {
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
      return rank() == cols();
    }

    /** \returns true if the matrix of which *this is the QR decomposition represents a surjective
      *          linear map; false otherwise.
      *
      * \note This method has to determine which pivots should be considered nonzero.
      *       For that, it uses the threshold value that you can control by calling
      *       setThreshold(const RealScalar&).
      */
    inline bool isSurjective() const
    {
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
      return rank() == rows();
    }

    /** \returns true if the matrix of which *this is the QR decomposition is invertible.
      *
      * \note This method has to determine which pivots should be considered nonzero.
      *       For that, it uses the threshold value that you can control by calling
      *       setThreshold(const RealScalar&).
      */
    inline bool isInvertible() const
    {
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
      return isInjective() && isSurjective();
    }

    /** \returns the inverse of the matrix of which *this is the QR decomposition.
      *
      * \note If this matrix is not invertible, the returned matrix has undefined coefficients.
      *       Use isInvertible() to first determine whether this matrix is invertible.
311 312
      */
    inline const Inverse<FullPivHouseholderQR> inverse() const
LM's avatar
LM committed
313 314
    {
      eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
315
      return Inverse<FullPivHouseholderQR>(*this);
LM's avatar
LM committed
316 317 318 319
    }

    inline Index rows() const { return m_qr.rows(); }
    inline Index cols() const { return m_qr.cols(); }
Don Gagne's avatar
Don Gagne committed
320 321 322 323 324
    
    /** \returns a const reference to the vector of Householder coefficients used to represent the factor \c Q.
      * 
      * For advanced uses only.
      */
LM's avatar
LM committed
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
    const HCoeffsType& hCoeffs() const { return m_hCoeffs; }

    /** Allows to prescribe a threshold to be used by certain methods, such as rank(),
      * who need to determine when pivots are to be considered nonzero. This is not used for the
      * QR decomposition itself.
      *
      * When it needs to get the threshold value, Eigen calls threshold(). By default, this
      * uses a formula to automatically determine a reasonable threshold.
      * Once you have called the present method setThreshold(const RealScalar&),
      * your value is used instead.
      *
      * \param threshold The new value to use as the threshold.
      *
      * A pivot will be considered nonzero if its absolute value is strictly greater than
      *  \f$ \vert pivot \vert \leqslant threshold \times \vert maxpivot \vert \f$
      * where maxpivot is the biggest pivot.
      *
      * If you want to come back to the default behavior, call setThreshold(Default_t)
      */
    FullPivHouseholderQR& setThreshold(const RealScalar& threshold)
    {
      m_usePrescribedThreshold = true;
      m_prescribedThreshold = threshold;
      return *this;
    }

    /** Allows to come back to the default behavior, letting Eigen use its default formula for
      * determining the threshold.
      *
      * You should pass the special object Eigen::Default as parameter here.
      * \code qr.setThreshold(Eigen::Default); \endcode
      *
      * See the documentation of setThreshold(const RealScalar&).
      */
    FullPivHouseholderQR& setThreshold(Default_t)
    {
      m_usePrescribedThreshold = false;
      return *this;
    }

    /** Returns the threshold that will be used by certain methods such as rank().
      *
      * See the documentation of setThreshold(const RealScalar&).
      */
    RealScalar threshold() const
    {
      eigen_assert(m_isInitialized || m_usePrescribedThreshold);
      return m_usePrescribedThreshold ? m_prescribedThreshold
      // this formula comes from experimenting (see "LU precision tuning" thread on the list)
      // and turns out to be identical to Higham's formula used already in LDLt.
375
                                      : NumTraits<Scalar>::epsilon() * RealScalar(m_qr.diagonalSize());
LM's avatar
LM committed
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
    }

    /** \returns the number of nonzero pivots in the QR decomposition.
      * Here nonzero is meant in the exact sense, not in a fuzzy sense.
      * So that notion isn't really intrinsically interesting, but it is
      * still useful when implementing algorithms.
      *
      * \sa rank()
      */
    inline Index nonzeroPivots() const
    {
      eigen_assert(m_isInitialized && "LU is not initialized.");
      return m_nonzero_pivots;
    }

    /** \returns the absolute value of the biggest pivot, i.e. the biggest
      *          diagonal coefficient of U.
      */
    RealScalar maxPivot() const { return m_maxpivot; }
395 396 397 398 399 400
    
    #ifndef EIGEN_PARSED_BY_DOXYGEN
    template<typename RhsType, typename DstType>
    EIGEN_DEVICE_FUNC
    void _solve_impl(const RhsType &rhs, DstType &dst) const;
    #endif
LM's avatar
LM committed
401 402

  protected:
403 404 405 406 407 408
    
    static void check_template_parameters()
    {
      EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
    }
    
409 410
    void computeInPlace();
    
LM's avatar
LM committed
411 412
    MatrixType m_qr;
    HCoeffsType m_hCoeffs;
413 414
    IntDiagSizeVectorType m_rows_transpositions;
    IntDiagSizeVectorType m_cols_transpositions;
LM's avatar
LM committed
415 416 417 418 419 420 421 422 423 424 425 426
    PermutationType m_cols_permutation;
    RowVectorType m_temp;
    bool m_isInitialized, m_usePrescribedThreshold;
    RealScalar m_prescribedThreshold, m_maxpivot;
    Index m_nonzero_pivots;
    RealScalar m_precision;
    Index m_det_pq;
};

template<typename MatrixType>
typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::absDeterminant() const
{
Don Gagne's avatar
Don Gagne committed
427
  using std::abs;
LM's avatar
LM committed
428 429
  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
Don Gagne's avatar
Don Gagne committed
430
  return abs(m_qr.diagonal().prod());
LM's avatar
LM committed
431 432 433 434 435 436 437 438 439 440
}

template<typename MatrixType>
typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::logAbsDeterminant() const
{
  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
  return m_qr.diagonal().cwiseAbs().array().log().sum();
}

Don Gagne's avatar
Don Gagne committed
441 442 443 444 445 446
/** Performs the QR factorization of the given matrix \a matrix. The result of
  * the factorization is stored into \c *this, and a reference to \c *this
  * is returned.
  *
  * \sa class FullPivHouseholderQR, FullPivHouseholderQR(const MatrixType&)
  */
LM's avatar
LM committed
447
template<typename MatrixType>
448 449 450 451 452 453 454 455 456 457
template<typename InputType>
FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(const EigenBase<InputType>& matrix)
{
  m_qr = matrix.derived();
  computeInPlace();
  return *this;
}

template<typename MatrixType>
void FullPivHouseholderQR<MatrixType>::computeInPlace()
LM's avatar
LM committed
458
{
459
  check_template_parameters();
460

Don Gagne's avatar
Don Gagne committed
461
  using std::abs;
462 463
  Index rows = m_qr.rows();
  Index cols = m_qr.cols();
Don Gagne's avatar
Don Gagne committed
464
  Index size = (std::min)(rows,cols);
LM's avatar
LM committed
465

466
  
LM's avatar
LM committed
467 468 469 470
  m_hCoeffs.resize(size);

  m_temp.resize(cols);

471
  m_precision = NumTraits<Scalar>::epsilon() * RealScalar(size);
LM's avatar
LM committed
472

473 474
  m_rows_transpositions.resize(size);
  m_cols_transpositions.resize(size);
LM's avatar
LM committed
475 476 477 478 479 480 481 482 483 484
  Index number_of_transpositions = 0;

  RealScalar biggest(0);

  m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
  m_maxpivot = RealScalar(0);

  for (Index k = 0; k < size; ++k)
  {
    Index row_of_biggest_in_corner, col_of_biggest_in_corner;
485 486
    typedef internal::scalar_score_coeff_op<Scalar> Scoring;
    typedef typename Scoring::result_type Score;
LM's avatar
LM committed
487

488 489 490
    Score score = m_qr.bottomRightCorner(rows-k, cols-k)
                      .unaryExpr(Scoring())
                      .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
LM's avatar
LM committed
491 492
    row_of_biggest_in_corner += k;
    col_of_biggest_in_corner += k;
493
    RealScalar biggest_in_corner = internal::abs_knowing_score<Scalar>()(m_qr(row_of_biggest_in_corner, col_of_biggest_in_corner), score);
LM's avatar
LM committed
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
    if(k==0) biggest = biggest_in_corner;

    // if the corner is negligible, then we have less than full rank, and we can finish early
    if(internal::isMuchSmallerThan(biggest_in_corner, biggest, m_precision))
    {
      m_nonzero_pivots = k;
      for(Index i = k; i < size; i++)
      {
        m_rows_transpositions.coeffRef(i) = i;
        m_cols_transpositions.coeffRef(i) = i;
        m_hCoeffs.coeffRef(i) = Scalar(0);
      }
      break;
    }

    m_rows_transpositions.coeffRef(k) = row_of_biggest_in_corner;
    m_cols_transpositions.coeffRef(k) = col_of_biggest_in_corner;
    if(k != row_of_biggest_in_corner) {
      m_qr.row(k).tail(cols-k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols-k));
      ++number_of_transpositions;
    }
    if(k != col_of_biggest_in_corner) {
      m_qr.col(k).swap(m_qr.col(col_of_biggest_in_corner));
      ++number_of_transpositions;
    }

    RealScalar beta;
    m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
    m_qr.coeffRef(k,k) = beta;

    // remember the maximum absolute value of diagonal coefficients
Don Gagne's avatar
Don Gagne committed
525
    if(abs(beta) > m_maxpivot) m_maxpivot = abs(beta);
LM's avatar
LM committed
526 527 528 529 530 531 532 533 534 535 536 537 538

    m_qr.bottomRightCorner(rows-k, cols-k-1)
        .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
  }

  m_cols_permutation.setIdentity(cols);
  for(Index k = 0; k < size; ++k)
    m_cols_permutation.applyTranspositionOnTheRight(k, m_cols_transpositions.coeff(k));

  m_det_pq = (number_of_transpositions%2) ? -1 : 1;
  m_isInitialized = true;
}

539 540 541 542
#ifndef EIGEN_PARSED_BY_DOXYGEN
template<typename _MatrixType>
template<typename RhsType, typename DstType>
void FullPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const
LM's avatar
LM committed
543
{
544 545
  eigen_assert(rhs.rows() == rows());
  const Index l_rank = rank();
LM's avatar
LM committed
546

547 548 549
  // FIXME introduce nonzeroPivots() and use it here. and more generally,
  // make the same improvements in this dec as in FullPivLU.
  if(l_rank==0)
LM's avatar
LM committed
550
  {
551 552 553
    dst.setZero();
    return;
  }
LM's avatar
LM committed
554

555
  typename RhsType::PlainObject c(rhs);
LM's avatar
LM committed
556

557 558 559 560 561 562 563 564 565
  Matrix<Scalar,1,RhsType::ColsAtCompileTime> temp(rhs.cols());
  for (Index k = 0; k < l_rank; ++k)
  {
    Index remainingSize = rows()-k;
    c.row(k).swap(c.row(m_rows_transpositions.coeff(k)));
    c.bottomRightCorner(remainingSize, rhs.cols())
      .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize-1),
                               m_hCoeffs.coeff(k), &temp.coeffRef(0));
  }
LM's avatar
LM committed
566

567 568 569
  m_qr.topLeftCorner(l_rank, l_rank)
      .template triangularView<Upper>()
      .solveInPlace(c.topRows(l_rank));
LM's avatar
LM committed
570

571 572 573 574
  for(Index i = 0; i < l_rank; ++i) dst.row(m_cols_permutation.indices().coeff(i)) = c.row(i);
  for(Index i = l_rank; i < cols(); ++i) dst.row(m_cols_permutation.indices().coeff(i)).setZero();
}
#endif
LM's avatar
LM committed
575

576 577 578 579 580 581 582 583 584 585
namespace internal {
  
template<typename DstXprType, typename MatrixType>
struct Assignment<DstXprType, Inverse<FullPivHouseholderQR<MatrixType> >, internal::assign_op<typename DstXprType::Scalar,typename FullPivHouseholderQR<MatrixType>::Scalar>, Dense2Dense>
{
  typedef FullPivHouseholderQR<MatrixType> QrType;
  typedef Inverse<QrType> SrcXprType;
  static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<typename DstXprType::Scalar,typename QrType::Scalar> &)
  {    
    dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols()));
LM's avatar
LM committed
586 587 588
  }
};

Don Gagne's avatar
Don Gagne committed
589 590 591 592 593 594 595 596 597 598
/** \ingroup QR_Module
  *
  * \brief Expression type for return value of FullPivHouseholderQR::matrixQ()
  *
  * \tparam MatrixType type of underlying dense matrix
  */
template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType
  : public ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
{
public:
599
  typedef typename FullPivHouseholderQR<MatrixType>::IntDiagSizeVectorType IntDiagSizeVectorType;
Don Gagne's avatar
Don Gagne committed
600 601 602 603 604 605
  typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
  typedef Matrix<typename MatrixType::Scalar, 1, MatrixType::RowsAtCompileTime, RowMajor, 1,
                 MatrixType::MaxRowsAtCompileTime> WorkVectorType;

  FullPivHouseholderQRMatrixQReturnType(const MatrixType&       qr,
                                        const HCoeffsType&      hCoeffs,
606
                                        const IntDiagSizeVectorType& rowsTranspositions)
Don Gagne's avatar
Don Gagne committed
607 608 609
    : m_qr(qr),
      m_hCoeffs(hCoeffs),
      m_rowsTranspositions(rowsTranspositions)
610
  {}
Don Gagne's avatar
Don Gagne committed
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639

  template <typename ResultType>
  void evalTo(ResultType& result) const
  {
    const Index rows = m_qr.rows();
    WorkVectorType workspace(rows);
    evalTo(result, workspace);
  }

  template <typename ResultType>
  void evalTo(ResultType& result, WorkVectorType& workspace) const
  {
    using numext::conj;
    // compute the product H'_0 H'_1 ... H'_n-1,
    // where H_k is the k-th Householder transformation I - h_k v_k v_k'
    // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...]
    const Index rows = m_qr.rows();
    const Index cols = m_qr.cols();
    const Index size = (std::min)(rows, cols);
    workspace.resize(rows);
    result.setIdentity(rows, rows);
    for (Index k = size-1; k >= 0; k--)
    {
      result.block(k, k, rows-k, rows-k)
            .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), conj(m_hCoeffs.coeff(k)), &workspace.coeffRef(k));
      result.row(k).swap(result.row(m_rowsTranspositions.coeff(k)));
    }
  }

640 641
  Index rows() const { return m_qr.rows(); }
  Index cols() const { return m_qr.rows(); }
Don Gagne's avatar
Don Gagne committed
642 643 644 645

protected:
  typename MatrixType::Nested m_qr;
  typename HCoeffsType::Nested m_hCoeffs;
646
  typename IntDiagSizeVectorType::Nested m_rowsTranspositions;
Don Gagne's avatar
Don Gagne committed
647 648
};

649 650 651 652 653
// template<typename MatrixType>
// struct evaluator<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
//  : public evaluator<ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> > >
// {};

LM's avatar
LM committed
654 655 656
} // end namespace internal

template<typename MatrixType>
Don Gagne's avatar
Don Gagne committed
657
inline typename FullPivHouseholderQR<MatrixType>::MatrixQReturnType FullPivHouseholderQR<MatrixType>::matrixQ() const
LM's avatar
LM committed
658 659
{
  eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
Don Gagne's avatar
Don Gagne committed
660
  return MatrixQReturnType(m_qr, m_hCoeffs, m_rows_transpositions);
LM's avatar
LM committed
661 662 663 664 665 666 667 668 669 670 671 672 673
}

/** \return the full-pivoting Householder QR decomposition of \c *this.
  *
  * \sa class FullPivHouseholderQR
  */
template<typename Derived>
const FullPivHouseholderQR<typename MatrixBase<Derived>::PlainObject>
MatrixBase<Derived>::fullPivHouseholderQr() const
{
  return FullPivHouseholderQR<PlainObject>(eval());
}

Don Gagne's avatar
Don Gagne committed
674 675
} // end namespace Eigen

LM's avatar
LM committed
676
#endif // EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H