20#ifndef EIGEN_SIMPLICIAL_CHOLESKY_IMPL_H
21#define EIGEN_SIMPLICIAL_CHOLESKY_IMPL_H
24#include "./InternalHeaderCheck.h"
30template <
typename Scalar,
typename StorageIndex>
31struct simpl_chol_helper {
32 using CholMatrixType = SparseMatrix<Scalar, ColMajor, StorageIndex>;
33 using InnerIterator =
typename CholMatrixType::InnerIterator;
34 using VectorI = Matrix<StorageIndex, Dynamic, 1>;
35 static constexpr StorageIndex kEmpty = -1;
42 const Index m_maxSize;
43 Stack(StorageIndex* data, StorageIndex size, StorageIndex maxSize)
44 : m_data(data), m_size(size), m_maxSize(maxSize) {
45 eigen_assert(size >= 0);
46 eigen_assert(maxSize >= size);
49 Stack(StorageIndex* data, StorageIndex size, StorageIndex ) : m_data(data), m_size(size) {}
51 bool empty()
const {
return m_size == 0; }
52 Index size()
const {
return m_size; }
53 StorageIndex back()
const {
54 eigen_assert(m_size > 0);
55 return m_data[m_size - 1];
57 void push(
const StorageIndex& value) {
59 eigen_assert(m_size < m_maxSize);
61 m_data[m_size] = value;
65 eigen_assert(m_size > 0);
73 DisjointSet(StorageIndex* set, StorageIndex size) : m_set(set) { std::iota(set, set + size, 0); }
75 StorageIndex find(StorageIndex u)
const {
76 eigen_assert(u != kEmpty);
77 while (m_set[u] != u) {
84 void compress(StorageIndex u, StorageIndex v) {
85 eigen_assert(u != kEmpty);
86 eigen_assert(v != kEmpty);
87 while (m_set[u] != v) {
88 StorageIndex next = m_set[u];
100 static void calc_hadj_outer(
const StorageIndex size,
const CholMatrixType& ap, StorageIndex* outerIndex) {
101 for (StorageIndex j = 1; j < size; j++) {
102 for (InnerIterator it(ap, j); it; ++it) {
103 StorageIndex i = it.index();
104 if (i < j) outerIndex[i + 1]++;
107 std::partial_sum(outerIndex, outerIndex + size + 1, outerIndex);
111 static void calc_hadj_inner(
const StorageIndex size,
const CholMatrixType& ap,
const StorageIndex* outerIndex,
112 StorageIndex* innerIndex, StorageIndex* tmp) {
113 std::fill_n(tmp, size, 0);
115 for (StorageIndex j = 1; j < size; j++) {
116 for (InnerIterator it(ap, j); it; ++it) {
117 StorageIndex i = it.index();
119 StorageIndex b = outerIndex[i] + tmp[i];
135 static void calc_etree(
const StorageIndex size,
const CholMatrixType& ap, StorageIndex* parent, StorageIndex* tmp) {
136 std::fill_n(parent, size, kEmpty);
138 DisjointSet ancestor(tmp, size);
140 for (StorageIndex j = 1; j < size; j++) {
141 for (InnerIterator it(ap, j); it; ++it) {
142 StorageIndex i = it.index();
144 StorageIndex r = ancestor.find(i);
145 if (r != j) parent[r] = j;
146 ancestor.compress(i, j);
153 static void calc_lineage(
const StorageIndex size,
const StorageIndex* parent, StorageIndex* firstChild,
154 StorageIndex* firstSibling) {
155 std::fill_n(firstChild, size, kEmpty);
156 std::fill_n(firstSibling, size, kEmpty);
158 for (StorageIndex j = 0; j < size; j++) {
159 StorageIndex p = parent[j];
160 if (p == kEmpty)
continue;
161 StorageIndex c = firstChild[p];
165 while (firstSibling[c] != kEmpty) c = firstSibling[c];
172 static void calc_post(
const StorageIndex size,
const StorageIndex* parent, StorageIndex* firstChild,
173 const StorageIndex* firstSibling, StorageIndex* post, StorageIndex* dfs) {
174 Stack post_stack(post, 0, size);
175 for (StorageIndex j = 0; j < size; j++) {
176 if (parent[j] != kEmpty)
continue;
178 Stack dfs_stack(dfs, 0, size);
180 while (!dfs_stack.empty()) {
181 StorageIndex i = dfs_stack.back();
182 StorageIndex c = firstChild[i];
189 firstChild[i] = firstSibling[c];
193 eigen_assert(post_stack.size() == size);
194 eigen_assert(std::all_of(firstChild, firstChild + size, [](StorageIndex a) {
return a == kEmpty; }));
203 static void calc_colcount(
const StorageIndex size,
const StorageIndex* hadjOuter,
const StorageIndex* hadjInner,
204 const StorageIndex* parent, StorageIndex* prevLeaf, StorageIndex* tmp,
205 const StorageIndex* post, StorageIndex* nonZerosPerCol,
bool doLDLT) {
207 std::fill_n(nonZerosPerCol, size, 1);
208 for (StorageIndex j = 0; j < size; j++) {
209 StorageIndex p = parent[j];
211 if (p != kEmpty) nonZerosPerCol[p] = 0;
214 DisjointSet parentSet(tmp, size);
216 eigen_assert(std::all_of(prevLeaf, prevLeaf + size, [](StorageIndex a) {
return a == kEmpty; }));
218 for (StorageIndex j_ = 0; j_ < size; j_++) {
219 StorageIndex j = post[j_];
220 nonZerosPerCol[j] += hadjOuter[j + 1] - hadjOuter[j];
221 for (StorageIndex k = hadjOuter[j]; k < hadjOuter[j + 1]; k++) {
222 StorageIndex i = hadjInner[k];
224 StorageIndex prev = prevLeaf[i];
225 if (prev != kEmpty) {
226 StorageIndex q = parentSet.find(prev);
227 parentSet.compress(prev, q);
232 StorageIndex p = parent[j];
233 if (p != kEmpty) parentSet.compress(j, p);
236 for (StorageIndex j = 0; j < size; j++) {
237 StorageIndex p = parent[j];
238 if (p != kEmpty) nonZerosPerCol[p] += nonZerosPerCol[j] - 1;
239 if (doLDLT) nonZerosPerCol[j]--;
244 static void init_matrix(
const StorageIndex size,
const StorageIndex* nonZerosPerCol, CholMatrixType& L) {
245 eigen_assert(L.outerIndexPtr()[0] == 0);
246 std::partial_sum(nonZerosPerCol, nonZerosPerCol + size, L.outerIndexPtr() + 1);
247 L.resizeNonZeros(L.outerIndexPtr()[size]);
251 static void run(
const StorageIndex size,
const CholMatrixType& ap, CholMatrixType& L, VectorI& parent,
252 VectorI& workSpace,
bool doLDLT) {
254 workSpace.resize(4 * size);
255 L.resize(size, size);
257 StorageIndex* tmp1 = workSpace.data();
258 StorageIndex* tmp2 = workSpace.data() + size;
259 StorageIndex* tmp3 = workSpace.data() + 2 * size;
260 StorageIndex* tmp4 = workSpace.data() + 3 * size;
263 StorageIndex* hadj_outer = L.outerIndexPtr();
264 calc_hadj_outer(size, ap, hadj_outer);
266 ei_declare_aligned_stack_constructed_variable(StorageIndex, hadj_inner, hadj_outer[size],
nullptr);
267 calc_hadj_inner(size, ap, hadj_outer, hadj_inner, tmp1);
269 calc_etree(size, ap, parent.data(), tmp1);
270 calc_lineage(size, parent.data(), tmp1, tmp2);
271 calc_post(size, parent.data(), tmp1, tmp2, tmp3, tmp4);
272 calc_colcount(size, hadj_outer, hadj_inner, parent.data(), tmp1, tmp2, tmp3, tmp4, doLDLT);
273 init_matrix(size, tmp4, L);
279template <
typename Derived>
280void SimplicialCholeskyBase<Derived>::analyzePattern_preordered(
const CholMatrixType& ap,
bool doLDLT) {
281 using Helper = internal::simpl_chol_helper<Scalar, StorageIndex>;
283 eigen_assert(ap.innerSize() == ap.outerSize());
284 const StorageIndex size = internal::convert_index<StorageIndex>(ap.outerSize());
286 Helper::run(size, ap, m_matrix, m_parent, m_workSpace, doLDLT);
288 m_isInitialized =
true;
290 m_analysisIsOk =
true;
291 m_factorizationIsOk =
false;
294template <
typename Derived>
295template <
bool DoLDLT,
bool NonHermitian>
296void SimplicialCholeskyBase<Derived>::factorize_preordered(
const CholMatrixType& ap) {
298 const StorageIndex size = StorageIndex(ap.rows());
300 eigen_assert(m_analysisIsOk &&
"You must first call analyzePattern()");
301 eigen_assert(ap.rows() == ap.cols());
302 eigen_assert(m_parent.size() == size);
303 eigen_assert(m_workSpace.size() >= 3 * size);
305 const StorageIndex* Lp = m_matrix.outerIndexPtr();
306 StorageIndex* Li = m_matrix.innerIndexPtr();
307 Scalar* Lx = m_matrix.valuePtr();
309 ei_declare_aligned_stack_constructed_variable(
Scalar, y, size, 0);
310 StorageIndex* nonZerosPerCol = m_workSpace.data();
311 StorageIndex* pattern = m_workSpace.data() + size;
312 StorageIndex* tags = m_workSpace.data() + 2 * size;
315 m_diag.resize(DoLDLT ? size : 0);
317 for (StorageIndex k = 0; k < size; ++k) {
320 StorageIndex top = size;
322 nonZerosPerCol[k] = 0;
323 for (
typename CholMatrixType::InnerIterator it(ap, k); it; ++it) {
324 StorageIndex i = it.index();
326 y[i] += getSymm(it.value());
328 for (len = 0; tags[i] != k; i = m_parent[i]) {
332 while (len > 0) pattern[--top] = pattern[--len];
339 getDiag(y[k]) * m_shiftScale + m_shiftOffset;
341 for (; top < size; ++top) {
342 Index i = pattern[top];
349 l_ki = yi / getDiag(m_diag[i]);
351 yi = l_ki = yi / Lx[Lp[i]];
353 Index p2 = Lp[i] + nonZerosPerCol[i];
355 for (p = Lp[i] + (DoLDLT ? 0 : 1); p < p2; ++p) y[Li[p]] -= getSymm(Lx[p]) * yi;
356 d -= getDiag(l_ki * getSymm(yi));
363 if (d == RealScalar(0)) {
368 Index p = Lp[k] + nonZerosPerCol[k]++;
370 if (NonHermitian ? d == RealScalar(0) : numext::real(d) <= RealScalar(0)) {
379 m_factorizationIsOk =
true;
@ NumericalIssue
Definition Constants.h:442
@ Success
Definition Constants.h:440
Namespace containing all symbols from the Eigen library.
Definition B01_Experimental.dox:1
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition Meta.h:82