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