DUNE-ACFEM (unstable)

operationtraits.hh
Go to the documentation of this file.
1#ifndef __DUNE_ACFEM_EXPRESSIONS_OPERATIONTRAITS_HH__
2#define __DUNE_ACFEM_EXPRESSIONS_OPERATIONTRAITS_HH__
3
9#include "../common/ostream.hh"
10#include "../common/literals.hh"
11#include "../mpl/tostring.hh"
12#include "../mpl/foreach.hh"
13
14#include "expressiontraits.hh"
15#include "constantoperations.hh"
16#include "expressionoperations.hh"
17
18namespace Dune
19{
20
21 namespace ACFem
22 {
23
24 // inject math-functions into ACFem::
25#include "usingstd.hh"
26
61 // forward
62 template<class Operation>
63 struct OperationTraits;
64
66
67 template<template<class...> class Predicate, class T>
68 struct FunctorHas
69 : FalseType
70 {};
71
72 template<template<class...> class Predicate, class T>
73 struct FunctorHas<Predicate, T&>
74 : FunctorHas<Predicate, std::decay_t<T> >
75 {};
76
77 template<template<class...> class Predicate, class T>
78 struct FunctorHas<Predicate, T&&>
79 : FunctorHas<Predicate, std::decay_t<T> >
80 {};
81
82 template<template<class...> class Predicate, class T>
83 struct FunctorHas<Predicate, OperationTraits<T> >
84 : Predicate<T>
85 {};
86
87 /**************************************************************************
88 *
89 * Identity stuff
90 *
91 */
92
93 template<class F>
94 using IsIdentityOperation = std::is_same<IdentityOperation, F>;
95
96 template<class T>
97 using IsIdentityExpression = IsIdentityOperation<Expressions::Operation<T> >;
98
99 /**************************************************************************
100 *
101 * Product stuff
102 *
103 */
104
110 template<class T>
112 : FalseType
113 {};
114
118 template<class T>
120
121 template<>
123 : TrueType
124 {};
125
126 template<>
127 struct IsProductOperation<SMultiplyOperation>
128 : TrueType
129 {};
130
131 template<class F>
132 using IsSMultiplyOperation = std::is_same<SMultiplyOperation, F>;
133
134 template<class T>
135 using IsSMultiplyExpression = IsSMultiplyOperation<Expressions::Operation<T> >;
136
138
139 template<class T>
140 constexpr inline bool MultiplicationAdmitsScalarsV = false;
141
142 template<class T>
143 constexpr inline bool MultiplicationAdmitsScalarsV<T&> = MultiplicationAdmitsScalarsV<std::decay_t<T> >;
144
145 template<class T>
146 constexpr inline bool MultiplicationAdmitsScalarsV<OperationTraits<T> > = MultiplicationAdmitsScalarsV<T>;
147
148 template<>
149 constexpr inline bool MultiplicationAdmitsScalarsV<SMultiplyOperation> = true;
150
151 template<>
152 constexpr inline bool MultiplicationAdmitsScalarsV<LogicalAndOperation> = true;
153
154 /**************************************************************************
155 *
156 * !, &&, ||
157 *
158 */
159
160 template<class T>
161 using IsLogicalOrExpression = std::is_same<Expressions::Operation<T>, LogicalOrOperation>;
162
163 template<class T>
164 using IsLogicalAndExpression = std::is_same<Expressions::Operation<T>, LogicalAndOperation>;;
165
166 template<class T>
167 using IsLogicalNotExpression = std::is_same<Expressions::Operation<T>, LogicalNotOperation>;
168
169 /**************************************************************************
170 *
171 * +/-
172 *
173 */
174
175 template<class F>
176 using IsPlusOperation = std::is_same<PlusOperation, F>;
177
178 template<class F>
179 using IsMinusOperation = std::is_same<MinusOperation, F>;
180
181 template<class F>
182 using IsPlusOrMinusOperation = BoolConstant<IsPlusOperation<F>::value || IsMinusOperation<F>::value>;
183
184 template<class T>
185 using IsBinaryPlusExpression =
186 BoolConstant<(IsExpressionOfArity<2, T>::value
187 && std::is_same<Expressions::Operation<T>, PlusOperation>::value)>;
188
189 template<class T>
190 using IsBinaryMinusExpression =
191 BoolConstant<(IsExpressionOfArity<2, T>::value
192 && std::is_same<Expressions::Operation<T>, MinusOperation>::value)>;
193
194 template<class T>
195 using IsUnaryMinusExpression =
196 BoolConstant<(IsExpressionOfArity<1, T>::value
197 && std::is_same<Expressions::Operation<T>, MinusOperation>::value)>;
198
199 template<class T>
200 using IsPlusOrMinusExpression = BoolConstant<IsBinaryPlusExpression<T>::value || IsBinaryMinusExpression<T>::value>;
201
202 using PlusFunctor = OperationTraits<PlusOperation>;
203 using MinusFunctor = OperationTraits<MinusOperation>;
204
205 namespace {
206
207 template<class F0, class F1>
208 struct NestedSumFunctorHelper
209 {
210 using Type = MinusFunctor;
211 };
212
213 template<class F>
214 struct NestedSumFunctorHelper<F, F>
215 {
216 using Type = PlusFunctor;
217 };
218 }
219
220 template<class F0, class F1>
221 using NestedSumFunctor = typename NestedSumFunctorHelper<F0, F1>::Type;
222
224 template<class Operation, class SFINAE = void>
226 : IsProductOperation<Operation>
227 {};
228
229 /**************************************************************************
230 *
231 * Pow, Sqrt, Square, 1/ support
232 *
233 */
234
235 template<class T>
236 struct IsReciprocalExpression
237 : std::is_same<Expressions::Operation<T>, ReciprocalOperation>
238 {};
239
240 template<class T>
241 struct IsSqrtExpression
242 : std::is_same<Expressions::Operation<T>, SqrtOperation>
243 {};
244
245 template<class T>
246 struct IsSquareExpression
247 : std::is_same<Expressions::Operation<T>, SquareOperation>
248 {};
249
250 template<class T>
251 struct IsPowExpression
252 : std::is_same<Expressions::Operation<T>, PowOperation>
253 {};
254
255 template<class T>
256 struct IsExponentiationOperation
257 : BoolConstant<(std::is_same<T, ReciprocalOperation>::value
258 || std::is_same<T, SqrtOperation>::value
259 || std::is_same<T, SquareOperation>::value
260 || std::is_same<T, PowOperation>::value
261 )>
262 {};
263
264 template<class T>
265 struct IsExponentiationExpression
266 : BoolConstant<(IsPowExpression<T>::value
267 || IsSqrtExpression<T>::value
268 || IsSquareExpression<T>::value
269 || IsReciprocalExpression<T>::value)>
270 {};
271
272 template<class T, std::enable_if_t<IsPowExpression<T>::value, int> = 0>
273 constexpr decltype(auto) exponent(T&& t)
274 {
275 return std::forward<T>(t).template operand<1>();
276 }
277
278 template<class T, std::enable_if_t<IsSqrtExpression<T>::value, int> = 0>
279 constexpr auto exponent(T&& t)
280 {
281 return IntFraction<1, 2>{};
282 }
283
284 template<class T, std::enable_if_t<IsSquareExpression<T>::value, int> = 0>
285 constexpr auto exponent(T&& t)
286 {
287 return IntFraction<2>{};
288 }
289
290 template<class T, std::enable_if_t<IsReciprocalExpression<T>::value, int> = 0>
291 constexpr auto exponent(T&& t)
292 {
293 return IntFraction<-1>{};
294 }
295
296 constexpr auto exponent(SqrtOperation)
297 {
298 return IntFraction<1, 2>{};
299 }
300
301 constexpr auto exponent(SquareOperation)
302 {
303 return IntFraction<2>{};
304 }
305
306 constexpr auto exponent(ReciprocalOperation)
307 {
308 return IntFraction<-1>{};
309 }
310
311 template<class Operation>
312 constexpr auto exponent(OperationTraits<Operation>)
313 {
314 return exponent(Operation{});
315 }
316
317 template<class WhatEver>
318 constexpr auto exponent()
319 {
320 return exponent(WhatEver{});
321 }
322
323 template<class T, class SFINAE = void>
324 struct ExponentiationTraits
325 {};
326
327 template<class T>
328 struct ExponentiationTraits<T, std::enable_if_t<IsExponentiationExpression<T>::value> >
329 {
330 using BaseType = Expressions::Operand<0, T>;
331 using ExponentType = std::decay_t<decltype(exponent(std::declval<T>()))>;
332 };
333
334 template<class T>
335 using ExponentOfPower = typename ExponentiationTraits<T>::ExponentType;
336
337 template<class T>
338 using BaseOfPower = typename ExponentiationTraits<T>::BaseType;
339
340 using SquareFunctor = OperationTraits<SquareOperation>;
341
342 template<class T, class SFINAE = void>
343 struct SquareTraits;
344
345 /**************************************************************************
346 *
347 * AssumeOperation
348 *
349 */
350
351 template<class T>
352 struct IsAssumeOperation
353 : FalseType
354 {};
355
356 template<class... Properties>
357 struct IsAssumeOperation<AssumeOperation<Properties...> >
358 : TrueType
359 {};
360
361 template<class T>
362 using IsAssumeExpression = IsAssumeOperation<Expressions::Operation<T> >;
363
364 template<class T>
365 struct AssumeTraits
366 {
367 using Properties = void;
368 };
369
370 template<class... Property>
371 struct AssumeTraits<AssumeOperation<Property...> >
372 {
373 using Properties = MPL::TagContainer<Property...>;
374 };
375
376 template<class... Properties>
377 struct AssumeTraits<OperationTraits<AssumeOperation<Properties...> > >
378 : AssumeTraits<AssumeOperation<Properties...> >
379 {};
380
381 /**************************************************************************
382 *
383 * IndeterminateOperation
384 *
385 */
386
387 template<class T>
388 struct IsIndeterminateOperation
389 : FalseType
390 {};
391
392 template<std::size_t Id>
393 struct IsIndeterminateOperation<IndeterminateOperation<Id> >
394 : TrueType
395 {};
396
397 template<class T>
398 using IsIndeterminateExpression = IsIndeterminateOperation<Expressions::Operation<T> >;
399
400 template<class T, class SFINAE = void>
401 struct IndeterminateTraits;
402
403 template<std::size_t Id>
404 struct IndeterminateTraits<IndeterminateOperation<Id> >
405 {
406 static constexpr std::size_t id_ = Id;
407 using IdType = IndexConstant<Id>;
408 };
409
410 template<std::size_t Id>
411 struct IndeterminateTraits<OperationTraits<IndeterminateOperation<Id> > >
412 : IndeterminateTraits<IndeterminateOperation<Id> >
413 {};
414
415 template<class T>
416 struct IndeterminateTraits<
417 T,
418 std::enable_if_t<IsIndeterminateOperation<Expressions::Operation<T> >::value> >
419 : IndeterminateTraits<Expressions::Operation<T> >
420 {};
421
422 template<class Candidate, class Id, class SFINAE = void>
423 struct IndeterminateMatch
424 : FalseType
425 {};
426
427 template<class Candidate, class Id>
428 struct IndeterminateMatch<
429 Candidate, Id,
430 std::enable_if_t<IndeterminateTraits<Candidate>::id_ == Id::value> >
431 : TrueType
432 {};
433
434 template<std::size_t Id, class T>
435 constexpr bool indeterminateMatch(T&& t, IndexConstant<Id> = IndexConstant<Id>::value)
436 {
437 return IndeterminateMatch<T, IndexConstant<Id> >::value;
438 }
439
440 /**************************************************************************
441 *
442 * PlaceholderOperation
443 *
444 */
445
446 template<class T>
447 struct IsPlaceholderOperation
448 : FalseType
449 {};
450
451 template<class Placeholder>
452 struct IsPlaceholderOperation<PlaceholderOperation<Placeholder> >
453 : TrueType
454 {};
455
456 template<class T>
457 using IsPlaceholderExpression = IsPlaceholderOperation<Expressions::Operation<T> >;
458
459 template<class T, class SFINAE = void>
460 struct PlaceholderTraits;
461
462 template<class Placeholder>
463 struct PlaceholderTraits<PlaceholderOperation<Placeholder> >
464 {
465 using PlaceholderType = Placeholder;
466 };
467
468 template<class Placeholder>
469 struct PlaceholderTraits<OperationTraits<PlaceholderOperation<Placeholder> > >
470 : PlaceholderTraits<PlaceholderOperation<Placeholder> >
471 {};
472
473 template<class T>
474 struct PlaceholderTraits<
475 T,
476 std::enable_if_t<IsPlaceholderOperation<Expressions::Operation<T> >::value> >
477 : PlaceholderTraits<Expressions::Operation<T> >
478 {};
479
480 template<class Candidate, class Placeholder, class SFINAE = void>
481 struct PlaceholderMatch
482 : FalseType
483 {};
484
485 template<class Candidate, class Placeholder>
486 struct PlaceholderMatch<
487 Candidate, Placeholder,
488 std::enable_if_t<std::is_same<typename PlaceholderTraits<Candidate>::PlaceholderType, Placeholder>::value> >
489 : TrueType
490 {};
491
492 template<class Placeholder, class T>
493 constexpr bool placeholderMatch(T&& t, Placeholder&&)
494 {
495 return PlaceholderMatch<T, Placeholder>::value;
496 }
497
498 template<class Placeholder, class T>
499 constexpr bool placeholderMatch(T&& t)
500 {
501 return PlaceholderMatch<T, Placeholder>::value;
502 }
503
504 /**************************************************************************
505 *
506 * SubExpressionOperation
507 *
508 */
509
510 template<class T>
511 struct IsSubExpressionOperation
512 : FalseType
513 {};
514
515 template<class Id>
516 struct IsSubExpressionOperation<SubExpressionOperation<Id> >
517 : TrueType
518 {};
519
520 template<class T>
521 using IsSubExpressionExpression = IsSubExpressionOperation<Expressions::Operation<T> >;
522
523 template<class T, class SFINAE = void>
524 struct SubExpressionTraits;
525
526 template<std::size_t... OperandPos>
527 struct SubExpressionTraits<SubExpressionOperation<IndexSequence<OperandPos...> > >
528 {
529 using TreePos = IndexSequence<OperandPos...>;
530 };
531
532 template<std::size_t... OperandPos>
533 struct SubExpressionTraits<OperationTraits<SubExpressionOperation<IndexSequence<OperandPos...> > > >
534 : SubExpressionTraits<SubExpressionOperation<IndexSequence<OperandPos...> > >
535 {};
536
537 template<class T>
538 struct SubExpressionTraits<
539 T,
540 std::enable_if_t<IsSubExpressionOperation<Expressions::Operation<T> >::value> >
541 : SubExpressionTraits<Expressions::Operation<T> >
542 {};
543
544 /**************************************************************************
545 *
546 * Volatile operations render the resulting expression as "must
547 * not be optimized away", except for "runtime-equal"
548 * optimizations.
549 *
550 */
551
552 template<class T>
553 struct IsVolatileOperation
554 : FalseType
555 {};
556
560 template<class Placeholder>
561 struct IsVolatileOperation<PlaceholderOperation<Placeholder> >
562 : TrueType
563 {};
564
566 template<std::size_t Id>
567 struct IsVolatileOperation<IndeterminateOperation<Id> >
568 : TrueType
569 {};
570
571 /**************************************************************************
572 *
573 * Dynamic operations on constant objects render the result
574 * dynamic, see IsRuntimeEqual, AreRuntimeEqual.
575 *
576 */
577
586 template<class T, class SFINAE = void>
588 : IsVolatileOperation<T>
589 {};
590
592
593 namespace Expressions
594 {
595 template<class Operation>
596 using F = OperationTraits<Operation>;
597 }
598
600 template<class F>
601 std::string operationName(F&& f, const std::string& arg)
602 {
603 return std::forward<F>(f).name() + "(" + arg + ")";
604 }
605
607 template<class F>
608 std::string operationName(F&& f, const std::string& left, const std::string& right)
609 {
610 return "(" + left + " " + std::forward<F>(f).name() + " " + right + ")";
611 }
612
613 namespace {
614
615 template<class String>
616 std::string operationNameHelper(String&& last)
617 {
618 return std::forward<String>(last);
619 }
620
621 template<class... Strings>
622 std::string operationNameHelper(const std::string& s0, const std::string& s1, Strings&&... rest)
623 {
624 return s0 + ", " + operationNameHelper(s1, std::forward<Strings>(rest)...);
625 }
626 }
627
629 template<class F, class... Strings, std::enable_if_t<(sizeof...(Strings) > 2), int> = 0>
630 std::string operationName(F&& f, Strings&&... strings)
631 {
632 return (std::forward<F>(f).name()
633 +
634 "(" + operationNameHelper(std::forward<Strings>(strings)...) + ")"
635 );
636 }
637
638 template<>
639 struct OperationTraits<IdentityOperation>
640 {
641 using InvertibleOperation = IdentityOperation;
642 using OperationType = IdentityOperation;
643
644 template<class Value>
645 using ResultType = Value;
646
647 template<class Order>
648 static constexpr auto polynomialOrder(Order oldOrder)
649 {
650 return oldOrder;
651 }
652
653 template<class Sign>
654 static constexpr auto signPropagation(Sign)
655 {
656 return Sign{};
657 }
658
659 static std::string name()
660 {
661 return "Id";
662 }
663
664 template<class T>
665 constexpr decltype(auto) operator()(T&& arg) const
666 {
667 return std::forward<T>(arg);
668 }
669 };
670
676 template<class... Property>
677 struct OperationTraits<AssumeOperation<Property...> >
678 {
679 using InvertibleOperation = void;
680 using OperationType = AssumeOperation<Property...>;
681 using Properties = typename AssumeOperation<Property...>::Properties;
682
683 template<class T, class SFINAE = void>
684 struct HasOperation
685 : FalseType
686 {
687 // assume elementary type if no indeterminate operation is defined.
688 using ResultType = FloatingPointClosure<T>;
689 };
690
691 template<class T>
692 struct HasOperation<T, std::enable_if_t<(sizeof(decltype(assume(std::declval<T>(), Properties{}))) >= 0)> >
693 : TrueType
694 {
695 using ResultType = std::decay_t<decltype(assume(std::declval<T>(), Properties{}))>;
696 };
697
698 template<class T>
699 using ResultType = typename HasOperation<T>::ResultType;
700
701 //TODO: may depend on the property
702 template<class Order>
703 static constexpr auto polynomialOrder(Order oldOrder)
704 {
705 return oldOrder;
706 }
707
708 //TODO: may depend on the propery
709 template<class Sign>
710 static constexpr auto signPropagation(Sign)
711 {
712 return UnknownExpressionSign{};
713 }
714
715 static std::string name()
716 {
717 // indeterminates are always called "x", unless they are called "y" ;)
718 auto str = (std::string("assume<") + ... + toString(Property{}));
719 str += str.back() == '>' ? " >" : ">";
720 return str;
721 }
722
724 template<class T, std::enable_if_t<HasOperation<T>::value, int> = 0>
725 constexpr auto operator()(T&& t) const
726 {
727 return assume(std::forward<T>(t), Properties{});
728 }
729
734 template<class T, std::enable_if_t<!HasOperation<T>::value, int> = 0>
735 constexpr decltype(auto) operator()(T&& t) const
736 {
737 return forwardReturnValue<T>(t);
738 }
739
740 };
741
742 template<std::size_t Id>
743 struct OperationTraits<IndeterminateOperation<Id> >
744 {
745 using InvertibleOperation = void;
746 using OperationType = IndeterminateOperation<Id>;
747
748 template<class T, class SFINAE = void>
749 struct HasOperation
750 : FalseType
751 {
752 // assume elementary type if no indeterminate operation is defined.
753 using ResultType = FloatingPointClosure<T>;
754 };
755
756 template<class T>
757 struct HasOperation<T, std::enable_if_t<(sizeof(decltype(indeterminate(std::declval<T>(), IndexConstant<Id>{}))) >= 0)> >
758 : TrueType
759 {
760 using ResultType = std::decay_t<decltype(indeterminate(std::declval<T>(), IndexConstant<Id>{}))>;
761 };
762
763 template<class T>
764 using ResultType = typename HasOperation<T>::ResultType;
765
766 template<class Order>
767 static constexpr auto polynomialOrder(Order oldOrder)
768 {
769 return oldOrder;
770 }
771
772 template<class Sign>
773 static constexpr auto signPropagation(Sign)
774 {
775 return UnknownExpressionSign{};
776 }
777
778 static std::string name()
779 {
780 // indeterminates are always called "x", unless they are called "y" ;)
781 return "X["+std::to_string(Id)+"]";
782 }
783
785 template<class T, std::enable_if_t<HasOperation<T>::value, int> = 0>
786 auto operator()(T&& t) const
787 {
788 return indeterminate(std::forward<T>(t), IndexConstant<Id>{});
789 }
790
795 template<class T, std::enable_if_t<!HasOperation<T>::value, int> = 0>
796 constexpr FloatingPointClosure<T> operator()(T&& t) const
797 {
798 return t;
799 }
800
801 };
802
803 template<class Placeholder>
804 struct OperationTraits<PlaceholderOperation<Placeholder> >
805 {
806 using InvertibleOperation = void;
807 using OperationType = PlaceholderOperation<Placeholder>;
808
809 template<class T, class SFINAE = void>
810 struct HasOperation
811 : FalseType
812 {
813 // assume elementary type if no placeholder operation is defined.
814 using ResultType = T;
815 };
816
817 template<class T>
818 struct HasOperation<T, VoidType<decltype(placeholder(std::declval<T>(), OperationType{}))> >
819 : TrueType
820 {
821 using ResultType = std::decay_t<decltype(placeholder(std::declval<T>(), OperationType{}))>;
822 };
823
824 template<class T>
825 using ResultType = typename HasOperation<T>::ResultType;
826
827 template<class Order>
828 static constexpr auto polynomialOrder(Order oldOrder)
829 {
830 return oldOrder;
831 }
832
833 template<class Sign>
834 static constexpr auto signPropagation(Sign)
835 {
836 return Sign{};
837 }
838
839 template<class T, std::enable_if_t<HasOperation<T>::value, int> = 0>
840 constexpr auto operator()(T&& t) const
841 {
842 return placeholder(std::forward<T>(t), OperationType{});
843 }
844
849 template<class T, std::enable_if_t<!HasOperation<T>::value, int> = 0>
850 constexpr T /*FloatingPointClosure<T>*/ operator()(T&& t) const
851 {
852 return std::forward<T>(t);
853 }
854
855 static std::string name()
856 {
857 return "?!";
858 }
859
860 private:
861#if 0
862 static std::string idString(UnknownExpression<>)
863 {
864 return "";
865 }
866#endif
867
868 template<class T>
869 static std::string idString(T)
870 {
871 return toString(T{});
872 }
873 };
874
875 template<std::size_t... OperandPos>
876 struct OperationTraits<SubExpressionOperation<IndexSequence<OperandPos...> > >
877 {
878 using TreePos = IndexSequence<OperandPos...>;
879 using InvertibleOperation = void;
880 using OperationType = SubExpressionOperation<TreePos>;
881
882 template<class T1, class T2, class SFINAE = void>
883 struct HasOperation
884 : FalseType
885 {
886 // assume elementary type if no indeterminate operation is defined.
887 using ResultType = FloatingPointClosure<T1>;
888 };
889
890 template<class T1, class T2>
891 struct HasOperation<T1, T2, std::enable_if_t<(sizeof(decltype(subExpression(std::declval<T1>(), std::declval<T2>(), TreePos{}))) >= 0)> >
892 : TrueType
893 {
894 using ResultType = std::decay_t<decltype(subExpression(std::declval<T1>(), std::declval<T2>(), TreePos{}))>;
895 };
896
897 template<class T1, class T2>
898 using ResultType = typename HasOperation<T1, T2>::ResultType;
899
900 template<class Order>
901 static constexpr auto polynomialOrder(std::size_t order1, Order order2)
902 {
903 return order2;
904 }
905
906 template<class S1, class S2>
907 static constexpr auto signPropagation(const S1&, const S2&)
908 {
909 return S2{};
910 }
911
912 static std::string name()
913 {
914 return "SExp"+(size<TreePos>() > 0 ? "{" + toString(TreePos{}) + "}" : "");
915 }
916
917// template<class T1, class T2, std::enable_if_t<HasOperation<T1, T2>::value, int> = 0>
918 template<class T1, class T2, std::enable_if_t<IsExpression<T1>::value || IsExpression<T2>::value, int> = 0>
919 auto operator()(T1&& t1, T2&& t2) const
920 {
921 return subExpression(std::forward<T1>(t1), std::forward<T2>(t2), TreePos{});
922 }
923
927// template<class T1, class T2,std::enable_if_t<!HasOperation<T1, T2>::value, int> = 0>
928 template<class T1, class T2, std::enable_if_t<!IsExpression<T1>::value && !IsExpression<T2>::value, int> = 0>
929 constexpr FloatingPointClosure<T1> operator()(T1&& t1, T2&& t2) const
930 {
931 return t1;
932 }
933
934 };
935
937
943 template<>
944 struct OperationTraits<EqOperation>
945 {
946 using InvertibleOperation = void;
947 using OperationType = EqOperation;
948
949 template<class T0, class T1>
950 using ResultType = bool;
951
952 template<class Order0, class Order1>
953 static constexpr auto polynomialOrder(Order0, Order1)
954 {
955 using namespace Literals;
956 return 0_f;
957 }
958
959 template<class Sign0, class Sign1>
960 static constexpr auto signPropagation(Sign0, Sign1)
961 {
962 return SemiPositiveExpressionSign{};
963 }
964
965 static std::string name()
966 {
967 return "==";
968 }
969
970 template<class T0, class T1>
971 constexpr auto operator()(T0&& t0, T1&& t1) const
972 {
973 return std::forward<T0>(t0) == std::forward<T1>(t1);
974 }
975 };
976
977 template<>
978 struct OperationTraits<NeOperation>
979 {
980 using InvertibleOperation = void;
981 using OperationType = NeOperation;
982
983 template<class T0, class T1>
984 using ResultType = bool;
985
986 template<class Order0, class Order1>
987 static constexpr auto polynomialOrder(Order0, Order1)
988 {
989 using namespace Literals;
990 return 0_f;
991 }
992
993 template<class Sign0, class Sign1>
994 static constexpr auto signPropagation(Sign0, Sign1)
995 {
996 return SemiPositiveExpressionSign{};
997 }
998
999 static std::string name()
1000 {
1001 return "!=";
1002 }
1003
1004 template<class T0, class T1>
1005 constexpr auto operator()(T0&& t0, T1&& t1) const
1006 {
1007 return std::forward<T0>(t0) != std::forward<T1>(t1);
1008 }
1009 };
1010
1011 template<>
1012 struct OperationTraits<GtOperation>
1013 {
1014 using InvertibleOperation = void;
1015 using OperationType = GtOperation;
1016
1017 template<class T0, class T1>
1018 using ResultType = bool;
1019
1020 template<class Order0, class Order1>
1021 static constexpr auto polynomialOrder(Order0, Order1)
1022 {
1023 using namespace Literals;
1024 return 0_f;
1025 }
1026
1027 template<class Sign0, class Sign1>
1028 static constexpr auto signPropagation(Sign0, Sign1)
1029 {
1030 return SemiPositiveExpressionSign{};
1031 }
1032
1033 static std::string name()
1034 {
1035 return ">";
1036 }
1037
1038 template<class T0, class T1>
1039 constexpr auto operator()(T0&& t0, T1&& t1) const
1040 {
1041 return std::forward<T0>(t0) > std::forward<T1>(t1);
1042 }
1043 };
1044
1045 template<>
1046 struct OperationTraits<GeOperation>
1047 {
1048 using InvertibleOperation = void;
1049 using OperationType = GeOperation;
1050
1051 template<class T0, class T1>
1052 using ResultType = bool;
1053
1054 template<class Order0, class Order1>
1055 static constexpr auto polynomialOrder(Order0, Order1)
1056 {
1057 using namespace Literals;
1058 return 0_f;
1059 }
1060
1061 template<class Sign0, class Sign1>
1062 static constexpr auto signPropagation(Sign0, Sign1)
1063 {
1064 return SemiPositiveExpressionSign{};
1065 }
1066
1067 static std::string name()
1068 {
1069 return ">=";
1070 }
1071
1072 template<class T0, class T1>
1073 constexpr auto operator()(T0&& t0, T1&& t1) const
1074 {
1075 return std::forward<T0>(t0) >= std::forward<T1>(t1);
1076 }
1077 };
1078
1079 template<>
1080 struct OperationTraits<LtOperation>
1081 {
1082 using InvertibleOperation = void;
1083 using OperationType = LtOperation;
1084
1085 template<class T0, class T1>
1086 using ResultType = bool;
1087
1088 template<class Order0, class Order1>
1089 static constexpr auto polynomialOrder(Order0, Order1)
1090 {
1091 using namespace Literals;
1092 return 0_f;
1093 }
1094
1095 template<class Sign0, class Sign1>
1096 static constexpr auto signPropagation(Sign0, Sign1)
1097 {
1098 return SemiPositiveExpressionSign{};
1099 }
1100
1101 static std::string name()
1102 {
1103 return "<";
1104 }
1105
1106 template<class T0, class T1>
1107 constexpr auto operator()(T0&& t0, T1&& t1) const
1108 {
1109 return std::forward<T0>(t0) < std::forward<T1>(t1);
1110 }
1111 };
1112
1113 template<>
1114 struct OperationTraits<LeOperation>
1115 {
1116 using InvertibleOperation = void;
1117 using OperationType = LeOperation;
1118
1119 template<class T0, class T1>
1120 using ResultType = bool;
1121
1122 template<class Order0, class Order1>
1123 static constexpr auto polynomialOrder(Order0, Order1)
1124 {
1125 using namespace Literals;
1126 return 0_f;
1127 }
1128
1129 template<class Sign0, class Sign1>
1130 static constexpr auto signPropagation(Sign0, Sign1)
1131 {
1132 return SemiPositiveExpressionSign{};
1133 }
1134
1135 static std::string name()
1136 {
1137 return "<=";
1138 }
1139
1140 template<class T0, class T1>
1141 constexpr auto operator()(T0&& t0, T1&& t1) const
1142 {
1143 return std::forward<T0>(t0) <= std::forward<T1>(t1);
1144 }
1145 };
1146
1148
1154 template<>
1155 struct OperationTraits<LogicalNotOperation>
1156 {
1157 using InvertibleOperation = LogicalNotOperation;
1158 using OperationType = LogicalNotOperation;
1159
1160 template<class T>
1161 using ResultType = std::decay_t<decltype(!std::declval<T>())>;
1162
1163 template<class Order>
1164 static constexpr auto polynomialOrder(Order oldOrder)
1165 {
1166 using namespace Literals;
1167 return 0_f;
1168 }
1169
1170 template<class Sign>
1171 static constexpr auto signPropagation(Sign)
1172 {
1173 return ExpressionSign<!Sign::isNonSingular,
1174 true, // semi-positive
1175 false, // semi-negative
1176 false>{};
1177 }
1178
1179 static std::string name()
1180 {
1181 return "!";
1182 }
1183
1184 template<class T>
1185 constexpr auto operator()(T&& arg) const
1186 {
1187 return !std::forward<T>(arg);
1188 }
1189 };
1190
1191 template<>
1192 struct OperationTraits<LogicalOrOperation>
1193 {
1194 using InvertibleOperation = void;
1195 using OperationType = LogicalOrOperation;
1196
1197 template<class T1, class T2>
1198 using ResultType = std::decay_t<decltype(std::declval<T1>() || std::declval<T2>())>;
1199
1200 static constexpr auto polynomialOrder(unsigned order1, unsigned order2)
1201 {
1202 using namespace Literals;
1203 return 0_f;
1204 }
1205
1206 template<class S1, class S2>
1207 static constexpr auto signPropagation(const S1&, const S2&)
1208 {
1209 return ExpressionSign<(S1::isNonSingular || S2::isNonSingular), true, false, 0>{};
1210 }
1211
1212 static std::string name()
1213 {
1214 return "||";
1215 }
1216
1217 template<class T1, class T2>
1218 constexpr auto operator()(T1&& t1, T2&& t2) const
1219 {
1220 return std::forward<T1>(t1) || std::forward<T2>(t2);
1221 }
1222 };
1223
1224 template<>
1225 struct OperationTraits<LogicalAndOperation>
1226 {
1227 using InvertibleOperation = void;
1228 using OperationType = LogicalAndOperation;
1229
1230 template<class T1, class T2>
1231 using ResultType = std::decay_t<decltype(std::declval<T1>() && std::declval<T2>())>;
1232
1233 static constexpr auto polynomialOrder(unsigned order1, unsigned order2)
1234 {
1235 using namespace Literals;
1236 return 0_f;
1237 }
1238
1239 template<class S1, class S2>
1240 static constexpr auto signPropagation(const S1&, const S2&)
1241 {
1242 return ExpressionSign<(S1::isNonSingular && S2::isNonSingular), true, false, 0>{};
1243 }
1244
1245 static std::string name()
1246 {
1247 return "&&";
1248 }
1249
1250 template<class T1, class T2>
1251 constexpr auto operator()(T1&& t1, T2&& t2) const
1252 {
1253 return std::forward<T1>(t1) && std::forward<T2>(t2);
1254 }
1255 };
1256
1258
1264 template<>
1265 struct OperationTraits<PlusOperation>
1266 {
1267 using InvertibleOperation = void;
1268 using OperationType = PlusOperation;
1269
1270 template<class T1, class T2>
1271 struct ResultHelper
1272 {
1273 using Type = std::decay_t<decltype(std::declval<T1>() + std::declval<T2>())>;
1274 };
1275
1276 template<class T>
1277 struct ResultHelper<T, void>
1278 {
1279 using Type = OperationTraits<IdentityOperation>::template ResultType<T>;
1280 };
1281
1282 // We need the helper struct as we must not instantiate the
1283 // binary plus expression if T2 is void.
1284 template<class T1, class T2 = void>
1285 using ResultType = typename ResultHelper<T1, T2>::Type;
1286
1287 static constexpr auto polynomialOrder(unsigned order1, unsigned order2)
1288 {
1289 return max(order1, order2);
1290 }
1291
1292 template<class S>
1293 static constexpr auto signPropagation(S)
1294 {
1295 return S{};
1296 }
1297
1298 template<class S1, class S2>
1299 static constexpr auto signPropagation(const S1&, const S2&)
1300 {
1301 return ExpressionSign<(S1::isNonSingular || S2::isNonSingular)
1302 &&
1303 ((S1::isSemiPositive && S2::isSemiPositive)
1304 ||
1305 (S1::isSemiNegative && S2::isSemiNegative)),
1306 S1::isSemiPositive && S2::isSemiPositive,
1307 S1::isSemiNegative && S2::isSemiNegative,
1308 S1::reference + S2::reference>{};
1309 }
1310
1311 template<class T>
1312 constexpr decltype(auto) operator()(T&& arg) const
1313 {
1314 return std::forward<T>(arg);
1315 }
1316
1317 template<class T1, class T2>
1318 constexpr auto operator()(T1&& t1, T2&& t2) const
1319 {
1320 return std::forward<T1>(t1) + std::forward<T2>(t2);
1321 }
1322
1323 static std::string name()
1324 {
1325 return "+";
1326 }
1327 };
1328
1329 template<>
1330 struct OperationTraits<PlusEqOperation>
1331 {
1332 using InvertibleOperation = void;
1333 using OperationType = PlusEqOperation;
1334
1335 template<class T1, class T2>
1336 using ResultType = std::decay_t<decltype(std::declval<T1>() += std::declval<T2>())>;
1337
1338 static constexpr auto polynomialOrder(unsigned order1, unsigned order2)
1339 {
1340 return max(order1, order2);
1341 }
1342
1343 template<class S1, class S2>
1344 static constexpr auto signPropagation(const S1&, const S2&)
1345 {
1346 return ExpressionSign<(S1::isNonSingular || S2::isNonSingular)
1347 &&
1348 ((S1::isSemiPositive && S2::isSemiPositive)
1349 ||
1350 (S1::isSemiNegative && S2::isSemiNegative)),
1351 S1::isSemiPositive && S2::isSemiPositive,
1352 S1::isSemiNegative && S2::isSemiNegative,
1353 S1::reference + S2::reference>{};
1354 }
1355
1356 template<class T1, class T2>
1357 constexpr decltype(auto) operator()(T1&& t1, T2&& t2) const
1358 {
1359 return std::forward<T1>(t1) += std::forward<T2>(t2);
1360 }
1361
1362 static std::string name()
1363 {
1364 return "+=";
1365 }
1366 };
1367
1368 template<>
1369 struct OperationTraits<MinusOperation>
1370 {
1371 using ThisType = OperationTraits<MinusOperation>;
1372 using InvertibleOperation = MinusOperation;
1373 using OperationType = MinusOperation;
1374
1375 template<class T1, class T2>
1376 struct ResultHelper
1377 {
1378 using Type = std::decay_t<decltype(std::declval<T1>() - std::declval<T2>())>;
1379 };
1380
1381 template<class T>
1382 struct ResultHelper<T, std::enable_if_t<HasUnaryMinus<T>::value> >
1383 {
1384 using Type = std::decay_t<decltype(-std::declval<T>())>;
1385 };
1386
1387 template<class T>
1388 struct ResultHelper<T, std::enable_if_t<!HasUnaryMinus<T>::value> >
1389 {
1390 using Type = std::decay_t<decltype(std::declval<T>())>;
1391 };
1392
1393 // We need the helper struct as we must not instantiate the
1394 // binary minus expression if T2 is void.
1395 template<class T1, class T2 = void>
1396 using ResultType = typename ResultHelper<T1, T2>::Type;
1397
1398 static constexpr auto polynomialOrder(unsigned order1, unsigned order2)
1399 {
1400 return max(order1, order2);
1401 }
1402
1403 template<class Order>
1404 static constexpr auto polynomialOrder(Order order)
1405 {
1406 return order;
1407 }
1408
1409 template<class Sign>
1410 static constexpr auto signPropagation(const Sign&)
1411 {
1412 // switch signs.
1413 return ExpressionSign<Sign::isNonSingular,
1414 Sign::isSemiNegative,
1415 Sign::isSemiPositive,
1416 -Sign::reference>{};
1417 }
1418
1419 template<class S1, class S2>
1420 static constexpr auto signPropagation(const S1&, const S2&)
1421 {
1422 return ExpressionSign<((S1::isNonSingular || S2::isNonSingular)
1423 &&
1424 ((S1::isSemiPositive && S2::isSemiNegative)
1425 ||
1426 (S1::isSemiNegative && S2::isSemiPositive))),
1427 S1::isSemiPositive && S2::isSemiNegative,
1428 S1::isSemiNegative && S2::isSemiPositive,
1429 S1::reference - S2::reference>{};
1430 }
1431
1432 static std::string name()
1433 {
1434 return "-";
1435 }
1436
1437 template<class T, std::enable_if_t<HasUnaryMinus<T>::value, int> = 0>
1438 constexpr auto operator()(T&& t) const
1439 {
1440 return -std::forward<T>(t);
1441 }
1442
1443 template<class T, std::enable_if_t<!HasUnaryMinus<T>::value, int> = 0>
1444 constexpr auto operator()(T&& t) const
1445 {
1446 std::decay_t<T> tmp(t);
1447 return (tmp *= -1);
1448 }
1449
1450 template<class T1, class T2>
1451 constexpr auto operator()(T1&& t1, T2&& t2) const
1452 {
1453 return std::forward<T1>(t1) - std::forward<T2>(t2);
1454 }
1455 };
1456
1457 template<>
1458 struct OperationTraits<MinusEqOperation>
1459 {
1460 using InvertibleOperation = void;
1461 using OperationType = MinusEqOperation;
1462
1463 template<class T1, class T2>
1464 using ResultType = std::decay_t<decltype(std::declval<T1>() -= std::declval<T2>())>;
1465
1466 static constexpr auto polynomialOrder(unsigned order1, unsigned order2)
1467 {
1468 return max(order1, order2);
1469 }
1470
1471 template<class S1, class S2>
1472 static constexpr auto signPropagation(const S1&, const S2&)
1473 {
1474 return ExpressionSign<(S1::isNonSingular || S2::isNonSingular)
1475 &&
1476 ((S1::isSemiPositive && S2::isSemiPositive)
1477 ||
1478 (S1::isSemiNegative && S2::isSemiNegative)),
1479 S1::isSemiPositive && S2::isSemiPositive,
1480 S1::isSemiNegative && S2::isSemiNegative,
1481 S1::reference + S2::reference>{};
1482 }
1483
1484 template<class T1, class T2>
1485 constexpr decltype(auto) operator()(T1&& t1, T2&& t2) const
1486 {
1487 return std::forward<T1>(t1) -= std::forward<T2>(t2);
1488 }
1489
1490 static std::string name()
1491 {
1492 return "-=";
1493 }
1494 };
1495
1496 template<>
1497 struct OperationTraits<ReciprocalOperation>
1498 {
1499 using InvertibleOperation = ReciprocalOperation;
1500 using OperationType = ReciprocalOperation;
1501
1502 template<class T, class SFINAE = void>
1503 struct HasOperation
1504 : FalseType
1505 {
1506 // assume elementary type if no indeterminate operation is defined.
1507 using ResultType = FloatingPointClosure<T>;
1508 };
1509
1510 template<class T>
1511 struct HasOperation<T, std::enable_if_t<(sizeof(decltype(reciprocal(std::declval<T>()))) >= 0)> >
1512 : TrueType
1513 {
1514 using ResultType = std::decay_t<decltype(reciprocal(std::declval<T>()))>;
1515 };
1516
1517 template<class T>
1518 using ResultType = typename HasOperation<T>::ResultType;
1519
1520 static std::size_t polynomialOrder(std::size_t oldOrder)
1521 {
1522 return oldOrder;
1523 }
1524
1525 template<class Sign, std::enable_if_t<Sign::reference == 0, int> = 0>
1526 static constexpr auto signPropagation(const Sign&)
1527 {
1528 return Sign{};
1529 }
1530
1531 template<class Sign, std::enable_if_t<(Sign::reference >= 1), int> = 0>
1532 static constexpr auto signPropagation(const Sign&)
1533 {
1534 // switch signs
1535 return ExpressionSign<Sign::isNonSingular,
1536 false,
1537 Sign::isSemiPositive,
1538 1>{};
1539 }
1540
1541 template<class Sign, std::enable_if_t<(Sign::reference <= -1), int> = 0>
1542 static constexpr auto signPropagation(const Sign&)
1543 {
1544 // switch signs
1545 return ExpressionSign<Sign::isNonSingular,
1546 Sign::isSemiNegative,
1547 false,
1548 -1>{};
1549 }
1550
1551 static std::string name()
1552 {
1553 return "1_c/";
1554 }
1555
1557 template<class T, std::enable_if_t<HasOperation<T>::value, int> = 0>
1558 auto operator()(T&& t) const
1559 {
1560 return reciprocal(std::forward<T>(t));
1561 }
1562
1565 template<
1566 class T,
1567 std::enable_if_t<(!HasOperation<T>::value
1568 && std::numeric_limits<std::decay_t<T> >::is_integer), int> = 0>
1569 constexpr auto operator()(T&& t) const
1570 {
1571 return 1./FloatingPointClosure<T>(t);
1572 }
1573
1576 template<
1577 class T,
1578 std::enable_if_t<(!HasOperation<T>::value
1579 && !std::numeric_limits<std::decay_t<T> >::is_integer
1580 ), int> = 0>
1581 constexpr auto operator()(T&& t) const
1582 {
1583 return one(std::forward<T>(t))/std::forward<T>(t);
1584 }
1585 };
1586
1587 template<>
1588 struct OperationTraits<SquareOperation>
1589 {
1590 using InvertibleOperation = SqrtOperation;
1591 using OperationType = SquareOperation;
1592
1593 template<class T, class SFINAE = void>
1594 struct HasOperation
1595 : FalseType
1596 {
1597 // assume elementary type if no indeterminate operation is defined.
1598 using ResultType = FloatingPointClosure<T>;
1599 };
1600
1601 template<class T>
1602 struct HasOperation<T, std::enable_if_t<(sizeof(decltype(sqr(std::declval<T>()))) >= 0)> >
1603 : TrueType
1604 {
1605 using ResultType = std::decay_t<decltype(sqr(std::declval<T>()))>;
1606 };
1607
1608 template<class T>
1609 using ResultType = typename HasOperation<T>::ResultType;
1610
1611 // Assuming only real numbers.
1612 template<class Sign>
1613 static constexpr auto signPropagation(const Sign&)
1614 {
1615 constexpr ssize_t reference = Sign::reference*Sign::reference;
1616 constexpr bool goodCase = ((Sign::reference >= 0 && Sign::isSemiPositive)
1617 ||
1618 (Sign::reference <= 0 && Sign::isSemiNegative));
1619 return ExpressionSign<goodCase && Sign::isNonSingular, true, false, goodCase*reference>{};
1620 }
1621
1622 static std::string name()
1623 {
1624 return "sqr";
1625 }
1626
1627 template<class Order>
1628 static constexpr auto polynomialOrder(Order oldOrder)
1629 {
1630 using namespace Literals;
1631 return 2_f*oldOrder;
1632 }
1633
1635 template<class T, std::enable_if_t<HasOperation<T>::value, int> = 0>
1636 auto operator()(T&& t) const
1637 {
1638 return sqr(std::forward<T>(t));
1639 }
1640
1641 template<class T, std::enable_if_t<!HasOperation<T>::value, int> = 0>
1642 constexpr auto operator()(T&& t) const
1643 {
1644 return std::forward<T>(t)*std::forward<T>(t);
1645 }
1646 };
1647
1648 template<>
1649 struct OperationTraits<SMultiplyOperation>
1650 {
1651 using OperationType = SMultiplyOperation;
1652 using InvertibleOperation = void;
1653
1654 template<class T1, class T2, class Enable = void>
1655 struct ResultHelper;
1656
1657 template<class T1, class T2>
1658 struct ResultHelper<T1, T2,
1659 std::enable_if_t<IsFieldVector<T2>::value && (T2::dimension > 1)> >
1660 {
1661 using ResultType = std::decay_t<T2>;
1662 };
1663
1664 template<class T1, class T2>
1665 struct ResultHelper<T1, T2,
1666 std::enable_if_t<IsFieldVector<T1>::value && (T1::dimension > 1)> >
1667 {
1668 using ResultType = std::decay_t<T1>;
1669 };
1670
1671 template<class T1, class T2>
1672 struct ResultHelper<T1, T2,
1673 std::enable_if_t<std::is_convertible<T1, typename FieldTraits<T1>::field_type>::value &&
1674 std::is_convertible<T2, typename FieldTraits<T2>::field_type>::value> >
1675 {
1676 using ResultType = std::decay_t<decltype(std::declval<T1>() * std::declval<T2>())>;
1677 };
1678
1679 template<class T1, class T2>
1680 using ResultType = typename ResultHelper<T1, T2>::ResultType;
1681
1682 template<class Order1, class Order2>
1683 static constexpr auto polynomialOrder(Order1 order1, Order2 order2)
1684 {
1685 return order1 + order2;
1686 }
1687
1688 // multiplication by scalars, non-zero property is maintained
1689 template<class S1, class S2>
1690 static constexpr auto signPropagation(const S1&, const S2&)
1691 {
1692 return ExpressionSign<// non-singular
1693 (S1::isNonSingular && S2::isNonSingular
1694 &&
1695 (((S1::reference >= 0) && S1::isSemiPositive)
1696 ||
1697 ((S1::reference <= 0) && S1::isSemiNegative))
1698 &&
1699 (((S2::reference >= 0) && S2::isSemiPositive)
1700 ||
1701 ((S2::reference <= 0) && S2::isSemiNegative))),
1702 // >= dim * S1::reference * S2::reference
1703 ((S1::reference*S2::reference >= 0)
1704 &&
1705 ((S1::isSemiPositive && S2::isSemiPositive)
1706 ||
1707 (S1::isSemiNegative && S2::isSemiNegative))),
1708 // >= dim * S1::reference * S2::reference
1709 ((S1::reference*S2::reference <= 0)
1710 &&
1711 ((S1::isSemiPositive && S2::isSemiNegative)
1712 ||
1713 (S1::isSemiNegative && S2::isSemiPositive))),
1714 // new reference
1715 S1::reference * S2::reference>{};
1716 }
1717
1718 static std::string name()
1719 {
1720 return "*";
1721 }
1722
1723 template<class T1, class T2>
1724 constexpr auto operator()(T1&& t1, T2&& t2) const
1725 {
1726 return std::forward<T1>(t1) * std::forward<T2>(t2);
1727 }
1728 };
1729
1730 template<>
1731 struct OperationTraits<SMultiplyEqOperation>
1732 {
1733 using OperationType = SMultiplyEqOperation;
1734 using InvertibleOperation = void;
1735
1736 template<class T1, class T2>
1737 using ResultType = std::decay_t<decltype(std::declval<T1>() *= std::declval<T2>())>;
1738
1739 template<class Order1, class Order2>
1740 static constexpr auto polynomialOrder(Order1 order1, Order2 order2)
1741 {
1742 return order1 + order2;
1743 }
1744
1745 // multiplication by scalars, non-zero property is maintained
1746 template<class S1, class S2>
1747 static constexpr auto signPropagation(const S1&, const S2&)
1748 {
1749 return ExpressionSign<// non-singular
1750 (S1::isNonSingular && S2::isNonSingular
1751 &&
1752 (((S1::reference >= 0) && S1::isSemiPositive)
1753 ||
1754 ((S1::reference <= 0) && S1::isSemiNegative))
1755 &&
1756 (((S2::reference >= 0) && S2::isSemiPositive)
1757 ||
1758 ((S2::reference <= 0) && S2::isSemiNegative))),
1759 // >= dim * S1::reference * S2::reference
1760 ((S1::reference*S2::reference >= 0)
1761 &&
1762 ((S1::isSemiPositive && S2::isSemiPositive)
1763 ||
1764 (S1::isSemiNegative && S2::isSemiNegative))),
1765 // >= dim * S1::reference * S2::reference
1766 ((S1::reference*S2::reference <= 0)
1767 &&
1768 ((S1::isSemiPositive && S2::isSemiNegative)
1769 ||
1770 (S1::isSemiNegative && S2::isSemiPositive))),
1771 // new reference
1772 S1::reference * S2::reference>{};
1773 }
1774
1775 static std::string name()
1776 {
1777 return "*=";
1778 }
1779
1780 template<class T1, class T2>
1781 constexpr decltype(auto) operator()(T1&& t1, T2&& t2) const
1782 {
1783 return std::forward<T1>(t1) *= std::forward<T2>(t2);
1784 }
1785 };
1786
1788
1794 template<>
1795 struct OperationTraits<SqrtOperation>
1796 {
1797 using InvertibleOperation = SquareOperation;
1798 using OperationType = SqrtOperation;
1799
1800 template<class Value>
1801 using ResultType = FloatingPointClosure<Value>;
1802
1804 static std::size_t polynomialOrder(std::size_t oldOrder)
1805 {
1806 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
1807 }
1808
1809 // Assuming only real numbers.
1810 template<class Sign>
1811 static constexpr auto signPropagation(const Sign&)
1812 {
1813 return ExpressionSign<Sign::reference >= 0 && Sign::isNonSingular, true, false>{};
1814 }
1815
1816 static std::string name()
1817 {
1818 return "sqrt";
1819 }
1820
1821 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
1822 constexpr auto operator()(T&& t) const
1823 {
1824 return sqrt(std::forward<T>(t));
1825 }
1826
1827 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
1828 constexpr auto operator()(T&& t) const
1829 {
1830 return sqrt(floatingPointClosure(std::forward<T>(t)));
1831 }
1832 };
1833
1834 template<>
1835 struct OperationTraits<ExpOperation>
1836 {
1837 using InvertibleOperation = LogOperation;
1838 using OperationType = ExpOperation;
1839
1840 template<class Value>
1841 using ResultType = FloatingPointClosure<Value>;
1842
1843 template<class Sign>
1844 static constexpr auto signPropagation(const Sign&)
1845 {
1846 return ExpressionSign<Sign::isNonSingular, true, false,
1847 std::max(0L, (ssize_t)Sign::isSemiPositive * (Sign::reference + 1L))>{};
1848 }
1849
1850 template<class Sign, std::enable_if_t<(Sign::reference < 0), int> = 0>
1851 static constexpr auto signPropagation(const Sign&)
1852 {
1853 return ExpressionSign<Sign::isNonSingular, true, false, 0>{};
1854 }
1855
1856 static std::string name()
1857 {
1858 return "exp";
1859 }
1860
1862 static std::size_t polynomialOrder(std::size_t oldOrder)
1863 {
1864 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
1865 }
1866
1867 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
1868 constexpr auto operator()(T&& t) const
1869 {
1870 return exp(std::forward<T>(t));
1871 }
1872
1873 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
1874 constexpr auto operator()(T&& t) const
1875 {
1876 return exp(floatingPointClosure(std::forward<T>(t)));
1877 }
1878 };
1879
1880 template<>
1881 struct OperationTraits<LogOperation>
1882 {
1883 using InvertibleOperation = ExpOperation;
1884 using OperationType = LogOperation;
1885
1886 template<class Value>
1887 using ResultType = FloatingPointClosure<Value>;
1888
1890 static std::size_t polynomialOrder(std::size_t oldOrder)
1891 {
1892 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
1893 }
1894
1895 template<class Sign>
1896 static constexpr auto signPropagation(const Sign&)
1897 {
1898 return ExpressionSign<!(Sign::reference == 1 && Sign::isZero),
1899 (Sign::reference >= 1) && Sign::isSemiPositive,
1900 (Sign::reference == 1) && Sign::isSemiNegative, 0>{};
1901 }
1902
1903 static std::string name()
1904 {
1905 return "log";
1906 }
1907
1908 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
1909 constexpr auto operator()(T&& t) const
1910 {
1911 return log(std::forward<T>(t));
1912 }
1913
1914 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
1915 constexpr auto operator()(T&& t) const
1916 {
1917 return log(floatingPointClosure(std::forward<T>(t)));
1918 }
1919 };
1920
1921 template<>
1922 struct OperationTraits<ErfOperation>
1923 {
1924 using InvertibleOperation = void;
1925 using OperationType = ErfOperation;
1926
1927 template<class Value>
1928 using ResultType = FloatingPointClosure<Value>;
1929
1930 template<class Sign>
1931 static constexpr auto signPropagation(Sign)
1932 {
1933 return Sign{};
1934 }
1935
1936 static std::string name()
1937 {
1938 return "erf";
1939 }
1940
1941 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
1942 {
1943 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
1944 }
1945
1946 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
1947 constexpr auto operator()(T&& t) const
1948 {
1949 return erf(std::forward<T>(t));
1950 }
1951
1952 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
1953 constexpr auto operator()(T&& t) const
1954 {
1955 return erf(floatingPointClosure(std::forward<T>(t)));
1956 }
1957 };
1958
1959 template<>
1960 struct OperationTraits<LGammaOperation>
1961 {
1962 using InvertibleOperation = void;
1963 using OperationType = LGammaOperation;
1964
1965 template<class Value>
1966 using ResultType = FloatingPointClosure<Value>;
1967
1968 template<class Sign>
1969 static constexpr auto signPropagation(Sign)
1970 {
1971 return SemiPositiveExpressionSign{};
1972 }
1973
1974 static std::string name()
1975 {
1976 return "lgamma";
1977 }
1978
1979 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
1980 {
1981 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
1982 }
1983
1984 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
1985 constexpr auto operator()(T&& t) const
1986 {
1987 return lgamma(std::forward<T>(t));
1988 }
1989
1990 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
1991 constexpr auto operator()(T&& t) const
1992 {
1993 return lgamma(floatingPointClosure(std::forward<T>(t)));
1994 }
1995 };
1996
1997 template<>
1998 struct OperationTraits<TGammaOperation>
1999 {
2000 using InvertibleOperation = void;
2001 using OperationType = TGammaOperation;
2002
2003 template<class Value>
2004 using ResultType = FloatingPointClosure<Value>;
2005
2006 template<class Sign>
2007 static constexpr auto signPropagation(Sign)
2008 {
2009 return PositiveExpressionSign{};
2010 }
2011
2012 static std::string name()
2013 {
2014 return "tgamma";
2015 }
2016
2017 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2018 {
2019 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2020 }
2021
2022 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2023 constexpr auto operator()(T&& t) const
2024 {
2025 return tgamma(std::forward<T>(t));
2026 }
2027
2028 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2029 constexpr auto operator()(T&& t) const
2030 {
2031 return tgamma(floatingPointClosure(std::forward<T>(t)));
2032 }
2033 };
2034
2035 template<>
2036 struct OperationTraits<CoshOperation>
2037 {
2038 using InvertibleOperation = AcoshOperation;
2039 using OperationType = CoshOperation;
2040
2041 template<class Value>
2042 using ResultType = FloatingPointClosure<Value>;
2043
2044 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2045 {
2046 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2047 }
2048
2049 template<class Sign>
2050 static constexpr auto signPropagation(const Sign&)
2051 {
2052 return ExpressionSign<false, // >= 1
2053 true, // semi positive,
2054 false, // not semi negative,
2055 1>{};
2056 }
2057
2058 static std::string name()
2059 {
2060 return "cosh";
2061 }
2062
2063 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2064 constexpr auto operator()(T&& t) const
2065 {
2066 return cosh(std::forward<T>(t));
2067 }
2068
2069 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2070 constexpr auto operator()(T&& t) const
2071 {
2072 return cosh(floatingPointClosure(std::forward<T>(t)));
2073 }
2074 };
2075
2076 template<>
2077 struct OperationTraits<SinhOperation>
2078 {
2079 using InvertibleOperation = AsinhOperation;
2080 using OperationType = SinhOperation;
2081
2082 template<class Value>
2083 using ResultType = FloatingPointClosure<Value>;
2084
2085 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2086 {
2087 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2088 }
2089
2090 template<class Sign>
2091 static constexpr auto signPropagation(const Sign&)
2092 {
2093 return Sign{};
2094 }
2095
2096 static std::string name()
2097 {
2098 return "sinh";
2099 }
2100
2101 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2102 constexpr auto operator()(T&& t) const
2103 {
2104 return sinh(std::forward<T>(t));
2105 }
2106
2107 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2108 constexpr auto operator()(T&& t) const
2109 {
2110 return sinh(floatingPointClosure(std::forward<T>(t)));
2111 }
2112 };
2113
2114 template<>
2115 struct OperationTraits<TanhOperation>
2116 {
2117 using InvertibleOperation = AtanhOperation;
2118 using OperationType = TanhOperation;
2119
2120 template<class Value>
2121 using ResultType = FloatingPointClosure<Value>;
2122
2123 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2124 {
2125 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2126 }
2127
2128 template<class Sign>
2129 static constexpr auto signPropagation(const Sign&)
2130 {
2131 return Sign{};
2132 }
2133
2134 static std::string name()
2135 {
2136 return "tanh";
2137 }
2138
2139 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2140 constexpr auto operator()(T&& t) const
2141 {
2142 return tanh(std::forward<T>(t));
2143 }
2144
2145 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2146 constexpr auto operator()(T&& t) const
2147 {
2148 return tanh(floatingPointClosure(std::forward<T>(t)));
2149 }
2150 };
2151
2152 template<>
2153 struct OperationTraits<AcoshOperation>
2154 {
2155 using InvertibleOperation = void;
2156 using OperationType = AcoshOperation;
2157
2158 template<class Value>
2159 using ResultType = FloatingPointClosure<Value>;
2160
2161 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2162 {
2163 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2164 }
2165
2166 template<class Sign>
2167 static constexpr auto signPropagation(const Sign&)
2168 {
2169 return ExpressionSign<false, // >= 0
2170 true, // semi positive,
2171 false // not semi negative
2172 >{};
2173 }
2174
2175 static std::string name()
2176 {
2177 return "acosh";
2178 }
2179
2180 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2181 constexpr auto operator()(T&& t) const
2182 {
2183 return acosh(std::forward<T>(t));
2184 }
2185
2186 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2187 constexpr auto operator()(T&& t) const
2188 {
2189 return acosh(floatingPointClosure(std::forward<T>(t)));
2190 }
2191 };
2192
2193 template<>
2194 struct OperationTraits<AsinhOperation>
2195 {
2196 using InvertibleOperation = SinhOperation;
2197 using OperationType = AsinhOperation;
2198
2199 template<class Value>
2200 using ResultType = FloatingPointClosure<Value>;
2201
2202 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2203 {
2204 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2205 }
2206
2207 template<class Sign>
2208 static constexpr auto signPropagation(const Sign&)
2209 {
2210 return Sign{};
2211 }
2212
2213 static std::string name()
2214 {
2215 return "sinh";
2216 }
2217
2218 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2219 constexpr auto operator()(T&& t) const
2220 {
2221 return asinh(std::forward<T>(t));
2222 }
2223
2224 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2225 constexpr auto operator()(T&& t) const
2226 {
2227 return asinh(floatingPointClosure(std::forward<T>(t)));
2228 }
2229 };
2230
2231 template<>
2232 struct OperationTraits<AtanhOperation>
2233 {
2234 using InvertibleOperation = TanhOperation;
2235 using OperationType = AtanhOperation;
2236
2237 template<class Value>
2238 using ResultType = FloatingPointClosure<Value>;
2239
2240 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2241 {
2242 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2243 }
2244
2245 template<class Sign>
2246 static constexpr auto signPropagation(const Sign&)
2247 {
2248 return Sign{};
2249 }
2250
2251 static std::string name()
2252 {
2253 return "atanh";
2254 }
2255
2256 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2257 constexpr auto operator()(T&& t) const
2258 {
2259 return atanh(std::forward<T>(t));
2260 }
2261
2262 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2263 constexpr auto operator()(T&& t) const
2264 {
2265 return atanh(floatingPointClosure(std::forward<T>(t)));
2266 }
2267 };
2268
2269 template<>
2270 struct OperationTraits<SinOperation>
2271 {
2272 using InvertibleOperation = AsinOperation;
2273 using OperationType = SinOperation;
2274
2275 template<class Value>
2276 using ResultType = FloatingPointClosure<Value>;
2277
2278 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2279 {
2280 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2281 }
2282
2283 //This operation destroys all knowledge about the sign.
2284 template<class Sign>
2285 static constexpr auto signPropagation(const Sign&)
2286 {
2287 return UnknownExpressionSign{};
2288 }
2289
2290 static std::string name()
2291 {
2292 return "sin";
2293 }
2294
2295 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2296 constexpr auto operator()(T&& t) const
2297 {
2298 return sin(std::forward<T>(t));
2299 }
2300
2301 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2302 constexpr auto operator()(T&& t) const
2303 {
2304 return sin(floatingPointClosure(std::forward<T>(t)));
2305 }
2306 };
2307
2308 template<>
2309 struct OperationTraits<CosOperation>
2310 {
2311 using InvertibleOperation = AcosOperation;
2312 using OperationType = CosOperation;
2313
2314 template<class Value>
2315 using ResultType = FloatingPointClosure<Value>;
2316
2317 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2318 {
2319 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2320 }
2321
2322 //This operation destroys all knowledge about the sign.
2323 template<class Sign>
2324 static constexpr auto signPropagation(const Sign&)
2325 {
2326 return UnknownExpressionSign{};
2327 }
2328
2329 static std::string name()
2330 {
2331 return "cos";
2332 }
2333
2334 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2335 constexpr auto operator()(T&& t) const
2336 {
2337 return cos(std::forward<T>(t));
2338 }
2339
2340 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2341 constexpr auto operator()(T&& t) const
2342 {
2343 return cos(floatingPointClosure(std::forward<T>(t)));
2344 }
2345 };
2346
2347 template<>
2348 struct OperationTraits<TanOperation>
2349 {
2350 using InvertibleOperation = AtanOperation;
2351 using OperationType = TanOperation;
2352
2353 template<class Value>
2354 using ResultType = FloatingPointClosure<Value>;
2355
2356 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2357 {
2358 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2359 }
2360
2361 template<class Sign>
2362 static constexpr auto signPropagation(const Sign&)
2363 {
2364 return UnknownExpressionSign{};
2365 }
2366
2367 static std::string name()
2368 {
2369 return "tan";
2370 }
2371
2372 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2373 constexpr auto operator()(T&& t) const
2374 {
2375 return tan(std::forward<T>(t));
2376 }
2377
2378 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2379 constexpr auto operator()(T&& t) const
2380 {
2381 return tan(floatingPointClosure(std::forward<T>(t)));
2382 }
2383 };
2384
2385 template<>
2386 struct OperationTraits<AsinOperation>
2387 {
2388 using InvertibleOperation = void;
2389 using OperationType = AsinOperation;
2390
2391 template<class Value>
2392 using ResultType = FloatingPointClosure<Value>;
2393
2394 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2395 {
2396 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2397 }
2398
2399 template<class Sign>
2400 static constexpr auto signPropagation(const Sign&)
2401 {
2402 return ExpressionSign<((Sign::reference >= 2 || Sign::reference <= -2)
2403 ||
2404 (Sign::reference == 0 && Sign::isNonSingular)
2405 ||
2406 (Sign::reference > 0 && Sign::isSemiPositive)
2407 ||
2408 (Sign::reference < 0 && Sign::isSemiNegative)),
2409 (Sign::reference >= 0 && Sign::isSemiPositive),
2410 (Sign::reference <= 0 && Sign::isSemiNegative),
2411 0>{};
2412 }
2413
2414 static std::string name()
2415 {
2416 return "asin";
2417 }
2418
2419 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2420 constexpr auto operator()(T&& t) const
2421 {
2422 return asin(std::forward<T>(t));
2423 }
2424
2425 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2426 constexpr auto operator()(T&& t) const
2427 {
2428 return asin(floatingPointClosure(std::forward<T>(t)));
2429 }
2430 };
2431
2432 template<>
2433 struct OperationTraits<AcosOperation>
2434 {
2435 using InvertibleOperation = void;
2436 using OperationType = AcosOperation;
2437
2438 template<class Value>
2439 using ResultType = FloatingPointClosure<Value>;
2440
2441 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2442 {
2443 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2444 }
2445
2446 template<class Sign>
2447 static constexpr auto signPropagation(const Sign&)
2448 {
2449 // cos is semiPositive
2450 return ExpressionSign<(Sign::reference == 0 && Sign::isSemiNegative)
2451 ||
2452 (Sign::reference == 1 && Sign::isNonSingular),
2453 true, false, 0>{};
2454 }
2455
2456 static std::string name()
2457 {
2458 return "acos";
2459 }
2460
2461 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2462 constexpr auto operator()(T&& t) const
2463 {
2464 return acos(std::forward<T>(t));
2465 }
2466
2467 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2468 constexpr auto operator()(T&& t) const
2469 {
2470 return acos(floatingPointClosure(std::forward<T>(t)));
2471 }
2472 };
2473
2474 template<>
2475 struct OperationTraits<AtanOperation>
2476 {
2477 using InvertibleOperation = void;
2478 using OperationType = AtanOperation;
2479
2480 template<class Value>
2481 using ResultType = FloatingPointClosure<Value>;
2482
2483 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2484 {
2485 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2486 }
2487
2488 template<class Sign>
2489 static constexpr auto signPropagation(const Sign&)
2490 {
2491 return ExpressionSign<((Sign::reference >= 2 || Sign::reference <= -2)
2492 ||
2493 (Sign::reference == 0 && Sign::isNonSingular)
2494 ||
2495 (Sign::reference == 1 && Sign::isSemiPositive)
2496 ||
2497 (Sign::reference == -1 && Sign::isSemiNegative)),
2498 (Sign::reference >= 0 && Sign::isSemiPositive),
2499 (Sign::reference <= 0 && Sign::isSemiNegative),
2500 0>{};
2501 }
2502
2503 static std::string name()
2504 {
2505 return "atan";
2506 }
2507
2508 template<class T, std::enable_if_t<!IsScalar<T>::value, int> = 0>
2509 constexpr auto operator()(T&& t) const
2510 {
2511 return atan(std::forward<T>(t));
2512 }
2513
2514 template<class T, std::enable_if_t<IsScalar<T>::value, int> = 0>
2515 constexpr auto operator()(T&& t) const
2516 {
2517 return atan(floatingPointClosure(std::forward<T>(t)));
2518 }
2519 };
2520
2521 template<>
2522 struct OperationTraits<PowOperation>
2523 {
2524 using InvertibleOperation = void;
2525 using OperationType = PowOperation;
2526
2527 template<class T1, class T2>
2528 using ResultType = typename FieldPromotion<T1, FloatingPointClosure<T2> >::Type;
2529
2530 static constexpr std::size_t polynomialOrder(unsigned order1, unsigned order2)
2531 {
2532 return order2 == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2533 }
2534
2535 // Assuming only real numbers.
2536 template<class S1, class S2>
2537 static constexpr auto signPropagation(const S1&, const S2&)
2538 {
2539 return ExpressionSign<S1::reference >= 0 && S1::isNonSingular, true, false>{};
2540 }
2541
2542 static std::string name()
2543 {
2544 return "^";
2545 }
2546
2547 template<class T1, class T2, std::enable_if_t<!IsScalar<T1>::value && !IsScalar<T2>::value, int> = 0>
2548 constexpr auto operator()(T1&& t1, T2&& t2) const
2549 {
2550 return pow(std::forward<T1>(t1), std::forward<T2>(t2));
2551 }
2552
2553 template<class T1, class T2, std::enable_if_t<IsScalar<T1>::value && IsScalar<T2>::value, int> = 0>
2554 constexpr auto operator()(T1&& t1, T2&& t2) const
2555 {
2556 return pow(floatingPointClosure(std::forward<T1>(t1)), floatingPointClosure(std::forward<T2>(t2)));
2557 }
2558
2559 template<class T, class I, I N,
2560 std::enable_if_t<(N % 2 == 1
2561 && N < 0
2562 && -N < 20
2563 && IsScalar<T>::value
2564 ), int> = 0>
2565 constexpr auto operator()(T&& t, TypedValue::FractionConstant<I, N, 2>) const
2566 {
2567 using namespace Literals;
2568
2569 return 1_f / sqrt(multiplyLoop<-N>(1_f, [&](auto i) { return std::forward<T>(t); }));
2570 }
2571
2572 template<class T, class I, I N,
2573 std::enable_if_t<(N < 0
2574 && -N < 20
2575 && IsScalar<T>::value
2576 ), int> = 0>
2577 constexpr auto operator()(T&& t, TypedValue::FractionConstant<I, N, 1>) const
2578 {
2579 using namespace Literals;
2580
2581 return 1_f / multiplyLoop<-N>(1_f, [&](auto i) { return std::forward<T>(t); });
2582 }
2583
2584 template<class T, class I, I N,
2585 std::enable_if_t<(N > 0
2586 && N < 20
2587 && IsScalar<T>::value
2588 ), int> = 0>
2589 constexpr auto operator()(T&& t, TypedValue::FractionConstant<I, N, 1>) const
2590 {
2591 using namespace Literals;
2592
2593 return multiplyLoop<N>(1_f, [&](auto i) { return std::forward<T>(t); });
2594 }
2595
2596 };
2597
2598 template<>
2599 struct OperationTraits<Atan2Operation>
2600 {
2601 using InvertibleOperation = void;
2602 using OperationType = Atan2Operation;
2603
2604 template<class T1, class T2>
2605 using ResultType = typename FieldPromotion<T1, T2>::Type;
2606
2607 static constexpr std::size_t polynomialOrder(unsigned order1, unsigned order2)
2608 {
2609 return order1 == 0 && order2 == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2610 }
2611
2612 // Assuming only real numbers.
2613 template<class S1, class S2>
2614 static constexpr auto signPropagation(const S1&, const S2&)
2615 {
2616 return ExpressionSign<((S1::reference >= 0 && S1::isPositive)
2617 ||
2618 (S1::reference <= 0 && S1::isNegative)),
2619 S1::reference >= 0 && S1::isSemiPositive,
2620 S1::reference <= 0 && S1::isSemiNegative>{};
2621 }
2622
2623 static std::string name()
2624 {
2625 return "atan2";
2626 }
2627
2628 template<class T1, class T2, std::enable_if_t<!IsScalar<T1>::value && !IsScalar<T2>::value, int> = 0>
2629 constexpr auto operator()(T1&& t1, T2&& t2) const
2630 {
2631 return atan2(std::forward<T1>(t1), std::forward<T2>(t2));
2632 }
2633
2634 template<class T1, class T2, std::enable_if_t<IsScalar<T1>::value && IsScalar<T2>::value, int> = 0>
2635 constexpr auto operator()(T1&& t1, T2&& t2) const
2636 {
2637 return atan2(floatingPointClosure(std::forward<T1>(t1)), floatingPointClosure(std::forward<T2>(t2)));
2638 }
2639 };
2640
2641 template<>
2642 struct OperationTraits<MinOperation>
2643 {
2644 using InvertibleOperation = void;
2645 using OperationType = MinOperation;
2646
2647 template<class T1, class T2>
2648 using ResultType = std::decay_t<decltype(min(std::declval<T1>(), std::declval<T2>()))>;
2649
2650 static constexpr std::size_t polynomialOrder(unsigned order1, unsigned order2)
2651 {
2652 return std::max(order1, order2); // don't know
2653 }
2654
2655 // Assuming only real numbers.
2656 template<class S1, class S2>
2657 static constexpr auto signPropagation(const S1&, const S2&)
2658 {
2659 return ExpressionSign<(S1::reference == S2::reference
2660 &&
2661 ((S1::isNonSingular && S1::isNegative)
2662 ||
2663 (S2::isNonSingular && S2::isNegative))),
2664 (S1::reference == S2::reference
2665 &&
2666 S1::isSemiPositive
2667 &&
2668 S2::isSemiPositive),
2669 (S1::reference == S2::reference
2670 &&
2671 S1::isSemiNegative
2672 &&
2673 S2::isSemiNegative)>{};
2674 }
2675
2676 static std::string name()
2677 {
2678 return "min";
2679 }
2680
2681 template<class T1, class T2>
2682 constexpr auto operator()(T1&& t1, T2&& t2) const
2683 {
2684 return min(std::forward<T1>(t1), std::forward<T2>(t2));
2685 }
2686 };
2687
2688 template<>
2689 struct OperationTraits<MaxOperation>
2690 {
2691 using InvertibleOperation = void;
2692 using OperationType = MaxOperation;
2693
2694 template<class T1, class T2>
2695 using ResultType = std::decay_t<decltype(max(std::declval<T1>(), std::declval<T2>()))>;
2696
2697 static constexpr std::size_t polynomialOrder(unsigned order1, unsigned order2)
2698 {
2699 return std::max(order1, order2); // don't know
2700 }
2701
2702 // Assuming only real numbers.
2703 template<class S1, class S2>
2704 static constexpr auto signPropagation(const S1&, const S2&)
2705 {
2706 return ExpressionSign<(S1::reference == S2::reference
2707 &&
2708 ((S1::isNonSingular && S1::isNegative)
2709 ||
2710 (S2::isNonSingular && S2::isNegative))),
2711 (S1::reference == S2::reference
2712 &&
2713 S1::isSemiPositive
2714 &&
2715 S2::isSemiPositive),
2716 (S1::reference == S2::reference
2717 &&
2718 S1::isSemiNegative
2719 &&
2720 S2::isSemiNegative)>{};
2721 }
2722
2723 static std::string name()
2724 {
2725 return "max";
2726 }
2727
2728 template<class T1, class T2>
2729 constexpr auto operator()(T1&& t1, T2&& t2) const
2730 {
2731 return max(std::forward<T1>(t1), std::forward<T2>(t2));
2732 }
2733 };
2734
2735 template<>
2736 struct OperationTraits<TernaryOperation>
2737 {
2738 using InvertibleOperation = void;
2739 using OperationType = TernaryOperation;
2740
2741 template<class T1>
2742 using ResultType = double;
2743
2744 template<class Order>
2745 static constexpr auto polynomialOrder(Order)
2746 {
2747 using namespace Literals;
2748
2749 return 0_f;
2750 }
2751
2752 // Assuming only real numbers.
2753 template<class S1>
2754 static constexpr auto signPropagation(const S1&)
2755 {
2756 return SemiPositiveExpressionSign{};
2757 }
2758
2759 static std::string name()
2760 {
2761 return "if";
2762 }
2763
2764 template<class T1>
2765 constexpr auto operator()(T1&& t1) const
2766 {
2767 if(t1 > 0)
2768 return 1.;
2769 else
2770 return 0.;
2771 }
2772 };
2773
2775
2777
2779
2780 } // ACFem
2781
2782} // Dune
2783
2784#endif // __DUNE_ACFEM_EXPRESSIONS_OPERATIONTRAITS_HH__
std::string operationName(F &&f, const std::string &arg)
Verbose print of an operation, helper function to produce noise.
Definition: operationtraits.hh:601
constexpr auto floatingPointClosure(T &&t)
Convert in particular integer types to a decent floating point type.
Definition: fieldpromotion.hh:80
constexpr auto one(T &&t)
Use the one fraction as canonical zero element for scalars.
Definition: constantoperations.hh:88
constexpr auto multiplyLoop(T &&init, F &&f, IndexConstant< N >=IndexConstant< N >{})
Version with just a plain number as argument.
Definition: foreach.hh:135
auto pow(T1 &&t1, T2 &&t2)
Power operations with scalar exponents are promoted to component-wise power operations by multiplying...
Definition: expressions.hh:525
Sequence< std::size_t, V... > IndexSequence
Sequence of std::size_t values.
Definition: types.hh:64
Constant< bool, V > BoolConstant
Short-cut for integral constant of type bool.
Definition: types.hh:48
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
ExpressionSign< false, false, false > UnknownExpressionSign
Sign traits structure with names matching the expression tag structs.
Definition: sign.hh:64
STL namespace.
Indeterminate operation, wrap another object and attach an id.
Definition: expressionoperations.hh:113
True for expressions which can be moved inside or outside of sums.
Definition: operationtraits.hh:227
Should be overloaded to std::true_type for operations which introduce runtime variable data into the ...
Definition: operationtraits.hh:589
Evaluate to std::true_type if the operation is product-like.
Definition: operationtraits.hh:113
Logical And.
Definition: expressionoperations.hh:55
Placeholder operation wraps another object and attaches an id to it.
Definition: expressionoperations.hh:126
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)