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