Loading [MathJax]/extensions/TeX/AMSmath.js

DUNE-ACFEM (unstable)

associativity.hh
1#ifndef __DUNE_ACFEM_TENSORS_OPERATIONS_ASSOCIATIVITY_HH__
2#define __DUNE_ACFEM_TENSORS_OPERATIONS_ASSOCIATIVITY_HH__
3
4#include "../tensorbase.hh"
5#include "../expressionoperations.hh"
6#include "einsum.hh"
7#include "product.hh"
8
9namespace Dune {
10
11 namespace ACFem {
12
13 namespace Tensor {
14
15 namespace ProductOperations {
16
17 template<class F, class T0, class T1, class SFINAE = void>
18 struct IsRightAssociative
19 : FalseType
20 {};
21
22 template<class F, class T0, class T1>
23 struct IsRightAssociative<F, T0, T1, std::enable_if_t<!IsDecay<F>::value> >
24 : IsRightAssociative<std::decay_t<F>, T0, T1>
25 {};
26
30 template<class Seq0, class Seq1, class Dims, class T0, class T1>
31 struct IsRightAssociative<OperationTraits<EinsumOperation<Seq0, Seq1, Dims> >, T0, T1>
32 : FunctorHas<IsEinsumOperation, Functor<T0> >
33 {};
34
35 template<class Seq0, class Seq1, class Dims, class T0, class T1>
36 struct IsRightAssociative<
37 OperationTraits<TensorProductOperation<Seq0, Seq1, Dims> >, T0, T1,
38 std::enable_if_t<(FunctorHas<IsTensorProductOperation, Functor<T0> >::value
39 && isSimple(Seq0{})
40 && std::is_same<Seq0, Seq1>::value
41 && std::is_same<typename TensorProductTraits<Operation<T0> >::LeftIndexPositions,
42 typename TensorProductTraits<Operation<T0> >::RightIndexPositions>::value
43 && std::is_same<Seq0,
44 typename TensorProductTraits<Operation<T0> >::RightIndexPositions>::value
45 )> >
46 : TrueType
47 {};
48
50 template<class F, class T0, class T1, class SFINAE = void>
52 : FalseType
53 {};
54
55 template<class F, class T0, class T1>
56 struct IsLeftAssociative<F, T0, T1, std::enable_if_t<!IsDecay<F>::value> >
57 : IsLeftAssociative<std::decay_t<F>, T0, T1>
58 {};
59
63 template<class Seq0, class Seq1, class Dims, class T0, class T1>
64 struct IsLeftAssociative<OperationTraits<EinsumOperation<Seq0, Seq1, Dims> >, T0, T1>
65 : FunctorHas<IsEinsumOperation, Functor<T1> >
66 {};
67
68 template<class Seq0, class Seq1, class Dims, class T0, class T1>
69 struct IsLeftAssociative<
70 OperationTraits<TensorProductOperation<Seq0, Seq1, Dims> >, T0, T1,
71 std::enable_if_t<(FunctorHas<IsTensorProductOperation, Functor<T1> >::value
72 && isSimple(Seq0{})
73 && std::is_same<Seq0, Seq1>::value
74 && std::is_same<typename TensorProductTraits<Operation<T1> >::LeftIndexPositions,
75 typename TensorProductTraits<Operation<T1> >::RightIndexPositions>::value
76 && std::is_same<Seq0,
77 typename TensorProductTraits<Operation<T1> >::RightIndexPositions>::value
78 )> >
79 : TrueType
80 {};
81
89 template<class InnerLeftIndexPositions, class InnerRightIndexPositions, class InnerDims,
90 class LeftIndexPositions, class RightIndexPositions, class OuterDims,
91 std::size_t Rank1, std::size_t Rank2, std::size_t Rank3,
92 std::enable_if_t<Rank1 * Rank2 * Rank3 != 0, int> = 0>
93 constexpr auto associateRightOperations(
97 {
98 // this ain't pretty ...
99
100 constexpr std::size_t innerDefectRank = InnerDims::size();
101 constexpr std::ptrdiff_t rightRank = Rank3;
102
103 constexpr std::ptrdiff_t innerLeftRank = Rank1;
104 constexpr std::ptrdiff_t innerLeftDefectRank = innerLeftRank - innerDefectRank;
105 constexpr std::ptrdiff_t innerRightRank = Rank2;
106 constexpr std::ptrdiff_t innerRightDefectRank = innerRightRank - innerDefectRank;
107
108 // Indices of the outer contraction positions referring to type One and Two
111
112 // Parts of the outer left contraction positions referring to type One and Two
113 using InnerLeftPos = SequenceSlice<LeftIndexPositions, InnerLeftPosIndices>;
114 using InnerRightPos = OffsetSequence<-innerLeftDefectRank, SequenceSlice<LeftIndexPositions, InnerRightPosIndices> >;
115
116 // Parts of the outer right contraction positions referring to type Two and Three
117 using OuterLeftPos = SequenceSlice<RightIndexPositions, InnerLeftPosIndices>;
118 using OuterRightPos = SequenceSlice<RightIndexPositions, InnerRightPosIndices>;
119
120 // Lookup table to convert to original indices for left (inner) tensors
121 using InnerLeftLookup = SequenceSliceComplement<MakeIndexSequence<innerLeftRank>, InnerLeftIndexPositions>;
122 using InnerRightLookup = SequenceSliceComplement<MakeIndexSequence<innerRightRank>, InnerRightIndexPositions>;
123
124 // Map the outer contraction indices to the original indices
125 using InnerLeftMappedPos = TransformedSequence<MapSequenceFunctor<InnerLeftLookup>, InnerLeftPos>;
126 using InnerRightMappedPos = TransformedSequence<MapSequenceFunctor<InnerRightLookup>, InnerRightPos>;
127
128 // Contraction indices for One. Concat the inner contraction
129 // indices with the mapped outer contraction indices
130 // referring to one
133
134 // Contraction indices for Two. Map the indices referring to
135 // Two to the original indices.
136 using TwoPos = InnerRightMappedPos;
137
138 // contraction position for Three which refer to B
139 using ThreePos = OuterRightPos;
140 using ThreeDims = SequenceSlice<OuterDims, InnerRightPosIndices>;
141
142 // Contraction indices for the contraction of One with (Two
143 // * Three). This refers to the contraction of One with
144 // Two. We need the indices referring to Two in the
145 // contraction of (Two * Three).
146 using TwoThreeTwoPosLookup = SequenceSliceComplement<MakeIndexSequence<innerRightRank>, TwoPos>;
147 using TwoThreeTwoMappedPos = TransformedSequence<InverseMapSequenceFunctor<TwoThreeTwoPosLookup>, InnerRightIndexPositions>;
148
149 using TwoThreeThreePosLookup = SequenceSliceComplement<MakeIndexSequence<rightRank>, ThreePos>;
150 using TwoThreeThreeMappedPos = TransformedSequence<InverseMapSequenceFunctor<TwoThreeThreePosLookup>, OuterLeftPos>;
151
152 using TwoThreePos = SequenceCat<TwoThreeTwoMappedPos, OffsetSequence<innerRightRank-TwoPos::size() ,TwoThreeThreeMappedPos> >;
153
154#if 0
155 std::clog << "One: " << OnePos{} << std::endl;
156 std::clog << "TwoThree: " << TwoThreePos{} << std::endl;
157 std::clog << "Two: " << TwoPos{} << std::endl;
158 std::clog << "Three: " << ThreePos{} << std::endl;
159#endif
160
161 return std::make_pair(OperationTraits<EinsumOperation<OnePos, TwoThreePos, OneDims> >{},
162 OperationTraits<EinsumOperation<TwoPos, ThreePos, ThreeDims> >{});
163 }
164
165 template<class InnerLeftIndexPositions, class InnerRightIndexPositions, class InnerDims,
166 class LeftIndexPositions, class RightIndexPositions, class OuterDims,
167 std::size_t Rank1, std::size_t Rank2, std::size_t Rank3,
168 std::enable_if_t<Rank1 * Rank2 * Rank3 == 0, int> = 0>
169 constexpr auto associateRightOperations(
170 OperationTraits<EinsumOperation<InnerLeftIndexPositions, InnerRightIndexPositions, InnerDims> > f1,
171 OperationTraits<EinsumOperation<LeftIndexPositions, RightIndexPositions, OuterDims> > f2,
172 IndexSequence<Rank1, Rank2, Rank3>)
173 {
174 // (A *1 B) *2 C
175 // A scalar: A *1 (B *2 C)
176 // B scalar: A *2 (B *1 C)
177 // C scalar: A *1 (B *2 C)
178 if constexpr (Rank1 == 0) {
179 return std::make_pair(f1, f2);
180 } else if constexpr (Rank2 == 0) {
181 return std::make_pair(f2, f1);
182 } else {
183 return std::make_pair(f1, f2);
184 }
185 }
186
194 template<class LeftIndexPositions, class RightIndexPositions, class OuterDims,
195 class InnerLeftIndexPositions, class InnerRightIndexPositions, class InnerDims,
196 std::size_t Rank1, std::size_t Rank2, std::size_t Rank3,
197 std::enable_if_t<Rank1 * Rank2 * Rank3 != 0, int> = 0>
198 constexpr auto associateLeftOperations(
199 OperationTraits<EinsumOperation<LeftIndexPositions, RightIndexPositions, OuterDims> >,
200 OperationTraits<EinsumOperation<InnerLeftIndexPositions, InnerRightIndexPositions, InnerDims> >,
201 IndexSequence<Rank1, Rank2, Rank3>)
202 {
203 // this ain't pretty ...
204 constexpr std::size_t innerDefectRank = InnerDims::size();
205 constexpr std::ptrdiff_t leftRank = Rank1;
206
207 constexpr std::ptrdiff_t innerLeftRank = Rank2;
208 constexpr std::ptrdiff_t innerLeftDefectRank = innerLeftRank - innerDefectRank;
209 constexpr std::ptrdiff_t innerRightRank = Rank3;
210 constexpr std::ptrdiff_t innerRightDefectRank = innerRightRank - innerDefectRank;
211
212 // Indices of the outer contraction positions referring to type two and three
213 using InnerLeftPosIndices = TransformSequence<RightIndexPositions, Seq<>, IndexFunctor, AcceptInputInRangeFunctor<std::size_t, 0, innerLeftDefectRank> >;
214 using InnerRightPosIndices = TransformSequence<RightIndexPositions, Seq<>, IndexFunctor, AcceptInputInRangeFunctor<std::size_t, innerLeftDefectRank, innerLeftDefectRank+innerRightDefectRank> >;
215
216 // Parts of the outer right contraction positions referring to type Two and Three
217 using InnerLeftPos = SequenceSlice<RightIndexPositions, InnerLeftPosIndices>;
218 using InnerRightPos = OffsetSequence<-innerLeftDefectRank, SequenceSlice<RightIndexPositions, InnerRightPosIndices> >;
219
220 // Parts of the outer left contraction positions referring to type Two and Three
221 using OuterLeftPos = SequenceSlice<LeftIndexPositions, InnerLeftPosIndices>;
222 using OuterRightPos = SequenceSlice<LeftIndexPositions, InnerRightPosIndices>;
223
224 // Lookup table to convert to original indices for left (inner) tensors
225 using InnerLeftLookup = SequenceSliceComplement<MakeIndexSequence<innerLeftRank>, InnerLeftIndexPositions>;
226 using InnerRightLookup = SequenceSliceComplement<MakeIndexSequence<innerRightRank>, InnerRightIndexPositions>;
227
228 // Map the outer contraction indices to the original indices
229 using InnerLeftMappedPos = TransformedSequence<MapSequenceFunctor<InnerLeftLookup>, InnerLeftPos>;
230 using InnerRightMappedPos = TransformedSequence<MapSequenceFunctor<InnerRightLookup>, InnerRightPos>;
231
232 // Part of left-most contraction referring to two
233 using OnePos = OuterLeftPos;
234 using OneDims = SequenceSlice<OuterDims, InnerLeftPosIndices>;
235
236 // Contraction indices for Two.
237 using TwoPos = InnerLeftMappedPos;
238
239 // Contraction indices for Three. Concat the inner contraction
240 // indices with the mapped outer contraction indices
241 // referring to two and sort the result.
242 using ThreePos = SequenceCat<InnerRightMappedPos, InnerRightIndexPositions>;
243 using ThreeDims = SequenceCat<SequenceSlice<OuterDims, InnerRightPosIndices>, InnerDims>;
244
245 // Contraction indices for the contraction of (One*Two) with
246 // Three. This refers to the contraction of One with Three
247 // and Two with Three. We need the indices referring to Two
248 // in the contraction of (One * Two).
249
250 // indices for A
251 using OneTwoOnePosLookup = SequenceSliceComplement<MakeIndexSequence<leftRank>, OnePos>;
252 using OneTwoOneMappedPos = TransformedSequence<InverseMapSequenceFunctor<OneTwoOnePosLookup>, OuterRightPos>;
253
254 // indices for B
255 using OneTwoTwoPosLookup = SequenceSliceComplement<MakeIndexSequence<innerLeftRank>, TwoPos>;
256 using OneTwoTwoMappedPos = TransformedSequence<InverseMapSequenceFunctor<OneTwoTwoPosLookup>, InnerLeftIndexPositions>;
257
258 using OneTwoPos = SequenceCat<OneTwoOneMappedPos, OffsetSequence<leftRank-OnePos::size(), OneTwoTwoMappedPos> >;
259
260 return std::make_pair(
261 OperationTraits<EinsumOperation<OnePos, TwoPos, OneDims> >{},
262 OperationTraits<EinsumOperation<OneTwoPos, ThreePos, ThreeDims> >{});
263 }
264
268 template<class LeftIndexPositions, class RightIndexPositions, class OuterDims,
269 class InnerLeftIndexPositions, class InnerRightIndexPositions, class InnerDims,
270 std::size_t Rank1, std::size_t Rank2, std::size_t Rank3,
271 std::enable_if_t<Rank1 * Rank2 * Rank3 == 0, int> = 0>
272 constexpr auto associateLeftOperations(
273 OperationTraits<EinsumOperation<LeftIndexPositions, RightIndexPositions, OuterDims> > f1,
274 OperationTraits<EinsumOperation<InnerLeftIndexPositions, InnerRightIndexPositions, InnerDims> > f2,
275 IndexSequence<Rank1, Rank2, Rank3>)
276 {
277 // A *1 (B *2 C)
278 // A scalar: (A *1 B) *2 C
279 // B scalar: (A *2 B) *1 C
280 // C scalar: (A *1 B) *2 C
281 if constexpr (Rank1 == 0) {
282 return std::make_pair(f1, f2);
283 } else if constexpr (Rank2 == 0) {
284 return std::make_pair(f2, f1);
285 } else {
286 return std::make_pair(f1, f2);
287 }
288 }
289
295 template<class Defects, class Dims,
296 std::size_t Rank1, std::size_t Rank2, std::size_t Rank3>
297 constexpr auto associateRightOperations(
298 OperationTraits<TensorProductOperation<Defects, Defects, Dims> > f1,
299 OperationTraits<TensorProductOperation<Defects, Defects, Dims> > f2,
300 IndexSequence<Rank1, Rank2, Rank3>)
301 {
302 return std::make_pair(f1, f2);
303 }
304
312 template<class Defects, class Dims,
313 std::size_t Rank1, std::size_t Rank2, std::size_t Rank3>
314 constexpr auto associateLeftOperations(
315 OperationTraits<TensorProductOperation<Defects, Defects, Dims> > f1,
316 OperationTraits<TensorProductOperation<Defects, Defects, Dims> > f2,
317 IndexSequence<Rank1, Rank2, Rank3>)
318 {
319 return std::make_pair(f1, f2);
320 }
321
322 template<class F, class T0, class T1,
323 class OptimizeInner = Expressions::OptimizeTop,
324 std::enable_if_t<IsRightAssociative<F, T0, T1>::value, int> = 0>
325 constexpr auto associateRightExpression(F&& f, T0&& t0, T1&& t1, OptimizeInner = OptimizeInner{})
326 {
327 auto operations = associateRightOperations(
328 std::forward<T0>(t0).operation(), std::forward<F>(f),
329 IndexSequence<TensorTraits<Operand<0, T0> >::rank, TensorTraits<Operand<1, T0> >::rank, TensorTraits<T1>::rank>{});
330
332 std::move(operations.first),
333 std::forward<T0>(t0).operand(0_c),
334 operate(
335 OptimizeInner{},
336 std::move(operations.second),
337 std::forward<T0>(t0).operand(1_c),
338 std::forward<T1>(t1)
339 )
340 );
341 }
342
343 template<class F, class T0, class T1,
344 std::enable_if_t<(!IsRightAssociative<F, T0, T1>::value
345 && FunctorHas<IsProductOperation, F>::value
346 && IsProductExpression<T1>::value
347 ), int> = 0>
348 constexpr auto associateRightExpression(F&& f, T0&& t0, T1&& t1, DontOptimize = DontOptimize{})
349 {
350 return Expressions::storage(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1));
351 }
352
353#if 1
354 template<class F, class T0, class T1,
355 class OptimizeOuter = Expressions::OptimizeTop,
356 class OptimizeInner = Expressions::OptimizeTop,
357 std::enable_if_t<AreProperTensors<T0, T1>::value, int> = 0>
358 constexpr decltype(auto) associateRight(F&& f, T0&& t0, T1&& t1,
359 OptimizeOuter = OptimizeOuter{}, OptimizeInner = OptimizeInner{})
360 {
361 auto expr = associateRightExpression(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1), OptimizeInner{});
362 return operate(
363 OptimizeOuter{},
364 std::move(expr).operation(),
365 std::move(expr).operand(0_c),
366 std::move(expr).operand(1_c));
367 }
368#else
369 template<class F, class T0, class T1,
370 class OptimizeOuter = Expressions::OptimizeTop,
371 class OptimizeInner = Expressions::OptimizeTop,
372 std::enable_if_t<(// && AreProperTensors<T0, T1>::value
373 IsRightAssociative<F, T0, T1>::value), int> = 0>
374 constexpr decltype(auto) associateRight(F&& f, T0&& t0, T1&& t1,
375 OptimizeOuter = OptimizeOuter{}, OptimizeInner = OptimizeInner{})
376 {
377 auto operations = associateRightOperations(
378 std::forward<T0>(t0).operation(), std::forward<F>(f),
379 IndexSequence<TensorTraits<Operand<0, T0> >::rank, TensorTraits<Operand<1, T0> >::rank, TensorTraits<T1>::rank>{});
380
381 // Do we need forwardReturnValue here?
382 return operate(
383 OptimizeOuter{},
384 std::move(operations.first),
385 std::forward<T0>(t0).operand(0_c),
386 operate(
387 OptimizeInner{},
388 std::move(operations.second),
389 std::forward<T0>(t0).operand(1_c),
390 std::forward<T1>(t1)
391 )
392 );
393 }
394
395 template<class F, class T0, class T1,
396 class OptimizeOuter = OptimizeTop,
397 std::enable_if_t<(!IsRightAssociative<F, T0, T1>::value
398 && FunctorHas<IsProductOperation, F>::value
399 && IsProductExpression<T1>::value
400 ), int> = 0>
401 constexpr decltype(auto) associateRight(F&& f, T0&& t0, T1&& t1,
402 OptimizeOuter = OptimizeOuter{}, OptimizeTop = OptimizeTop{})
403 {
404 return operate(OptimizeOuter{}, std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1));
405 }
406#endif
407
408 template<class F, class T0, class T1,
409 class OptimizeInner = OptimizeTop,
410 std::enable_if_t<IsLeftAssociative<F, T0, T1>::value, int> = 0>
411 constexpr auto associateLeftExpression(F&& f, T0&& t0, T1&& t1,
412 OptimizeInner = OptimizeInner{})
413 {
414 // A*(B*C) -> (A*B)*C
415 auto operations = associateLeftOperations(
416 std::forward<F>(f), std::forward<T1>(t1).operation(),
417 IndexSequence<TensorTraits<T0>::rank, TensorTraits<Operand<0, T1> >::rank, TensorTraits<Operand<1, T1> >::rank>{});
418
420 std::move(operations.second), // outer
421 operate(
422 OptimizeInner{},
423 std::move(operations.first), // inner
424 std::forward<T0>(t0),
425 std::forward<T1>(t1).operand(0_c)
426 ),
427 std::forward<T1>(t1).operand(1_c)
428 );
429 }
430
435 template<class F, class T0, class T1,
436 std::enable_if_t<(!IsLeftAssociative<F, T0, T1>::value
437 && IsProductExpression<T0>::value
438 && FunctorHas<IsProductOperation, F>::value
439 ), int> = 0>
440 constexpr auto associateLeftExpression(F&& f, T0&& t0, T1&& t1,
442 {
443 return Expressions::storage(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1));
444 }
445
446#if 1
447 template<class F, class T0, class T1,
448 class OptimizeOuter = OptimizeTop, class OptimizeInner = OptimizeTop,
449 std::enable_if_t<AreProperTensors<T0, T1>::value, int> = 0>
450 constexpr decltype(auto) associateLeft(F&& f, T0&& t0, T1&& t1,
451 OptimizeOuter = OptimizeOuter{}, OptimizeInner = OptimizeInner{})
452 {
453 auto expr = associateLeftExpression(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1), OptimizeInner{});
454
455 return operate(
456 OptimizeOuter{},
457 std::move(expr).operation(),
458 std::move(expr).operand(0_c),
459 std::move(expr).operand(1_c));
460 }
461#else
462 template<class F, class T0, class T1,
463 class OptimizeOuter = OptimizeTop, class OptimizeInner = OptimizeTop,
464 std::enable_if_t<(// && AreProperTensors<T0, T1>::value
465 IsLeftAssociative<F, T0, T1>::value), int> = 0>
466 constexpr decltype(auto) associateLeft(F&& f, T0&& t0, T1&& t1,
467 OptimizeOuter = OptimizeOuter{}, OptimizeInner = OptimizeInner{})
468 {
469 // A*(B*C) -> (A*B)*C
470 auto operations = associateLeftOperations(
471 std::forward<F>(f), std::forward<T1>(t1).operation(),
472 IndexSequence<TensorTraits<T0>::rank, TensorTraits<Operand<0, T1> >::rank, TensorTraits<Operand<1, T1> >::rank>{});
473
474 return operate(
475 OptimizeOuter{},
476 std::move(operations.second), // outer
477 operate(
478 OptimizeInner{},
479 std::move(operations.first), // inner
480 std::forward<T0>(t0),
481 std::forward<T1>(t1).operand(0_c)
482 ),
483 std::forward<T1>(t1).operand(1_c)
484 );
485 }
486
491 template<class F, class T0, class T1,
492 class OptimizeOuter = OptimizeTop,
493 std::enable_if_t<(// && AreProperTensors<T0, T1>::value
494 !IsLeftAssociative<F, T0, T1>::value
495 && IsProductExpression<T0>::value
496 && FunctorHas<IsProductOperation, F>::value
497 ), int> = 0>
498 constexpr decltype(auto) associateLeft(F&& f, T0&& t0, T1&& t1,
499 OptimizeOuter = OptimizeOuter{}, DontOptimize = DontOptimize{})
500 {
501 return operate(OptimizeOuter{}, std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1));
502 }
503#endif
504
505 template<std::size_t N, class F, class T0, class T1>
506 using AssociateRightOperation =
507 TupleElement<N,
508 decltype(
509 associateRightOperations(
510 std::declval<Functor<T0> >(), std::declval<F>(),
511 IndexSequence<TensorTraits<Operand<0, T0> >::rank,
512 TensorTraits<Operand<1, T0> >::rank,
513 TensorTraits<T1>::rank>{})
514 )>;
515
516 template<std::size_t N, class F, class T0, class T1>
517 using AssociateLeftOperation =
518 TupleElement<N,
519 decltype(
520 associateLeftOperations(
521 std::declval<F>(), std::declval<Functor<T1> >(),
522 IndexSequence<TensorTraits<T0>::rank,
523 TensorTraits<Operand<0, T1> >::rank,
524 TensorTraits<Operand<1, T1> >::rank>{})
525 )>;
526
535 template<class T>
536 constexpr decltype(auto) rightMostFactor(T&& t)
537 {
538 if constexpr (!IsProductExpression<T>::value) {
539 return std::forward<T>(t);
540 } else if constexpr (!IsLeftAssociative<Functor<T>, Operand<0, T>, Operand<1, T> >::value) {
541 return std::forward<T>(t).operand(1_c);
542 } else {
543 return rightMostFactor(std::forward<T>(t).operand(1_c));
544 }
545 }
546
555 template<class T>
556 constexpr decltype(auto) leftMostFactor(T&& t)
557 {
558 if constexpr (!IsProductExpression<T>::value) {
559 return std::forward<T>(t);
560 } else if constexpr (!IsRightAssociative<Functor<T>, Operand<0, T>, Operand<1, T> >::value) {
561 return std::forward<T>(t).operand(0_c);
562 } else {
563 return leftMostFactor(std::forward<T>(t).operand(0_c));
564 }
565 }
566
572 template<class F, class T0, class T1, class Optimize = OptimizeTop,
573 std::enable_if_t<FunctorHas<IsProductOperation, F>::value, int> = 0>
574 constexpr auto factorOutRight(const F& f, T0&& t0, T1&& t1, Optimize = Optimize{})
575 {
576 if constexpr (!IsLeftAssociative<F, T0, T1>::value) {
577 return Expressions::Storage<F, T0, T1>(f, std::forward<T0>(t0), std::forward<T1>(t1));
578 } else {
579 // A*(B*C) -> (A*B)*C
580 auto operations = associateLeftOperations(
581 f, std::forward<T1>(t1).operation(),
582 IndexSequence<TensorTraits<T0>::rank, TensorTraits<Operand<0, T1> >::rank, TensorTraits<Operand<1, T1> >::rank>{});
583
584 return factorOutRight(std::move(operations.second),
585 operate(
586 Optimize{},
587 std::move(operations.first), // inner
588 std::forward<T0>(t0),
589 std::forward<T1>(t1).operand(0_c)
590 ),
591 std::forward<T1>(t1).operand(1_c));
592 }
593 }
594
606 template<class F, class T0, class T1, class Optimize = OptimizeTop,
607 std::enable_if_t<FunctorHas<IsProductOperation, F>::value, int> = 0>
608 constexpr auto factorOutLeft(const F& f, T0&& t0, T1&& t1, Optimize = Optimize{})
609 {
610 if constexpr (!IsRightAssociative<F, T0, T1>::value) {
611 return Expressions::Storage<F, T0, T1>(f, std::forward<T0>(t0), std::forward<T1>(t1));
612 } else {
613 // (A*B)*C -> A*(B*C)
614 auto operations = associateRightOperations(
615 std::forward<T0>(t0).operation(), f,
616 IndexSequence<TensorTraits<Operand<0, T0> >::rank, TensorTraits<Operand<1, T0> >::rank, TensorTraits<T1>::rank>{});
617
618 return factorOutLeft(std::move(operations.first),
619 std::forward<T0>(t0).operand(0_c),
620 operate(
621 Optimize{},
622 std::move(operations.second), // inner
623 std::forward<T0>(t0).operand(1_c),
624 std::forward<T1>(t1)));
625 }
626 }
627
628 template<class F, class T0, class T1>
629 using FactorOutRight = std::decay_t<decltype(factorOutRight(std::declval<F>(), std::declval<T0>(), std::declval<T1>()))>;
630
631 template<class F, class T0, class T1>
632 using FactorOutLeft = std::decay_t<decltype(factorOutLeft(std::declval<F>(), std::declval<T0>(), std::declval<T1>()))>;
633
634#if 1
635 template<class T>
636 using RightMostFactor = decltype(rightMostFactor(std::declval<T>()));
637
638 template<class T>
639 using LeftMostFactor = decltype(leftMostFactor(std::declval<T>()));
640#else
641 namespace {
642 template<class T, class SFINAE = void>
643 struct RightMostFactorHelper
644 {
645 using Type = T;
646 };
647
648 template<class T>
649 struct RightMostFactorHelper<T, std::enable_if_t<IsProductExpression<T>::value> >
650 {
651 using Type = ConditionalType<IsLeftAssociative<Functor<T>, Operand<0, T>, Operand<1, T> >::value,
652 typename RightMostFactorHelper<Operand<1, T> >::Type,
653 Operand<1, T> >;
654 };
655
656 template<class T, class SFINAE = void>
657 struct LeftMostFactorHelper
658 {
659 using Type = T;
660 };
661
662 template<class T>
663 struct LeftMostFactorHelper<T, std::enable_if_t<IsProductExpression<T>::value> >
664 {
665 using Type = ConditionalType<IsRightAssociative<Functor<T>, Operand<0, T>, Operand<1, T> >::value,
666 typename LeftMostFactorHelper<Operand<0, T> >::Type,
667 Operand<0, T> >;
668 };
669 }
670
671 template<class T>
672 using RightMostFactor = typename RightMostFactorHelper<T>::Type;
673
674 template<class T>
675 using LeftMostFactor = typename LeftMostFactorHelper<T>::Type;
676#endif
677
678 } // NS ProductOperations
679
680 using ProductOperations::IsRightAssociative;
681 using ProductOperations::IsLeftAssociative;
682 using ProductOperations::AssociateRightOperation;
683 using ProductOperations::associateRightExpression;
684 using ProductOperations::associateRight;
685 using ProductOperations::associateRight;
686 using ProductOperations::AssociateLeftOperation;
687 using ProductOperations::associateLeftOperations;
688 using ProductOperations::associateLeftExpression ;
689 using ProductOperations::associateLeft;
690 using ProductOperations::factorOutRight;
691 using ProductOperations::rightMostFactor;
692 using ProductOperations::RightMostFactor;
693 using ProductOperations::FactorOutRight;
694 using ProductOperations::factorOutLeft;
695 using ProductOperations::leftMostFactor;
696 using ProductOperations::LeftMostFactor;
697 using ProductOperations::FactorOutLeft;
698
699 } // NS Tensor
700
701 } // NS ACFem
702
703} // NS Dune
704
705#endif // __DUNE_ACFEM_TENSORS_OPERATIONS_ASSOCIATIVITY_HH__
OptimizeTag< Policy::OptimizationLevelMax::value > OptimizeTop
The top-level optmization tag.
Definition: optimizationbase.hh:59
OptimizeTag< 0 > DontOptimize
Bottom level is overloaded to do nothing.
Definition: optimizationbase.hh:74
constexpr auto storage(const F &f, T &&... t)
Generate an expression storage container.
Definition: storage.hh:704
std::tuple_element_t< N, std::decay_t< TupleLike > > TupleElement
Forward to std::tuple_element<N, std::decay_t<T> >
Definition: access.hh:125
constexpr std::size_t size()
Gives the number of elements in tuple-likes and std::integer_sequence.
Definition: size.hh:73
TransformSequence< Seq, Sequence< Tout >, F > TransformedSequence
Transform given sequence.
Definition: transform.hh:273
typename SequenceCatHelper2< S... >::Type SequenceCat
Concatenate the given sequences, in order, to <S0, S1, ... >.
Definition: transform.hh:220
typename TransformSequenceHelper< SeqIn, SeqOut, TransformFunctor, AcceptFunctor >::Type TransformSequence
General sequence transformation alias.
Definition: transform.hh:172
Sequence< std::size_t, V... > IndexSequence
Sequence of std::size_t values.
Definition: types.hh:64
BoolConstant< false > FalseType
Alias for std::false_type.
Definition: types.hh:110
BoolConstant< true > TrueType
Alias for std::true_type.
Definition: types.hh:107
STL namespace.
Accept if input-value is in range of given bounds.
Definition: transform.hh:501
Einstein summation, i.e.
Definition: expressionoperations.hh:308
Index functor.
Definition: transform.hh:346
Component-wise product over given index-set.
Definition: expressionoperations.hh:389
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Mar 12, 23:28, 2025)