10#ifndef EIGEN_SPARSITY_PATTERN_REF_H
11#define EIGEN_SPARSITY_PATTERN_REF_H
14#include "./InternalHeaderCheck.h"
44template <
typename StorageIndex>
45struct SparsityPatternRef {
46 const StorageIndex* outer =
nullptr;
47 const StorageIndex* inner =
nullptr;
50 const StorageIndex* innerNonZero =
nullptr;
54 EIGEN_DEVICE_FUNC
inline bool isCompressed()
const {
return innerNonZero ==
nullptr; }
56 EIGEN_DEVICE_FUNC
inline Index nonZeros(Index j)
const {
57 return isCompressed() ? Index(outer[j + 1] - outer[j]) : Index(innerNonZero[j]);
72template <
typename Scalar,
typename StorageIndex>
73SparsityPatternRef<StorageIndex> make_col_major_pattern_ref(
const SparseMatrix<Scalar, ColMajor, StorageIndex>& amat,
74 Matrix<StorageIndex, Dynamic, 1>& ,
75 Matrix<StorageIndex, Dynamic, 1>& ) {
76 SparsityPatternRef<StorageIndex> p;
77 p.outer = amat.outerIndexPtr();
78 p.inner = amat.innerIndexPtr();
79 p.innerNonZero = amat.isCompressed() ? nullptr : amat.innerNonZeroPtr();
80 p.outerSize = amat.cols();
81 p.innerSize = amat.rows();
91template <
typename Derived>
92SparsityPatternRef<typename Derived::StorageIndex> make_col_major_pattern_ref(
93 const SparseMatrixBase<Derived>& amat_base, Matrix<typename Derived::StorageIndex, Dynamic, 1>& outer_buf,
94 Matrix<typename Derived::StorageIndex, Dynamic, 1>& inner_buf) {
95 using StorageIndex =
typename Derived::StorageIndex;
96 const Derived& amat = amat_base.derived();
97 internal::evaluator<Derived> amat_eval(amat);
98 const Index n_cols = amat.cols();
99 const Index n_outer = amat.outerSize();
101 outer_buf.setZero(n_cols + 1);
102 for (Index i = 0; i < n_outer; ++i)
103 for (
typename internal::evaluator<Derived>::InnerIterator it(amat_eval, i); it; ++it) ++outer_buf(it.col() + 1);
104 for (Index j = 0; j < n_cols; ++j) outer_buf(j + 1) += outer_buf(j);
105 inner_buf.resize(outer_buf(n_cols));
106 Matrix<StorageIndex, Dynamic, 1> head = outer_buf.head(n_cols);
107 for (Index i = 0; i < n_outer; ++i)
108 for (
typename internal::evaluator<Derived>::InnerIterator it(amat_eval, i); it; ++it)
109 inner_buf(head(it.col())++) = convert_index<StorageIndex>(it.row());
111 SparsityPatternRef<StorageIndex> p;
112 p.outer = outer_buf.data();
113 p.inner = inner_buf.data();
114 p.innerNonZero =
nullptr;
115 p.outerSize = n_cols;
116 p.innerSize = amat.rows();
140template <
typename StorageIndex>
141void materialize_col_major_pattern(
const SparsityPatternRef<StorageIndex>& pat,
const StorageIndex* row_perm,
142 SparseMatrix<signed char, ColMajor, StorageIndex>& out) {
143 const Index n_outer = pat.outerSize;
144 const Index n_inner = pat.innerSize;
145 out.resize(n_inner, n_outer);
148 if (pat.isCompressed()) {
149 total = pat.outer[n_outer];
151 for (Index j = 0; j < n_outer; ++j) total += pat.nonZeros(j);
153 out.resizeNonZeros(total);
155 StorageIndex* o_outer = out.outerIndexPtr();
156 StorageIndex* o_inner = out.innerIndexPtr();
157 if (pat.isCompressed()) {
163 std::copy(pat.outer, pat.outer + n_outer + 1, o_outer);
164 if (row_perm ==
nullptr) {
165 std::copy(pat.inner, pat.inner + total, o_inner);
170 for (Index j = 0; j < n_outer; ++j) {
171 const StorageIndex* src = pat.inner + o_outer[j];
172 StorageIndex* dst = o_inner + o_outer[j];
173 const Index nz = o_outer[j + 1] - o_outer[j];
174 for (Index k = 0; k < nz; ++k) dst[k] = row_perm[src[k]];
175 std::sort(dst, dst + nz);
180 for (Index j = 0; j < n_outer; ++j) {
181 const Index nz = pat.nonZeros(j);
182 o_outer[j + 1] = convert_index<StorageIndex>(o_outer[j] + nz);
183 const StorageIndex* src = pat.inner + pat.outer[j];
184 StorageIndex* dst = o_inner + o_outer[j];
185 if (row_perm ==
nullptr) {
186 std::copy(src, src + nz, dst);
188 for (Index k = 0; k < nz; ++k) dst[k] = row_perm[src[k]];
189 std::sort(dst, dst + nz);
196 std::fill_n(out.valuePtr(), total,
static_cast<signed char>(1));
200template <
typename StorageIndex>
201void materialize_col_major_pattern(
const SparsityPatternRef<StorageIndex>& pat,
202 SparseMatrix<signed char, ColMajor, StorageIndex>& out) {
203 materialize_col_major_pattern(pat,
static_cast<const StorageIndex*
>(
nullptr), out);
236template <
typename StorageIndex>
237void materialize_at_plus_a_pattern(
const SparsityPatternRef<StorageIndex>& A,
238 SparseMatrix<signed char, ColMajor, StorageIndex>& out) {
239 const Index n = A.outerSize;
240 eigen_assert(n == A.innerSize &&
"materialize_at_plus_a_pattern: A must be square");
243 Matrix<StorageIndex, Dynamic, 1> AT_p(n + 1);
245 for (Index j = 0; j < n; ++j) {
246 const Index nz = A.nonZeros(j);
247 const StorageIndex* col = A.inner + A.outer[j];
248 for (Index k = 0; k < nz; ++k) ++AT_p(col[k] + 1);
250 for (Index i = 0; i < n; ++i) AT_p(i + 1) += AT_p(i);
257 const StorageIndex a_nnz = AT_p(n);
258 Matrix<StorageIndex, Dynamic, 1> AT_i(a_nnz);
259 Matrix<StorageIndex, Dynamic, 1> head = AT_p.head(n);
260 for (Index j = 0; j < n; ++j) {
261 const Index nz = A.nonZeros(j);
262 const StorageIndex* col = A.inner + A.outer[j];
263 for (Index k = 0; k < nz; ++k) AT_i(head(col[k])++) = convert_index<StorageIndex>(j);
269 StorageIndex* out_p = out.outerIndexPtr();
271 for (Index j = 0; j < n; ++j) {
272 const StorageIndex* a_col = A.inner + A.outer[j];
273 const Index a_nz = A.nonZeros(j);
274 const StorageIndex* at_col = AT_i.data() + AT_p(j);
275 const Index at_nz = AT_p(j + 1) - AT_p(j);
276 Index ia = 0, it = 0, count = 0;
277 while (ia < a_nz && it < at_nz) {
278 const StorageIndex va = a_col[ia], vt = at_col[it];
281 }
else if (va > vt) {
289 count += (a_nz - ia) + (at_nz - it);
290 out_p[j + 1] = out_p[j] + convert_index<StorageIndex>(count);
293 const StorageIndex total = out_p[n];
294 out.resizeNonZeros(total);
297 StorageIndex* out_i = out.innerIndexPtr();
298 for (Index j = 0; j < n; ++j) {
299 const StorageIndex* a_col = A.inner + A.outer[j];
300 const Index a_nz = A.nonZeros(j);
301 const StorageIndex* at_col = AT_i.data() + AT_p(j);
302 const Index at_nz = AT_p(j + 1) - AT_p(j);
303 StorageIndex* dst = out_i + out_p[j];
304 Index ia = 0, it = 0;
305 while (ia < a_nz && it < at_nz) {
306 const StorageIndex va = a_col[ia], vt = at_col[it];
310 }
else if (va > vt) {
319 while (ia < a_nz) *dst++ = a_col[ia++];
320 while (it < at_nz) *dst++ = at_col[it++];
322 std::fill_n(out.valuePtr(), total,
static_cast<signed char>(1));
335template <
unsigned int UpLo,
typename StorageIndex>
336void materialize_selfadjoint_pattern(
const SparsityPatternRef<StorageIndex>& A,
337 SparseMatrix<signed char, ColMajor, StorageIndex>& out) {
338 static_assert(UpLo ==
static_cast<unsigned>(
Lower) || UpLo ==
static_cast<unsigned>(
Upper),
339 "UpLo must be Lower or Upper");
340 const Index n = A.outerSize;
341 eigen_assert(n == A.innerSize &&
"materialize_selfadjoint_pattern: A must be square");
342 constexpr bool IsLower = (UpLo ==
static_cast<unsigned>(
Lower));
347 Matrix<StorageIndex, Dynamic, 1> AT_p(n + 1);
349 for (Index j = 0; j < n; ++j) {
350 const Index nz = A.nonZeros(j);
351 const StorageIndex* col = A.inner + A.outer[j];
352 for (Index k = 0; k < nz; ++k) {
353 const StorageIndex r = col[k];
354 const bool keep = IsLower ? (Index(r) >= j) : (Index(r) <= j);
355 if (keep) ++AT_p(r + 1);
358 for (Index i = 0; i < n; ++i) AT_p(i + 1) += AT_p(i);
363 const StorageIndex a_nnz = AT_p(n);
364 Matrix<StorageIndex, Dynamic, 1> AT_i(a_nnz);
365 Matrix<StorageIndex, Dynamic, 1> head = AT_p.head(n);
366 for (Index j = 0; j < n; ++j) {
367 const Index nz = A.nonZeros(j);
368 const StorageIndex* col = A.inner + A.outer[j];
369 for (Index k = 0; k < nz; ++k) {
370 const StorageIndex r = col[k];
371 const bool keep = IsLower ? (Index(r) >= j) : (Index(r) <= j);
372 if (keep) AT_i(head(r)++) = convert_index<StorageIndex>(j);
381 Matrix<Index, Dynamic, 1> a_split(n);
382 for (Index j = 0; j < n; ++j) {
383 const StorageIndex* a_col = A.inner + A.outer[j];
384 const Index a_nz = A.nonZeros(j);
385 EIGEN_IF_CONSTEXPR (IsLower) {
386 a_split(j) = std::lower_bound(a_col, a_col + a_nz, StorageIndex(j)) - a_col;
388 a_split(j) = std::upper_bound(a_col, a_col + a_nz, StorageIndex(j)) - a_col;
395 StorageIndex* out_p = out.outerIndexPtr();
397 for (Index j = 0; j < n; ++j) {
398 const StorageIndex* a_col = A.inner + A.outer[j];
399 const Index a_nz = A.nonZeros(j);
400 const StorageIndex* a_kept = IsLower ? a_col + a_split(j) : a_col;
401 const Index a_kept_nz = IsLower ? (a_nz - a_split(j)) : a_split(j);
402 const StorageIndex* at_col = AT_i.data() + AT_p(j);
403 const Index at_nz = AT_p(j + 1) - AT_p(j);
404 Index ia = 0, it = 0, count = 0;
405 while (ia < a_kept_nz && it < at_nz) {
406 const StorageIndex va = a_kept[ia], vt = at_col[it];
409 }
else if (va > vt) {
417 count += (a_kept_nz - ia) + (at_nz - it);
418 out_p[j + 1] = out_p[j] + convert_index<StorageIndex>(count);
421 const StorageIndex total = out_p[n];
422 out.resizeNonZeros(total);
425 StorageIndex* out_i = out.innerIndexPtr();
426 for (Index j = 0; j < n; ++j) {
427 const StorageIndex* a_col = A.inner + A.outer[j];
428 const Index a_nz = A.nonZeros(j);
429 const StorageIndex* a_kept = IsLower ? a_col + a_split(j) : a_col;
430 const Index a_kept_nz = IsLower ? (a_nz - a_split(j)) : a_split(j);
431 const StorageIndex* at_col = AT_i.data() + AT_p(j);
432 const Index at_nz = AT_p(j + 1) - AT_p(j);
433 StorageIndex* dst = out_i + out_p[j];
434 Index ia = 0, it = 0;
435 while (ia < a_kept_nz && it < at_nz) {
436 const StorageIndex va = a_kept[ia], vt = at_col[it];
440 }
else if (va > vt) {
449 while (ia < a_kept_nz) *dst++ = a_kept[ia++];
450 while (it < at_nz) *dst++ = at_col[it++];
452 std::fill_n(out.valuePtr(), total,
static_cast<signed char>(1));
@ Lower
Definition Constants.h:212
@ Upper
Definition Constants.h:214