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 <concepts>
10#include <cstdint>
11#include <span>
12#include <tuple>
13#include <type_traits>
14#include <vector>
15
18{
19namespace impl
20{
23template <typename T, typename = void>
24struct scalar_value_type
25{
27 typedef T value_type;
28};
30template <typename T>
31struct scalar_value_type<T, std::void_t<typename T::value_type>>
32{
33 typedef typename T::value_type value_type;
34};
36template <typename T>
37using scalar_value_type_t = typename scalar_value_type<T>::value_type;
38} // namespace impl
39
84void prepare_permutation(std::span<std::size_t> perm);
85
136template <typename E>
137void apply_permutation(std::span<const std::size_t> perm, std::span<E> data,
138 std::size_t offset = 0, std::size_t n = 1)
139{
140 for (std::size_t i = 0; i < perm.size(); ++i)
141 for (std::size_t b = 0; b < n; ++b)
142 std::swap(data[n * (offset + i) + b], data[n * (offset + perm[i]) + b]);
143}
144
152template <typename E>
153void apply_permutation_mapped(std::span<const std::size_t> perm,
154 std::span<E> data, std::span<const int> emap,
155 std::size_t n = 1)
156{
157 for (std::size_t i = 0; i < perm.size(); ++i)
158 for (std::size_t b = 0; b < n; ++b)
159 std::swap(data[n * emap[i] + b], data[n * emap[perm[i]] + b]);
160}
161
181template <typename E>
182void apply_inv_permutation_right(std::span<const std::size_t> perm,
183 std::span<E> data, std::size_t offset = 0,
184 std::size_t n = 1)
185{
186 const std::size_t dim = perm.size();
187 const std::size_t data_size = (data.size() + (dim < n ? n - dim : 0)) / n;
188 for (std::size_t b = 0; b < n; ++b)
189 {
190 for (std::size_t i = 0; i < dim; ++i)
191 {
192 std::swap(data[data_size * b + offset + i],
193 data[data_size * b + offset + perm[i]]);
194 }
195 }
196}
197
213template <std::floating_point T>
214std::vector<std::size_t>
215prepare_matrix(std::pair<std::vector<T>, std::array<std::size_t, 2>>& A)
216{
217 return math::transpose_lu<T>(A);
218}
219
251template <typename T, typename E>
252void apply_matrix(std::span<const std::size_t> v_size_t,
253 md::mdspan<const T, md::dextents<std::size_t, 2>> M,
254 std::span<E> data, std::size_t offset = 0, std::size_t n = 1)
255{
256 using U = typename impl::scalar_value_type_t<E>;
257
258 const std::size_t dim = v_size_t.size();
260
261 // data has n contiguous (unit-stride) values per dof. Looping over b
262 // innermost vectorises each elimination step, but for small n (common
263 // in practice, e.g. 1-3) the loop-entry cost per (i, j) pair outweighs
264 // that benefit, so fall back to the original b-outermost ordering.
265 // Threshold chosen from measurements showing the crossover is n=12-16.
266 if (n <= 12)
267 {
268 for (std::size_t b = 0; b < n; ++b)
269 {
270 for (std::size_t i = 0; i < dim; ++i)
271 {
272 for (std::size_t j = i + 1; j < dim; ++j)
273 {
274 data[n * (offset + i) + b]
275 += static_cast<U>(M(i, j)) * data[n * (offset + j) + b];
276 }
277 }
278
279 for (std::size_t i = 1; i <= dim; ++i)
280 {
281 data[n * (offset + dim - i) + b] *= static_cast<U>(M(dim - i, dim - i));
282 for (std::size_t j = 0; j < dim - i; ++j)
283 {
284 data[n * (offset + dim - i) + b]
285 += static_cast<U>(M(dim - i, j)) * data[n * (offset + j) + b];
286 }
287 }
288 }
289 }
290 else
291 {
292 for (std::size_t i = 0; i < dim; ++i)
293 {
294 for (std::size_t j = i + 1; j < dim; ++j)
295 {
296 const U Mij = static_cast<U>(M(i, j));
297 for (std::size_t b = 0; b < n; ++b)
298 {
299 data[n * (offset + i) + b] += Mij * data[n * (offset + j) + b];
300 }
301 }
302 }
303
304 for (std::size_t i = 1; i <= dim; ++i)
305 {
306 const U Mdiag = static_cast<U>(M(dim - i, dim - i));
307 for (std::size_t b = 0; b < n; ++b)
308 data[n * (offset + dim - i) + b] *= Mdiag;
309
310 for (std::size_t j = 0; j < dim - i; ++j)
311 {
312 const U Mij = static_cast<U>(M(dim - i, j));
313 for (std::size_t b = 0; b < n; ++b)
314 {
315 data[n * (offset + dim - i) + b]
316 += Mij * data[n * (offset + j) + b];
317 }
318 }
319 }
320 }
321}
322
342template <typename T, typename E>
344 std::span<const std::size_t> v_size_t,
345 md::mdspan<const T, md::dextents<std::size_t, 2>> M, std::span<E> data,
346 std::size_t offset = 0, std::size_t n = 1)
347{
348 using U = typename impl::scalar_value_type_t<E>;
349
350 const std::size_t dim = v_size_t.size();
351 const std::size_t data_size = (data.size() + (dim < n ? n - dim : 0)) / n;
353 for (std::size_t b = 0; b < n; ++b)
354 {
355 for (std::size_t i = 0; i < dim; ++i)
356 {
357 for (std::size_t j = i + 1; j < dim; ++j)
358 {
359 data[data_size * b + offset + i]
360 += static_cast<U>(M(i, j)) * data[data_size * b + offset + j];
361 }
362 }
363 for (std::size_t i = 1; i <= dim; ++i)
364 {
365 data[data_size * b + offset + dim - i]
366 *= static_cast<U>(M(dim - i, dim - i));
367 for (std::size_t j = 0; j < dim - i; ++j)
368 {
369 data[data_size * b + offset + dim - i]
370 += static_cast<U>(M(dim - i, j)) * data[data_size * b + offset + j];
371 }
372 }
373 }
374}
375
376} // namespace basix::precompute
A finite element.
Definition finite-element.h:138
Matrix and permutation pre-computation.
Definition precompute.h:18
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:215
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:137
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:182
void prepare_permutation(std::span< std::size_t > perm)
Prepare a permutation.
Definition precompute.cpp:10
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:153
void apply_tranpose_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:343
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:252