File indexing completed on 2025-12-16 10:28:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef EIGEN_INCOMPLETE_LUT_H
0012 #define EIGEN_INCOMPLETE_LUT_H
0013
0014
0015 namespace RivetEigen {
0016
0017 namespace internal {
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 template <typename VectorV, typename VectorI>
0029 Index QuickSplit(VectorV &row, VectorI &ind, Index ncut)
0030 {
0031 typedef typename VectorV::RealScalar RealScalar;
0032 using std::swap;
0033 using std::abs;
0034 Index mid;
0035 Index n = row.size();
0036 Index first, last ;
0037
0038 ncut--;
0039 first = 0;
0040 last = n-1;
0041 if (ncut < first || ncut > last ) return 0;
0042
0043 do {
0044 mid = first;
0045 RealScalar abskey = abs(row(mid));
0046 for (Index j = first + 1; j <= last; j++) {
0047 if ( abs(row(j)) > abskey) {
0048 ++mid;
0049 swap(row(mid), row(j));
0050 swap(ind(mid), ind(j));
0051 }
0052 }
0053
0054 swap(row(mid), row(first));
0055 swap(ind(mid), ind(first));
0056
0057 if (mid > ncut) last = mid - 1;
0058 else if (mid < ncut ) first = mid + 1;
0059 } while (mid != ncut );
0060
0061 return 0;
0062 }
0063
0064 }
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 template <typename _Scalar, typename _StorageIndex = int>
0099 class IncompleteLUT : public SparseSolverBase<IncompleteLUT<_Scalar, _StorageIndex> >
0100 {
0101 protected:
0102 typedef SparseSolverBase<IncompleteLUT> Base;
0103 using Base::m_isInitialized;
0104 public:
0105 typedef _Scalar Scalar;
0106 typedef _StorageIndex StorageIndex;
0107 typedef typename NumTraits<Scalar>::Real RealScalar;
0108 typedef Matrix<Scalar,Dynamic,1> Vector;
0109 typedef Matrix<StorageIndex,Dynamic,1> VectorI;
0110 typedef SparseMatrix<Scalar,RowMajor,StorageIndex> FactorType;
0111
0112 enum {
0113 ColsAtCompileTime = Dynamic,
0114 MaxColsAtCompileTime = Dynamic
0115 };
0116
0117 public:
0118
0119 IncompleteLUT()
0120 : m_droptol(NumTraits<Scalar>::dummy_precision()), m_fillfactor(10),
0121 m_analysisIsOk(false), m_factorizationIsOk(false)
0122 {}
0123
0124 template<typename MatrixType>
0125 explicit IncompleteLUT(const MatrixType& mat, const RealScalar& droptol=NumTraits<Scalar>::dummy_precision(), int fillfactor = 10)
0126 : m_droptol(droptol),m_fillfactor(fillfactor),
0127 m_analysisIsOk(false),m_factorizationIsOk(false)
0128 {
0129 eigen_assert(fillfactor != 0);
0130 compute(mat);
0131 }
0132
0133 EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT { return m_lu.rows(); }
0134
0135 EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT { return m_lu.cols(); }
0136
0137
0138
0139
0140
0141
0142 ComputationInfo info() const
0143 {
0144 eigen_assert(m_isInitialized && "IncompleteLUT is not initialized.");
0145 return m_info;
0146 }
0147
0148 template<typename MatrixType>
0149 void analyzePattern(const MatrixType& amat);
0150
0151 template<typename MatrixType>
0152 void factorize(const MatrixType& amat);
0153
0154
0155
0156
0157
0158
0159 template<typename MatrixType>
0160 IncompleteLUT& compute(const MatrixType& amat)
0161 {
0162 analyzePattern(amat);
0163 factorize(amat);
0164 return *this;
0165 }
0166
0167 void setDroptol(const RealScalar& droptol);
0168 void setFillfactor(int fillfactor);
0169
0170 template<typename Rhs, typename Dest>
0171 void _solve_impl(const Rhs& b, Dest& x) const
0172 {
0173 x = m_Pinv * b;
0174 x = m_lu.template triangularView<UnitLower>().solve(x);
0175 x = m_lu.template triangularView<Upper>().solve(x);
0176 x = m_P * x;
0177 }
0178
0179 protected:
0180
0181
0182 struct keep_diag {
0183 inline bool operator() (const Index& row, const Index& col, const Scalar&) const
0184 {
0185 return row!=col;
0186 }
0187 };
0188
0189 protected:
0190
0191 FactorType m_lu;
0192 RealScalar m_droptol;
0193 int m_fillfactor;
0194 bool m_analysisIsOk;
0195 bool m_factorizationIsOk;
0196 ComputationInfo m_info;
0197 PermutationMatrix<Dynamic,Dynamic,StorageIndex> m_P;
0198 PermutationMatrix<Dynamic,Dynamic,StorageIndex> m_Pinv;
0199 };
0200
0201
0202
0203
0204
0205 template<typename Scalar, typename StorageIndex>
0206 void IncompleteLUT<Scalar,StorageIndex>::setDroptol(const RealScalar& droptol)
0207 {
0208 this->m_droptol = droptol;
0209 }
0210
0211
0212
0213
0214
0215 template<typename Scalar, typename StorageIndex>
0216 void IncompleteLUT<Scalar,StorageIndex>::setFillfactor(int fillfactor)
0217 {
0218 this->m_fillfactor = fillfactor;
0219 }
0220
0221 template <typename Scalar, typename StorageIndex>
0222 template<typename _MatrixType>
0223 void IncompleteLUT<Scalar,StorageIndex>::analyzePattern(const _MatrixType& amat)
0224 {
0225
0226
0227
0228
0229 SparseMatrix<Scalar,ColMajor, StorageIndex> mat1 = amat;
0230 SparseMatrix<Scalar,ColMajor, StorageIndex> mat2 = amat.transpose();
0231
0232
0233 SparseMatrix<Scalar,ColMajor, StorageIndex> AtA = mat2 + mat1;
0234 AMDOrdering<StorageIndex> ordering;
0235 ordering(AtA,m_P);
0236 m_Pinv = m_P.inverse();
0237 m_analysisIsOk = true;
0238 m_factorizationIsOk = false;
0239 m_isInitialized = true;
0240 }
0241
0242 template <typename Scalar, typename StorageIndex>
0243 template<typename _MatrixType>
0244 void IncompleteLUT<Scalar,StorageIndex>::factorize(const _MatrixType& amat)
0245 {
0246 using std::sqrt;
0247 using std::swap;
0248 using std::abs;
0249 using internal::convert_index;
0250
0251 eigen_assert((amat.rows() == amat.cols()) && "The factorization should be done on a square matrix");
0252 Index n = amat.cols();
0253 m_lu.resize(n,n);
0254
0255 Vector u(n) ;
0256 VectorI ju(n);
0257 VectorI jr(n);
0258
0259
0260 eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
0261 SparseMatrix<Scalar,RowMajor, StorageIndex> mat;
0262 mat = amat.twistedBy(m_Pinv);
0263
0264
0265 jr.fill(-1);
0266 ju.fill(0);
0267 u.fill(0);
0268
0269
0270 Index fill_in = (amat.nonZeros()*m_fillfactor)/n + 1;
0271 if (fill_in > n) fill_in = n;
0272
0273
0274 Index nnzL = fill_in/2;
0275 Index nnzU = nnzL;
0276 m_lu.reserve(n * (nnzL + nnzU + 1));
0277
0278
0279 for (Index ii = 0; ii < n; ii++)
0280 {
0281
0282
0283 Index sizeu = 1;
0284 Index sizel = 0;
0285 ju(ii) = convert_index<StorageIndex>(ii);
0286 u(ii) = 0;
0287 jr(ii) = convert_index<StorageIndex>(ii);
0288 RealScalar rownorm = 0;
0289
0290 typename FactorType::InnerIterator j_it(mat, ii);
0291 for (; j_it; ++j_it)
0292 {
0293 Index k = j_it.index();
0294 if (k < ii)
0295 {
0296
0297 ju(sizel) = convert_index<StorageIndex>(k);
0298 u(sizel) = j_it.value();
0299 jr(k) = convert_index<StorageIndex>(sizel);
0300 ++sizel;
0301 }
0302 else if (k == ii)
0303 {
0304 u(ii) = j_it.value();
0305 }
0306 else
0307 {
0308
0309 Index jpos = ii + sizeu;
0310 ju(jpos) = convert_index<StorageIndex>(k);
0311 u(jpos) = j_it.value();
0312 jr(k) = convert_index<StorageIndex>(jpos);
0313 ++sizeu;
0314 }
0315 rownorm += numext::abs2(j_it.value());
0316 }
0317
0318
0319 if(rownorm==0)
0320 {
0321 m_info = NumericalIssue;
0322 return;
0323 }
0324
0325 rownorm = sqrt(rownorm);
0326
0327
0328 Index jj = 0;
0329 Index len = 0;
0330 while (jj < sizel)
0331 {
0332
0333
0334 Index k;
0335 Index minrow = ju.segment(jj,sizel-jj).minCoeff(&k);
0336 k += jj;
0337 if (minrow != ju(jj))
0338 {
0339
0340 Index j = ju(jj);
0341 swap(ju(jj), ju(k));
0342 jr(minrow) = convert_index<StorageIndex>(jj);
0343 jr(j) = convert_index<StorageIndex>(k);
0344 swap(u(jj), u(k));
0345 }
0346
0347 jr(minrow) = -1;
0348
0349
0350 typename FactorType::InnerIterator ki_it(m_lu, minrow);
0351 while (ki_it && ki_it.index() < minrow) ++ki_it;
0352 eigen_internal_assert(ki_it && ki_it.col()==minrow);
0353 Scalar fact = u(jj) / ki_it.value();
0354
0355
0356 if(abs(fact) <= m_droptol)
0357 {
0358 jj++;
0359 continue;
0360 }
0361
0362
0363 ++ki_it;
0364 for (; ki_it; ++ki_it)
0365 {
0366 Scalar prod = fact * ki_it.value();
0367 Index j = ki_it.index();
0368 Index jpos = jr(j);
0369 if (jpos == -1)
0370 {
0371 Index newpos;
0372 if (j >= ii)
0373 {
0374 newpos = ii + sizeu;
0375 sizeu++;
0376 eigen_internal_assert(sizeu<=n);
0377 }
0378 else
0379 {
0380 newpos = sizel;
0381 sizel++;
0382 eigen_internal_assert(sizel<=ii);
0383 }
0384 ju(newpos) = convert_index<StorageIndex>(j);
0385 u(newpos) = -prod;
0386 jr(j) = convert_index<StorageIndex>(newpos);
0387 }
0388 else
0389 u(jpos) -= prod;
0390 }
0391
0392 u(len) = fact;
0393 ju(len) = convert_index<StorageIndex>(minrow);
0394 ++len;
0395
0396 jj++;
0397 }
0398
0399
0400 for(Index k = 0; k <sizeu; k++) jr(ju(ii+k)) = -1;
0401
0402
0403
0404
0405 sizel = len;
0406 len = (std::min)(sizel, nnzL);
0407 typename Vector::SegmentReturnType ul(u.segment(0, sizel));
0408 typename VectorI::SegmentReturnType jul(ju.segment(0, sizel));
0409 internal::QuickSplit(ul, jul, len);
0410
0411
0412 m_lu.startVec(ii);
0413 for(Index k = 0; k < len; k++)
0414 m_lu.insertBackByOuterInnerUnordered(ii,ju(k)) = u(k);
0415
0416
0417
0418 if (u(ii) == Scalar(0))
0419 u(ii) = sqrt(m_droptol) * rownorm;
0420 m_lu.insertBackByOuterInnerUnordered(ii, ii) = u(ii);
0421
0422
0423
0424 len = 0;
0425 for(Index k = 1; k < sizeu; k++)
0426 {
0427 if(abs(u(ii+k)) > m_droptol * rownorm )
0428 {
0429 ++len;
0430 u(ii + len) = u(ii + k);
0431 ju(ii + len) = ju(ii + k);
0432 }
0433 }
0434 sizeu = len + 1;
0435 len = (std::min)(sizeu, nnzU);
0436 typename Vector::SegmentReturnType uu(u.segment(ii+1, sizeu-1));
0437 typename VectorI::SegmentReturnType juu(ju.segment(ii+1, sizeu-1));
0438 internal::QuickSplit(uu, juu, len);
0439
0440
0441 for(Index k = ii + 1; k < ii + len; k++)
0442 m_lu.insertBackByOuterInnerUnordered(ii,ju(k)) = u(k);
0443 }
0444 m_lu.finalize();
0445 m_lu.makeCompressed();
0446
0447 m_factorizationIsOk = true;
0448 m_info = Success;
0449 }
0450
0451 }
0452
0453 #endif