12#ifndef EIGEN_INCOMPLETE_LUT_H
13#define EIGEN_INCOMPLETE_LUT_H
16#include "./InternalHeaderCheck.h"
31template <
typename VectorV,
typename VectorI>
32Index QuickSplit(VectorV& row, VectorI& ind, Index ncut) {
33 using RealScalar =
typename VectorV::RealScalar;
43 if (ncut < first || ncut > last)
return 0;
47 RealScalar abskey = abs(row(mid));
48 for (Index j = first + 1; j <= last; j++) {
49 if (abs(row(j)) > abskey) {
51 swap(row(mid), row(j));
52 swap(ind(mid), ind(j));
56 swap(row(mid), row(first));
57 swap(ind(mid), ind(first));
63 }
while (mid != ncut);
102template <
typename Scalar_,
typename StorageIndex_ =
int>
106 using Base::m_isInitialized;
109 using Scalar = Scalar_;
110 using StorageIndex = StorageIndex_;
111 using RealScalar =
typename NumTraits<Scalar>::Real;
116 enum { ColsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic };
120 : m_droptol(NumTraits<Scalar>::dummy_precision()),
122 m_analysisIsOk(
false),
123 m_factorizationIsOk(
false) {}
125 template <
typename MatrixType>
126 explicit IncompleteLUT(
const MatrixType& mat,
const RealScalar& droptol = NumTraits<Scalar>::dummy_precision(),
128 : m_droptol(droptol), m_fillfactor(fillfactor), m_analysisIsOk(
false), m_factorizationIsOk(
false) {
129 eigen_assert(fillfactor != 0);
134 const FactorType
matrixL()
const;
137 const FactorType
matrixU()
const;
139 constexpr Index rows()
const noexcept {
return m_lu.rows(); }
141 constexpr Index cols()
const noexcept {
return m_lu.cols(); }
153 eigen_assert(m_isInitialized &&
"IncompleteLUT is not initialized.");
157 template <
typename MatrixType>
158 void analyzePattern(
const MatrixType& amat);
160 template <
typename MatrixType>
161 void factorize(
const MatrixType& amat);
172 template <
typename MatrixType>
173 IncompleteLUT&
compute(
const MatrixType& amat) {
174 analyzePattern(amat);
182 template <
typename Rhs,
typename Dest>
183 void _solve_impl(
const Rhs& b, Dest& x)
const {
185 x = m_lu.template triangularView<UnitLower>().solve(x);
186 x = m_lu.template triangularView<Upper>().solve(x);
193 inline bool operator()(
const Index& row,
const Index& col,
const Scalar&)
const {
return row != col; }
196 template <
typename MatrixType>
197 Index computeRowMatching(
const MatrixType& amat);
201 RealScalar m_droptol;
204 bool m_factorizationIsOk;
216template <
typename Scalar,
typename StorageIndex>
218 this->m_droptol = droptol;
225template <
typename Scalar,
typename StorageIndex>
227 this->m_fillfactor = fillfactor;
235template <
typename Scalar,
typename StorageIndex>
237 eigen_assert(m_factorizationIsOk &&
"factorize() should be called first");
238 return m_lu.template triangularView<UnitLower>();
246template <
typename Scalar,
typename StorageIndex>
248 eigen_assert(m_factorizationIsOk &&
"Factorization must be computed first.");
249 return m_lu.template triangularView<Upper>();
257template <
typename Scalar,
typename StorageIndex>
258template <
typename MatrixType_>
259Index IncompleteLUT<Scalar, StorageIndex>::computeRowMatching(
const MatrixType_& amat) {
260 using internal::convert_index;
261 const Index n = amat.rows();
268 internal::SparsityPatternRef<StorageIndex> pat = internal::make_col_major_pattern_ref(amat, outer_buf, inner_buf);
269 const StorageIndex* outer = pat.outer;
270 const StorageIndex* inner = pat.inner;
272 const StorageIndex kUnmatched = StorageIndex(-1);
274 std::vector<StorageIndex> match_row(n, kUnmatched);
275 std::vector<StorageIndex> match_col(n, kUnmatched);
281 for (Index j = 0; j < n; ++j) {
282 const Index col_end = outer[j] + pat.nonZeros(j);
283 for (Index k = outer[j]; k < col_end; ++k) {
284 if (Index(inner[k]) == j) {
285 match_row[j] = convert_index<StorageIndex>(j);
286 match_col[j] = convert_index<StorageIndex>(j);
292 for (Index j = 0; j < n; ++j) {
293 if (match_row[j] != kUnmatched)
continue;
294 const Index col_end = outer[j] + pat.nonZeros(j);
295 for (Index k = outer[j]; k < col_end; ++k) {
297 if (match_col[i] == kUnmatched) {
298 match_row[j] = convert_index<StorageIndex>(i);
299 match_col[i] = convert_index<StorageIndex>(j);
305 std::vector<StorageIndex> visited(n, kUnmatched);
308 std::vector<Index> stack_col;
309 std::vector<Index> stack_pos;
310 std::vector<Index> stack_chosen_row;
311 stack_col.reserve(n);
312 stack_pos.reserve(n);
313 stack_chosen_row.reserve(n);
315 for (Index start = 0; start < n; ++start) {
316 if (match_row[start] != kUnmatched)
continue;
317 StorageIndex epoch = convert_index<StorageIndex>(start);
320 stack_chosen_row.clear();
321 stack_col.push_back(start);
322 stack_pos.push_back(outer[start]);
323 stack_chosen_row.push_back(-1);
325 while (!stack_col.empty()) {
326 Index j = stack_col.back();
327 Index pos = stack_pos.back();
328 Index col_end = outer[j] + pat.nonZeros(j);
329 bool advanced =
false;
331 while (pos < col_end) {
332 Index i = inner[pos];
334 if (visited[i] == epoch)
continue;
337 if (match_col[i] == kUnmatched) {
339 stack_chosen_row.back() = i;
340 stack_pos.back() = pos;
341 for (
size_t k = 0; k < stack_col.size(); ++k) {
342 Index col = stack_col[k];
343 Index row = stack_chosen_row[k];
344 match_row[col] = convert_index<StorageIndex>(row);
345 match_col[row] = convert_index<StorageIndex>(col);
351 stack_chosen_row.back() = i;
352 stack_pos.back() = pos;
353 Index next_col = match_col[i];
354 stack_col.push_back(next_col);
355 stack_pos.push_back(outer[next_col]);
356 stack_chosen_row.push_back(-1);
362 if (!advanced && !stack_col.empty()) {
363 stack_col.pop_back();
364 stack_pos.pop_back();
365 stack_chosen_row.pop_back();
373 std::vector<bool> col_used(n,
false), row_used(n,
false);
375 for (Index j = 0; j < n; ++j) {
376 if (match_row[j] != kUnmatched) {
377 m_Pr.indices()(match_row[j]) = convert_index<StorageIndex>(j);
379 row_used[match_row[j]] =
true;
384 for (Index i = 0; i < n; ++i) {
385 if (row_used[i])
continue;
386 while (next_col < n && col_used[next_col]) ++next_col;
387 m_Pr.indices()(i) = convert_index<StorageIndex>(next_col);
393template <
typename Scalar,
typename StorageIndex>
394template <
typename MatrixType_>
395void IncompleteLUT<Scalar, StorageIndex>::analyzePattern(
const MatrixType_& amat) {
396 eigen_assert((amat.rows() == amat.cols()) &&
"The factorization should be done on a square matrix");
401 computeRowMatching(amat);
414 internal::SparsityPatternRef<StorageIndex> pat = internal::make_col_major_pattern_ref(amat, outer_buf, inner_buf);
415 internal::materialize_col_major_pattern(pat, m_Pr.indices().data(), permuted_pattern);
418 ordering(permuted_pattern, m_P);
419 m_Pinv = m_P.inverse();
422 m_PinvPr = m_Pinv * m_Pr;
423 m_analysisIsOk =
true;
424 m_factorizationIsOk =
false;
425 m_isInitialized =
true;
428template <
typename Scalar,
typename StorageIndex>
429template <
typename MatrixType_>
430void IncompleteLUT<Scalar, StorageIndex>::factorize(
const MatrixType_& amat) {
431 using internal::convert_index;
436 eigen_assert((amat.rows() == amat.cols()) &&
"The factorization should be done on a square matrix");
437 Index n = amat.cols();
446 eigen_assert(m_analysisIsOk &&
"You must first call analyzePattern()");
449 mat = row_permuted_mat.
twistedBy(m_Pinv);
450 Index zero_pivots = 0;
458 Index fill_in = (amat.nonZeros() * m_fillfactor) / n + 1;
459 if (fill_in > n) fill_in = n;
462 Index nnzL = fill_in / 2;
464 m_lu.reserve(n * (nnzL + nnzU + 1));
467 for (Index ii = 0; ii < n; ii++) {
472 ju(ii) = convert_index<StorageIndex>(ii);
474 jr(ii) = convert_index<StorageIndex>(ii);
475 RealScalar rownorm = 0;
477 typename FactorType::InnerIterator j_it(mat, ii);
478 for (; j_it; ++j_it) {
479 Index k = j_it.index();
482 ju(sizel) = convert_index<StorageIndex>(k);
483 u(sizel) = j_it.value();
484 jr(k) = convert_index<StorageIndex>(sizel);
486 }
else if (k == ii) {
487 u(ii) = j_it.value();
490 Index jpos = ii + sizeu;
491 ju(jpos) = convert_index<StorageIndex>(k);
492 u(jpos) = j_it.value();
493 jr(k) = convert_index<StorageIndex>(jpos);
496 rownorm += numext::abs2(j_it.value());
505 rownorm = sqrt(rownorm);
514 Index minrow = ju.segment(jj, sizel - jj).minCoeff(&k);
516 if (minrow != ju(jj)) {
520 jr(minrow) = convert_index<StorageIndex>(jj);
521 jr(j) = convert_index<StorageIndex>(k);
528 typename FactorType::InnerIterator ki_it(m_lu, minrow);
529 while (ki_it && ki_it.index() < minrow) ++ki_it;
530 eigen_internal_assert(ki_it && ki_it.col() == minrow);
531 Scalar fact = u(jj) / ki_it.value();
534 if (abs(fact) <= m_droptol) {
541 for (; ki_it; ++ki_it) {
542 Scalar prod = fact * ki_it.value();
543 Index j = ki_it.index();
552 eigen_internal_assert(sizeu <= n);
557 eigen_internal_assert(sizel <= ii);
559 ju(newpos) = convert_index<StorageIndex>(j);
561 jr(j) = convert_index<StorageIndex>(newpos);
567 ju(len) = convert_index<StorageIndex>(minrow);
574 for (Index k = 0; k < sizeu; k++) jr(ju(ii + k)) = -1;
580 len = (std::min)(sizel, nnzL);
581 typename Vector::SegmentReturnType ul(u.segment(0, sizel));
582 typename VectorI::SegmentReturnType jul(ju.segment(0, sizel));
583 internal::QuickSplit(ul, jul, len);
587 for (Index k = 0; k < len; k++) m_lu.insertBackByOuterInnerUnordered(ii, ju(k)) = u(k);
591 if (u(ii) == Scalar(0)) {
592 u(ii) = sqrt(m_droptol) * rownorm;
595 m_lu.insertBackByOuterInnerUnordered(ii, ii) = u(ii);
600 for (Index k = 1; k < sizeu; k++) {
601 if (abs(u(ii + k)) > m_droptol * rownorm) {
603 u(ii + len) = u(ii + k);
604 ju(ii + len) = ju(ii + k);
608 len = (std::min)(sizeu, nnzU);
609 typename Vector::SegmentReturnType uu(u.segment(ii + 1, sizeu - 1));
610 typename VectorI::SegmentReturnType juu(ju.segment(ii + 1, sizeu - 1));
611 internal::QuickSplit(uu, juu, len);
614 for (Index k = ii + 1; k < ii + len; k++) m_lu.insertBackByOuterInnerUnordered(ii, ju(k)) = u(k);
617 m_lu.makeCompressed();
619 m_factorizationIsOk =
true;
void setFillfactor(int fillfactor)
Definition IncompleteLUT.h:226
IncompleteLUT & compute(const MatrixType &amat)
Definition IncompleteLUT.h:173
const FactorType matrixL() const
Extraction Method for L-Factor.
Definition IncompleteLUT.h:236
const FactorType matrixU() const
Extraction Method for U-Factor.
Definition IncompleteLUT.h:247
void setDroptol(const RealScalar &droptol)
Definition IncompleteLUT.h:217
ComputationInfo info() const
Reports whether previous computation was successful.
Definition IncompleteLUT.h:152
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188
Permutation matrix.
Definition PermutationMatrix.h:346
SparseSymmetricPermutationProduct< Derived, Upper|Lower > twistedBy(const PermutationMatrix< Dynamic, Dynamic, StorageIndex > &perm) const
Definition SparseMatrixBase.h:375
A versatile sparse matrix representation.
Definition SparseMatrix.h:122
SparseSolverBase()=default
ComputationInfo
Definition Constants.h:455
@ NumericalIssue
Definition Constants.h:459
@ Success
Definition Constants.h:457
Matrix< Type, Size, 1 > Vector
Size×1 vector of type Type.
Definition Matrix.h:532
Definition IncompleteLUT.h:192