DUNE-ACFEM (unstable)

operationtraits.hh
1 #ifndef __DUNE_ACFEM_TENSORS_OPERATIONTRAITS_HH__
2 #define __DUNE_ACFEM_TENSORS_OPERATIONTRAITS_HH__
3 
6 #include "../mpl/compare.hh"
7 #include "../expressions/storage.hh"
8 #include "../expressions/expressionoperations.hh"
9 #include "expressionoperations.hh"
10 #include "operations/einsum.hh"
11 #include "operations/product.hh"
12 #include "operations/restriction.hh"
13 #include "operations/transpose.hh"
14 
15 namespace Dune {
16 
17  namespace ACFem {
18 
34  template<std::size_t... Dims, std::size_t... PivotIndices>
35  struct OperationTraits<RestrictionOperation<IndexSequence<Dims...>, IndexSequence<PivotIndices...> > >
36  {
37  static_assert(sizeof...(Dims) == sizeof...(PivotIndices),
38  "Size of pivot indices must match size of co-dimension.");
39 
40  using PivotSequence = IndexSequence<PivotIndices...>;
41  using InvertibleOperation = void; // restrictions are not invertible
42  using OperationType = RestrictionOperation<IndexSequence<Dims...>, PivotSequence>;
43 
44  template<class T, class SFINAE = void>
45  struct HasOperation
46  : FalseType
47  {
48  // assume elementary type if no restriction operation is defined.
49  using ResultType = T;
50  };
51 
52  template<class T>
53  struct HasOperation<T, std::enable_if_t<(sizeof(decltype(restriction<Dims...>(std::declval<T>(), PivotSequence{}))) >= 0)> >
54  : TrueType
55  {
56  using ResultType = std::decay_t<decltype(restriction<Dims...>(std::declval<T>(), PivotSequence{}))>;
57  };
58 
59  template<class T>
60  using ResultType = typename HasOperation<T>::ResultType;
61 
62  // Assuming only real numbers.
63  template<class Sign>
64  static constexpr auto signPropagation(const Sign&)
65  {
66  return Sign{};
67  }
68 
69  static std::string name()
70  {
71  return "rst<"+toString(IndexSequence<Dims...>{})+"@"+toString(PivotSequence{})+">";
72  }
73 
74  template<class Order>
75  static constexpr auto polynomialOrder(Order oldOrder)
76  {
77  return oldOrder;
78  }
79 
80  template<class T, class... Rest, std::enable_if_t<HasOperation<T>::value, int> = 0>
81  auto operator()(T&& t, Rest&&...) const
82  {
83  return restriction<Dims...>(std::forward<T>(t), PivotSequence{});
84  }
85 
86  template<class T, class... Rest, std::enable_if_t<!HasOperation<T>::value, int> = 0>
87  constexpr decltype(auto) operator()(T&& t, Rest&&...) const
88  {
89  return std::forward<T>(t);
90  }
91 
92  using PivotType = PivotSequence;
93  PivotType pivotIndices_;
94  };
95 
96  template<std::size_t... Dims>
97  struct OperationTraits<RestrictionOperation<IndexSequence<Dims...>, IndexSequence<> > >
98  {
99  private:
100  using ThisType = OperationTraits;
101  public:
102  using InvertibleOperation = void; // restrictions are not invertible
103  using OperationType = RestrictionOperation<IndexSequence<Dims...>, IndexSequence<> >;
104 
105  OperationTraits()
106  : pivotIndices_({{}})
107  {}
108 
109  OperationTraits(const OperationTraits& other)
110  : pivotIndices_(other.pivotIndices_)
111  {}
112 
113  OperationTraits(OperationTraits&& other)
114  : pivotIndices_(std::move(other.pivotIndices_))
115  {}
116 
117  template<class List, std::size_t... I, std::enable_if_t<IsTupleLike<List>::value, int> = 0>
118  OperationTraits(const List& l, IndexSequence<I...>)
119  : pivotIndices_({{ (IndexType)get<I>(l)... }})
120  {}
121 
122  template<class List, std::enable_if_t<IsTupleLike<List>::value, int> = 0>
123  OperationTraits(const List& l)
124  : OperationTraits(l, MakeSequenceFor<List>{})
125  {}
126 
127  template<class T, std::size_t N, std::size_t... I>
128  OperationTraits(const T (&l)[N], IndexSequence<I...>)
129  : pivotIndices_({{ (IndexType)get<I>(l)... }})
130  {}
131 
132  template<class I, std::size_t N>
133  OperationTraits(const I (&l)[N])
134  : OperationTraits(l, MakeIndexSequence<N>{})
135  {}
136 
137  template<class T, class SFINAE = void>
138  struct HasOperation
139  : FalseType
140  {
141  // assume elementary type if no restriction operation is defined.
142  using ResultType = T;
143  };
144 
145  template<class T>
146  struct HasOperation<T, std::enable_if_t<sizeof(decltype(restriction<Dims...>(std::declval<T>()))) >= 0> >
147  : TrueType
148  {
149  using ResultType = std::decay_t<decltype(restriction<Dims...>(std::declval<T>()))>;
150  };
151 
152  template<class T>
153  using ResultType = typename HasOperation<T>::ResultType;
154 
155  // Assuming only real numbers.
156  template<class Sign>
157  static constexpr auto signPropagation(const Sign&)
158  {
159  return Sign{};
160  }
161 
162  std::string name() const
163  {
164  return "rst<"+toString(IndexSequence<Dims...>{})+"@["+toString(pivotIndices_)+"]>";
165  }
166 
167  template<class Order>
168  static constexpr auto polynomialOrder(Order oldOrder)
169  {
170  return oldOrder;
171  }
172 
173  public:
174  template<class T, class... Rest, std::enable_if_t<HasOperation<T>::value, int> = 0>
175  constexpr auto operator()(T&& t, Rest&&...) const
176  {
177  return restriction<Dims...>(std::forward<T>(t), pivotIndices_);
178  }
179 
180  template<class T, class... Rest, std::enable_if_t<!HasOperation<T>::value, int> = 0>
181  constexpr decltype(auto) operator()(T&& t, Rest&&...) const
182  {
183  return std::forward<T>(t);
184  }
185 
186  using IndexType = unsigned;
187  using PivotType = std::array<IndexType, sizeof...(Dims)>;
188  PivotType pivotIndices_;
189  };
190 
192 
198  template<class Perm>
199  struct OperationTraits<TransposeOperation<Perm> >
200  {
203 
204  template<class T, class SFINAE = void>
205  struct HasOperation
206  : FalseType
207  {
208  // assume elementary type if no restriction operation is defined.
209  using ResultType = T;
210  };
211 
212  template<class T>
213  struct HasOperation<T, VoidType<decltype(transpose(std::declval<T>(), Perm{}))> >
214  : TrueType
215  {
216  using ResultType = std::decay_t<decltype(transpose(std::declval<T>(), Perm{}))>;
217  };
218 
219  // Assuming only real numbers.
220  template<class Sign>
221  static constexpr auto signPropagation(const Sign&)
222  {
223  return Sign{};
224  }
225 
226  static std::string name()
227  {
228  return "tr<"+toString(Perm{})+">";
229  }
230 
231  template<class Order>
232  static constexpr auto polynomialOrder(Order oldOrder)
233  {
234  return oldOrder;
235  }
236 
237  template<class T>
238  auto operator()(T&& t) const
239  {
240  return transpose(std::forward<T>(t), Perm{});
241  }
242 
243  template<class T, std::enable_if_t<!HasOperation<T>::value, int> = 0>
244  constexpr decltype(auto) operator()(T&& t) const
245  {
246 #if 0
247  if (!IsScalar<T>::value) {
248  std::clog << "no transpose " << toString(Perm{}) << " for " << t.name() << std::endl;
249  }
250 #endif
251  assert(IsScalar<T>::value);
252  return std::forward<T>(t);
253  }
254  };
255 
257 
262  template<class Sig>
263  struct OperationTraits<ReshapeOperation<Sig> >
264  {
265  using InvertibleOperation = void;
267 
268  template<class T, class SFINAE = void>
269  struct HasOperation
270  : FalseType
271  {
272  // assume elementary type if no restriction operation is defined.
273  using ResultType = T;
274  };
275 
276  template<class T>
277  struct HasOperation<T, VoidType<decltype(reshape(std::declval<T>(), Sig{}))> >
278  : TrueType
279  {
280  using ResultType = std::decay_t<decltype(reshape(std::declval<T>(), Sig{}))>;
281  };
282 
283  // Assuming only real numbers.
284  template<class Sign>
285  static constexpr auto signPropagation(const Sign&)
286  {
287  return Sign{};
288  }
289 
290  static std::string name()
291  {
292  return "reshape<"+toString(Sig{})+">";
293  }
294 
295  template<class Order>
296  static constexpr auto polynomialOrder(Order oldOrder)
297  {
298  return oldOrder;
299  }
300 
301  template<class T>
302  auto operator()(T&& t) const
303  {
304  return reshape(std::forward<T>(t), Sig{});
305  }
306 
307  template<class T, std::enable_if_t<!HasOperation<T>::value, int> = 0>
308  constexpr decltype(auto) operator()(T&& t) const
309  {
310  assert(IsScalar<T>::value);
311  return std::forward<T>(t);
312  }
313  };
314 
316 
329  template<class Pos1, class Pos2, class Dims>
330  struct OperationTraits<EinsumOperation<Pos1, Pos2, Dims> >
331  {
332  static_assert(Pos1::size() == Pos2::size() && Pos2::size() == Dims::size(),
333  "Number of contraction indices must coincide for Einstein-summation.");
334 
335  using InvertibleOperation = void;
337 
338  using LeftIndexPositions = Pos1;
339  using RightIndexPositions = Pos2;
340  using Dimensions = Dims;
341 
342  template<class T0, class T1>
344  SequenceSliceComplement<typename TensorTraits<T1>::Signature, RightIndexPositions> >;
345 
346  static constexpr Dimensions dimensions()
347  {
348  return Dimensions{};
349  }
350 
351  static constexpr std::size_t contractionDimension()
352  {
353  return prod(dimensions());
354  }
355 
356  template<class T1, class T2, class SFINAE = void>
357  struct HasOperation
358  : FalseType
359  {
360  // assume elementary type if no restriction operation is defined.
361  using ResultType = std::decay_t<decltype(std::declval<T1>() * std::declval<T2>())>;
362  };
363 
364  template<class T1, class T2>
365  struct HasOperation<T1, T2, VoidType<decltype(einsum<Pos1, Pos2>(std::declval<T1>(), std::declval<T2>()))> >
366  : TrueType
367  {
368  using ResultType = std::decay_t<decltype(einsum<Pos1, Pos2>(std::declval<T1>(), std::declval<T2>()))>;
369  };
370 
371  template<class T1, class T2>
372  using ResultType = typename HasOperation<T1, T2>::ResultType;
373 
374  template<class Order1, class Order2>
375  static constexpr auto polynomialOrder(Order1 order1, Order2 order2)
376  {
377  return order1 + order2;
378  }
379 
380  static constexpr std::size_t dim = Prod<Dims>::value;
381 
382  // in arbitraty dimension this is a scalar product, hence the
383  // nonZero property need not be maintained.
384  template<class S1, class S2>
385  static constexpr auto signPropagation(const S1&, const S2&)
386  {
387  return ExpressionSign<// non-singular
388  (dim == 1
389  &&
390  S1::isNonSingular && S2::isNonSingular
391  &&
392  (((S1::reference >= 0) && S1::isSemiPositive)
393  ||
394  ((S1::reference <= 0) && S1::isSemiNegative))
395  &&
396  (((S2::reference >= 0) && S2::isSemiPositive)
397  ||
398  ((S2::reference <= 0) && S2::isSemiNegative))),
399  // >= dim * S1::reference * S2::reference
400  ((S1::reference*S2::reference >= 0)
401  &&
402  ((S1::isSemiPositive && S2::isSemiPositive)
403  ||
404  (S1::isSemiNegative && S2::isSemiNegative))),
405  // <= dim * S1::reference * S2::reference
406  ((S1::reference*S2::reference <= 0)
407  &&
408  ((S1::isSemiPositive && S2::isSemiNegative)
409  ||
410  (S1::isSemiNegative && S2::isSemiPositive))),
411  // new reference
412  dim * S1::reference * S2::reference>{};
413  }
414 
415  static std::string name()
416  {
417  return "*"+(Pos1::size() > 0 ? "["+toString(Pos1{})+"]["+toString(Pos2{})+"]" : "");
418  }
419 
420  template<class T1, class T2, std::enable_if_t<HasOperation<T1, T2>::value, int> = 0>
421  constexpr auto operator()(T1&& t1, T2&& t2) const
422  {
423  return einsum<Pos1, Pos2>(std::forward<T1>(t1), std::forward<T2>(t2));
424  }
425 
426  // degenerate to ordinary product for elementary operands
427  template<class T1, class T2, std::enable_if_t<!HasOperation<T1, T2>::value, int> = 0>
428  constexpr auto operator()(T1&& t1, T2&& t2) const
429  {
430  return std::forward<T1>(t1) * std::forward<T2>(t2);
431  }
432  };
433 
435 
448  template<class Pos1, class Pos2, class Dims>
449  struct OperationTraits<TensorProductOperation<Pos1, Pos2, Dims> >
450  {
451  static_assert(Pos1::size() == Pos2::size() && Pos2::size() == Dims::size(),
452  "Number of contraction indices must coincide for product operation.");
453 
454  using InvertibleOperation = void;
456 
457  using LeftIndexPositions = Pos1;
458  using RightIndexPositions = Pos2;
459  using Dimensions = Dims;
460 
461  template<class T1, class T2, class SFINAE = void>
462  struct HasOperation
463  : FalseType
464  {
465  // assume elementary type if no restriction operation is defined.
466  using ResultType = std::decay_t<decltype(std::declval<T1>() * std::declval<T2>())>;
467  };
468 
469  template<class T1, class T2>
470  struct HasOperation<T1, T2, std::enable_if_t<(sizeof(decltype(multiply<Pos1, Pos2>(std::declval<T1>(), std::declval<T2>()))) >= 0)> >
471  : TrueType
472  {
473  using ResultType = std::decay_t<decltype(multiply<Pos1, Pos2>(std::declval<T1>(), std::declval<T2>()))>;
474  };
475 
476  template<class T1, class T2>
477  using ResultType = typename HasOperation<T1, T2>::ResultType;
478 
479  template<class Order1, class Order2>
480  static constexpr auto polynomialOrder(Order1 order1, Order2 order2)
481  {
482  return order1 + order2;
483  }
484 
485  static constexpr std::size_t dim = 1; // pointwise, no summation
486 
487  // in arbitraty dimension this is a scalar product, hence the
488  // nonZero property need not be maintained.
489  template<class S1, class S2>
490  static constexpr auto signPropagation(const S1&, const S2&)
491  {
492  return ExpressionSign<// non-singular
493  (dim == 1
494  &&
495  S1::isNonSingular && S2::isNonSingular
496  &&
497  (((S1::reference >= 0) && S1::isSemiPositive)
498  ||
499  ((S1::reference <= 0) && S1::isSemiNegative))
500  &&
501  (((S2::reference >= 0) && S2::isSemiPositive)
502  ||
503  ((S2::reference <= 0) && S2::isSemiNegative))),
504  // >= dim * S1::reference * S2::reference
505  ((S1::reference*S2::reference >= 0)
506  &&
507  ((S1::isSemiPositive && S2::isSemiPositive)
508  ||
509  (S1::isSemiNegative && S2::isSemiNegative))),
510  // <= dim * S1::reference * S2::reference
511  ((S1::reference*S2::reference <= 0)
512  &&
513  ((S1::isSemiPositive && S2::isSemiNegative)
514  ||
515  (S1::isSemiNegative && S2::isSemiPositive))),
516  // new reference
517  dim * S1::reference * S2::reference>{};
518  }
519 
520  static std::string name()
521  {
522  return "."+(Pos1::size() > 0 ? "["+toString(Pos1{})+"]["+toString(Pos2{})+"]" : "");
523  }
524 
525  template<class T1, class T2>
526  auto operator()(T1&& t1, T2&& t2) const
527  {
528  return multiply<Pos1, Pos2>(std::forward<T1>(t1), std::forward<T2>(t2));
529  }
530 
531  // degenerate to ordinary product for elementary operands
532  template<class T1, class T2, std::enable_if_t<!HasOperation<T1, T2>::value, int> = 0>
533  constexpr auto operator()(T1&& t1, T2&& t2) const
534  {
535  return std::forward<T1>(t1) * std::forward<T2>(t2);
536  }
537  };
538 
539  template<class T>
540  struct SquareTraits<T, std::enable_if_t<(HasTensorTraitsV<T> && TensorTraits<T>::rank > 0)> >
541  {
542  using ExplodeFunctor = OperationTraits<
546  typename TensorTraits<T>::Signature>
547  >;
548  };
549 
550  template<class T>
551  struct SquareTraits<T, std::enable_if_t<(HasTensorTraitsV<T> && TensorTraits<T>::rank == 0)> >
552  {
553  using ExplodeFunctor = Tensor::ScalarEinsumFunctor;
554  };
555 
557 
559 
561 
562  } // NS ACFem
563 
564 } // NS Dune
565 
566 #endif // __DUNE_ACFEM_TENSORS_OPERATIONTRAITS_HH__
constexpr std::size_t size()
Gives the number of elements in tuple-likes and std::integer_sequence.
Definition: size.hh:73
MakeIndexSequence< size< T >()> MakeSequenceFor
Make a simple index sequence of the size of the argument, which may be anything for which size<T>() e...
Definition: generators.hh:41
MakeSequence< std::size_t, N, Offset, Stride, Repeat > MakeIndexSequence
Make a sequence of std::size_t elements.
Definition: generators.hh:34
typename SequenceCatHelper2< S... >::Type SequenceCat
Concatenate the given sequences, in order, to <S0, S1, ...
Definition: transform.hh:220
auto restriction(T &&t, Indices &&indices, Seq< IndexPositions... >=Seq< IndexPositions... >{})
Generate a compile-time dynamic restriction with position given from a tuple-like object.
Definition: operandpromotion.hh:241
constexpr decltype(auto) einsum(T1 &&t1, T2 &&t2)
Tensor contraction for proper tensors.
Definition: einsum.hh:561
constexpr decltype(auto) transpose(T &&t, Seq< Perm... >=Seq< Perm... >{})
Promote operands to tensor transposition operation.
Definition: operandpromotion.hh:309
Sequence< std::size_t, V... > IndexSequence
Sequence of std::size_t values.
Definition: types.hh:64
typename MakeType< void, Other... >::Type VoidType
Generate void regardless of the template argument list.
Definition: types.hh:151
BoolConstant< false > FalseType
Alias for std::false_type.
Definition: types.hh:110
BoolConstant< true > TrueType
Alias for std::true_type.
Definition: types.hh:107
Einstein summation, i.e.
Definition: expressionoperations.hh:308
A class mainting the sign of an expression during operations.
Definition: sign.hh:30
std::true_type if F is an "elementary" scalar.
Definition: typetraits.hh:35
Signature of index positions of tensors.
Definition: expressionoperations.hh:232
Component-wise product over given index-set.
Definition: expressionoperations.hh:389
Permutation of index positions of tensors.
Definition: expressionoperations.hh:167
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (Apr 26, 22:29, 2024)