1#ifndef __DUNE_ACFEM_TENSORS_EXPRESSIONS_HH__
2#define __DUNE_ACFEM_TENSORS_EXPRESSIONS_HH__
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"
10#include "tensorbase.hh"
11#include "expressiontraits.hh"
15#include "operations/einsum.hh"
16#include "operations/reciprocal.hh"
17#include "operationtraits.hh"
19#include "binaryexpression.hh"
20#include "unaryexpression.hh"
30#include "../expressions/usingstd.hh"
31#include "../expressions/usingtyped.hh"
32#include "../expressions/usingpromotion.hh"
33#include "../mpl/usingcomparisons.hh"
44 template<class F, class T, std::enable_if_t<IsTensor<T>::value,
int> = 0>
47 return zeros(TensorTraits<T>::signature(), Disclosure{});
50 template<class T0, class T1, std::enable_if_t<IsTensor<T0>::value && IsTensor<T1>::value,
int> = 0>
51 auto zero(MinusFunctor, T0&&, T1&&)
53 return zeros(TensorTraits<T0>::signature(), Disclosure{});
56 template<
class Seq0,
class Seq1,
class Dims,
class T0,
class T1>
57 auto zero(OperationTraits<EinsumOperation<Seq0, Seq1, Dims> >, T0&&, T1&&)
59 return zeros(EinsumSignature<T0, Seq0, T1, Seq1>{}, Disclosure{});
62 template<
class Seq0,
class Seq1,
class Dims,
class T0,
class T1>
63 auto zero(OperationTraits<TensorProductOperation<Seq0, Seq1, Dims> >, T0&&, T1&&)
65 return zeros(ProductSignature<T0, Seq0, T1, Seq1>{}, Disclosure{});
69 template<class T, std::enable_if_t<Tensor::IsTensor<T>::value,
int> = 0>
72 return Tensor::ConstantTensor<IntFraction<1>, Seq<> >{};
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)
78 return operate(ScalarEinsumFunctor{}, std::forward<T0>(t0), std::forward<T1>(t1));
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)
87 return finalize<PlusOperation>(std::forward<T1>(t1), std::forward<T2>(t2));
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)
93 return finalize<MinusOperation>(std::forward<T1>(t1), std::forward<T2>(t2));
96 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
97 constexpr decltype(
auto)
operator-(T&& t)
99 return finalize<MinusOperation>(std::forward<T>(t));
117 template<std::size_t N, class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value,
int> = 0>
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));
130 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value,
int> = 0>
133 return contractInner<1>(std::forward<T1>(t1), std::forward<T2>(t2));
137 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value,
int> = 0>
140 return einsum<Seq<>, Seq<> >(std::forward<T1>(t1), std::forward<T2>(t2));
144 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
149 return einsum<IndexPositions, IndexPositions>(std::forward<T>(t), eye(TensorTraits<T>::signature()));
153 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value,
int> = 0>
156 static_assert(TensorTraits<T1>::signature() == TensorTraits<T2>::signature(),
157 "Signature of both operands have to match for inner product.");
161 return einsum<IndexPositions, IndexPositions>(std::forward<T1>(t1), std::forward<T2>(t2));
165 template<class Arg, std::enable_if_t<IsProperTensor<Arg>::value,
int> = 0>
169 return einsum<Seq, Seq>(std::forward<Arg>(arg), std::forward<Arg>(arg));
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>()
182 auto operator*(T1&& t1, T2&& t2)
184 return contractInner<1>(std::forward<T1>(t1), std::forward<T2>(t2));
188 template<
class T1,
class T2,
189 std::enable_if_t<(AreProperTensors<T1, T2>::value
190 && TensorTraits<T1>::rank * TensorTraits<T2>::rank == 0
192 auto operator*(T1&& t1, T2&& t2)
194 return einsum<Seq<>, Seq<> >(std::forward<T1>(t1), std::forward<T2>(t2));
198 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value,
int> = 0>
201 return einsum(std::forward<T1>(t1), std::forward<T2>(t2));
205 template<
class T1,
class T2,
206 std::enable_if_t<(AreProperTensors<T1, T2>::value
207 && TensorTraits<T2>::rank == 0
209 auto operator/(T1&& t1, T2&& t2)
211 return std::forward<T1>(t1) * reciprocal(std::forward<T2>(t2));
215 template<
class T1,
class T2,
218 && (IsTensor<T1>::value || IsTensor<T2>::value)
222 static_assert(TensorTraits<T1>::hasMutableComponents,
223 "Destination of assignment must have assignable components.");
225 decltype(
auto) t1_ = tensor(std::forward<T1&>(t1));
226 assign(t1_, tensor(std::forward<T2>(t2)),
227 [](
auto& dst,
auto&& src) {
234 template<
class T1,
class T2,
237 && (IsTensor<T1>::value || IsTensor<T2>::value)
241 static_assert(TensorTraits<T1>::hasMutableComponents,
242 "Destination of assignment must have assignable components.");
244 decltype(
auto) t1_ = tensor(std::forward<T1&>(t1));
245 assign(t1_, tensor(std::forward<T2>(t2)),
246 [](
auto& dst,
auto&& src) {
253 template<
class T1,
class T2,
256 && (IsTensor<T1>::value || IsTensor<T2>::value)
257 && TensorTraits<T2>::rank == 0
261 static_assert(TensorTraits<T1>::hasMutableComponents,
262 "Destination of assignment must have assignable components.");
264 decltype(
auto) t1_ = tensor(std::forward<T1&>(t1));
265 assign(t1_, tensor(std::forward<T2>(t2)),
266 [](
auto& dst,
auto&& src) {
277 template<
class T1,
class T2,
class SFINAE =
void>
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
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
297 constexpr bool operator==(
const T1&,
const T2&)
303 template<
class T1,
class T2,
304 std::enable_if_t<(AreProperTensors<T1, T2>::value
305 && AreRuntimeEqualOperands<T1, T2>::value
307 constexpr bool operator==(
const T1&,
const T2&)
312 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value,
int> = 0>
313 constexpr bool operator!=(T1&& t1, T2&& t2)
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)
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())))) {
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)
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())));
345 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value,
int> = 0>
346 constexpr bool operator==(T1&& t1, T2&& t2)
348 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](
auto&& a,
auto&& b) {
353 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value,
int> = 0>
354 constexpr bool operator<(T1&& t1, T2&& t2)
356 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](
auto&& a,
auto&& b) {
361 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value,
int> = 0>
362 constexpr bool operator<=(T1&& t1, T2&& t2)
364 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](
auto&& a,
auto&& b) {
369 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value,
int> = 0>
370 constexpr bool operator>(T1&& t1, T2&& t2)
372 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](
auto&& a,
auto&& b) {
377 template<class T1, class T2, std::enable_if_t<AreRuntimeComparable<T1, T2>::value,
int> = 0>
378 constexpr bool operator>=(T1&& t1, T2&& t2)
380 return compareHelper(std::forward<T1>(t1), std::forward<T2>(t2), [](
auto&& a,
auto&& b) {
391 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
394 return finalize<SqrtOperation>(std::forward<T>(t));
397 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
400 return finalize<SquareOperation>(std::forward<T>(t));
403 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
406 return finalize<CosOperation>(std::forward<T>(t));
409 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
412 return finalize<SinOperation>(std::forward<T>(t));
415 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
418 return finalize<TanOperation>(std::forward<T>(t));
421 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
424 return finalize<AcosOperation>(std::forward<T>(t));
427 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
430 return finalize<AsinOperation>(std::forward<T>(t));
433 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
436 return finalize<AtanOperation>(std::forward<T>(t));
439 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
442 return finalize<ErfOperation>(std::forward<T>(t));
445 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
448 return finalize<LGammaOperation>(std::forward<T>(t));
451 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
454 return finalize<TGammaOperation>(std::forward<T>(t));
457 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
460 return finalize<ExpOperation>(std::forward<T>(t));
463 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
466 return finalize<LogOperation>(std::forward<T>(t));
469 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
472 return finalize<CoshOperation>(std::forward<T>(t));
475 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
478 return finalize<SinhOperation>(std::forward<T>(t));
481 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
484 return finalize<TanhOperation>(std::forward<T>(t));
487 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
490 return finalize<AcoshOperation>(std::forward<T>(t));
493 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
496 return finalize<AsinhOperation>(std::forward<T>(t));
499 template<class T, std::enable_if_t<IsProperTensor<T>::value,
int> = 0>
502 return finalize<AtanhOperation>(std::forward<T>(t));
505 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value,
int> = 0>
506 auto atan2(T1&& t1, T2&& t2)
508 static_assert(TensorTraits<T1>::signature() == TensorTraits<T2>::signature(),
509 "Tensor signatures must coincide for component-wise operations.");
511 return finalize<Atan2Operation>(std::forward<T1>(t1), std::forward<T2>(t2));
521 std::enable_if_t<(AreProperTensors<T1, T2>::value
522 && TensorTraits<T1>::rank != 0
523 && TensorTraits<T2>::rank == 0
525 auto pow(T1&& t1, T2&& t2)
527 return finalize<PowOperation>(
528 std::forward<T1>(t1),
530 ScalarEinsumFunctor{},
531 std::forward<T2>(t2),
541 std::enable_if_t<(AreProperTensors<T1, T2>::value
542 && TensorTraits<T1>::rank == TensorTraits<T2>::rank
544 auto pow(T1&& t1, T2&& t2)
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));
551 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value,
int> = 0>
552 auto min(T1&& t1, T2&& t2)
554 static_assert(TensorTraits<T1>::signature() == TensorTraits<T2>::signature(),
555 "Tensor signatures must coincide for component-wise operations.");
557 return finalize<MinOperation>(std::forward<T1>(t1), std::forward<T2>(t2));
560 template<class T1, class T2, std::enable_if_t<AreProperTensors<T1, T2>::value,
int> = 0>
561 auto max(T1&& t1, T2&& t2)
563 static_assert(TensorTraits<T1>::signature() == TensorTraits<T2>::signature(),
564 "Tensor signatures must coincide for component-wise operations.");
566 return finalize<MaxOperation>(std::forward<T1>(t1), std::forward<T2>(t2));
570 template<class T1, std::enable_if_t<IsProperTensor<T1>::value,
int> = 0>
571 auto ternary(T1&& t1)
573 return finalize<TernaryOperation>(std::forward<T1>(t1));
581 using Tensor::operator-;
582 using Tensor::operator+;
583 using Tensor::operator*;
584 using Tensor::operator/;
585 using Tensor::operator&;
587 using Tensor::operator==;
588 using Tensor::operator!=;
589 using Tensor::operator>=;
590 using Tensor::operator<=;
591 using Tensor::operator>;
592 using Tensor::operator<;
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
Definition: expressions.hh:280
Definition: tensorbase.hh:117