12#include <basix/mdspan.hpp>
20namespace dolfinx::math
27template <
typename U,
typename V>
28 requires scalar<typename U::value_type>
29 && std::same_as<typename U::value_type, typename V::value_type>
30constexpr std::array<typename U::value_type, 3> cross(
const U& u,
const V& v)
32 assert(u.size() == 3);
33 assert(v.size() == 3);
34 return {u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2],
35 u[0] * v[1] - u[1] * v[0]};
41template <std::
floating_po
int T>
42T difference_of_products(T a, T b, T c, T d)
noexcept
45 T err = std::fma(-b, c, w);
46 T diff = std::fma(a, d, -w);
57template <std::
floating_po
int T>
58auto det(
const T* A, std::array<std::size_t, 2> shape)
60 assert(shape[0] == shape[1]);
68 return difference_of_products(A[0], A[1], A[2], A[3]);
73 T w0 = difference_of_products(A[3 + 1], A[3 + 2], A[3 * 2 + 1],
75 T w1 = difference_of_products(A[3], A[3 + 2], A[3 * 2], A[3 * 2 + 2]);
76 T w2 = difference_of_products(A[3], A[3 + 1], A[3 * 2], A[3 * 2 + 1]);
77 T w3 = difference_of_products(A[0], A[1], w1, w0);
78 T w4 = std::fma(A[2], w2, w3);
82 throw std::runtime_error(
83 std::format(
"math::det is not implemented for {}x{} matrices.",
93template <
typename Matrix>
94 requires std::floating_point<typename Matrix::value_type>
97 static_assert(Matrix::rank() == 2,
"Must be rank 2");
98 assert(A.extent(0) == A.extent(1));
100 using value_type =
typename Matrix::value_type;
101 const int nrows = A.extent(0);
107 return difference_of_products(A(0, 0), A(0, 1), A(1, 0), A(1, 1));
112 value_type w0 = difference_of_products(A(1, 1), A(1, 2), A(2, 1), A(2, 2));
113 value_type w1 = difference_of_products(A(1, 0), A(1, 2), A(2, 0), A(2, 2));
114 value_type w2 = difference_of_products(A(1, 0), A(1, 1), A(2, 0), A(2, 1));
115 value_type w3 = difference_of_products(A(0, 0), A(0, 1), w1, w0);
116 value_type w4 = std::fma(A(0, 2), w2, w3);
120 throw std::runtime_error(
121 std::format(
"math::det is not implemented for {}x{} matrices.",
122 A.extent(0), A.extent(1)));
133template <
typename U,
typename V>
134 requires std::floating_point<typename U::value_type>
137 static_assert(U::rank() == 2,
"Must be rank 2");
138 static_assert(V::rank() == 2,
"Must be rank 2");
140 using value_type =
typename U::value_type;
141 const std::size_t nrows = A.extent(0);
145 B(0, 0) = value_type{1} / A(0, 0);
149 value_type idet = 1. / det(A);
150 B(0, 0) = idet * A(1, 1);
151 B(0, 1) = -idet * A(0, 1);
152 B(1, 0) = -idet * A(1, 0);
153 B(1, 1) = idet * A(0, 0);
158 value_type w0 = difference_of_products(A(1, 1), A(1, 2), A(2, 1), A(2, 2));
159 value_type w1 = difference_of_products(A(1, 0), A(1, 2), A(2, 0), A(2, 2));
160 value_type w2 = difference_of_products(A(1, 0), A(1, 1), A(2, 0), A(2, 1));
161 value_type w3 = difference_of_products(A(0, 0), A(0, 1), w1, w0);
162 value_type det = std::fma(A(0, 2), w2, w3);
164 value_type idet = 1 / det;
167 B(1, 0) = -w1 * idet;
169 B(0, 1) = difference_of_products(A(0, 2), A(0, 1), A(2, 2), A(2, 1)) * idet;
170 B(0, 2) = difference_of_products(A(0, 1), A(0, 2), A(1, 1), A(1, 2)) * idet;
171 B(1, 1) = difference_of_products(A(0, 0), A(0, 2), A(2, 0), A(2, 2)) * idet;
172 B(1, 2) = difference_of_products(A(1, 0), A(0, 0), A(1, 2), A(0, 2)) * idet;
173 B(2, 1) = difference_of_products(A(2, 0), A(0, 0), A(2, 1), A(0, 1)) * idet;
174 B(2, 2) = difference_of_products(A(0, 0), A(1, 0), A(0, 1), A(1, 1)) * idet;
178 throw std::runtime_error(
179 std::format(
"math::inv is not implemented for {}x{} matrices.",
180 A.extent(0), A.extent(1)));
190template <
typename U,
typename V,
typename P>
191 requires scalar<typename U::value_type> && scalar<typename V::value_type>
192 && scalar<typename P::value_type>
193constexpr void dot(U A, V B, P C,
bool transpose =
false)
195 static_assert(U::rank() == 2,
"Must be rank 2");
196 static_assert(V::rank() == 2,
"Must be rank 2");
197 static_assert(P::rank() == 2,
"Must be rank 2");
201 assert(A.extent(0) == B.extent(1));
202 for (std::size_t i = 0; i < A.extent(1); i++)
203 for (std::size_t j = 0; j < B.extent(0); j++)
204 for (std::size_t k = 0; k < A.extent(0); k++)
205 C(i, j) += A(k, i) * B(j, k);
209 assert(A.extent(1) == B.extent(0));
210 for (std::size_t i = 0; i < A.extent(0); i++)
211 for (std::size_t j = 0; j < B.extent(1); j++)
212 for (std::size_t k = 0; k < A.extent(1); k++)
213 C(i, j) += A(i, k) * B(k, j);
225template <
typename U,
typename V>
226 requires std::floating_point<typename U::value_type>
229 static_assert(U::rank() == 2,
"Must be rank 2");
230 static_assert(V::rank() == 2,
"Must be rank 2");
232 assert(A.extent(0) > A.extent(1));
233 assert(P.extent(1) == A.extent(0));
234 assert(P.extent(0) == A.extent(1));
235 using T =
typename U::value_type;
236 if (A.extent(1) == 2)
239 assert(A.extent(0) == 3);
240 std::array<T, 6> ATb;
241 std::array<T, 4> ATAb, Invb;
242 md::mdspan<T, md::extents<std::size_t, 2, 3>> AT(ATb.data(), 2, 3);
243 md::mdspan<T, md::extents<std::size_t, 2, 2>> ATA(ATAb.data(), 2, 2);
244 md::mdspan<T, md::extents<std::size_t, 2, 2>> Inv(Invb.data(), 2, 2);
246 for (std::size_t i = 0; i < AT.extent(0); ++i)
247 for (std::size_t j = 0; j < AT.extent(1); ++j)
250 std::ranges::fill(ATAb, 0.0);
251 for (std::size_t i = 0; i < P.extent(0); ++i)
252 for (std::size_t j = 0; j < P.extent(1); ++j)
260 else if (A.extent(1) == 1)
263 for (std::size_t i = 0; i < A.extent(0); ++i)
264 for (std::size_t j = 0; j < A.extent(1); ++j)
265 res += A(i, j) * A(i, j);
267 for (std::size_t i = 0; i < A.extent(0); ++i)
268 for (std::size_t j = 0; j < A.extent(1); ++j)
269 P(j, i) = (1 / res) * A(i, j);
273 throw std::runtime_error(
274 std::format(
"math::pinv is not implemented for {}x{} matrices.",
275 A.extent(0), A.extent(1)));