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 #ifndef EIGEN_LU_H
00026 #define EIGEN_LU_H
00027
00060 template<typename MatrixType> class LU
00061 {
00062 public:
00063
00064 typedef typename MatrixType::Scalar Scalar;
00065 typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
00066 typedef Matrix<int, 1, MatrixType::ColsAtCompileTime, MatrixType::Options, 1, MatrixType::MaxColsAtCompileTime> IntRowVectorType;
00067 typedef Matrix<int, MatrixType::RowsAtCompileTime, 1, MatrixType::Options, MatrixType::MaxRowsAtCompileTime, 1> IntColVectorType;
00068 typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime, MatrixType::Options, 1, MatrixType::MaxColsAtCompileTime> RowVectorType;
00069 typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1, MatrixType::Options, MatrixType::MaxRowsAtCompileTime, 1> ColVectorType;
00070
00071 enum { MaxSmallDimAtCompileTime = EIGEN_SIZE_MIN(
00072 MatrixType::MaxColsAtCompileTime,
00073 MatrixType::MaxRowsAtCompileTime)
00074 };
00075
00076 typedef Matrix<typename MatrixType::Scalar,
00077 MatrixType::ColsAtCompileTime,
00078
00079 Dynamic,
00080 MatrixType::Options,
00081 MatrixType::MaxColsAtCompileTime,
00082 MatrixType::MaxColsAtCompileTime
00083
00084 > KernelResultType;
00085
00086 typedef Matrix<typename MatrixType::Scalar,
00087 MatrixType::RowsAtCompileTime,
00088
00089 Dynamic,
00090 MatrixType::Options,
00091 MatrixType::MaxRowsAtCompileTime,
00092 MatrixType::MaxColsAtCompileTime
00093 > ImageResultType;
00094
00099 LU(const MatrixType& matrix);
00100
00107 inline const MatrixType& matrixLU() const
00108 {
00109 return m_lu;
00110 }
00111
00118 inline const IntColVectorType& permutationP() const
00119 {
00120 return m_p;
00121 }
00122
00129 inline const IntRowVectorType& permutationQ() const
00130 {
00131 return m_q;
00132 }
00133
00148 template<typename KernelMatrixType>
00149 void computeKernel(KernelMatrixType *result) const;
00150
00164 template<typename ImageMatrixType>
00165 void computeImage(ImageMatrixType *result) const;
00166
00181 const KernelResultType kernel() const;
00182
00196 const ImageResultType image() const;
00197
00219 template<typename OtherDerived, typename ResultType>
00220 bool solve(const MatrixBase<OtherDerived>& b, ResultType *result) const;
00221
00237 typename ei_traits<MatrixType>::Scalar determinant() const;
00238
00244 inline int rank() const
00245 {
00246 return m_rank;
00247 }
00248
00254 inline int dimensionOfKernel() const
00255 {
00256 return m_lu.cols() - m_rank;
00257 }
00258
00265 inline bool isInjective() const
00266 {
00267 return m_rank == m_lu.cols();
00268 }
00269
00276 inline bool isSurjective() const
00277 {
00278 return m_rank == m_lu.rows();
00279 }
00280
00286 inline bool isInvertible() const
00287 {
00288 return isInjective() && isSurjective();
00289 }
00290
00300 template<typename ResultType>
00301 inline void computeInverse(ResultType *result) const
00302 {
00303 solve(MatrixType::Identity(m_lu.rows(), m_lu.cols()), result);
00304 }
00305
00313 inline MatrixType inverse() const
00314 {
00315 MatrixType result;
00316 computeInverse(&result);
00317 return result;
00318 }
00319
00320 protected:
00321 const MatrixType& m_originalMatrix;
00322 MatrixType m_lu;
00323 IntColVectorType m_p;
00324 IntRowVectorType m_q;
00325 int m_det_pq;
00326 int m_rank;
00327 RealScalar m_precision;
00328 };
00329
00330 template<typename MatrixType>
00331 LU<MatrixType>::LU(const MatrixType& matrix)
00332 : m_originalMatrix(matrix),
00333 m_lu(matrix),
00334 m_p(matrix.rows()),
00335 m_q(matrix.cols())
00336 {
00337 const int size = matrix.diagonal().size();
00338 const int rows = matrix.rows();
00339 const int cols = matrix.cols();
00340
00341
00342
00343 m_precision = machine_epsilon<Scalar>() * size;
00344
00345 IntColVectorType rows_transpositions(matrix.rows());
00346 IntRowVectorType cols_transpositions(matrix.cols());
00347 int number_of_transpositions = 0;
00348
00349 RealScalar biggest = RealScalar(0);
00350 m_rank = size;
00351 for(int k = 0; k < size; ++k)
00352 {
00353 int row_of_biggest_in_corner, col_of_biggest_in_corner;
00354 RealScalar biggest_in_corner;
00355
00356 biggest_in_corner = m_lu.corner(Eigen::BottomRight, rows-k, cols-k)
00357 .cwise().abs()
00358 .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
00359 row_of_biggest_in_corner += k;
00360 col_of_biggest_in_corner += k;
00361 if(k==0) biggest = biggest_in_corner;
00362
00363
00364 if(ei_isMuchSmallerThan(biggest_in_corner, biggest, m_precision))
00365 {
00366 m_rank = k;
00367 for(int i = k; i < size; i++)
00368 {
00369 rows_transpositions.coeffRef(i) = i;
00370 cols_transpositions.coeffRef(i) = i;
00371 }
00372 break;
00373 }
00374
00375 rows_transpositions.coeffRef(k) = row_of_biggest_in_corner;
00376 cols_transpositions.coeffRef(k) = col_of_biggest_in_corner;
00377 if(k != row_of_biggest_in_corner) {
00378 m_lu.row(k).swap(m_lu.row(row_of_biggest_in_corner));
00379 ++number_of_transpositions;
00380 }
00381 if(k != col_of_biggest_in_corner) {
00382 m_lu.col(k).swap(m_lu.col(col_of_biggest_in_corner));
00383 ++number_of_transpositions;
00384 }
00385 if(k<rows-1)
00386 m_lu.col(k).end(rows-k-1) /= m_lu.coeff(k,k);
00387 if(k<size-1)
00388 for(int col = k + 1; col < cols; ++col)
00389 m_lu.col(col).end(rows-k-1) -= m_lu.col(k).end(rows-k-1) * m_lu.coeff(k,col);
00390 }
00391
00392 for(int k = 0; k < matrix.rows(); ++k) m_p.coeffRef(k) = k;
00393 for(int k = size-1; k >= 0; --k)
00394 std::swap(m_p.coeffRef(k), m_p.coeffRef(rows_transpositions.coeff(k)));
00395
00396 for(int k = 0; k < matrix.cols(); ++k) m_q.coeffRef(k) = k;
00397 for(int k = 0; k < size; ++k)
00398 std::swap(m_q.coeffRef(k), m_q.coeffRef(cols_transpositions.coeff(k)));
00399
00400 m_det_pq = (number_of_transpositions%2) ? -1 : 1;
00401 }
00402
00403 template<typename MatrixType>
00404 typename ei_traits<MatrixType>::Scalar LU<MatrixType>::determinant() const
00405 {
00406 return Scalar(m_det_pq) * m_lu.diagonal().redux(ei_scalar_product_op<Scalar>());
00407 }
00408
00409 template<typename MatrixType>
00410 template<typename KernelMatrixType>
00411 void LU<MatrixType>::computeKernel(KernelMatrixType *result) const
00412 {
00413 ei_assert(!isInvertible());
00414 const int dimker = dimensionOfKernel(), cols = m_lu.cols();
00415 result->resize(cols, dimker);
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 Matrix<Scalar, Dynamic, Dynamic, MatrixType::Options,
00434 MatrixType::MaxColsAtCompileTime, MatrixType::MaxColsAtCompileTime>
00435 y(-m_lu.corner(TopRight, m_rank, dimker));
00436
00437 m_lu.corner(TopLeft, m_rank, m_rank)
00438 .template marked<UpperTriangular>()
00439 .solveTriangularInPlace(y);
00440
00441 for(int i = 0; i < m_rank; ++i) result->row(m_q.coeff(i)) = y.row(i);
00442 for(int i = m_rank; i < cols; ++i) result->row(m_q.coeff(i)).setZero();
00443 for(int k = 0; k < dimker; ++k) result->coeffRef(m_q.coeff(m_rank+k), k) = Scalar(1);
00444 }
00445
00446 template<typename MatrixType>
00447 const typename LU<MatrixType>::KernelResultType
00448 LU<MatrixType>::kernel() const
00449 {
00450 KernelResultType result(m_lu.cols(), dimensionOfKernel());
00451 computeKernel(&result);
00452 return result;
00453 }
00454
00455 template<typename MatrixType>
00456 template<typename ImageMatrixType>
00457 void LU<MatrixType>::computeImage(ImageMatrixType *result) const
00458 {
00459 ei_assert(m_rank > 0);
00460 result->resize(m_originalMatrix.rows(), m_rank);
00461 for(int i = 0; i < m_rank; ++i)
00462 result->col(i) = m_originalMatrix.col(m_q.coeff(i));
00463 }
00464
00465 template<typename MatrixType>
00466 const typename LU<MatrixType>::ImageResultType
00467 LU<MatrixType>::image() const
00468 {
00469 ImageResultType result(m_originalMatrix.rows(), m_rank);
00470 computeImage(&result);
00471 return result;
00472 }
00473
00474 template<typename MatrixType>
00475 template<typename OtherDerived, typename ResultType>
00476 bool LU<MatrixType>::solve(
00477 const MatrixBase<OtherDerived>& b,
00478 ResultType *result
00479 ) const
00480 {
00481
00482
00483
00484
00485
00486
00487
00488
00489 const int rows = m_lu.rows(), cols = m_lu.cols();
00490 ei_assert(b.rows() == rows);
00491 const int smalldim = std::min(rows, cols);
00492
00493 typename OtherDerived::PlainMatrixType c(b.rows(), b.cols());
00494
00495
00496 for(int i = 0; i < rows; ++i) c.row(m_p.coeff(i)) = b.row(i);
00497
00498
00499 m_lu.corner(Eigen::TopLeft,smalldim,smalldim).template marked<UnitLowerTriangular>()
00500 .solveTriangularInPlace(
00501 c.corner(Eigen::TopLeft, smalldim, c.cols()));
00502 if(rows>cols)
00503 {
00504 c.corner(Eigen::BottomLeft, rows-cols, c.cols())
00505 -= m_lu.corner(Eigen::BottomLeft, rows-cols, cols) * c.corner(Eigen::TopLeft, cols, c.cols());
00506 }
00507
00508
00509 if(!isSurjective())
00510 {
00511
00512 RealScalar biggest_in_c = m_rank>0 ? c.corner(TopLeft, m_rank, c.cols()).cwise().abs().maxCoeff() : RealScalar(0);
00513 for(int col = 0; col < c.cols(); ++col)
00514 for(int row = m_rank; row < c.rows(); ++row)
00515 if(!ei_isMuchSmallerThan(c.coeff(row,col), biggest_in_c, m_precision))
00516 return false;
00517 }
00518 if(m_rank>0)
00519 m_lu.corner(TopLeft, m_rank, m_rank)
00520 .template marked<UpperTriangular>()
00521 .solveTriangularInPlace(c.corner(TopLeft, m_rank, c.cols()));
00522
00523
00524 result->resize(m_lu.cols(), b.cols());
00525 for(int i = 0; i < m_rank; ++i) result->row(m_q.coeff(i)) = c.row(i);
00526 for(int i = m_rank; i < m_lu.cols(); ++i) result->row(m_q.coeff(i)).setZero();
00527 return true;
00528 }
00529
00536 template<typename Derived>
00537 inline const LU<typename MatrixBase<Derived>::PlainMatrixType>
00538 MatrixBase<Derived>::lu() const
00539 {
00540 return LU<PlainMatrixType>(eval());
00541 }
00542
00543 #endif // EIGEN_LU_H