Basix 0.12.0.dev0
Loading...
Searching...
No Matches
precompute.h
1// Copyright (c) 2020 Matthew Scroggs
2// FEniCS Project
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include "math.h"
8#include "mdspan.hpp"
9#include <array>
10#include <concepts>
11#include <cstddef>
12#include <cstdint>
13#include <span>
14#include <tuple>
15#include <type_traits>
16#include <utility>
17#include <vector>
18
21{
22namespace impl
23{
26template <typename T, typename = void>
27struct scalar_value_type
28{
30 typedef T value_type;
31};
33template <typename T>
34struct scalar_value_type<T, std::void_t<typename T::value_type>>
35{
36 typedef typename T::value_type value_type;
37};
39template <typename T>
40using scalar_value_type_t = typename scalar_value_type<T>::value_type;
41} // namespace impl
42
87void prepare_permutation(std::span<std::size_t> perm);
88
142template <typename E>
143void apply_permutation(std::span<const std::size_t> perm, std::span<E> data,
144 std::size_t offset = 0, std::size_t n = 1)
145{
146 for (std::size_t i = 0; i < perm.size(); ++i)
147 for (std::size_t b = 0; b < n; ++b)
148 std::swap(data[n * (offset + i) + b], data[n * (offset + perm[i]) + b]);
149}
150
158template <typename E>
159void apply_permutation_mapped(std::span<const std::size_t> perm,
160 std::span<E> data, std::span<const int> emap,
161 std::size_t n = 1)
162{
163 for (std::size_t i = 0; i < perm.size(); ++i)
164 for (std::size_t b = 0; b < n; ++b)
165 std::swap(data[n * emap[i] + b], data[n * emap[perm[i]] + b]);
166}
167
187template <typename E>
188void apply_inv_permutation_right(std::span<const std::size_t> perm,
189 std::span<E> data, std::size_t offset = 0,
190 std::size_t n = 1)
191{
192 const std::size_t dim = perm.size();
193 const std::size_t data_size = (data.size() + (dim < n ? n - dim : 0)) / n;
194 for (std::size_t b = 0; b < n; ++b)
195 {
196 for (std::size_t i = 0; i < dim; ++i)
197 {
198 std::swap(data[data_size * b + offset + i],
199 data[data_size * b + offset + perm[i]]);
200 }
201 }
202}
203
219template <std::floating_point T>
220std::vector<std::size_t>
221prepare_matrix(std::pair<std::vector<T>, std::array<std::size_t, 2>>& A)
222{
223 return math::transpose_lu<T>(A);
224}
225
257template <typename T, typename E>
258void apply_matrix(std::span<const std::size_t> v_size_t,
259 md::mdspan<const T, md::dextents<std::size_t, 2>> M,
260 std::span<E> data, std::size_t offset = 0, std::size_t n = 1)
261{
262 using U = typename impl::scalar_value_type_t<E>;
263
264 const std::size_t dim = v_size_t.size();
265 apply_permutation(v_size_t, data, offset, n);
266
267 // data has n contiguous (unit-stride) values per dof. Looping over b
268 // innermost vectorises each elimination step, but for small n (common
269 // in practice, e.g. 1-3) the loop-entry cost per (i, j) pair outweighs
270 // that benefit, so fall back to the original b-outermost ordering.
271 // Threshold chosen from measurements showing the crossover is n=12-16.
272 if (n <= 12)
273 {
274 for (std::size_t b = 0; b < n; ++b)
275 {
276 for (std::size_t i = 0; i < dim; ++i)
277 {
278 for (std::size_t j = i + 1; j < dim; ++j)
279 {
280 data[n * (offset + i) + b]
281 += static_cast<U>(M(i, j)) * data[n * (offset + j) + b];
282 }
283 }
284
285 for (std::size_t i = 1; i <= dim; ++i)
286 {
287 data[n * (offset + dim - i) + b] *= static_cast<U>(M(dim - i, dim - i));
288 for (std::size_t j = 0; j < dim - i; ++j)
289 {
290 data[n * (offset + dim - i) + b]
291 += static_cast<U>(M(dim - i, j)) * data[n * (offset + j) + b];
292 }
293 }
294 }
295 }
296 else
297 {
298 for (std::size_t i = 0; i < dim; ++i)
299 {
300 for (std::size_t j = i + 1; j < dim; ++j)
301 {
302 const U Mij = static_cast<U>(M(i, j));
303 for (std::size_t b = 0; b < n; ++b)
304 {
305 data[n * (offset + i) + b] += Mij * data[n * (offset + j) + b];
306 }
307 }
308 }
309
310 for (std::size_t i = 1; i <= dim; ++i)
311 {
312 const U Mdiag = static_cast<U>(M(dim - i, dim - i));
313 for (std::size_t b = 0; b < n; ++b)
314 data[n * (offset + dim - i) + b] *= Mdiag;
315
316 for (std::size_t j = 0; j < dim - i; ++j)
317 {
318 const U Mij = static_cast<U>(M(dim - i, j));
319 for (std::size_t b = 0; b < n; ++b)
320 {
321 data[n * (offset + dim - i) + b] += Mij * data[n * (offset + j) + b];
322 }
323 }
324 }
325 }
326}
327
347template <typename T, typename E>
349 std::span<const std::size_t> v_size_t,
350 md::mdspan<const T, md::dextents<std::size_t, 2>> M, std::span<E> data,
351 std::size_t offset = 0, std::size_t n = 1)
352{
353 using U = typename impl::scalar_value_type_t<E>;
354
355 const std::size_t dim = v_size_t.size();
356 const std::size_t data_size = (data.size() + (dim < n ? n - dim : 0)) / n;
357 apply_inv_permutation_right(v_size_t, data, offset, n);
358 for (std::size_t b = 0; b < n; ++b)
359 {
360 for (std::size_t i = 0; i < dim; ++i)
361 {
362 for (std::size_t j = i + 1; j < dim; ++j)
363 {
364 data[data_size * b + offset + i]
365 += static_cast<U>(M(i, j)) * data[data_size * b + offset + j];
366 }
367 }
368 for (std::size_t i = 1; i <= dim; ++i)
369 {
370 data[data_size * b + offset + dim - i]
371 *= static_cast<U>(M(dim - i, dim - i));
372 for (std::size_t j = 0; j < dim - i; ++j)
373 {
374 data[data_size * b + offset + dim - i]
375 += static_cast<U>(M(dim - i, j)) * data[data_size * b + offset + j];
376 }
377 }
378 }
379}
380
381} // namespace basix::precompute
std::vector< std::size_t > transpose_lu(std::pair< std::vector< T >, std::array< std::size_t, 2 > > &A)
Compute the LU decomposition of the transpose of a square matrix A.
Definition math.h:296
Matrix and permutation pre-computation.
Definition precompute.h:21
std::vector< std::size_t > prepare_matrix(std::pair< std::vector< T >, std::array< std::size_t, 2 > > &A)
Prepare a square matrix.
Definition precompute.h:221
void apply_permutation(std::span< const std::size_t > perm, std::span< E > data, std::size_t offset=0, std::size_t n=1)
Apply a (precomputed) permutation .
Definition precompute.h:143
void apply_inv_permutation_right(std::span< const std::size_t > perm, std::span< E > data, std::size_t offset=0, std::size_t n=1)
Apply a (precomputed) permutation to some transposed data.
Definition precompute.h:188
void prepare_permutation(std::span< std::size_t > perm)
Prepare a permutation.
Definition precompute.cpp:12
void apply_permutation_mapped(std::span< const std::size_t > perm, std::span< E > data, std::span< const int > emap, std::size_t n=1)
Permutation of mapped data.
Definition precompute.h:159
void apply_transpose_matrix_right(std::span< const std::size_t > v_size_t, md::mdspan< const T, md::dextents< std::size_t, 2 > > M, std::span< E > data, std::size_t offset=0, std::size_t n=1)
Apply a (precomputed) matrix to some transposed data.
Definition precompute.h:348
void apply_matrix(std::span< const std::size_t > v_size_t, md::mdspan< const T, md::dextents< std::size_t, 2 > > M, std::span< E > data, std::size_t offset=0, std::size_t n=1)
Apply a (precomputed) matrix.
Definition precompute.h:258