00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef EIGEN_INCOMPLETE_LUT_H
00011 #define EIGEN_INCOMPLETE_LUT_H
00012
00013
00014 namespace Eigen {
00015
00016 namespace internal {
00017
00027 template <typename VectorV, typename VectorI, typename Index>
00028 Index QuickSplit(VectorV &row, VectorI &ind, Index ncut)
00029 {
00030 typedef typename VectorV::RealScalar RealScalar;
00031 using std::swap;
00032 using std::abs;
00033 Index mid;
00034 Index n = row.size();
00035 Index first, last ;
00036
00037 ncut--;
00038 first = 0;
00039 last = n-1;
00040 if (ncut < first || ncut > last ) return 0;
00041
00042 do {
00043 mid = first;
00044 RealScalar abskey = abs(row(mid));
00045 for (Index j = first + 1; j <= last; j++) {
00046 if ( abs(row(j)) > abskey) {
00047 ++mid;
00048 swap(row(mid), row(j));
00049 swap(ind(mid), ind(j));
00050 }
00051 }
00052
00053 swap(row(mid), row(first));
00054 swap(ind(mid), ind(first));
00055
00056 if (mid > ncut) last = mid - 1;
00057 else if (mid < ncut ) first = mid + 1;
00058 } while (mid != ncut );
00059
00060 return 0;
00061 }
00062
00063 }
00064
00095 template <typename _Scalar>
00096 class IncompleteLUT : internal::noncopyable
00097 {
00098 typedef _Scalar Scalar;
00099 typedef typename NumTraits<Scalar>::Real RealScalar;
00100 typedef Matrix<Scalar,Dynamic,1> Vector;
00101 typedef SparseMatrix<Scalar,RowMajor> FactorType;
00102 typedef SparseMatrix<Scalar,ColMajor> PermutType;
00103 typedef typename FactorType::Index Index;
00104
00105 public:
00106 typedef Matrix<Scalar,Dynamic,Dynamic> MatrixType;
00107
00108 IncompleteLUT()
00109 : m_droptol(NumTraits<Scalar>::dummy_precision()), m_fillfactor(10),
00110 m_analysisIsOk(false), m_factorizationIsOk(false), m_isInitialized(false)
00111 {}
00112
00113 template<typename MatrixType>
00114 IncompleteLUT(const MatrixType& mat, const RealScalar& droptol=NumTraits<Scalar>::dummy_precision(), int fillfactor = 10)
00115 : m_droptol(droptol),m_fillfactor(fillfactor),
00116 m_analysisIsOk(false),m_factorizationIsOk(false),m_isInitialized(false)
00117 {
00118 eigen_assert(fillfactor != 0);
00119 compute(mat);
00120 }
00121
00122 Index rows() const { return m_lu.rows(); }
00123
00124 Index cols() const { return m_lu.cols(); }
00125
00131 ComputationInfo info() const
00132 {
00133 eigen_assert(m_isInitialized && "IncompleteLUT is not initialized.");
00134 return m_info;
00135 }
00136
00137 template<typename MatrixType>
00138 void analyzePattern(const MatrixType& amat);
00139
00140 template<typename MatrixType>
00141 void factorize(const MatrixType& amat);
00142
00148 template<typename MatrixType>
00149 IncompleteLUT<Scalar>& compute(const MatrixType& amat)
00150 {
00151 analyzePattern(amat);
00152 factorize(amat);
00153 m_isInitialized = m_factorizationIsOk;
00154 return *this;
00155 }
00156
00157 void setDroptol(const RealScalar& droptol);
00158 void setFillfactor(int fillfactor);
00159
00160 template<typename Rhs, typename Dest>
00161 void _solve(const Rhs& b, Dest& x) const
00162 {
00163 x = m_Pinv * b;
00164 x = m_lu.template triangularView<UnitLower>().solve(x);
00165 x = m_lu.template triangularView<Upper>().solve(x);
00166 x = m_P * x;
00167 }
00168
00169 template<typename Rhs> inline const internal::solve_retval<IncompleteLUT, Rhs>
00170 solve(const MatrixBase<Rhs>& b) const
00171 {
00172 eigen_assert(m_isInitialized && "IncompleteLUT is not initialized.");
00173 eigen_assert(cols()==b.rows()
00174 && "IncompleteLUT::solve(): invalid number of rows of the right hand side matrix b");
00175 return internal::solve_retval<IncompleteLUT, Rhs>(*this, b.derived());
00176 }
00177
00178 protected:
00179
00181 struct keep_diag {
00182 inline bool operator() (const Index& row, const Index& col, const Scalar&) const
00183 {
00184 return row!=col;
00185 }
00186 };
00187
00188 protected:
00189
00190 FactorType m_lu;
00191 RealScalar m_droptol;
00192 int m_fillfactor;
00193 bool m_analysisIsOk;
00194 bool m_factorizationIsOk;
00195 bool m_isInitialized;
00196 ComputationInfo m_info;
00197 PermutationMatrix<Dynamic,Dynamic,Index> m_P;
00198 PermutationMatrix<Dynamic,Dynamic,Index> m_Pinv;
00199 };
00200
00205 template<typename Scalar>
00206 void IncompleteLUT<Scalar>::setDroptol(const RealScalar& droptol)
00207 {
00208 this->m_droptol = droptol;
00209 }
00210
00215 template<typename Scalar>
00216 void IncompleteLUT<Scalar>::setFillfactor(int fillfactor)
00217 {
00218 this->m_fillfactor = fillfactor;
00219 }
00220
00221 template <typename Scalar>
00222 template<typename _MatrixType>
00223 void IncompleteLUT<Scalar>::analyzePattern(const _MatrixType& amat)
00224 {
00225
00226 SparseMatrix<Scalar,ColMajor, Index> mat1 = amat;
00227 SparseMatrix<Scalar,ColMajor, Index> mat2 = amat.transpose();
00228
00229
00230
00231 SparseMatrix<Scalar,ColMajor, Index> AtA = mat2 + mat1;
00232 AtA.prune(keep_diag());
00233 internal::minimum_degree_ordering<Scalar, Index>(AtA, m_P);
00234
00235 m_Pinv = m_P.inverse();
00236
00237 m_analysisIsOk = true;
00238 }
00239
00240 template <typename Scalar>
00241 template<typename _MatrixType>
00242 void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat)
00243 {
00244 using std::sqrt;
00245 using std::swap;
00246 using std::abs;
00247
00248 eigen_assert((amat.rows() == amat.cols()) && "The factorization should be done on a square matrix");
00249 Index n = amat.cols();
00250 m_lu.resize(n,n);
00251
00252 Vector u(n) ;
00253 VectorXi ju(n);
00254 VectorXi jr(n);
00255
00256
00257 eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
00258 SparseMatrix<Scalar,RowMajor, Index> mat;
00259 mat = amat.twistedBy(m_Pinv);
00260
00261
00262 jr.fill(-1);
00263 ju.fill(0);
00264 u.fill(0);
00265
00266
00267 Index fill_in = static_cast<Index> (amat.nonZeros()*m_fillfactor)/n+1;
00268 if (fill_in > n) fill_in = n;
00269
00270
00271 Index nnzL = fill_in/2;
00272 Index nnzU = nnzL;
00273 m_lu.reserve(n * (nnzL + nnzU + 1));
00274
00275
00276 for (Index ii = 0; ii < n; ii++)
00277 {
00278
00279
00280 Index sizeu = 1;
00281 Index sizel = 0;
00282 ju(ii) = ii;
00283 u(ii) = 0;
00284 jr(ii) = ii;
00285 RealScalar rownorm = 0;
00286
00287 typename FactorType::InnerIterator j_it(mat, ii);
00288 for (; j_it; ++j_it)
00289 {
00290 Index k = j_it.index();
00291 if (k < ii)
00292 {
00293
00294 ju(sizel) = k;
00295 u(sizel) = j_it.value();
00296 jr(k) = sizel;
00297 ++sizel;
00298 }
00299 else if (k == ii)
00300 {
00301 u(ii) = j_it.value();
00302 }
00303 else
00304 {
00305
00306 Index jpos = ii + sizeu;
00307 ju(jpos) = k;
00308 u(jpos) = j_it.value();
00309 jr(k) = jpos;
00310 ++sizeu;
00311 }
00312 rownorm += numext::abs2(j_it.value());
00313 }
00314
00315
00316 if(rownorm==0)
00317 {
00318 m_info = NumericalIssue;
00319 return;
00320 }
00321
00322 rownorm = sqrt(rownorm);
00323
00324
00325 Index jj = 0;
00326 Index len = 0;
00327 while (jj < sizel)
00328 {
00329
00330
00331 Index k;
00332 Index minrow = ju.segment(jj,sizel-jj).minCoeff(&k);
00333 k += jj;
00334 if (minrow != ju(jj))
00335 {
00336
00337 Index j = ju(jj);
00338 swap(ju(jj), ju(k));
00339 jr(minrow) = jj; jr(j) = k;
00340 swap(u(jj), u(k));
00341 }
00342
00343 jr(minrow) = -1;
00344
00345
00346 typename FactorType::InnerIterator ki_it(m_lu, minrow);
00347 while (ki_it && ki_it.index() < minrow) ++ki_it;
00348 eigen_internal_assert(ki_it && ki_it.col()==minrow);
00349 Scalar fact = u(jj) / ki_it.value();
00350
00351
00352 if(abs(fact) <= m_droptol)
00353 {
00354 jj++;
00355 continue;
00356 }
00357
00358
00359 ++ki_it;
00360 for (; ki_it; ++ki_it)
00361 {
00362 Scalar prod = fact * ki_it.value();
00363 Index j = ki_it.index();
00364 Index jpos = jr(j);
00365 if (jpos == -1)
00366 {
00367 Index newpos;
00368 if (j >= ii)
00369 {
00370 newpos = ii + sizeu;
00371 sizeu++;
00372 eigen_internal_assert(sizeu<=n);
00373 }
00374 else
00375 {
00376 newpos = sizel;
00377 sizel++;
00378 eigen_internal_assert(sizel<=ii);
00379 }
00380 ju(newpos) = j;
00381 u(newpos) = -prod;
00382 jr(j) = newpos;
00383 }
00384 else
00385 u(jpos) -= prod;
00386 }
00387
00388 u(len) = fact;
00389 ju(len) = minrow;
00390 ++len;
00391
00392 jj++;
00393 }
00394
00395
00396 for(Index k = 0; k <sizeu; k++) jr(ju(ii+k)) = -1;
00397
00398
00399
00400
00401 sizel = len;
00402 len = (std::min)(sizel, nnzL);
00403 typename Vector::SegmentReturnType ul(u.segment(0, sizel));
00404 typename VectorXi::SegmentReturnType jul(ju.segment(0, sizel));
00405 internal::QuickSplit(ul, jul, len);
00406
00407
00408 m_lu.startVec(ii);
00409 for(Index k = 0; k < len; k++)
00410 m_lu.insertBackByOuterInnerUnordered(ii,ju(k)) = u(k);
00411
00412
00413
00414 if (u(ii) == Scalar(0))
00415 u(ii) = sqrt(m_droptol) * rownorm;
00416 m_lu.insertBackByOuterInnerUnordered(ii, ii) = u(ii);
00417
00418
00419
00420 len = 0;
00421 for(Index k = 1; k < sizeu; k++)
00422 {
00423 if(abs(u(ii+k)) > m_droptol * rownorm )
00424 {
00425 ++len;
00426 u(ii + len) = u(ii + k);
00427 ju(ii + len) = ju(ii + k);
00428 }
00429 }
00430 sizeu = len + 1;
00431 len = (std::min)(sizeu, nnzU);
00432 typename Vector::SegmentReturnType uu(u.segment(ii+1, sizeu-1));
00433 typename VectorXi::SegmentReturnType juu(ju.segment(ii+1, sizeu-1));
00434 internal::QuickSplit(uu, juu, len);
00435
00436
00437 for(Index k = ii + 1; k < ii + len; k++)
00438 m_lu.insertBackByOuterInnerUnordered(ii,ju(k)) = u(k);
00439 }
00440
00441 m_lu.finalize();
00442 m_lu.makeCompressed();
00443
00444 m_factorizationIsOk = true;
00445 m_info = Success;
00446 }
00447
00448 namespace internal {
00449
00450 template<typename _MatrixType, typename Rhs>
00451 struct solve_retval<IncompleteLUT<_MatrixType>, Rhs>
00452 : solve_retval_base<IncompleteLUT<_MatrixType>, Rhs>
00453 {
00454 typedef IncompleteLUT<_MatrixType> Dec;
00455 EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
00456
00457 template<typename Dest> void evalTo(Dest& dst) const
00458 {
00459 dec()._solve(rhs(),dst);
00460 }
00461 };
00462
00463 }
00464
00465 }
00466
00467 #endif // EIGEN_INCOMPLETE_LUT_H