FullPivHouseholderQR.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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. #ifndef EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
  11. #define EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
  12. namespace Eigen {
  13. namespace internal {
  14. template<typename _MatrixType> struct traits<FullPivHouseholderQR<_MatrixType> >
  15. : traits<_MatrixType>
  16. {
  17. typedef MatrixXpr XprKind;
  18. typedef SolverStorage StorageKind;
  19. typedef int StorageIndex;
  20. enum { Flags = 0 };
  21. };
  22. template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType;
  23. template<typename MatrixType>
  24. struct traits<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
  25. {
  26. typedef typename MatrixType::PlainObject ReturnType;
  27. };
  28. } // end namespace internal
  29. /** \ingroup QR_Module
  30. *
  31. * \class FullPivHouseholderQR
  32. *
  33. * \brief Householder rank-revealing QR decomposition of a matrix with full pivoting
  34. *
  35. * \tparam _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 P', \b Q and \b R
  38. * such that
  39. * \f[
  40. * \mathbf{P} \, \mathbf{A} \, \mathbf{P}' = \mathbf{Q} \, \mathbf{R}
  41. * \f]
  42. * by using Householder transformations. Here, \b P and \b P' are permutation matrices, \b Q a unitary matrix
  43. * and \b R an upper triangular matrix.
  44. *
  45. * This decomposition performs a very prudent full pivoting in order to be rank-revealing and achieve optimal
  46. * numerical stability. The trade-off is that it is slower than HouseholderQR and ColPivHouseholderQR.
  47. *
  48. * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism.
  49. *
  50. * \sa MatrixBase::fullPivHouseholderQr()
  51. */
  52. template<typename _MatrixType> class FullPivHouseholderQR
  53. : public SolverBase<FullPivHouseholderQR<_MatrixType> >
  54. {
  55. public:
  56. typedef _MatrixType MatrixType;
  57. typedef SolverBase<FullPivHouseholderQR> Base;
  58. friend class SolverBase<FullPivHouseholderQR>;
  59. EIGEN_GENERIC_PUBLIC_INTERFACE(FullPivHouseholderQR)
  60. enum {
  61. MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
  62. MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
  63. };
  64. typedef internal::FullPivHouseholderQRMatrixQReturnType<MatrixType> MatrixQReturnType;
  65. typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
  66. typedef Matrix<StorageIndex, 1,
  67. EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime,RowsAtCompileTime), RowMajor, 1,
  68. EIGEN_SIZE_MIN_PREFER_FIXED(MaxColsAtCompileTime,MaxRowsAtCompileTime)> IntDiagSizeVectorType;
  69. typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
  70. typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
  71. typedef typename internal::plain_col_type<MatrixType>::type ColVectorType;
  72. typedef typename MatrixType::PlainObject PlainObject;
  73. /** \brief Default Constructor.
  74. *
  75. * The default constructor is useful in cases in which the user intends to
  76. * perform decompositions via FullPivHouseholderQR::compute(const MatrixType&).
  77. */
  78. FullPivHouseholderQR()
  79. : m_qr(),
  80. m_hCoeffs(),
  81. m_rows_transpositions(),
  82. m_cols_transpositions(),
  83. m_cols_permutation(),
  84. m_temp(),
  85. m_isInitialized(false),
  86. m_usePrescribedThreshold(false) {}
  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 FullPivHouseholderQR()
  92. */
  93. FullPivHouseholderQR(Index rows, Index cols)
  94. : m_qr(rows, cols),
  95. m_hCoeffs((std::min)(rows,cols)),
  96. m_rows_transpositions((std::min)(rows,cols)),
  97. m_cols_transpositions((std::min)(rows,cols)),
  98. m_cols_permutation(cols),
  99. m_temp(cols),
  100. m_isInitialized(false),
  101. m_usePrescribedThreshold(false) {}
  102. /** \brief Constructs a QR factorization from a given matrix
  103. *
  104. * This constructor computes the QR factorization of the matrix \a matrix by calling
  105. * the method compute(). It is a short cut for:
  106. *
  107. * \code
  108. * FullPivHouseholderQR<MatrixType> qr(matrix.rows(), matrix.cols());
  109. * qr.compute(matrix);
  110. * \endcode
  111. *
  112. * \sa compute()
  113. */
  114. template<typename InputType>
  115. explicit FullPivHouseholderQR(const EigenBase<InputType>& matrix)
  116. : m_qr(matrix.rows(), matrix.cols()),
  117. m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
  118. m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())),
  119. m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())),
  120. m_cols_permutation(matrix.cols()),
  121. m_temp(matrix.cols()),
  122. m_isInitialized(false),
  123. m_usePrescribedThreshold(false)
  124. {
  125. compute(matrix.derived());
  126. }
  127. /** \brief Constructs a QR factorization from a given matrix
  128. *
  129. * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when \c MatrixType is a Eigen::Ref.
  130. *
  131. * \sa FullPivHouseholderQR(const EigenBase&)
  132. */
  133. template<typename InputType>
  134. explicit FullPivHouseholderQR(EigenBase<InputType>& matrix)
  135. : m_qr(matrix.derived()),
  136. m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
  137. m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())),
  138. m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())),
  139. m_cols_permutation(matrix.cols()),
  140. m_temp(matrix.cols()),
  141. m_isInitialized(false),
  142. m_usePrescribedThreshold(false)
  143. {
  144. computeInPlace();
  145. }
  146. #ifdef EIGEN_PARSED_BY_DOXYGEN
  147. /** This method finds a solution x to the equation Ax=b, where A is the matrix of which
  148. * \c *this is the QR decomposition.
  149. *
  150. * \param b the right-hand-side of the equation to solve.
  151. *
  152. * \returns the exact or least-square solution if the rank is greater or equal to the number of columns of A,
  153. * and an arbitrary solution otherwise.
  154. *
  155. * \note_about_checking_solutions
  156. *
  157. * \note_about_arbitrary_choice_of_solution
  158. *
  159. * Example: \include FullPivHouseholderQR_solve.cpp
  160. * Output: \verbinclude FullPivHouseholderQR_solve.out
  161. */
  162. template<typename Rhs>
  163. inline const Solve<FullPivHouseholderQR, Rhs>
  164. solve(const MatrixBase<Rhs>& b) const;
  165. #endif
  166. /** \returns Expression object representing the matrix Q
  167. */
  168. MatrixQReturnType matrixQ(void) const;
  169. /** \returns a reference to the matrix where the Householder QR decomposition is stored
  170. */
  171. const MatrixType& matrixQR() const
  172. {
  173. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  174. return m_qr;
  175. }
  176. template<typename InputType>
  177. FullPivHouseholderQR& compute(const EigenBase<InputType>& matrix);
  178. /** \returns a const reference to the column permutation matrix */
  179. const PermutationType& colsPermutation() const
  180. {
  181. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  182. return m_cols_permutation;
  183. }
  184. /** \returns a const reference to the vector of indices representing the rows transpositions */
  185. const IntDiagSizeVectorType& rowsTranspositions() const
  186. {
  187. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  188. return m_rows_transpositions;
  189. }
  190. /** \returns the absolute value of the determinant of the matrix of which
  191. * *this is the QR decomposition. It has only linear complexity
  192. * (that is, O(n) where n is the dimension of the square matrix)
  193. * as the QR decomposition has already been computed.
  194. *
  195. * \note This is only for square matrices.
  196. *
  197. * \warning a determinant can be very big or small, so for matrices
  198. * of large enough dimension, there is a risk of overflow/underflow.
  199. * One way to work around that is to use logAbsDeterminant() instead.
  200. *
  201. * \sa logAbsDeterminant(), MatrixBase::determinant()
  202. */
  203. typename MatrixType::RealScalar absDeterminant() const;
  204. /** \returns the natural log of the absolute value of the determinant of the matrix of which
  205. * *this is the QR decomposition. It has only linear complexity
  206. * (that is, O(n) where n is the dimension of the square matrix)
  207. * as the QR decomposition has already been computed.
  208. *
  209. * \note This is only for square matrices.
  210. *
  211. * \note This method is useful to work around the risk of overflow/underflow that's inherent
  212. * to determinant computation.
  213. *
  214. * \sa absDeterminant(), MatrixBase::determinant()
  215. */
  216. typename MatrixType::RealScalar logAbsDeterminant() const;
  217. /** \returns the rank of the matrix of which *this is the QR decomposition.
  218. *
  219. * \note This method has to determine which pivots should be considered nonzero.
  220. * For that, it uses the threshold value that you can control by calling
  221. * setThreshold(const RealScalar&).
  222. */
  223. inline Index rank() const
  224. {
  225. using std::abs;
  226. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  227. RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold();
  228. Index result = 0;
  229. for(Index i = 0; i < m_nonzero_pivots; ++i)
  230. result += (abs(m_qr.coeff(i,i)) > premultiplied_threshold);
  231. return result;
  232. }
  233. /** \returns the dimension of the kernel of the matrix of which *this is the QR decomposition.
  234. *
  235. * \note This method has to determine which pivots should be considered nonzero.
  236. * For that, it uses the threshold value that you can control by calling
  237. * setThreshold(const RealScalar&).
  238. */
  239. inline Index dimensionOfKernel() const
  240. {
  241. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  242. return cols() - rank();
  243. }
  244. /** \returns true if the matrix of which *this is the QR decomposition represents an injective
  245. * linear map, i.e. has trivial kernel; false otherwise.
  246. *
  247. * \note This method has to determine which pivots should be considered nonzero.
  248. * For that, it uses the threshold value that you can control by calling
  249. * setThreshold(const RealScalar&).
  250. */
  251. inline bool isInjective() const
  252. {
  253. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  254. return rank() == cols();
  255. }
  256. /** \returns true if the matrix of which *this is the QR decomposition represents a surjective
  257. * linear map; false otherwise.
  258. *
  259. * \note This method has to determine which pivots should be considered nonzero.
  260. * For that, it uses the threshold value that you can control by calling
  261. * setThreshold(const RealScalar&).
  262. */
  263. inline bool isSurjective() const
  264. {
  265. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  266. return rank() == rows();
  267. }
  268. /** \returns true if the matrix of which *this is the QR decomposition is invertible.
  269. *
  270. * \note This method has to determine which pivots should be considered nonzero.
  271. * For that, it uses the threshold value that you can control by calling
  272. * setThreshold(const RealScalar&).
  273. */
  274. inline bool isInvertible() const
  275. {
  276. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  277. return isInjective() && isSurjective();
  278. }
  279. /** \returns the inverse of the matrix of which *this is the QR decomposition.
  280. *
  281. * \note If this matrix is not invertible, the returned matrix has undefined coefficients.
  282. * Use isInvertible() to first determine whether this matrix is invertible.
  283. */
  284. inline const Inverse<FullPivHouseholderQR> inverse() const
  285. {
  286. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  287. return Inverse<FullPivHouseholderQR>(*this);
  288. }
  289. inline Index rows() const { return m_qr.rows(); }
  290. inline Index cols() const { return m_qr.cols(); }
  291. /** \returns a const reference to the vector of Householder coefficients used to represent the factor \c Q.
  292. *
  293. * For advanced uses only.
  294. */
  295. const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
  296. /** Allows to prescribe a threshold to be used by certain methods, such as rank(),
  297. * who need to determine when pivots are to be considered nonzero. This is not used for the
  298. * QR decomposition itself.
  299. *
  300. * When it needs to get the threshold value, Eigen calls threshold(). By default, this
  301. * uses a formula to automatically determine a reasonable threshold.
  302. * Once you have called the present method setThreshold(const RealScalar&),
  303. * your value is used instead.
  304. *
  305. * \param threshold The new value to use as the threshold.
  306. *
  307. * A pivot will be considered nonzero if its absolute value is strictly greater than
  308. * \f$ \vert pivot \vert \leqslant threshold \times \vert maxpivot \vert \f$
  309. * where maxpivot is the biggest pivot.
  310. *
  311. * If you want to come back to the default behavior, call setThreshold(Default_t)
  312. */
  313. FullPivHouseholderQR& setThreshold(const RealScalar& threshold)
  314. {
  315. m_usePrescribedThreshold = true;
  316. m_prescribedThreshold = threshold;
  317. return *this;
  318. }
  319. /** Allows to come back to the default behavior, letting Eigen use its default formula for
  320. * determining the threshold.
  321. *
  322. * You should pass the special object Eigen::Default as parameter here.
  323. * \code qr.setThreshold(Eigen::Default); \endcode
  324. *
  325. * See the documentation of setThreshold(const RealScalar&).
  326. */
  327. FullPivHouseholderQR& setThreshold(Default_t)
  328. {
  329. m_usePrescribedThreshold = false;
  330. return *this;
  331. }
  332. /** Returns the threshold that will be used by certain methods such as rank().
  333. *
  334. * See the documentation of setThreshold(const RealScalar&).
  335. */
  336. RealScalar threshold() const
  337. {
  338. eigen_assert(m_isInitialized || m_usePrescribedThreshold);
  339. return m_usePrescribedThreshold ? m_prescribedThreshold
  340. // this formula comes from experimenting (see "LU precision tuning" thread on the list)
  341. // and turns out to be identical to Higham's formula used already in LDLt.
  342. : NumTraits<Scalar>::epsilon() * RealScalar(m_qr.diagonalSize());
  343. }
  344. /** \returns the number of nonzero pivots in the QR decomposition.
  345. * Here nonzero is meant in the exact sense, not in a fuzzy sense.
  346. * So that notion isn't really intrinsically interesting, but it is
  347. * still useful when implementing algorithms.
  348. *
  349. * \sa rank()
  350. */
  351. inline Index nonzeroPivots() const
  352. {
  353. eigen_assert(m_isInitialized && "LU is not initialized.");
  354. return m_nonzero_pivots;
  355. }
  356. /** \returns the absolute value of the biggest pivot, i.e. the biggest
  357. * diagonal coefficient of U.
  358. */
  359. RealScalar maxPivot() const { return m_maxpivot; }
  360. #ifndef EIGEN_PARSED_BY_DOXYGEN
  361. template<typename RhsType, typename DstType>
  362. void _solve_impl(const RhsType &rhs, DstType &dst) const;
  363. template<bool Conjugate, typename RhsType, typename DstType>
  364. void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
  365. #endif
  366. protected:
  367. static void check_template_parameters()
  368. {
  369. EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
  370. }
  371. void computeInPlace();
  372. MatrixType m_qr;
  373. HCoeffsType m_hCoeffs;
  374. IntDiagSizeVectorType m_rows_transpositions;
  375. IntDiagSizeVectorType m_cols_transpositions;
  376. PermutationType m_cols_permutation;
  377. RowVectorType m_temp;
  378. bool m_isInitialized, m_usePrescribedThreshold;
  379. RealScalar m_prescribedThreshold, m_maxpivot;
  380. Index m_nonzero_pivots;
  381. RealScalar m_precision;
  382. Index m_det_pq;
  383. };
  384. template<typename MatrixType>
  385. typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::absDeterminant() const
  386. {
  387. using std::abs;
  388. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  389. eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
  390. return abs(m_qr.diagonal().prod());
  391. }
  392. template<typename MatrixType>
  393. typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::logAbsDeterminant() const
  394. {
  395. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  396. eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
  397. return m_qr.diagonal().cwiseAbs().array().log().sum();
  398. }
  399. /** Performs the QR factorization of the given matrix \a matrix. The result of
  400. * the factorization is stored into \c *this, and a reference to \c *this
  401. * is returned.
  402. *
  403. * \sa class FullPivHouseholderQR, FullPivHouseholderQR(const MatrixType&)
  404. */
  405. template<typename MatrixType>
  406. template<typename InputType>
  407. FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(const EigenBase<InputType>& matrix)
  408. {
  409. m_qr = matrix.derived();
  410. computeInPlace();
  411. return *this;
  412. }
  413. template<typename MatrixType>
  414. void FullPivHouseholderQR<MatrixType>::computeInPlace()
  415. {
  416. check_template_parameters();
  417. using std::abs;
  418. Index rows = m_qr.rows();
  419. Index cols = m_qr.cols();
  420. Index size = (std::min)(rows,cols);
  421. m_hCoeffs.resize(size);
  422. m_temp.resize(cols);
  423. m_precision = NumTraits<Scalar>::epsilon() * RealScalar(size);
  424. m_rows_transpositions.resize(size);
  425. m_cols_transpositions.resize(size);
  426. Index number_of_transpositions = 0;
  427. RealScalar biggest(0);
  428. m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
  429. m_maxpivot = RealScalar(0);
  430. for (Index k = 0; k < size; ++k)
  431. {
  432. Index row_of_biggest_in_corner, col_of_biggest_in_corner;
  433. typedef internal::scalar_score_coeff_op<Scalar> Scoring;
  434. typedef typename Scoring::result_type Score;
  435. Score score = m_qr.bottomRightCorner(rows-k, cols-k)
  436. .unaryExpr(Scoring())
  437. .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
  438. row_of_biggest_in_corner += k;
  439. col_of_biggest_in_corner += k;
  440. RealScalar biggest_in_corner = internal::abs_knowing_score<Scalar>()(m_qr(row_of_biggest_in_corner, col_of_biggest_in_corner), score);
  441. if(k==0) biggest = biggest_in_corner;
  442. // if the corner is negligible, then we have less than full rank, and we can finish early
  443. if(internal::isMuchSmallerThan(biggest_in_corner, biggest, m_precision))
  444. {
  445. m_nonzero_pivots = k;
  446. for(Index i = k; i < size; i++)
  447. {
  448. m_rows_transpositions.coeffRef(i) = internal::convert_index<StorageIndex>(i);
  449. m_cols_transpositions.coeffRef(i) = internal::convert_index<StorageIndex>(i);
  450. m_hCoeffs.coeffRef(i) = Scalar(0);
  451. }
  452. break;
  453. }
  454. m_rows_transpositions.coeffRef(k) = internal::convert_index<StorageIndex>(row_of_biggest_in_corner);
  455. m_cols_transpositions.coeffRef(k) = internal::convert_index<StorageIndex>(col_of_biggest_in_corner);
  456. if(k != row_of_biggest_in_corner) {
  457. m_qr.row(k).tail(cols-k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols-k));
  458. ++number_of_transpositions;
  459. }
  460. if(k != col_of_biggest_in_corner) {
  461. m_qr.col(k).swap(m_qr.col(col_of_biggest_in_corner));
  462. ++number_of_transpositions;
  463. }
  464. RealScalar beta;
  465. m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
  466. m_qr.coeffRef(k,k) = beta;
  467. // remember the maximum absolute value of diagonal coefficients
  468. if(abs(beta) > m_maxpivot) m_maxpivot = abs(beta);
  469. m_qr.bottomRightCorner(rows-k, cols-k-1)
  470. .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
  471. }
  472. m_cols_permutation.setIdentity(cols);
  473. for(Index k = 0; k < size; ++k)
  474. m_cols_permutation.applyTranspositionOnTheRight(k, m_cols_transpositions.coeff(k));
  475. m_det_pq = (number_of_transpositions%2) ? -1 : 1;
  476. m_isInitialized = true;
  477. }
  478. #ifndef EIGEN_PARSED_BY_DOXYGEN
  479. template<typename _MatrixType>
  480. template<typename RhsType, typename DstType>
  481. void FullPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const
  482. {
  483. const Index l_rank = rank();
  484. // FIXME introduce nonzeroPivots() and use it here. and more generally,
  485. // make the same improvements in this dec as in FullPivLU.
  486. if(l_rank==0)
  487. {
  488. dst.setZero();
  489. return;
  490. }
  491. typename RhsType::PlainObject c(rhs);
  492. Matrix<typename RhsType::Scalar,1,RhsType::ColsAtCompileTime> temp(rhs.cols());
  493. for (Index k = 0; k < l_rank; ++k)
  494. {
  495. Index remainingSize = rows()-k;
  496. c.row(k).swap(c.row(m_rows_transpositions.coeff(k)));
  497. c.bottomRightCorner(remainingSize, rhs.cols())
  498. .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize-1),
  499. m_hCoeffs.coeff(k), &temp.coeffRef(0));
  500. }
  501. m_qr.topLeftCorner(l_rank, l_rank)
  502. .template triangularView<Upper>()
  503. .solveInPlace(c.topRows(l_rank));
  504. for(Index i = 0; i < l_rank; ++i) dst.row(m_cols_permutation.indices().coeff(i)) = c.row(i);
  505. for(Index i = l_rank; i < cols(); ++i) dst.row(m_cols_permutation.indices().coeff(i)).setZero();
  506. }
  507. template<typename _MatrixType>
  508. template<bool Conjugate, typename RhsType, typename DstType>
  509. void FullPivHouseholderQR<_MatrixType>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
  510. {
  511. const Index l_rank = rank();
  512. if(l_rank == 0)
  513. {
  514. dst.setZero();
  515. return;
  516. }
  517. typename RhsType::PlainObject c(m_cols_permutation.transpose()*rhs);
  518. m_qr.topLeftCorner(l_rank, l_rank)
  519. .template triangularView<Upper>()
  520. .transpose().template conjugateIf<Conjugate>()
  521. .solveInPlace(c.topRows(l_rank));
  522. dst.topRows(l_rank) = c.topRows(l_rank);
  523. dst.bottomRows(rows()-l_rank).setZero();
  524. Matrix<Scalar, 1, DstType::ColsAtCompileTime> temp(dst.cols());
  525. const Index size = (std::min)(rows(), cols());
  526. for (Index k = size-1; k >= 0; --k)
  527. {
  528. Index remainingSize = rows()-k;
  529. dst.bottomRightCorner(remainingSize, dst.cols())
  530. .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize-1).template conjugateIf<!Conjugate>(),
  531. m_hCoeffs.template conjugateIf<Conjugate>().coeff(k), &temp.coeffRef(0));
  532. dst.row(k).swap(dst.row(m_rows_transpositions.coeff(k)));
  533. }
  534. }
  535. #endif
  536. namespace internal {
  537. template<typename DstXprType, typename MatrixType>
  538. struct Assignment<DstXprType, Inverse<FullPivHouseholderQR<MatrixType> >, internal::assign_op<typename DstXprType::Scalar,typename FullPivHouseholderQR<MatrixType>::Scalar>, Dense2Dense>
  539. {
  540. typedef FullPivHouseholderQR<MatrixType> QrType;
  541. typedef Inverse<QrType> SrcXprType;
  542. static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<typename DstXprType::Scalar,typename QrType::Scalar> &)
  543. {
  544. dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols()));
  545. }
  546. };
  547. /** \ingroup QR_Module
  548. *
  549. * \brief Expression type for return value of FullPivHouseholderQR::matrixQ()
  550. *
  551. * \tparam MatrixType type of underlying dense matrix
  552. */
  553. template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType
  554. : public ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
  555. {
  556. public:
  557. typedef typename FullPivHouseholderQR<MatrixType>::IntDiagSizeVectorType IntDiagSizeVectorType;
  558. typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
  559. typedef Matrix<typename MatrixType::Scalar, 1, MatrixType::RowsAtCompileTime, RowMajor, 1,
  560. MatrixType::MaxRowsAtCompileTime> WorkVectorType;
  561. FullPivHouseholderQRMatrixQReturnType(const MatrixType& qr,
  562. const HCoeffsType& hCoeffs,
  563. const IntDiagSizeVectorType& rowsTranspositions)
  564. : m_qr(qr),
  565. m_hCoeffs(hCoeffs),
  566. m_rowsTranspositions(rowsTranspositions)
  567. {}
  568. template <typename ResultType>
  569. void evalTo(ResultType& result) const
  570. {
  571. const Index rows = m_qr.rows();
  572. WorkVectorType workspace(rows);
  573. evalTo(result, workspace);
  574. }
  575. template <typename ResultType>
  576. void evalTo(ResultType& result, WorkVectorType& workspace) const
  577. {
  578. using numext::conj;
  579. // compute the product H'_0 H'_1 ... H'_n-1,
  580. // where H_k is the k-th Householder transformation I - h_k v_k v_k'
  581. // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...]
  582. const Index rows = m_qr.rows();
  583. const Index cols = m_qr.cols();
  584. const Index size = (std::min)(rows, cols);
  585. workspace.resize(rows);
  586. result.setIdentity(rows, rows);
  587. for (Index k = size-1; k >= 0; k--)
  588. {
  589. result.block(k, k, rows-k, rows-k)
  590. .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), conj(m_hCoeffs.coeff(k)), &workspace.coeffRef(k));
  591. result.row(k).swap(result.row(m_rowsTranspositions.coeff(k)));
  592. }
  593. }
  594. Index rows() const { return m_qr.rows(); }
  595. Index cols() const { return m_qr.rows(); }
  596. protected:
  597. typename MatrixType::Nested m_qr;
  598. typename HCoeffsType::Nested m_hCoeffs;
  599. typename IntDiagSizeVectorType::Nested m_rowsTranspositions;
  600. };
  601. // template<typename MatrixType>
  602. // struct evaluator<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
  603. // : public evaluator<ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> > >
  604. // {};
  605. } // end namespace internal
  606. template<typename MatrixType>
  607. inline typename FullPivHouseholderQR<MatrixType>::MatrixQReturnType FullPivHouseholderQR<MatrixType>::matrixQ() const
  608. {
  609. eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
  610. return MatrixQReturnType(m_qr, m_hCoeffs, m_rows_transpositions);
  611. }
  612. /** \return the full-pivoting Householder QR decomposition of \c *this.
  613. *
  614. * \sa class FullPivHouseholderQR
  615. */
  616. template<typename Derived>
  617. const FullPivHouseholderQR<typename MatrixBase<Derived>::PlainObject>
  618. MatrixBase<Derived>::fullPivHouseholderQr() const
  619. {
  620. return FullPivHouseholderQR<PlainObject>(eval());
  621. }
  622. } // end namespace Eigen
  623. #endif // EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H