DUNE-ACFEM (unstable)

product.hh
1 #ifndef __DUNE_ACFEM_TENSORS_OPERATIONS_PRODUCT_HH__
2 #define __DUNE_ACFEM_TENSORS_OPERATIONS_PRODUCT_HH__
3 
4 #include "../../expressions/storage.hh"
5 #include "../../expressions/expressionoperations.hh" // FieldPromotion
6 #include "../../mpl/insertat.hh"
7 
8 #include "../tensorbase.hh"
9 #include "../modules.hh"
10 #include "restrictiondetail.hh"
11 
12 namespace Dune {
13 
14  namespace ACFem {
15 
16  // forward
17  template<class Pos1, class Pos2, class ProductDims>
18  struct TensorProductOperation;
19 
28  namespace Tensor {
29 
65  template<class LeftTensor, class LeftIndices, class RightTensor, class RightIndices>
67 
68  template<class Left, class LPos, class Right, class RPos, class SFINAE = void>
69  struct ProductOperationTraits
70  {
71  using Signature = SequenceCat<SequenceSlice<Left, LPos>,
72  SequenceSliceComplement<Left, LPos>,
73  SequenceSliceComplement<Right, RPos> >;
75  using Functor = OperationTraits<Operation>;
76  };
77 
78  template<class Left, class LPos, class Right, class RPos>
79  struct ProductOperationTraits<Left, LPos, Right, RPos,
80  std::enable_if_t<(IsTensorOperand<Left>::value
81  && IsTensorOperand<Right>::value
82  )> >
83  : ProductOperationTraits<typename TensorTraits<Left>::Signature, LPos,
84  typename TensorTraits<Right>::Signature, RPos>
85  {};
86 
91  template<class Left, class LPos, class Right, class RPos>
92  using ProductSignature = typename ProductOperationTraits<typename TensorTraits<Left>::TensorType, LPos,
93  typename TensorTraits<Right>::TensorType, RPos>::Signature;
94 
95  template<class Left, class LPos, class Right, class RPos>
96  using ProductFunctor = typename ProductOperationTraits<typename TensorTraits<Left>::TensorType, LPos,
97  typename TensorTraits<Right>::TensorType, RPos>::Functor;
98 
99  template<class T>
103  typename TensorTraits<T>::Signature
104  >;
105 
106  template<class LeftTensor, std::size_t... LeftIndices, class RightTensor, std::size_t... RightIndices>
107  class ProductTensor<LeftTensor, Seq<LeftIndices...>, RightTensor, Seq<RightIndices...> >
108  : public TensorBase<typename FieldPromotion<LeftTensor, RightTensor>::Type,
109  ProductSignature<LeftTensor, Seq<LeftIndices...>, RightTensor, Seq<RightIndices...> >,
110  ProductTensor<LeftTensor, Seq<LeftIndices...>, RightTensor, Seq<RightIndices...> > >
111  , public Expressions::Storage<ProductFunctor<LeftTensor, Seq<LeftIndices...>, RightTensor, Seq<RightIndices...> >,
112  LeftTensor, RightTensor>
113  // Expressions model rvalues. We are constant if the underlying
114  // expression claims to be so or if we store a copy and the
115  // underlying expression is "independent" (i.e. determined at
116  // runtime only by the contained data)
117  {
118  using ThisType = ProductTensor;
119  using LeftType = LeftTensor;
120  using RightType = RightTensor;
121  using LeftTensorType = std::decay_t<LeftTensor>;
122  using RightTensorType = std::decay_t<RightTensor>;
123  using LeftSignature = typename LeftTensorType::Signature;
124  using RightSignature = typename RightTensorType::Signature;
125  using LeftDefectSignature = SubSequence<LeftSignature, LeftIndices...>;
126  using RightDefectSignature = SubSequence<RightSignature, RightIndices...>;
127  using LeftSignatureRest = SubSequenceComplement<LeftSignature, LeftIndices...>;
128  using RightSignatureRest = SubSequenceComplement<RightSignature, RightIndices...>;
129  public:
130  using LeftIndexPositions = Seq<LeftIndices...>;
131  using RightIndexPositions = Seq<RightIndices...>;
133  using FieldType = typename FieldPromotion<LeftType, RightType>::Type;
134  using FunctorType = OperationTraits<TensorProductOperation<LeftIndexPositions, RightIndexPositions, LeftDefectSignature> >;
135  private:
136  // Mmmh. Should we really support this?
137  using LeftSorted = SortSequence<LeftIndexPositions>;
138  using RightSorted = SortSequence<RightIndexPositions>;
139  using LeftPermutation = typename LeftSorted::Permutation;
140  using RightPermutation = typename RightSorted::Permutation;
141  using LeftSortedPos = typename LeftSorted::Result;
142  using RightSortedPos = typename RightSorted::Result;
143  static constexpr bool leftIsSorted_ = isSimple(LeftPermutation{});
144  static constexpr bool rightIsSorted_ = isSimple(RightPermutation{});
147  using StorageType = Expressions::Storage<FunctorType, LeftTensor, RightTensor>;
148  public:
149  using StorageType::operation;
150  using StorageType::operand;
151  using BaseType::rank;
152  static constexpr std::size_t leftRank_ = LeftSignatureRest::size();
153  static constexpr std::size_t rightRank_ = RightSignatureRest::size();
154  static constexpr std::size_t frontRank_ = rank - leftRank_ - rightRank_;
155  using FrontArgs = MakeIndexSequence<frontRank_>;
158  private:
159 
160  static_assert(sizeof...(LeftIndices) == sizeof...(RightIndices),
161  "Number of contraction indices must coincide.");
162  static_assert(LeftTensorType::rank >= sizeof...(LeftIndices),
163  "Left: Number of index-positions must fit into tensor rank.");
164  static_assert(RightTensorType::rank >= sizeof...(RightIndices),
165  "Right: Number of index-positions must fit into tensor rank.");
166  static_assert(std::is_same<LeftDefectSignature, RightDefectSignature>::value,
167  "Left- and right defect-dimensions must coincide.");
168 
169  public:
170  using DefectSignature = LeftDefectSignature;
171  static constexpr std::size_t defectRank_ = DefectSignature::size();
172 
173  template<class LeftArg, class RightArg,
174  std::enable_if_t<std::is_constructible<LeftType, LeftArg>::value && std::is_constructible<RightType, RightArg>::value, int> = 0>
175  ProductTensor(LeftArg&& left, RightArg&& right)
176  : StorageType(std::forward<LeftArg>(left), std::forward<RightArg>(right))
177  {}
178 
180  template<
181  class... Dummy,
182  std::enable_if_t<(sizeof...(Dummy) == 0
184  && IsTypedValue<RightType>::value), int> = 0>
185  ProductTensor(Dummy&&...)
186  : StorageType(LeftType{}, RightType{})
187  {}
188 
192  template<class... Dims,
193  std::enable_if_t<(sizeof...(Dims) == rank
194  &&
196  , int> = 0>
197  auto operator()(Dims... indices) const
198  {
199  auto frontIndices = forwardSubTuple(std::forward_as_tuple(indices...), FrontArgs{});
200  auto leftIndices = forwardSubTuple(std::forward_as_tuple(indices...), LeftArgs{});
201  auto rightIndices = forwardSubTuple(std::forward_as_tuple(indices...), RightArgs{});
202 
203  return
204  tensorValue(operand(0_c), insertAt(leftIndices, permute(frontIndices, LeftPermutation{}), LeftSortedPos{}))
205  *
206  tensorValue(operand(1_c), insertAt(rightIndices, permute(frontIndices, RightPermutation{}), RightSortedPos{}));
207  }
208 
210  template<std::size_t... Indices,
211  std::enable_if_t<(sizeof...(Indices) == rank
212  && ThisType::template isZero<Indices...>()
213  ), int> = 0>
214  auto constexpr operator()(Seq<Indices...>) const
215  {
216  return IntFraction<0>{};
217  }
218 
220  template<std::size_t... Indices,
221  std::enable_if_t<(sizeof...(Indices) == rank
222  && !ThisType::template isZero<Indices...>()
223  ), int> = 0>
224  auto constexpr operator()(Seq<Indices...>) const
225  {
226  using IndexSeq = Seq<Indices...>;
227  using ArgFrontIndices = SequenceSlice<IndexSeq, FrontArgs>;
228  using ArgLeftIndices = SequenceSlice<IndexSeq, LeftArgs>;
229  using ArgRightIndices = SequenceSlice<IndexSeq, RightArgs>;
232 
233  return operand(0_c)(LeftArg{}) * operand(1_c)(RightArg{});
234  }
235 
236  private:
237  template<std::size_t... Indices, class Pos = MakeIndexSequence<sizeof...(Indices)> >
238  static bool constexpr isZeroWorker(Seq<Indices...> = Seq<Indices...>{}, Pos = Pos{})
239  {
240  // This ain't pretty ;)
241 
242  // Truncate Pos to size of Indices and sort it, otherwise
243  // the JoinedDefects stuff will not work properly
244  using TruncatedPos = HeadPart<sizeof...(Indices), Pos>;
245  using RealPos = typename SortSequence<TruncatedPos>::Result;
246  using Permutation = typename SortSequence<TruncatedPos>::Permutation;
247  using RealIndices = PermuteSequence<Seq<Indices...>, Permutation>;
248 
249  // Extract leading product indices
250  using FrontPosInd =
251  TransformSequence<RealPos, Seq<>, IndexFunctor, AcceptInputInRangeFunctor<std::size_t, 0, frontRank_> >;
252  using FrontInd = SequenceSlice<RealIndices, FrontPosInd>;
253  using FrontPos = SequenceSlice<RealPos, FrontPosInd>;
254 
255  using LeftFrontPos = SequenceSlice<LeftIndexPositions, FrontPos>;
256  using RightFrontPos = SequenceSlice<RightIndexPositions, FrontPos>;
257 
258  // Extract the indices referring to the left Tensor
259  using LeftPosInd =
260  TransformSequence<RealPos, Seq<>, IndexFunctor, AcceptInputInRangeFunctor<std::size_t, frontRank_, frontRank_ + leftRank_> >;
261  using LeftPos = TransformSequence<SequenceSlice<RealPos, LeftPosInd>, Seq<>, OffsetFunctor<-(std::ptrdiff_t)frontRank_> >;
262  using LeftInd = SequenceSlice<RealIndices, LeftPosInd>;
263 
264  // The total set of left index positions, contraction and taken from Indices...
265  using LeftLookup = SequenceSliceComplement<MakeIndexSequence<frontRank_+leftRank_>, LeftSortedPos>;
266  using LeftTotalPos = SequenceCat<LeftFrontPos, TransformedSequence<MapSequenceFunctor<LeftLookup>, LeftPos> >;
267  using LeftTotalInd = SequenceCat<FrontInd, LeftInd>;
268 
269  // Extract the indices referring to the right Tensor
270  using RightPosInd =
271  TransformSequence<RealPos, Seq<>, IndexFunctor, AcceptInputInRangeFunctor<std::size_t, frontRank_ + leftRank_, frontRank_ + leftRank_ + rightRank_> >;
272  using RightPos = TransformSequence<SequenceSlice<RealPos, RightPosInd>, Seq<>, OffsetFunctor<-(std::ptrdiff_t)(frontRank_+leftRank_)> >;
273  using RightInd = SequenceSlice<RealIndices, RightPosInd>;
274 
275  // The total set of right index positions, contraction and taken from Indices...
276  using RightLookup = SequenceSliceComplement<MakeIndexSequence<frontRank_+rightRank_>, RightSortedPos>;
277  using RightTotalPos = SequenceCat<RightFrontPos, TransformedSequence<MapSequenceFunctor<RightLookup>, RightPos> >;
278  using RightTotalInd = SequenceCat<FrontInd, RightInd>;
279 
280  return
281  LeftTensorType::isZero(LeftTotalInd{}, LeftTotalPos{})
282  ||
283  RightTensorType::isZero(RightTotalInd{}, RightTotalPos{});
284  }
285 
286  public:
287  template<std::size_t... Indices, class Pos = MakeIndexSequence<sizeof...(Indices)> >
288  static bool constexpr isZero(Seq<Indices...> = Seq<Indices...>{}, Pos = Pos{})
289  {
290 // if constexpr (ExpressionTraits<LeftTensorType>::isZero || ExpressionTraits<RightTensorType>::isZero) {
291 // return true;
292 // } else {
293  return isZeroWorker(Seq<Indices...>{}, Pos{});
294 // }
295  }
296 
297  std::string name() const
298  {
299  using TL = LeftTensor;
300  using TR = RightTensor;
301  std::string pfxL = std::is_reference<TL>::value ? (RefersConst<TL>::value ? "cref" : "ref") : "";
302  std::string pfxR = std::is_reference<TR>::value ? (RefersConst<TR>::value ? "cref" : "ref") : "";
303 
304  return operationName(operation(), pfxL+operand(0_c).name(), pfxR+operand(1_c).name());
305  }
306 
307  }; // ProductTensor class
308 
310  template<class Seq1, class Seq2, class T1, class T2,
311  std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
312  constexpr decltype(auto) multiply(T1&& t1, T2&& t2)
313  {
314  return Expressions::finalize(ProductFunctor<T1, Seq1, T2, Seq2>{}, std::forward<T1>(t1), std::forward<T2>(t2));
315  }
316 
320  template<class T1, class T2,
321  std::enable_if_t<AreProperTensors<T1, T2>::value, int> = 0>
322  constexpr decltype(auto) multiply(T1&& t1, T2&& t2)
323  {
324  constexpr std::size_t numDims = CommonHead<typename TensorTraits<T1>::Signature,
325  typename TensorTraits<T2>::Signature>::value;
326  using ContractPos = MakeIndexSequence<numDims>;
327  return multiply<ContractPos, ContractPos>(std::forward<T1>(t1), std::forward<T2>(t2));
328  }
329 
333  template<class Seq0, class Seq1, class Dims, class T0, class T1>
334  constexpr auto operate(Expressions::DontOptimize, OperationTraits<TensorProductOperation<Seq0, Seq1, Dims> >, T0&& t0, T1&& t1)
335  {
336  DUNE_ACFEM_RECORD_OPTIMIZATION;
337 
338  return ProductTensor<T0, Seq0, T1, Seq1>(std::forward<T0>(t0), std::forward<T1>(t1));
339  }
340 
341  } // NS Tensor
342 
343  // Point here is that the operations defined in
344  // ./expressionoperations.hh need the name "multiply".
345  using Tensor::multiply;
346 
347  } // NS ACFem
348 
349  template<class LeftTensor, class LeftIndices, class RightTensor, class RightIndices>
350  struct FieldTraits<ACFem::Tensor::ProductTensor<LeftTensor, LeftIndices, RightTensor, RightIndices> >
351  : FieldTraits<typename ACFem::FieldPromotion<LeftTensor, RightTensor>::Type>
352  {};
353 
355 
357 
358 } // NS Dune
359 
360 #endif // __DUNE_ACFEM_TENSORS_OPERATIONS_PRODUCT_HH__
Compute the component-wise product ".[i][j]" over selected indices:
Definition: product.hh:66
OptimizeTag< 0 > DontOptimize
Bottom level is overloaded to do nothing.
Definition: optimizationbase.hh:74
std::string operationName(F &&f, const std::string &arg)
Verbose print of an operation, helper function to produce noise.
Definition: operationtraits.hh:601
BoolConstant< ExpressionTraits< T >::isTypedValue > IsTypedValue
Compile-time true if T is a "typed value", e.g. a std::integral_constant.
Definition: expressiontraits.hh:90
typename GetHeadPartHelper< Cnt, Seq >::Type HeadPart
Extract Cnt many consecutive elements from the front of Seq.
Definition: access.hh:217
constexpr std::size_t size()
Gives the number of elements in tuple-likes and std::integer_sequence.
Definition: size.hh:73
IndexConstant< CommonHeadHelper< 0UL, Seq1, Seq2 >::value > CommonHead
Compute the number of identical indices at the head of the sequence.
Definition: filter.hh:173
MakeSequence< std::size_t, N, Offset, Stride, Repeat > MakeIndexSequence
Make a sequence of std::size_t elements.
Definition: generators.hh:34
MultiplyOffsetFunctor< 1, Offset > OffsetFunctor
Offset functor.
Definition: transform.hh:335
typename SequenceCatHelper2< S... >::Type SequenceCat
Concatenate the given sequences, in order, to <S0, S1, ...
Definition: transform.hh:220
typename InsertAtHelper< Sequence< typename Input::value_type >, Input, Inject, Pos, AssumeSorted >::Type InsertAt
Insert Inject into the sequence Input at the position specified by Pos.
Definition: insertat.hh:87
auto insertAt(SrcTuple &&src, DataTuple &&data, BoolConstant< AssumeSorted >=BoolConstant< AssumeSorted >{})
Insert the elements of data at positions given by pos into src in turn.
Definition: subtuple.hh:106
auto forwardSubTuple(const TupleLike &t, IndexSequence< I... >=IndexSequence< I... >{})
Like subTuble() but forward the arguments, possibly in order to be expanded as parameters to another ...
Definition: subtuple.hh:162
constexpr decltype(auto) multiply(T1 &&t1, T2 &&t2)
Greedy tensor contraction for proper tensors, multiplying over all matching dimensions.
Definition: product.hh:322
typename ProductOperationTraits< typename TensorTraits< Left >::TensorType, LPos, typename TensorTraits< Right >::TensorType, RPos >::Signature ProductSignature
Generate the signature of the ProductTensor when the operands have the given signature and the produc...
Definition: product.hh:93
ProductTensor(Dummy &&...)
Allow default construction if contained types fulfill IsTypedValue.
Definition: product.hh:185
constexpr auto operate(Expressions::DontOptimize, OperationTraits< TensorProductOperation< Seq0, Seq1, Dims > >, T0 &&t0, T1 &&t1)
Definition: product.hh:334
auto operator()(Dims... indices) const
Insert the current view-indices at their proper positions and foward to the underlying "host" tensor.
Definition: product.hh:197
constexpr auto permute(Seq, IndexSequence< Ps... >=IndexSequence< Ps... >{})
Permute the given sequence.
Definition: permutation.hh:116
constexpr bool isSimple(Sequence< T, V... > seq)
Definition: compare.hh:334
decltype(isIntegralPack(std::declval< T >()...)) IsIntegralPack
Decide whether the given parameter pack contains only integral types.
Definition: compare.hh:377
std::decay_t< decltype(permute(Sequence{}, Perm{}))> PermuteSequence
Apply the given permutation to the positions of the given sequence.
Definition: permutation.hh:137
constexpr bool isZero
Shortcut identifying a zero model.
Definition: modeltraits.hh:642
Component-wise product over given index-set.
Definition: expressionoperations.hh:389
Base class for all tensors.
Definition: tensorbase.hh:144
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 16, 22:29, 2024)