Dune-Fufem 2.11
Loading...
Searching...
No Matches
tensors.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3
4// SPDX-FileCopyrightText: Copyright © DUNE-FUFEM Project contributors, see file AUTHORS.md
5// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
6
7#ifndef DUNE_FUFEM_FORMS_TENSORS_HH
8#define DUNE_FUFEM_FORMS_TENSORS_HH
9
10#include <array>
11#include <cstddef>
12#include <type_traits>
13#include <utility>
14
18
21
22
23namespace Dune::Fufem::Forms::Impl::Tensor {
24
25
26
27 // Class to tag tensor implementations
28 template<class T>
29 struct IsTensor : public std::false_type
30 {};
31
32 // Class to tag tensor with lazy evaluation
33 template<class T>
34 struct IsLazyTensor : public std::false_type
35 {};
36
37
38
39 // This forwards operator()(i,...) to subsequent operator[](i) calls
40 template<class T, std::size_t k>
41 class TensorView
42 {
43 T& t_;
44
45 static decltype(auto) resolveIndices(auto&& t)
46 {
47 return t;
48 }
49
50 static decltype(auto) resolveIndices(auto&& t, const auto& i0, const auto&... i)
51 {
52 return resolveIndices(t[i0], i...);
53 }
54
55 template<class I, I... i>
56 static decltype(auto) resolveIndexSequence(auto&&t, std::integer_sequence<I, i...>)
57 {
58 return resolveIndices(t, i...);
59 }
60
61 public:
62
64
65 static constexpr Dune::index_constant<k> rank()
66 {
67 return {};
68 }
69
70 TensorView(T& t, Dune::index_constant<k>)
71 : t_(t)
72 {}
73
74 decltype(auto) operator()(const auto&... i) const
75 {
76 return resolveIndices(t_, i...);
77 }
78 };
79
80 template<class T, std::size_t k>
81 struct IsTensor<TensorView<T, k>> : public std::true_type
82 {};
83
84
85
86 // This wraps a T and makes it available using k calls to operator[]
87 template<class T, std::size_t k>
88 requires(k>0)
89 class LiftRank
90 {
91 using RawT = Dune::ResolveRef_t<T>;
92 T t_;
93 public:
94
95 using value_type = typename T::value_type;
96
97 static constexpr Dune::index_constant<RawT::rank()+k> rank()
98 {
99 return {};
100 }
101
102 LiftRank(T t, Dune::index_constant<k>)
103 : t_(t)
104 {}
105
106 template<class I0, class... I>
107 requires (k==1)
108 decltype(auto) operator()(const I0& i0, const I&... i) const
109 {
110 return Dune::resolveRef(t_)(i...);
111 }
112
113 template<class I0, class I1, class... I>
114 requires (k==2)
115 decltype(auto) operator()(const I0& i0, const I1& i1, const I&... i) const
116 {
117 return Dune::resolveRef(t_)(i...);
118 }
119 };
120
121 template<class T, std::size_t k>
122 struct IsTensor<LiftRank<T, k>> : public std::true_type
123 {};
124
125
126
127 // This wraps flips the first k indices between 0 and 1
128 template<class T, std::size_t k>
129 class FlipIndices
130 {
131 using RawT = Dune::ResolveRef_t<T>;
132 T t_;
133 public:
134
135 using value_type = typename RawT::value_type;
136
137 static constexpr Dune::index_constant<RawT::rank()> rank()
138 {
139 return {};
140 }
141
142 FlipIndices(T t, Dune::index_constant<k>)
143 : t_(t)
144 {}
145
146 template<class I0, class... I>
147 requires (k==1)
148 decltype(auto) operator()(const I0& i0, const I&... i) const
149 {
150 return Dune::resolveRef(t_)(not i0, i...);
151 }
152
153 template<class I0, class I1, class... I>
154 requires (k==2)
155 decltype(auto) operator()(const I0& i0, const I1& i1, const I&... i) const
156 {
157 return Dune::resolveRef(t_)(not i0, not i1, i...);
158 }
159 };
160
161 template<class T, std::size_t k>
162 struct IsTensor<FlipIndices<T, k>> : public std::true_type
163 {};
164
165
166
167 template<class Value>
168 class RankZeroTensor
169 {
170 public:
171
172 using value_type = Value;
173
174 static constexpr Dune::index_constant<0> rank()
175 {
176 return {};
177 }
178
179 RankZeroTensor(Value value)
180 : value_(std::move(value))
181 {}
182
183 template<class F>
184 friend void sparseForEach(const RankZeroTensor& tensor, F&& f)
185 {
186 f(tensor.value_);
187 }
188
189 template<class Outer>
190 friend auto compose(const Outer& outer, const RankZeroTensor& inner)
191 {
192 return Dune::Fufem::Forms::Impl::Tensor::RankZeroTensor(outer(inner()));
193 }
194
195 static constexpr std::size_t nnz()
196 {
197 return 1;
198 }
199
200 // Special interface for rank=0
201 const Value& operator()() const
202 {
203 return value_;
204 }
205
206 protected:
207 Value value_;
208 };
209
210 template<class Value>
211 struct IsTensor<RankZeroTensor<Value>> : public std::true_type
212 {};
213
214
215
216 template<std::size_t r, class Value, class ForEach>
217 class SparseTensor
218 {
219 public:
220
221 using value_type = std::decay_t<Value>;
222
223 static constexpr Dune::index_constant<r> rank()
224 {
225 return {};
226 }
227
228 SparseTensor(Dune::index_constant<r>, ForEach forEach, std::size_t nnz, Dune::MetaType<Value>)
229 : forEach_(std::move(forEach))
230 , nnz_(nnz)
231 {}
232
233 template<class F>
234 friend void sparseForEach(const SparseTensor& tensor, F&& f)
235 {
236 tensor.forEach_(f);
237 }
238
239 template<class Outer>
240 friend auto compose(const Outer& outer, const SparseTensor& inner)
241 {
243 return Dune::Fufem::Forms::Impl::Tensor::SparseTensor(
244 inner.rank(),
245 [outer, innerForEach=inner.forEach_](auto&& f) {
246 innerForEach([&](const auto& y_i, auto... i) {
247 f(outer(y_i), i...);
248 });
249 },
250 inner.nnz(),
252 );
253 }
254
255 std::size_t nnz() const
256 {
257 return nnz_;
258 }
259
260 protected:
261 ForEach forEach_;
262 std::size_t nnz_;
263 };
264
265 template<std::size_t r, class Value, class ForEach>
266 struct IsTensor<SparseTensor<r, Value, ForEach>> : public std::true_type
267 {};
268
269 template<std::size_t r, class Value, class ForEach>
270 struct IsLazyTensor<SparseTensor<r, Value, ForEach>> : public std::is_rvalue_reference<Value>
271 {};
272
273
274
275 template<class Product, class T0, class T1>
276 class SparseProductTensor
277 {
278 public:
279
281
282 static constexpr Dune::index_constant<T0::rank() + T1::rank()> rank()
283 {
284 return {};
285 }
286
287 SparseProductTensor(Product product, T0 t0, T1 t1)
288 : product_(std::move(product))
289 , t0_(std::move(t0))
290 , t1_(std::move(t1))
291 {}
292
293 template<class F>
294 friend void sparseForEach(const SparseProductTensor& tensor, F&& f)
295 {
296 using namespace Dune::Indices;
297 if constexpr(T0::rank() == 0)
298 sparseForEach(tensor.t1_, [&](const auto& x1_j, auto... j) {
299 f(tensor.product_(tensor.t0_(), x1_j), j...);
300 });
301 else if constexpr(T1::rank() == 0)
302 sparseForEach(tensor.t0_, [&](const auto& x0_i, auto... i) {
303 f(tensor.product_(x0_i, tensor.t1_()), i...);
304 });
305 else if constexpr((T0::rank() == 2) and (T1::rank() == 2))
306 sparseForEach(tensor.t0_, [&](const auto& x0_i, auto i0, auto i1) {
307 sparseForEach(tensor.t1_, [&](const auto& x1_j, auto j0, auto j1) {
308 f(tensor.product_(x0_i, x1_j), i0, j0, i1, j1);
309 });
310 });
311 }
312
313 template<class Outer>
314 friend auto compose(const Outer& outer, const SparseProductTensor& inner)
315 {
316 using namespace Dune::Indices;
317 return Dune::Fufem::Forms::Impl::Tensor::SparseProductTensor(
318 [outer, innerProduct=inner.product()](const auto&... args) { return outer(innerProduct(args...)); },
319 inner.factor(_0),
320 inner.factor(_1)
321 );
322 }
323
324 std::size_t nnz() const
325 {
326 return t0_.nnz() * t1_.nnz();
327 }
328
329 // Special interface for product tensor
330 const Product& product() const
331 {
332 return product_;
333 }
334
335 template<std::size_t k>
336 const auto& factor(Dune::index_constant<k> = {}) const
337 {
338 if constexpr(k==0)
339 return t0_;
340 else if constexpr(k==1)
341 return t1_;
342 }
343
344 protected:
345 Product product_;
346 T0 t0_;
347 T1 t1_;
348 };
349
350 template<class Product, class T0, class T1>
351 struct IsTensor<SparseProductTensor<Product, T0, T1>> : public std::true_type
352 {};
353
354 template<class Product, class T0, class T1>
355 struct IsLazyTensor<SparseProductTensor<Product, T0, T1>> : public std::true_type
356 {};
357
358
359
360 template<class Product, class X, class Y>
361 requires (IsTensor<X>::value and IsTensor<Y>::value)
362 auto interleavedOuterProduct(Product product, const X& x, const Y& y)
363 {
364 using namespace Dune::Indices;
365 if constexpr((X::rank() == 0) and (Y::rank() == 0))
366 return RankZeroTensor(product(x(), y()));
367 else
368 return SparseProductTensor(product, x, y);
369 }
370
371
372
373 template<class K, std::size_t rank, class Value, class ForEach, class Y>
374 requires(
376 and IsTensor<Y>::value
377 and (rank == Y::rank())
378 )
379 void axpy(const K& alpha, const SparseTensor<rank, Value, ForEach>& x, Y& y)
380 {
381 sparseForEach(x, [&](const auto& xi, auto...i) {
382 y(i...) += Dune::Fufem::asNumber(alpha*xi);
383 });
384 }
385
386 template<class K, class Product, class T0, class T1, class Y>
387 requires(
389 and IsTensor<Y>::value
390 and (SparseProductTensor<Product, T0, T1>::rank() == Y::rank())
391 )
392 void axpy(const K& alpha, const SparseProductTensor<Product, T0, T1>& x, Y& y)
393 {
394 using namespace Dune::Indices;
396 // Since x.product() is a bilinear we can factor out
397 // the multiplication with alpha.
398 if constexpr(T0::rank() == 0)
399 sparseForEach(x.factor(_1), [&](const auto& x1_j, auto... j) {
400 y(j...) += Dune::Fufem::asNumber(x.product()(mult(alpha,x.factor(_0)()), x1_j));
401 });
402 else if constexpr(T1::rank() == 0)
403 sparseForEach(x.factor(_0), [&](const auto& x0_i, auto... i) {
404 y(i...) += Dune::Fufem::asNumber(x.product()(x0_i, mult(alpha,x.factor(_1)())));
405 });
406 else if constexpr((T0::rank() == 2) and (T1::rank() == 2))
407 sparseForEach(x.factor(_0), [&](const auto& x0_i, auto i0, auto i1) {
408 auto x0_i_alpha = mult(x0_i,alpha);
409 sparseForEach(x.factor(_1), [&](const auto& x1_j, auto j0, auto j1) {
410 y(i0, j0, i1, j1) += Dune::Fufem::asNumber(x.product()(x0_i_alpha, x1_j));
411 });
412 });
413 else
414 static_assert((T0::rank() == 2) and (T1::rank() == 2));
415 }
416
417} // namespace Dune::Fufem::Forms::Impl::Tensor
418
419
420
421#endif // DUNE_FUFEM_FORMS_TENSORS_HH
void axpy(const Ta &a, const type &y)
double alpha() const
auto operator()(T &&t) -> decltype(this->apply(t, std::index_sequence_for< Args... >{})) const
constexpr void forEach(Range &&range, F &&f)
constexpr T & resolveRef(T &gf) noexcept
virtual void operator()()=0
T forward(T... args)
auto product(const Op &op, const L &l, const R &r)
Generic exterior product of two multilinear operators.
Definition userfunctions.hh:407
auto compose(const OuterOp &outerOp, const InnerOp &innerOp)
Generic composition of a multilinear operators with a pointwise outer operator.
Definition userfunctions.hh:483
T move(T... args)
const T & asNumber(const T &t)
Forward given value as number.
Definition asnumber.hh:23
STL namespace.
Definition localoperators.hh:397