Warning, file /include/eigen3/Eigen/src/QR/ColPivHouseholderQR.h was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
0012 #define EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
0013
0014 namespace Eigen {
0015
0016 namespace internal {
0017 template<typename _MatrixType> struct traits<ColPivHouseholderQR<_MatrixType> >
0018 : traits<_MatrixType>
0019 {
0020 typedef MatrixXpr XprKind;
0021 typedef SolverStorage StorageKind;
0022 typedef int StorageIndex;
0023 enum { Flags = 0 };
0024 };
0025
0026 }
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 template<typename _MatrixType> class ColPivHouseholderQR
0052 : public SolverBase<ColPivHouseholderQR<_MatrixType> >
0053 {
0054 public:
0055
0056 typedef _MatrixType MatrixType;
0057 typedef SolverBase<ColPivHouseholderQR> Base;
0058 friend class SolverBase<ColPivHouseholderQR>;
0059
0060 EIGEN_GENERIC_PUBLIC_INTERFACE(ColPivHouseholderQR)
0061 enum {
0062 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
0063 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
0064 };
0065 typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
0066 typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
0067 typedef typename internal::plain_row_type<MatrixType, Index>::type IntRowVectorType;
0068 typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
0069 typedef typename internal::plain_row_type<MatrixType, RealScalar>::type RealRowVectorType;
0070 typedef HouseholderSequence<MatrixType,typename internal::remove_all<typename HCoeffsType::ConjugateReturnType>::type> HouseholderSequenceType;
0071 typedef typename MatrixType::PlainObject PlainObject;
0072
0073 private:
0074
0075 typedef typename PermutationType::StorageIndex PermIndexType;
0076
0077 public:
0078
0079
0080
0081
0082
0083
0084
0085 ColPivHouseholderQR()
0086 : m_qr(),
0087 m_hCoeffs(),
0088 m_colsPermutation(),
0089 m_colsTranspositions(),
0090 m_temp(),
0091 m_colNormsUpdated(),
0092 m_colNormsDirect(),
0093 m_isInitialized(false),
0094 m_usePrescribedThreshold(false) {}
0095
0096
0097
0098
0099
0100
0101
0102 ColPivHouseholderQR(Index rows, Index cols)
0103 : m_qr(rows, cols),
0104 m_hCoeffs((std::min)(rows,cols)),
0105 m_colsPermutation(PermIndexType(cols)),
0106 m_colsTranspositions(cols),
0107 m_temp(cols),
0108 m_colNormsUpdated(cols),
0109 m_colNormsDirect(cols),
0110 m_isInitialized(false),
0111 m_usePrescribedThreshold(false) {}
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125 template<typename InputType>
0126 explicit ColPivHouseholderQR(const EigenBase<InputType>& matrix)
0127 : m_qr(matrix.rows(), matrix.cols()),
0128 m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
0129 m_colsPermutation(PermIndexType(matrix.cols())),
0130 m_colsTranspositions(matrix.cols()),
0131 m_temp(matrix.cols()),
0132 m_colNormsUpdated(matrix.cols()),
0133 m_colNormsDirect(matrix.cols()),
0134 m_isInitialized(false),
0135 m_usePrescribedThreshold(false)
0136 {
0137 compute(matrix.derived());
0138 }
0139
0140
0141
0142
0143
0144
0145
0146 template<typename InputType>
0147 explicit ColPivHouseholderQR(EigenBase<InputType>& matrix)
0148 : m_qr(matrix.derived()),
0149 m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
0150 m_colsPermutation(PermIndexType(matrix.cols())),
0151 m_colsTranspositions(matrix.cols()),
0152 m_temp(matrix.cols()),
0153 m_colNormsUpdated(matrix.cols()),
0154 m_colNormsDirect(matrix.cols()),
0155 m_isInitialized(false),
0156 m_usePrescribedThreshold(false)
0157 {
0158 computeInPlace();
0159 }
0160
0161 #ifdef EIGEN_PARSED_BY_DOXYGEN
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176 template<typename Rhs>
0177 inline const Solve<ColPivHouseholderQR, Rhs>
0178 solve(const MatrixBase<Rhs>& b) const;
0179 #endif
0180
0181 HouseholderSequenceType householderQ() const;
0182 HouseholderSequenceType matrixQ() const
0183 {
0184 return householderQ();
0185 }
0186
0187
0188
0189 const MatrixType& matrixQR() const
0190 {
0191 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0192 return m_qr;
0193 }
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204 const MatrixType& matrixR() const
0205 {
0206 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0207 return m_qr;
0208 }
0209
0210 template<typename InputType>
0211 ColPivHouseholderQR& compute(const EigenBase<InputType>& matrix);
0212
0213
0214 const PermutationType& colsPermutation() const
0215 {
0216 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0217 return m_colsPermutation;
0218 }
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233 typename MatrixType::RealScalar absDeterminant() const;
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247 typename MatrixType::RealScalar logAbsDeterminant() const;
0248
0249
0250
0251
0252
0253
0254
0255 inline Index rank() const
0256 {
0257 using std::abs;
0258 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0259 RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold();
0260 Index result = 0;
0261 for(Index i = 0; i < m_nonzero_pivots; ++i)
0262 result += (abs(m_qr.coeff(i,i)) > premultiplied_threshold);
0263 return result;
0264 }
0265
0266
0267
0268
0269
0270
0271
0272 inline Index dimensionOfKernel() const
0273 {
0274 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0275 return cols() - rank();
0276 }
0277
0278
0279
0280
0281
0282
0283
0284
0285 inline bool isInjective() const
0286 {
0287 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0288 return rank() == cols();
0289 }
0290
0291
0292
0293
0294
0295
0296
0297
0298 inline bool isSurjective() const
0299 {
0300 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0301 return rank() == rows();
0302 }
0303
0304
0305
0306
0307
0308
0309
0310 inline bool isInvertible() const
0311 {
0312 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0313 return isInjective() && isSurjective();
0314 }
0315
0316
0317
0318
0319
0320
0321 inline const Inverse<ColPivHouseholderQR> inverse() const
0322 {
0323 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0324 return Inverse<ColPivHouseholderQR>(*this);
0325 }
0326
0327 inline Index rows() const { return m_qr.rows(); }
0328 inline Index cols() const { return m_qr.cols(); }
0329
0330
0331
0332
0333
0334 const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353 ColPivHouseholderQR& setThreshold(const RealScalar& threshold)
0354 {
0355 m_usePrescribedThreshold = true;
0356 m_prescribedThreshold = threshold;
0357 return *this;
0358 }
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368 ColPivHouseholderQR& setThreshold(Default_t)
0369 {
0370 m_usePrescribedThreshold = false;
0371 return *this;
0372 }
0373
0374
0375
0376
0377
0378 RealScalar threshold() const
0379 {
0380 eigen_assert(m_isInitialized || m_usePrescribedThreshold);
0381 return m_usePrescribedThreshold ? m_prescribedThreshold
0382
0383
0384 : NumTraits<Scalar>::epsilon() * RealScalar(m_qr.diagonalSize());
0385 }
0386
0387
0388
0389
0390
0391
0392
0393
0394 inline Index nonzeroPivots() const
0395 {
0396 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0397 return m_nonzero_pivots;
0398 }
0399
0400
0401
0402
0403 RealScalar maxPivot() const { return m_maxpivot; }
0404
0405
0406
0407
0408
0409
0410
0411 ComputationInfo info() const
0412 {
0413 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
0414 return Success;
0415 }
0416
0417 #ifndef EIGEN_PARSED_BY_DOXYGEN
0418 template<typename RhsType, typename DstType>
0419 void _solve_impl(const RhsType &rhs, DstType &dst) const;
0420
0421 template<bool Conjugate, typename RhsType, typename DstType>
0422 void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
0423 #endif
0424
0425 protected:
0426
0427 friend class CompleteOrthogonalDecomposition<MatrixType>;
0428
0429 static void check_template_parameters()
0430 {
0431 EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
0432 }
0433
0434 void computeInPlace();
0435
0436 MatrixType m_qr;
0437 HCoeffsType m_hCoeffs;
0438 PermutationType m_colsPermutation;
0439 IntRowVectorType m_colsTranspositions;
0440 RowVectorType m_temp;
0441 RealRowVectorType m_colNormsUpdated;
0442 RealRowVectorType m_colNormsDirect;
0443 bool m_isInitialized, m_usePrescribedThreshold;
0444 RealScalar m_prescribedThreshold, m_maxpivot;
0445 Index m_nonzero_pivots;
0446 Index m_det_pq;
0447 };
0448
0449 template<typename MatrixType>
0450 typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::absDeterminant() const
0451 {
0452 using std::abs;
0453 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0454 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
0455 return abs(m_qr.diagonal().prod());
0456 }
0457
0458 template<typename MatrixType>
0459 typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::logAbsDeterminant() const
0460 {
0461 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0462 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
0463 return m_qr.diagonal().cwiseAbs().array().log().sum();
0464 }
0465
0466
0467
0468
0469
0470
0471
0472 template<typename MatrixType>
0473 template<typename InputType>
0474 ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const EigenBase<InputType>& matrix)
0475 {
0476 m_qr = matrix.derived();
0477 computeInPlace();
0478 return *this;
0479 }
0480
0481 template<typename MatrixType>
0482 void ColPivHouseholderQR<MatrixType>::computeInPlace()
0483 {
0484 check_template_parameters();
0485
0486
0487 eigen_assert(m_qr.cols()<=NumTraits<int>::highest());
0488
0489 using std::abs;
0490
0491 Index rows = m_qr.rows();
0492 Index cols = m_qr.cols();
0493 Index size = m_qr.diagonalSize();
0494
0495 m_hCoeffs.resize(size);
0496
0497 m_temp.resize(cols);
0498
0499 m_colsTranspositions.resize(m_qr.cols());
0500 Index number_of_transpositions = 0;
0501
0502 m_colNormsUpdated.resize(cols);
0503 m_colNormsDirect.resize(cols);
0504 for (Index k = 0; k < cols; ++k) {
0505
0506
0507 m_colNormsDirect.coeffRef(k) = m_qr.col(k).norm();
0508 m_colNormsUpdated.coeffRef(k) = m_colNormsDirect.coeffRef(k);
0509 }
0510
0511 RealScalar threshold_helper = numext::abs2<RealScalar>(m_colNormsUpdated.maxCoeff() * NumTraits<RealScalar>::epsilon()) / RealScalar(rows);
0512 RealScalar norm_downdate_threshold = numext::sqrt(NumTraits<RealScalar>::epsilon());
0513
0514 m_nonzero_pivots = size;
0515 m_maxpivot = RealScalar(0);
0516
0517 for(Index k = 0; k < size; ++k)
0518 {
0519
0520 Index biggest_col_index;
0521 RealScalar biggest_col_sq_norm = numext::abs2(m_colNormsUpdated.tail(cols-k).maxCoeff(&biggest_col_index));
0522 biggest_col_index += k;
0523
0524
0525
0526 if(m_nonzero_pivots==size && biggest_col_sq_norm < threshold_helper * RealScalar(rows-k))
0527 m_nonzero_pivots = k;
0528
0529
0530 m_colsTranspositions.coeffRef(k) = biggest_col_index;
0531 if(k != biggest_col_index) {
0532 m_qr.col(k).swap(m_qr.col(biggest_col_index));
0533 std::swap(m_colNormsUpdated.coeffRef(k), m_colNormsUpdated.coeffRef(biggest_col_index));
0534 std::swap(m_colNormsDirect.coeffRef(k), m_colNormsDirect.coeffRef(biggest_col_index));
0535 ++number_of_transpositions;
0536 }
0537
0538
0539 RealScalar beta;
0540 m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
0541
0542
0543 m_qr.coeffRef(k,k) = beta;
0544
0545
0546 if(abs(beta) > m_maxpivot) m_maxpivot = abs(beta);
0547
0548
0549 m_qr.bottomRightCorner(rows-k, cols-k-1)
0550 .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
0551
0552
0553 for (Index j = k + 1; j < cols; ++j) {
0554
0555
0556
0557
0558 if (m_colNormsUpdated.coeffRef(j) != RealScalar(0)) {
0559 RealScalar temp = abs(m_qr.coeffRef(k, j)) / m_colNormsUpdated.coeffRef(j);
0560 temp = (RealScalar(1) + temp) * (RealScalar(1) - temp);
0561 temp = temp < RealScalar(0) ? RealScalar(0) : temp;
0562 RealScalar temp2 = temp * numext::abs2<RealScalar>(m_colNormsUpdated.coeffRef(j) /
0563 m_colNormsDirect.coeffRef(j));
0564 if (temp2 <= norm_downdate_threshold) {
0565
0566
0567 m_colNormsDirect.coeffRef(j) = m_qr.col(j).tail(rows - k - 1).norm();
0568 m_colNormsUpdated.coeffRef(j) = m_colNormsDirect.coeffRef(j);
0569 } else {
0570 m_colNormsUpdated.coeffRef(j) *= numext::sqrt(temp);
0571 }
0572 }
0573 }
0574 }
0575
0576 m_colsPermutation.setIdentity(PermIndexType(cols));
0577 for(PermIndexType k = 0; k < size; ++k)
0578 m_colsPermutation.applyTranspositionOnTheRight(k, PermIndexType(m_colsTranspositions.coeff(k)));
0579
0580 m_det_pq = (number_of_transpositions%2) ? -1 : 1;
0581 m_isInitialized = true;
0582 }
0583
0584 #ifndef EIGEN_PARSED_BY_DOXYGEN
0585 template<typename _MatrixType>
0586 template<typename RhsType, typename DstType>
0587 void ColPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const
0588 {
0589 const Index nonzero_pivots = nonzeroPivots();
0590
0591 if(nonzero_pivots == 0)
0592 {
0593 dst.setZero();
0594 return;
0595 }
0596
0597 typename RhsType::PlainObject c(rhs);
0598
0599 c.applyOnTheLeft(householderQ().setLength(nonzero_pivots).adjoint() );
0600
0601 m_qr.topLeftCorner(nonzero_pivots, nonzero_pivots)
0602 .template triangularView<Upper>()
0603 .solveInPlace(c.topRows(nonzero_pivots));
0604
0605 for(Index i = 0; i < nonzero_pivots; ++i) dst.row(m_colsPermutation.indices().coeff(i)) = c.row(i);
0606 for(Index i = nonzero_pivots; i < cols(); ++i) dst.row(m_colsPermutation.indices().coeff(i)).setZero();
0607 }
0608
0609 template<typename _MatrixType>
0610 template<bool Conjugate, typename RhsType, typename DstType>
0611 void ColPivHouseholderQR<_MatrixType>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
0612 {
0613 const Index nonzero_pivots = nonzeroPivots();
0614
0615 if(nonzero_pivots == 0)
0616 {
0617 dst.setZero();
0618 return;
0619 }
0620
0621 typename RhsType::PlainObject c(m_colsPermutation.transpose()*rhs);
0622
0623 m_qr.topLeftCorner(nonzero_pivots, nonzero_pivots)
0624 .template triangularView<Upper>()
0625 .transpose().template conjugateIf<Conjugate>()
0626 .solveInPlace(c.topRows(nonzero_pivots));
0627
0628 dst.topRows(nonzero_pivots) = c.topRows(nonzero_pivots);
0629 dst.bottomRows(rows()-nonzero_pivots).setZero();
0630
0631 dst.applyOnTheLeft(householderQ().setLength(nonzero_pivots).template conjugateIf<!Conjugate>() );
0632 }
0633 #endif
0634
0635 namespace internal {
0636
0637 template<typename DstXprType, typename MatrixType>
0638 struct Assignment<DstXprType, Inverse<ColPivHouseholderQR<MatrixType> >, internal::assign_op<typename DstXprType::Scalar,typename ColPivHouseholderQR<MatrixType>::Scalar>, Dense2Dense>
0639 {
0640 typedef ColPivHouseholderQR<MatrixType> QrType;
0641 typedef Inverse<QrType> SrcXprType;
0642 static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<typename DstXprType::Scalar,typename QrType::Scalar> &)
0643 {
0644 dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols()));
0645 }
0646 };
0647
0648 }
0649
0650
0651
0652
0653 template<typename MatrixType>
0654 typename ColPivHouseholderQR<MatrixType>::HouseholderSequenceType ColPivHouseholderQR<MatrixType>
0655 ::householderQ() const
0656 {
0657 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
0658 return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate());
0659 }
0660
0661
0662
0663
0664
0665 template<typename Derived>
0666 const ColPivHouseholderQR<typename MatrixBase<Derived>::PlainObject>
0667 MatrixBase<Derived>::colPivHouseholderQr() const
0668 {
0669 return ColPivHouseholderQR<PlainObject>(eval());
0670 }
0671
0672 }
0673
0674 #endif