00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef EIGEN_PARTIALLU_H
00027 #define EIGEN_PARTIALLU_H
00028
00060 template<typename _MatrixType> class PartialPivLU
00061 {
00062 public:
00063
00064 typedef _MatrixType MatrixType;
00065 enum {
00066 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00067 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00068 Options = MatrixType::Options,
00069 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00070 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
00071 };
00072 typedef typename MatrixType::Scalar Scalar;
00073 typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
00074 typedef typename internal::traits<MatrixType>::StorageKind StorageKind;
00075 typedef typename MatrixType::Index Index;
00076 typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationType;
00077 typedef Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime> TranspositionType;
00078
00079
00086 PartialPivLU();
00087
00094 PartialPivLU(Index size);
00095
00103 PartialPivLU(const MatrixType& matrix);
00104
00105 PartialPivLU& compute(const MatrixType& matrix);
00106
00113 inline const MatrixType& matrixLU() const
00114 {
00115 eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
00116 return m_lu;
00117 }
00118
00121 inline const PermutationType& permutationP() const
00122 {
00123 eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
00124 return m_p;
00125 }
00126
00144 template<typename Rhs>
00145 inline const internal::solve_retval<PartialPivLU, Rhs>
00146 solve(const MatrixBase<Rhs>& b) const
00147 {
00148 eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
00149 return internal::solve_retval<PartialPivLU, Rhs>(*this, b.derived());
00150 }
00151
00159 inline const internal::solve_retval<PartialPivLU,typename MatrixType::IdentityReturnType> inverse() const
00160 {
00161 eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
00162 return internal::solve_retval<PartialPivLU,typename MatrixType::IdentityReturnType>
00163 (*this, MatrixType::Identity(m_lu.rows(), m_lu.cols()));
00164 }
00165
00179 typename internal::traits<MatrixType>::Scalar determinant() const;
00180
00181 MatrixType reconstructedMatrix() const;
00182
00183 inline Index rows() const { return m_lu.rows(); }
00184 inline Index cols() const { return m_lu.cols(); }
00185
00186 protected:
00187 MatrixType m_lu;
00188 PermutationType m_p;
00189 TranspositionType m_rowsTranspositions;
00190 Index m_det_p;
00191 bool m_isInitialized;
00192 };
00193
00194 template<typename MatrixType>
00195 PartialPivLU<MatrixType>::PartialPivLU()
00196 : m_lu(),
00197 m_p(),
00198 m_rowsTranspositions(),
00199 m_det_p(0),
00200 m_isInitialized(false)
00201 {
00202 }
00203
00204 template<typename MatrixType>
00205 PartialPivLU<MatrixType>::PartialPivLU(Index size)
00206 : m_lu(size, size),
00207 m_p(size),
00208 m_rowsTranspositions(size),
00209 m_det_p(0),
00210 m_isInitialized(false)
00211 {
00212 }
00213
00214 template<typename MatrixType>
00215 PartialPivLU<MatrixType>::PartialPivLU(const MatrixType& matrix)
00216 : m_lu(matrix.rows(), matrix.rows()),
00217 m_p(matrix.rows()),
00218 m_rowsTranspositions(matrix.rows()),
00219 m_det_p(0),
00220 m_isInitialized(false)
00221 {
00222 compute(matrix);
00223 }
00224
00225 namespace internal {
00226
00228 template<typename Scalar, int StorageOrder, typename PivIndex>
00229 struct partial_lu_impl
00230 {
00231
00232
00233
00234
00235
00236 typedef Map<Matrix<Scalar, Dynamic, Dynamic, StorageOrder> > MapLU;
00237 typedef Block<MapLU, Dynamic, Dynamic> MatrixType;
00238 typedef Block<MatrixType,Dynamic,Dynamic> BlockType;
00239 typedef typename MatrixType::RealScalar RealScalar;
00240 typedef typename MatrixType::Index Index;
00241
00252 static Index unblocked_lu(MatrixType& lu, PivIndex* row_transpositions, PivIndex& nb_transpositions)
00253 {
00254 const Index rows = lu.rows();
00255 const Index cols = lu.cols();
00256 const Index size = std::min(rows,cols);
00257 nb_transpositions = 0;
00258 int first_zero_pivot = -1;
00259 for(Index k = 0; k < size; ++k)
00260 {
00261 Index rrows = rows-k-1;
00262 Index rcols = cols-k-1;
00263
00264 Index row_of_biggest_in_col;
00265 RealScalar biggest_in_corner
00266 = lu.col(k).tail(rows-k).cwiseAbs().maxCoeff(&row_of_biggest_in_col);
00267 row_of_biggest_in_col += k;
00268
00269 row_transpositions[k] = row_of_biggest_in_col;
00270
00271 if(biggest_in_corner != 0)
00272 {
00273 if(k != row_of_biggest_in_col)
00274 {
00275 lu.row(k).swap(lu.row(row_of_biggest_in_col));
00276 ++nb_transpositions;
00277 }
00278
00279
00280
00281 lu.col(k).tail(rrows) /= lu.coeff(k,k);
00282 }
00283 else if(first_zero_pivot==-1)
00284 {
00285
00286
00287 first_zero_pivot = k;
00288 }
00289
00290 if(k<rows-1)
00291 lu.bottomRightCorner(rrows,rcols).noalias() -= lu.col(k).tail(rrows) * lu.row(k).tail(rcols);
00292 }
00293 return first_zero_pivot;
00294 }
00295
00311 static Index blocked_lu(Index rows, Index cols, Scalar* lu_data, Index luStride, PivIndex* row_transpositions, PivIndex& nb_transpositions, Index maxBlockSize=256)
00312 {
00313 MapLU lu1(lu_data,StorageOrder==RowMajor?rows:luStride,StorageOrder==RowMajor?luStride:cols);
00314 MatrixType lu(lu1,0,0,rows,cols);
00315
00316 const Index size = std::min(rows,cols);
00317
00318
00319 if(size<=16)
00320 {
00321 return unblocked_lu(lu, row_transpositions, nb_transpositions);
00322 }
00323
00324
00325
00326 Index blockSize;
00327 {
00328 blockSize = size/8;
00329 blockSize = (blockSize/16)*16;
00330 blockSize = std::min(std::max(blockSize,Index(8)), maxBlockSize);
00331 }
00332
00333 nb_transpositions = 0;
00334 int first_zero_pivot = -1;
00335 for(Index k = 0; k < size; k+=blockSize)
00336 {
00337 Index bs = std::min(size-k,blockSize);
00338 Index trows = rows - k - bs;
00339 Index tsize = size - k - bs;
00340
00341
00342
00343
00344
00345 BlockType A_0(lu,0,0,rows,k);
00346 BlockType A_2(lu,0,k+bs,rows,tsize);
00347 BlockType A11(lu,k,k,bs,bs);
00348 BlockType A12(lu,k,k+bs,bs,tsize);
00349 BlockType A21(lu,k+bs,k,trows,bs);
00350 BlockType A22(lu,k+bs,k+bs,trows,tsize);
00351
00352 PivIndex nb_transpositions_in_panel;
00353
00354
00355 Index ret = blocked_lu(trows+bs, bs, &lu.coeffRef(k,k), luStride,
00356 row_transpositions+k, nb_transpositions_in_panel, 16);
00357 if(ret>=0 && first_zero_pivot==-1)
00358 first_zero_pivot = k+ret;
00359
00360 nb_transpositions += nb_transpositions_in_panel;
00361
00362 for(Index i=k; i<k+bs; ++i)
00363 {
00364 Index piv = (row_transpositions[i] += k);
00365 A_0.row(i).swap(A_0.row(piv));
00366 }
00367
00368 if(trows)
00369 {
00370
00371 for(Index i=k;i<k+bs; ++i)
00372 A_2.row(i).swap(A_2.row(row_transpositions[i]));
00373
00374
00375 A11.template triangularView<UnitLower>().solveInPlace(A12);
00376
00377 A22.noalias() -= A21 * A12;
00378 }
00379 }
00380 return first_zero_pivot;
00381 }
00382 };
00383
00386 template<typename MatrixType, typename TranspositionType>
00387 void partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, typename TranspositionType::Index& nb_transpositions)
00388 {
00389 eigen_assert(lu.cols() == row_transpositions.size());
00390 eigen_assert((&row_transpositions.coeffRef(1)-&row_transpositions.coeffRef(0)) == 1);
00391
00392 partial_lu_impl
00393 <typename MatrixType::Scalar, MatrixType::Flags&RowMajorBit?RowMajor:ColMajor, typename TranspositionType::Index>
00394 ::blocked_lu(lu.rows(), lu.cols(), &lu.coeffRef(0,0), lu.outerStride(), &row_transpositions.coeffRef(0), nb_transpositions);
00395 }
00396
00397 }
00398
00399 template<typename MatrixType>
00400 PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const MatrixType& matrix)
00401 {
00402 m_lu = matrix;
00403
00404 eigen_assert(matrix.rows() == matrix.cols() && "PartialPivLU is only for square (and moreover invertible) matrices");
00405 const Index size = matrix.rows();
00406
00407 m_rowsTranspositions.resize(size);
00408
00409 typename TranspositionType::Index nb_transpositions;
00410 internal::partial_lu_inplace(m_lu, m_rowsTranspositions, nb_transpositions);
00411 m_det_p = (nb_transpositions%2) ? -1 : 1;
00412
00413 m_p = m_rowsTranspositions;
00414
00415 m_isInitialized = true;
00416 return *this;
00417 }
00418
00419 template<typename MatrixType>
00420 typename internal::traits<MatrixType>::Scalar PartialPivLU<MatrixType>::determinant() const
00421 {
00422 eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
00423 return Scalar(m_det_p) * m_lu.diagonal().prod();
00424 }
00425
00429 template<typename MatrixType>
00430 MatrixType PartialPivLU<MatrixType>::reconstructedMatrix() const
00431 {
00432 eigen_assert(m_isInitialized && "LU is not initialized.");
00433
00434 MatrixType res = m_lu.template triangularView<UnitLower>().toDenseMatrix()
00435 * m_lu.template triangularView<Upper>();
00436
00437
00438 res = m_p.inverse() * res;
00439
00440 return res;
00441 }
00442
00443
00444
00445 namespace internal {
00446
00447 template<typename _MatrixType, typename Rhs>
00448 struct solve_retval<PartialPivLU<_MatrixType>, Rhs>
00449 : solve_retval_base<PartialPivLU<_MatrixType>, Rhs>
00450 {
00451 EIGEN_MAKE_SOLVE_HELPERS(PartialPivLU<_MatrixType>,Rhs)
00452
00453 template<typename Dest> void evalTo(Dest& dst) const
00454 {
00455
00456
00457
00458
00459
00460
00461
00462 eigen_assert(rhs().rows() == dec().matrixLU().rows());
00463
00464
00465 dst = dec().permutationP() * rhs();
00466
00467
00468 dec().matrixLU().template triangularView<UnitLower>().solveInPlace(dst);
00469
00470
00471 dec().matrixLU().template triangularView<Upper>().solveInPlace(dst);
00472 }
00473 };
00474
00475 }
00476
00477
00478
00485 template<typename Derived>
00486 inline const PartialPivLU<typename MatrixBase<Derived>::PlainObject>
00487 MatrixBase<Derived>::partialPivLu() const
00488 {
00489 return PartialPivLU<PlainObject>(eval());
00490 }
00491
00492 #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS
00493
00501 template<typename Derived>
00502 inline const PartialPivLU<typename MatrixBase<Derived>::PlainObject>
00503 MatrixBase<Derived>::lu() const
00504 {
00505 return PartialPivLU<PlainObject>(eval());
00506 }
00507 #endif
00508
00509 #endif // EIGEN_PARTIALLU_H