DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
matrix_csr_impl.h
1// Copyright (C) 2021-2026 Garth N. Wells and Chris N. Richardson
2//
3// This file is part of DOLFINx (https://www.fenicsproject.org)
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6
7#pragma once
8
9#include <cassert>
10#include <concepts>
11#include <numeric>
12#include <span>
13#include <stdexcept>
14#include <type_traits>
15#include <utility>
16#include <vector>
17
18namespace dolfinx::la
19{
20namespace impl
21{
23template <typename T>
24struct is_integral_constant : std::false_type
25{
26};
27template <std::integral U, U N>
28struct is_integral_constant<std::integral_constant<U, N>> : std::true_type
29{
30};
31
35template <typename T>
36concept BlockSizeArg = std::integral<std::remove_cvref_t<T>>
37 or is_integral_constant<std::remove_cvref_t<T>>::value;
39
69template <int BS0, int BS1, typename OP, typename U, typename V, typename W,
70 typename X, typename Y>
71void insert_csr(U&& data, const V& cols, const W& row_ptr, const X& x,
72 const Y& xrows, const Y& xcols, OP op,
73 [[maybe_unused]] typename Y::value_type num_rows)
74{
75 const std::size_t nc = xcols.size();
76 assert(x.size() == xrows.size() * xcols.size() * BS0 * BS1);
77 for (std::size_t r = 0; r < xrows.size(); ++r)
78 {
79 // Row index and current data row
80 auto row = xrows[r];
81 using T = typename X::value_type;
82 const T* xr = x.data() + r * nc * BS0 * BS1;
83
84#ifndef NDEBUG
85 if (row >= num_rows)
86 throw std::out_of_range("Local row out of range");
87#endif
88 // Columns indices for row
89 auto cit0 = std::next(cols.begin(), row_ptr[row]);
90 auto cit1 = std::next(cols.begin(), row_ptr[row + 1]);
91 for (std::size_t c = 0; c < nc; ++c)
92 {
93 // Find position of column index
94 auto it = std::lower_bound(cit0, cit1, xcols[c]);
95 if (it == cit1 or *it != xcols[c])
96 throw std::out_of_range("Entry not in sparsity");
97
98 std::size_t d = std::ranges::distance(cols.begin(), it);
99 std::size_t di = d * BS0 * BS1;
100 std::size_t xi = c * BS1;
101 assert(di < data.size());
102 for (int i = 0; i < BS0; ++i)
103 {
104 for (int j = 0; j < BS1; ++j)
105 op(data[di + j], xr[xi + j]);
106 di += BS1;
107 xi += nc * BS1;
108 }
109 }
110 }
111}
112
134template <int BS0, int BS1, typename OP, typename U, typename V, typename W,
135 typename X, typename Y>
136void insert_blocked_csr(U&& data, const V& cols, const W& row_ptr, const X& x,
137 const Y& xrows, const Y& xcols, OP op,
138 [[maybe_unused]] typename Y::value_type num_rows)
139{
140 const std::size_t nc = xcols.size();
141 assert(x.size() == xrows.size() * xcols.size() * BS0 * BS1);
142 for (std::size_t r = 0; r < xrows.size(); ++r)
143 {
144 // Row index and current data row
145 auto row = xrows[r] * BS0;
146#ifndef NDEBUG
147 if (row >= num_rows)
148 throw std::out_of_range("Local row out of range");
149#endif
150
151 for (int i = 0; i < BS0; ++i)
152 {
153 using T = typename X::value_type;
154 const T* xr = x.data() + (r * BS0 + i) * nc * BS1;
155
156 // Columns indices for row
157 auto cit0 = std::next(cols.begin(), row_ptr[row + i]);
158 auto cit1 = std::next(cols.begin(), row_ptr[row + i + 1]);
159 for (std::size_t c = 0; c < nc; ++c)
160 {
161 // Find position of column index
162 auto it = std::lower_bound(cit0, cit1, xcols[c] * BS1);
163 if (it == cit1 or *it != xcols[c] * BS1)
164 throw std::out_of_range("Entry not in sparsity");
165
166 std::size_t d = std::ranges::distance(cols.begin(), it);
167 assert(d < data.size());
168 std::size_t xi = c * BS1;
169 for (int j = 0; j < BS1; ++j)
170 op(data[d + j], xr[xi + j]);
171 }
172 }
173 }
174}
175
195template <typename OP, typename U, typename V, typename W, typename X,
196 typename Y>
197void insert_nonblocked_csr(U&& data, const V& cols, const W& row_ptr,
198 const X& x, const Y& xrows, const Y& xcols, OP op,
199 [[maybe_unused]] typename Y::value_type num_rows,
200 int bs0, int bs1)
201{
202 const std::size_t nc = xcols.size();
203 const int nbs = bs0 * bs1;
204
205 assert(x.size() == xrows.size() * xcols.size());
206 for (std::size_t r = 0; r < xrows.size(); ++r)
207 {
208 // Row index and current data row
209 auto rdiv = std::div(xrows[r], bs0);
210 using T = typename X::value_type;
211 const T* xr = x.data() + r * nc;
212
213#ifndef NDEBUG
214 if (rdiv.quot >= num_rows)
215 throw std::out_of_range("Local row out of range");
216#endif
217 // Columns indices for row
218 auto cit0 = std::next(cols.begin(), row_ptr[rdiv.quot]);
219 auto cit1 = std::next(cols.begin(), row_ptr[rdiv.quot + 1]);
220 for (std::size_t c = 0; c < nc; ++c)
221 {
222 // Find position of column index
223 auto cdiv = std::div(xcols[c], bs1);
224 auto it = std::lower_bound(cit0, cit1, cdiv.quot);
225 if (it == cit1 or *it != cdiv.quot)
226 throw std::out_of_range("Entry not in sparsity");
227
228 std::size_t d = std::ranges::distance(cols.begin(), it);
229 std::size_t di = d * nbs + rdiv.rem * bs1 + cdiv.rem;
230 assert(di < data.size());
231 op(data[di], xr[c]);
232 }
233 }
234}
235
261template <typename T>
262void spmv(std::span<const T> values, std::span<const std::int64_t> row_begin,
263 std::span<const std::int64_t> row_end,
264 std::span<const std::int32_t> indices, std::span<const T> x,
265 std::span<T> y, BlockSizeArg auto bs0, BlockSizeArg auto bs1)
266{
267 assert(row_begin.size() == row_end.size());
268 // Block layout: row-major within each block. The element at row-offset
269 // k0 (∈ [0, bs0)) and column-offset k1 (∈ [0, bs1)) of block entry j
270 // is stored at values[j * bs0 * bs1 + k0 * bs1 + k1].
271 for (decltype(+bs0) k0 = 0; k0 < bs0; ++k0)
272 {
273 for (std::size_t i = 0; i < row_begin.size(); i++)
274 {
275 T vi{0};
276 for (std::int64_t j = row_begin[i]; j < row_end[i]; j++)
277 {
278 for (decltype(+bs1) k1 = 0; k1 < bs1; ++k1)
279 {
280 vi += values[j * bs0 * bs1 + k0 * bs1 + k1]
281 * x[indices[j] * bs1 + k1];
282 }
283 }
284
285 y[i * bs0 + k0] += vi;
286 }
287 }
288}
289
321template <typename T>
322void spmvT(std::span<const T> values, std::span<const std::int64_t> row_begin,
323 std::span<const std::int64_t> row_end,
324 std::span<const std::int32_t> indices, std::span<const T> x,
325 std::span<T> y, BlockSizeArg auto bs0, BlockSizeArg auto bs1)
326{
327 assert(row_begin.size() == row_end.size());
328
329 // Block layout: row-major within each block.
330 for (decltype(+bs0) k0 = 0; k0 < bs0; ++k0)
331 {
332 for (std::size_t i = 0; i < row_begin.size(); i++)
333 {
334 const T xval = x[i * bs0 + k0];
335 for (std::int64_t j = row_begin[i]; j < row_end[i]; j++)
336 {
337 for (decltype(+bs1) k1 = 0; k1 < bs1; ++k1)
338 {
339 y[indices[j] * bs1 + k1]
340 += values[j * bs0 * bs1 + k0 * bs1 + k1] * xval;
341 }
342 }
343 }
344 }
345}
346
347} // namespace impl
348} // namespace dolfinx::la
Fetch the rows of B that correspond to the ghost columns of A.
Definition matmul.h:39
void insert_csr(U &&data, const V &cols, const W &row_ptr, const X &x, const Y &xrows, const Y &xcols, OP op, typename Y::value_type num_rows)
Incorporate data into a CSR matrix.
Definition matrix_csr_impl.h:71
void spmv(std::span< const T > values, std::span< const std::int64_t > row_begin, std::span< const std::int64_t > row_end, std::span< const std::int32_t > indices, std::span< const T > x, std::span< T > y, BlockSizeArg auto bs0, BlockSizeArg auto bs1)
Sparse matrix-vector product implementation.
Definition matrix_csr_impl.h:262
void insert_blocked_csr(U &&data, const V &cols, const W &row_ptr, const X &x, const Y &xrows, const Y &xcols, OP op, typename Y::value_type num_rows)
Incorporate blocked data with given block sizes into a non-blocked MatrixCSR.
Definition matrix_csr_impl.h:136
void insert_nonblocked_csr(U &&data, const V &cols, const W &row_ptr, const X &x, const Y &xrows, const Y &xcols, OP op, typename Y::value_type num_rows, int bs0, int bs1)
Incorporate non-blocked data into a blocked matrix (data block size=1).
Definition matrix_csr_impl.h:197
void spmvT(std::span< const T > values, std::span< const std::int64_t > row_begin, std::span< const std::int64_t > row_end, std::span< const std::int32_t > indices, std::span< const T > x, std::span< T > y, BlockSizeArg auto bs0, BlockSizeArg auto bs1)
Sparse matrix-vector transpose product implementation.
Definition matrix_csr_impl.h:322
Linear algebra interface.
Definition dolfinx_la.h:7