12#ifndef EIGEN_INCOMPLETE_CHOlESKY_H
13#define EIGEN_INCOMPLETE_CHOlESKY_H
19#include "./InternalHeaderCheck.h"
51template <
typename Scalar,
int UpLo_ = Lower,
typename OrderingType_ = AMDOrdering<
int> >
55 using Base::m_isInitialized;
58 using RealScalar =
typename NumTraits<Scalar>::Real;
59 using OrderingType = OrderingType_;
60 using PermutationType =
typename OrderingType::PermutationType;
61 using StorageIndex =
typename PermutationType::StorageIndex;
66 using VectorList = std::vector<std::list<StorageIndex>>;
67 enum { UpLo = UpLo_ };
68 enum { ColsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic };
77 IncompleteCholesky() : m_initialShift(1e-3), m_analysisIsOk(false), m_factorizationIsOk(false) {}
81 template <
typename MatrixType>
83 : m_initialShift(1e-3), m_analysisIsOk(false), m_factorizationIsOk(false) {
88 constexpr Index
rows() const noexcept {
return m_L.rows(); }
91 constexpr Index
cols() const noexcept {
return m_L.cols(); }
102 eigen_assert(m_isInitialized &&
"IncompleteCholesky is not initialized.");
112 template <
typename MatrixType>
115 PermutationType pinv;
116 ord(mat.template selfadjointView<UpLo>(), pinv);
118 m_perm = pinv.inverse();
121 m_L.resize(mat.rows(), mat.cols());
122 m_analysisIsOk =
true;
123 m_isInitialized =
true;
134 template <
typename MatrixType>
143 template <
typename MatrixType>
150 template <
typename Rhs,
typename Dest>
151 void _solve_impl(
const Rhs& b, Dest& x)
const {
152 eigen_assert(m_factorizationIsOk &&
"factorize() should be called first");
153 if (m_perm.rows() == b.rows())
157 x = m_scale.asDiagonal() * x;
158 x = m_L.template triangularView<Lower>().solve(x);
159 x = m_L.adjoint().template triangularView<Upper>().solve(x);
160 x = m_scale.asDiagonal() * x;
161 if (m_perm.rows() == b.rows()) x = m_perm.inverse() * x;
166 eigen_assert(m_factorizationIsOk &&
"factorize() should be called first");
172 eigen_assert(m_factorizationIsOk &&
"factorize() should be called first");
178 eigen_assert(m_analysisIsOk &&
"analyzePattern() should be called first");
183 RealScalar
shift()
const {
return m_shift; }
188 RealScalar m_initialShift;
190 bool m_factorizationIsOk;
192 PermutationType m_perm;
197 const Index& jk, VectorIx& firstElt, VectorList& listCol);
204template <
typename Scalar,
int UpLo_,
typename OrderingType>
205template <
typename MatrixType_>
208 eigen_assert(m_analysisIsOk &&
"analyzePattern() should be called first");
214 if (m_perm.rows() == mat.rows())
217 FactorType tmp(mat.rows(), mat.cols());
218 tmp = mat.template selfadjointView<UpLo_>().twistedBy(m_perm);
219 m_L.template selfadjointView<Lower>() = tmp.template selfadjointView<Lower>();
221 m_L.template selfadjointView<Lower>() = mat.template selfadjointView<UpLo_>();
228 bool modified =
false;
229 for (Index i = 0; i < mat.cols(); ++i) {
230 bool inserted =
false;
231 m_L.findOrInsertCoeff(i, i, &inserted);
236 if (modified) m_L.makeCompressed();
238 Index n = m_L.cols();
239 Index nnz = m_L.nonZeros();
243 VectorIx firstElt(n - 1);
244 VectorList listCol(n);
245 VectorSx col_vals(n);
246 VectorIx col_irow(n);
247 VectorIx col_pattern(n);
248 col_pattern.fill(-1);
249 StorageIndex col_nnz;
254 for (Index j = 0; j < n; j++)
255 for (Index k = colPtr[j]; k < colPtr[j + 1]; k++) {
256 m_scale(j) += numext::abs2(vals(k));
257 if (rowIdx[k] != j) m_scale(rowIdx[k]) += numext::abs2(vals(k));
260 m_scale = m_scale.cwiseSqrt().cwiseSqrt();
262 for (Index j = 0; j < n; ++j)
263 if (m_scale(j) > (std::numeric_limits<RealScalar>::min)())
264 m_scale(j) = RealScalar(1) / m_scale(j);
271 RealScalar mindiag = NumTraits<RealScalar>::highest();
272 for (Index j = 0; j < n; j++) {
273 for (Index k = colPtr[j]; k < colPtr[j + 1]; k++) vals[k] *= (m_scale(j) * m_scale(rowIdx[k]));
274 eigen_internal_assert(rowIdx[colPtr[j]] == j &&
275 "IncompleteCholesky: only the lower triangular part must be stored");
276 mindiag = numext::mini(numext::real(vals[colPtr[j]]), mindiag);
279 FactorType L_save = m_L;
281 m_shift = RealScalar(0);
282 if (mindiag <= RealScalar(0.)) m_shift = m_initialShift - mindiag;
290 for (Index j = 0; j < n; j++) vals[colPtr[j]] += m_shift;
297 Scalar diag = vals[colPtr[j]];
299 for (Index i = colPtr[j] + 1; i < colPtr[j + 1]; i++) {
300 StorageIndex l = rowIdx[i];
301 col_vals(col_nnz) = vals[i];
302 col_irow(col_nnz) = l;
303 col_pattern(l) = col_nnz;
307 typename std::list<StorageIndex>::iterator k;
309 for (k = listCol[j].begin(); k != listCol[j].end(); k++) {
310 Index jk = firstElt(*k);
311 eigen_internal_assert(rowIdx[jk] == j);
312 Scalar v_j_jk = numext::conj(vals[jk]);
315 for (Index i = jk; i < colPtr[*k + 1]; i++) {
316 StorageIndex l = rowIdx[i];
317 if (col_pattern[l] < 0) {
318 col_vals(col_nnz) = vals[i] * v_j_jk;
319 col_irow[col_nnz] = l;
320 col_pattern(l) = col_nnz;
323 col_vals(col_pattern[l]) -= vals[i] * v_j_jk;
325 updateList(colPtr, rowIdx, vals, *k, jk, firstElt, listCol);
330 if (numext::real(diag) <= 0) {
331 if (++iter >= 10)
return;
334 m_shift = numext::maxi(m_initialShift, RealScalar(2) * m_shift);
339 col_pattern.fill(-1);
340 for (Index i = 0; i < n; ++i) listCol[i].clear();
345 RealScalar rdiag = sqrt(numext::real(diag));
346 vals[colPtr[j]] = rdiag;
347 for (Index k = 0; k < col_nnz; ++k) {
348 Index i = col_irow[k];
350 col_vals(k) /= rdiag;
352 vals[colPtr[i]] -= numext::abs2(col_vals(k));
356 Index p = colPtr[j + 1] - colPtr[j] - 1;
359 internal::QuickSplit(cvals, cirow, p);
362 for (Index i = colPtr[j] + 1; i < colPtr[j + 1]; i++) {
363 vals[i] = col_vals(cpt);
364 rowIdx[i] = col_irow(cpt);
366 col_pattern(col_irow(cpt)) = -1;
370 Index jk = colPtr(j) + 1;
371 updateList(colPtr, rowIdx, vals, j, jk, firstElt, listCol);
375 m_factorizationIsOk =
true;
381template <
typename Scalar,
int UpLo_,
typename OrderingType>
382inline void IncompleteCholesky<Scalar, UpLo_, OrderingType>::updateList(
Ref<const VectorIx> colPtr,
384 const Index& col,
const Index& jk,
385 VectorIx& firstElt, VectorList& listCol) {
386 if (jk < colPtr(col + 1)) {
387 Index p = colPtr(col + 1) - jk;
389 rowIdx.segment(jk, p).minCoeff(&minpos);
391 if (rowIdx(minpos) != rowIdx(jk)) {
393 std::swap(rowIdx(jk), rowIdx(minpos));
394 std::swap(vals(jk), vals(minpos));
396 firstElt(col) = internal::convert_index<StorageIndex, Index>(jk);
397 listCol[rowIdx(jk)].push_back(internal::convert_index<StorageIndex, Index>(col));
ComputationInfo info() const
Reports whether previous computation was successful.
Definition IncompleteCholesky.h:101
IncompleteCholesky(const MatrixType &matrix)
Definition IncompleteCholesky.h:82
const VectorRx & scalingS() const
Definition IncompleteCholesky.h:171
const FactorType & matrixL() const
Definition IncompleteCholesky.h:165
const PermutationType & permutationP() const
Definition IncompleteCholesky.h:177
constexpr Index rows() const noexcept
Definition IncompleteCholesky.h:88
void factorize(const MatrixType &mat)
Performs the numerical factorization of the input matrix mat.
IncompleteCholesky()
Definition IncompleteCholesky.h:77
void compute(const MatrixType &mat)
Definition IncompleteCholesky.h:144
void analyzePattern(const MatrixType &mat)
Computes the fill reducing permutation vector using the sparsity pattern of mat.
Definition IncompleteCholesky.h:113
constexpr Index cols() const noexcept
Definition IncompleteCholesky.h:91
RealScalar shift() const
Definition IncompleteCholesky.h:183
void setInitialShift(RealScalar shift)
Set the initial shift parameter .
Definition IncompleteCholesky.h:108
A matrix or vector expression mapping an existing array of data.
Definition Map.h:97
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188
A matrix or vector expression mapping an existing expression.
Definition Ref.h:262
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