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