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
12namespace 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 {
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
STL namespace.
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.111.3 (Dec 28, 23:30, 2024)