DUNE-ACFEM (unstable)

expressions.hh
1#ifndef __DUNE_ACFEM_TENSORS_EXPRESSIONS_HH__
2#define __DUNE_ACFEM_TENSORS_EXPRESSIONS_HH__
3
4#include "../common/literals.hh"
5#include "../expressions/storage.hh"
6#include "../expressions/expressionoperations.hh"
7#include "../expressions/constantoperations.hh"
8#include "../expressions/operandpromotion.hh"
9
10#include "tensorbase.hh"
11#include "expressiontraits.hh"
12#include "bindings.hh"
13//#include "optimization.hh"
14#include "modules.hh"
15#include "operations/einsum.hh"
16#include "operations/reciprocal.hh"
17#include "operationtraits.hh"
18
19#include "binaryexpression.hh"
20#include "unaryexpression.hh"
21
22namespace Dune {
23
24 namespace ACFem {
25
26 namespace Tensor {
27
28// Suck in using declarations. This is needed as we define operator
29// functions of the same name in our own namespace.
30#include "../expressions/usingstd.hh"
31#include "../expressions/usingtyped.hh"
32#include "../expressions/usingpromotion.hh"
33#include "../mpl/usingcomparisons.hh"
34
44 template<class F, class T, std::enable_if_t<IsTensor<T>::value, int> = 0>
45 auto zero(F&&, T&&)
46 {
47 return zeros(TensorTraits<T>::signature(), Disclosure{});
48 }
49
50 template<class T0, class T1, std::enable_if_t<IsTensor<T0>::value && IsTensor<T1>::value, int> = 0>
51 auto zero(MinusFunctor, T0&&, T1&&)
52 {
53 return zeros(TensorTraits<T0>::signature(), Disclosure{});
54 }
55
56 template<class Seq0, class Seq1, class Dims, class T0, class T1>
57 auto zero(OperationTraits<EinsumOperation<Seq0, Seq1, Dims> >, T0&&, T1&&)
58 {
59 return zeros(EinsumSignature<T0, Seq0, T1, Seq1>{}, Disclosure{});
60 }
61
62 template<class Seq0, class Seq1, class Dims, class T0, class T1>
63 auto zero(OperationTraits<TensorProductOperation<Seq0, Seq1, Dims> >, T0&&, T1&&)
64 {
65 return zeros(ProductSignature<T0, Seq0, T1, Seq1>{}, Disclosure{});
66 }
67
69 template<class T, std::enable_if_t<Tensor::IsTensor<T>::value, int> = 0>
70 auto one(T&&)
71 {
72 return Tensor::ConstantTensor<IntFraction<1>, Seq<> >{};
73 }
74
75 template<class T0, class T1, std::enable_if_t<IsTensor<T0>::value && IsTensor<T1>::value, int> = 0>
76 constexpr auto multiplyScalars(T0&& t0, T1&& t1)
77 {
78 return operate(ScalarEinsumFunctor{}, std::forward<T0>(t0), std::forward<T1>(t1));
79 }
80
82
83
84 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
85 constexpr decltype(auto) operator+(T1&& t1, T2&& t2)
86 {
87 return finalize<PlusOperation>(std::forward<T1>(t1), std::forward<T2>(t2));
88 }
89
90 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
91 constexpr decltype(auto) operator-(T1&& t1, T2&& t2)
92 {
93 return finalize<MinusOperation>(std::forward<T1>(t1), std::forward<T2>(t2));
94 }
95
96 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
97 constexpr decltype(auto) operator-(T&& t)
98 {
99 return finalize<MinusOperation>(std::forward<T>(t));
100 }
101
117 template<std::size_t N, class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
118 constexpr auto contractInner(T1&& t1, T2&& t2, IndexConstant<N> = IndexConstant<N>{})
119 {
121 ==
122 HeadPart<N, typename TensorTraits<T2>::Signature>{},
123 "Tensor signatures have to match for inner product.");
124 using LeftPos = MakeIndexSequence<N, TensorTraits<T1>::rank - N>;
125 using RightPos = MakeIndexSequence<N>;
126 return einsum<LeftPos, RightPos>(std::forward<T1>(t1), std::forward<T2>(t2));
127 }
128
130 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
131 auto contractInner(T1&& t1, T2&& t2)
132 {
133 return contractInner<1>(std::forward<T1>(t1), std::forward<T2>(t2));
134 }
135
137 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
138 auto outer(T1&& t1, T2&& t2)
139 {
140 return einsum<Seq<>, Seq<> >(std::forward<T1>(t1), std::forward<T2>(t2));
141 }
142
144 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
145 constexpr auto trace(T&& t)
146 {
147 using IndexPositions = MakeIndexSequence<TensorTraits<T>::rank>;
148
149 return einsum<IndexPositions, IndexPositions>(std::forward<T>(t), eye(TensorTraits<T>::signature()));
150 }
151
153 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
154 auto inner(T1&& t1, T2&& t2)
155 {
156 static_assert(TensorTraits<T1>::signature() == TensorTraits<T2>::signature(),
157 "Signature of both operands have to match for inner product.");
158
159 using IndexPositions = MakeIndexSequence<TensorTraits<T1>::rank>;
160
161 return einsum<IndexPositions, IndexPositions>(std::forward<T1>(t1), std::forward<T2>(t2));
162 }
163
165 template<class Arg, std::enable_if_t<IsProperTensor<Arg>::value, int> = 0>
166 constexpr auto frobenius2(Arg&& arg)
167 {
169 return einsum<Seq, Seq>(std::forward<Arg>(arg), std::forward<Arg>(arg));
170 }
171
176 template<class T1, class T2,
177 std::enable_if_t<(AreProperTensors<T1, T2>::value
178 && TensorTraits<T1>::rank > 0
179 && TensorTraits<T2>::rank > 0
180 && TensorTraits<T1>::template dim<TensorTraits<T1>::rank - 1>() == TensorTraits<T2>::template dim<0>()
181 ), int> = 0>
182 auto operator*(T1&& t1, T2&& t2)
183 {
184 return contractInner<1>(std::forward<T1>(t1), std::forward<T2>(t2));
185 }
186
188 template<class T1, class T2,
189 std::enable_if_t<(AreProperTensors<T1, T2>::value
190 && TensorTraits<T1>::rank * TensorTraits<T2>::rank == 0
191 ), int> = 0>
192 auto operator*(T1&& t1, T2&& t2)
193 {
194 return einsum<Seq<>, Seq<> >(std::forward<T1>(t1), std::forward<T2>(t2));
195 }
196
198 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
199 auto operator&(T1&& t1, T2&& t2)
200 {
201 return einsum(std::forward<T1>(t1), std::forward<T2>(t2));
202 }
203
205 template<class T1, class T2,
206 std::enable_if_t<(AreProperTensors<T1, T2>::value
207 && TensorTraits<T2>::rank == 0
208 ), int> = 0>
209 auto operator/(T1&& t1, T2&& t2)
210 {
211 return std::forward<T1>(t1) * reciprocal(std::forward<T2>(t2));
212 }
213
215 template<class T1, class T2,
216 std::enable_if_t<(IsTensorOperand<T1>::value
218 && (IsTensor<T1>::value || IsTensor<T2>::value)
219 ), int> = 0>
220 T1& operator+=(T1& t1, T2&& t2)
221 {
222 static_assert(TensorTraits<T1>::hasMutableComponents,
223 "Destination of assignment must have assignable components.");
224
225 decltype(auto) t1_ = tensor(std::forward<T1&>(t1));
226 assign(t1_, tensor(std::forward<T2>(t2)),
227 [](auto& dst, auto&& src) {
228 dst += src;
229 });
230 return t1;
231 }
232
234 template<class T1, class T2,
235 std::enable_if_t<(IsTensorOperand<T1>::value
237 && (IsTensor<T1>::value || IsTensor<T2>::value)
238 ), int> = 0>
239 T1& operator-=(T1& t1, T2&& t2)
240 {
241 static_assert(TensorTraits<T1>::hasMutableComponents,
242 "Destination of assignment must have assignable components.");
243
244 decltype(auto) t1_ = tensor(std::forward<T1&>(t1));
245 assign(t1_, tensor(std::forward<T2>(t2)),
246 [](auto& dst, auto&& src) {
247 dst -= src;
248 });
249 return t1;
250 }
251
253 template<class T1, class T2,
254 std::enable_if_t<(IsTensorOperand<T1>::value
256 && (IsTensor<T1>::value || IsTensor<T2>::value)
257 && TensorTraits<T2>::rank == 0
258 ), int> = 0>
259 T1& operator*=(T1& t1, T2&& t2)
260 {
261 static_assert(TensorTraits<T1>::hasMutableComponents,
262 "Destination of assignment must have assignable components.");
263
264 decltype(auto) t1_ = tensor(std::forward<T1&>(t1));
265 assign(t1_, tensor(std::forward<T2>(t2)),
266 [](auto& dst, auto&& src) {
267 dst *= src;
268 });
269 return t1;
270 }
271
277 template<class T1, class T2, class SFINAE = void>
279 : FalseType
280 {};
281
282 template<class T1, class T2>
284 T1, T2, std::enable_if_t<(AreProperTensors<T1, T2>::value
285 && !AreRuntimeEqualOperands<T1, T2>::value
286 && std::is_same<typename std::decay_t<T1>::Signature, typename std::decay_t<T2>::Signature>::value
287 )> >
288 : TrueType
289 {};
290
292 template<class T1, class T2,
293 std::enable_if_t<(AreProperTensors<T1, T2>::value
294 && !std::is_same<typename std::decay_t<T1>::Signature,
295 typename std::decay_t<T2>::Signature>::value
296 ), int> = 0>
297 constexpr bool operator==(const T1&, const T2&)
298 {
299 return false;
300 }
301
303 template<class T1, class T2,
304 std::enable_if_t<(AreProperTensors<T1, T2>::value
305 && AreRuntimeEqualOperands<T1, T2>::value
306 ), int> = 0>
307 constexpr bool operator==(const T1&, const T2&)
308 {
309 return true;
310 }
311
312 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
313 constexpr bool operator!=(T1&& t1, T2&& t2)
314 {
315 return !(t1 == t2);
316 }
317
318 namespace {
319
320 template<class T1, class T2, class F,
321 std::enable_if_t<(std::decay_t<T1>::dim() > Policy::TemplateForEachLimit::value), int> = 0>
322 constexpr bool compareHelper(T1&& t1, T2&& t2, F&& f)
323 {
324 for (unsigned i = 0; i < TensorTraits<T1>::dim(); ++i) {
325 if (!f(tensorValue(t1, multiIndex(i, TensorTraits<T1>::signature())), tensorValue(t2, multiIndex(i, TensorTraits<T2>::signature())))) {
326 return false;
327 }
328 }
329 return true;
330 }
331
332 template<class T1, class T2, class F,
333 std::enable_if_t<std::decay_t<T1>::dim() <= Policy::TemplateForEachLimit::value, int> = 0>
334 constexpr bool compareHelper(T1&& t1, T2&& t2, F&& f)
335 {
336 return forEachWhile(MakeIndexSequence<TensorTraits<T1>::dim()>{}, [&](auto i) {
337 using I = decltype(i);
338 return f(tensorValue(t1, multiIndex<I::value>(TensorTraits<T1>::signature())),
339 tensorValue(t2, multiIndex<I::value>(TensorTraits<T2>::signature())));
340 });
341 }
342
343 } // NS anonymous
344
345 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value, int> = 0>
346 constexpr bool operator==(T1&& t1, T2&& t2)
347 {
348 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](auto&& a, auto&& b) {
349 return a == b;
350 });
351 }
352
353 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value, int> = 0>
354 constexpr bool operator<(T1&& t1, T2&& t2)
355 {
356 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](auto&& a, auto&& b) {
357 return a < b;
358 });
359 }
360
361 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value, int> = 0>
362 constexpr bool operator<=(T1&& t1, T2&& t2)
363 {
364 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](auto&& a, auto&& b) {
365 return a <= b;
366 });
367 }
368
369 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value, int> = 0>
370 constexpr bool operator>(T1&& t1, T2&& t2)
371 {
372 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](auto&& a, auto&& b) {
373 return a > b;
374 });
375 }
376
377 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value, int> = 0>
378 constexpr bool operator>=(T1&& t1, T2&& t2)
379 {
380 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](auto&& a, auto&& b) {
381 return a >= b;
382 });
383 }
384
386
391 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
392 auto sqrt(T&& t)
393 {
394 return finalize<SqrtOperation>(std::forward<T>(t));
395 }
396
397 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
398 auto sqr(T&& t)
399 {
400 return finalize<SquareOperation>(std::forward<T>(t));
401 }
402
403 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
404 auto cos(T&& t)
405 {
406 return finalize<CosOperation>(std::forward<T>(t));
407 }
408
409 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
410 auto sin(T&& t)
411 {
412 return finalize<SinOperation>(std::forward<T>(t));
413 }
414
415 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
416 auto tan(T&& t)
417 {
418 return finalize<TanOperation>(std::forward<T>(t));
419 }
420
421 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
422 auto acos(T&& t)
423 {
424 return finalize<AcosOperation>(std::forward<T>(t));
425 }
426
427 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
428 auto asin(T&& t)
429 {
430 return finalize<AsinOperation>(std::forward<T>(t));
431 }
432
433 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
434 auto atan(T&& t)
435 {
436 return finalize<AtanOperation>(std::forward<T>(t));
437 }
438
439 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
440 auto erf(T&& t)
441 {
442 return finalize<ErfOperation>(std::forward<T>(t));
443 }
444
445 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
446 auto lgamma(T&& t)
447 {
448 return finalize<LGammaOperation>(std::forward<T>(t));
449 }
450
451 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
452 auto tgamma(T&& t)
453 {
454 return finalize<TGammaOperation>(std::forward<T>(t));
455 }
456
457 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
458 auto exp(T&& t)
459 {
460 return finalize<ExpOperation>(std::forward<T>(t));
461 }
462
463 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
464 auto log(T&& t)
465 {
466 return finalize<LogOperation>(std::forward<T>(t));
467 }
468
469 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
470 auto cosh(T&& t)
471 {
472 return finalize<CoshOperation>(std::forward<T>(t));
473 }
474
475 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
476 auto sinh(T&& t)
477 {
478 return finalize<SinhOperation>(std::forward<T>(t));
479 }
480
481 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
482 auto tanh(T&& t)
483 {
484 return finalize<TanhOperation>(std::forward<T>(t));
485 }
486
487 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
488 auto acosh(T&& t)
489 {
490 return finalize<AcoshOperation>(std::forward<T>(t));
491 }
492
493 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
494 auto asinh(T&& t)
495 {
496 return finalize<AsinhOperation>(std::forward<T>(t));
497 }
498
499 template<class T, std::enable_if_t<IsProperTensor<T>::value, int> = 0>
500 auto atanh(T&& t)
501 {
502 return finalize<AtanhOperation>(std::forward<T>(t));
503 }
504
505 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
506 auto atan2(T1&& t1, T2&& t2)
507 {
508 static_assert(TensorTraits<T1>::signature() == TensorTraits<T2>::signature(),
509 "Tensor signatures must coincide for component-wise operations.");
510
511 return finalize<Atan2Operation>(std::forward<T1>(t1), std::forward<T2>(t2));
512 }
513
519 template<
520 class T1, class T2,
521 std::enable_if_t<(AreProperTensors<T1, T2>::value
522 && TensorTraits<T1>::rank != 0
523 && TensorTraits<T2>::rank == 0
524 ), int> = 0>
525 auto pow(T1&& t1, T2&& t2)
526 {
527 return finalize<PowOperation>(
528 std::forward<T1>(t1),
529 operate(
530 ScalarEinsumFunctor{},
531 std::forward<T2>(t2),
532 asExpression(ones<T1>()))
533 );
534 }
535
539 template<
540 class T1, class T2,
541 std::enable_if_t<(AreProperTensors<T1, T2>::value
542 && TensorTraits<T1>::rank == TensorTraits<T2>::rank
543 ), int> = 0>
544 auto pow(T1&& t1, T2&& t2)
545 {
546 static_assert(TensorTraits<T1>::signature() == TensorTraits<T2>::signature(),
547 "Tensor signatures must coincide for component-wise operations.");
548 return finalize<PowOperation>(std::forward<T1>(t1), std::forward<T2>(t2));
549 }
550
551 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
552 auto min(T1&& t1, T2&& t2)
553 {
554 static_assert(TensorTraits<T1>::signature() == TensorTraits<T2>::signature(),
555 "Tensor signatures must coincide for component-wise operations.");
556
557 return finalize<MinOperation>(std::forward<T1>(t1), std::forward<T2>(t2));
558 }
559
560 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
561 auto max(T1&& t1, T2&& t2)
562 {
563 static_assert(TensorTraits<T1>::signature() == TensorTraits<T2>::signature(),
564 "Tensor signatures must coincide for component-wise operations.");
565
566 return finalize<MaxOperation>(std::forward<T1>(t1), std::forward<T2>(t2));
567 }
568
569 //If, then else construct
570 template<class T1, std::enable_if_t<IsProperTensor<T1>::value, int> = 0>
571 auto ternary(T1&& t1)
572 {
573 return finalize<TernaryOperation>(std::forward<T1>(t1));
574 }
575
577
578 } // NS Tensor
579
580#if 1
581 using Tensor::operator-;
582 using Tensor::operator+;
583 using Tensor::operator*;
584 using Tensor::operator/;
585 using Tensor::operator&;
586
587 using Tensor::operator==;
588 using Tensor::operator!=;
589 using Tensor::operator>=;
590 using Tensor::operator<=;
591 using Tensor::operator>;
592 using Tensor::operator<;
593#endif
594
596
598
599 } // NS ACFem
600
601} // NS Dune
602
603#endif // __DUNE_ACFEM_TENSORS_EXPRESSIONS_HH__
constexpr decltype(auto) asExpression(T &&t)
Return a non-closure expression as is.
Definition: interface.hh:122
constexpr auto one(T &&t)
Use the one fraction as canonical zero element for scalars.
Definition: constantoperations.hh:88
constexpr auto zero(T &&t)
Use the zero fraction as canonical zero element for scalars.
Definition: constantoperations.hh:80
constexpr bool forEachWhile(F &&f, IndexSequence< I... >=IndexSequence< I... >{})
Repeat until F returns false.
Definition: foreach.hh:77
auto & assign(T1 &t1, T2 &&t2)
Assign one tuple-alike to another by looping over the elements.
Definition: assign.hh:40
typename GetTailPartHelper< Seq::size() -Cnt, Seq >::Type TailPart
Extract Cnt many consecutive elements from the end of Seq.
Definition: access.hh:221
MakeSequence< std::size_t, N, Offset, Stride, Repeat > MakeIndexSequence
Make a sequence of std::size_t elements.
Definition: generators.hh:34
T1 & operator-=(T1 &t1, T2 &&t2)
operator-=() with generic tensors.
Definition: expressions.hh:239
auto operator&(T1 &&t1, T2 &&t2)
Greedy contraction over all leading matching dimensions.
Definition: expressions.hh:199
auto contractInner(T1 &&t1, T2 &&t2)
Inner product w.r.t.
Definition: expressions.hh:131
T1 & operator*=(T1 &t1, T2 &&t2)
operator*=() with rank-0 tensors.
Definition: expressions.hh:259
constexpr auto trace(T &&t)
Trace is the contraction over all indices with the eye tensor.
Definition: expressions.hh:145
auto inner(T1 &&t1, T2 &&t2)
"scalar product"
Definition: expressions.hh:154
auto outer(T1 &&t1, T2 &&t2)
Outer tensor product.
Definition: expressions.hh:138
constexpr auto frobenius2(Arg &&arg)
Square of Frobenius norm.
Definition: expressions.hh:166
T1 & operator+=(T1 &t1, T2 &&t2)
operator+=() with generic tensors.
Definition: expressions.hh:220
auto pow(T1 &&t1, T2 &&t2)
Power operations with scalar exponents are promoted to component-wise power operations by multiplying...
Definition: expressions.hh:525
constexpr decltype(auto) einsum(T1 &&t1, T2 &&t2)
Tensor contraction for proper tensors.
Definition: einsum.hh:561
Constant< std::size_t, V > IndexConstant
Short-cut for integral constant of type std::size_t.
Definition: types.hh:44
BoolConstant< false > FalseType
Alias for std::false_type.
Definition: types.hh:110
BoolConstant< true > TrueType
Alias for std::true_type.
Definition: types.hh:107
constexpr auto multiIndex(IndexSequence< Dims... >, IndexConstant< I >=IndexConstant< I >{})
Generate the multi-index corresponding to the flattened index I where the multiindex varies between t...
Definition: multiindex.hh:60
STL namespace.
Definition: expressions.hh:280
Definition: tensorbase.hh:117
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)