1 #ifndef __DUNE_ACFEM_EXPRESSIONS_OPERATIONTRAITS_HH__
2 #define __DUNE_ACFEM_EXPRESSIONS_OPERATIONTRAITS_HH__
9 #include "../common/ostream.hh"
10 #include "../common/literals.hh"
11 #include "../mpl/tostring.hh"
12 #include "../mpl/foreach.hh"
14 #include "expressiontraits.hh"
15 #include "constantoperations.hh"
16 #include "expressionoperations.hh"
25 #include "usingstd.hh"
62 template<
class Operation>
63 struct OperationTraits;
67 template<
template<
class...>
class Predicate,
class T>
72 template<
template<
class...>
class Predicate,
class T>
73 struct FunctorHas<Predicate, T&>
74 : FunctorHas<Predicate, std::decay_t<T> >
77 template<
template<
class...>
class Predicate,
class T>
78 struct FunctorHas<Predicate, T&&>
79 : FunctorHas<Predicate, std::decay_t<T> >
82 template<
template<
class...>
class Predicate,
class T>
83 struct FunctorHas<Predicate, OperationTraits<T> >
94 using IsIdentityOperation = std::is_same<IdentityOperation, F>;
97 using IsIdentityExpression = IsIdentityOperation<Expressions::Operation<T> >;
127 struct IsProductOperation<SMultiplyOperation>
132 using IsSMultiplyOperation = std::is_same<SMultiplyOperation, F>;
135 using IsSMultiplyExpression = IsSMultiplyOperation<Expressions::Operation<T> >;
140 constexpr
inline bool MultiplicationAdmitsScalarsV =
false;
143 constexpr
inline bool MultiplicationAdmitsScalarsV<T&> = MultiplicationAdmitsScalarsV<std::decay_t<T> >;
146 constexpr
inline bool MultiplicationAdmitsScalarsV<OperationTraits<T> > = MultiplicationAdmitsScalarsV<T>;
149 constexpr
inline bool MultiplicationAdmitsScalarsV<SMultiplyOperation> =
true;
152 constexpr
inline bool MultiplicationAdmitsScalarsV<LogicalAndOperation> =
true;
161 using IsLogicalOrExpression = std::is_same<Expressions::Operation<T>, LogicalOrOperation>;
164 using IsLogicalAndExpression = std::is_same<Expressions::Operation<T>, LogicalAndOperation>;;
167 using IsLogicalNotExpression = std::is_same<Expressions::Operation<T>, LogicalNotOperation>;
176 using IsPlusOperation = std::is_same<PlusOperation, F>;
179 using IsMinusOperation = std::is_same<MinusOperation, F>;
182 using IsPlusOrMinusOperation = BoolConstant<IsPlusOperation<F>::value || IsMinusOperation<F>::value>;
185 using IsBinaryPlusExpression =
187 && std::is_same<Expressions::Operation<T>, PlusOperation>::value)>;
190 using IsBinaryMinusExpression =
192 && std::is_same<Expressions::Operation<T>, MinusOperation>::value)>;
195 using IsUnaryMinusExpression =
197 && std::is_same<Expressions::Operation<T>, MinusOperation>::value)>;
200 using IsPlusOrMinusExpression = BoolConstant<IsBinaryPlusExpression<T>::value || IsBinaryMinusExpression<T>::value>;
202 using PlusFunctor = OperationTraits<PlusOperation>;
203 using MinusFunctor = OperationTraits<MinusOperation>;
207 template<
class F0,
class F1>
208 struct NestedSumFunctorHelper
210 using Type = MinusFunctor;
214 struct NestedSumFunctorHelper<F, F>
216 using Type = PlusFunctor;
220 template<
class F0,
class F1>
221 using NestedSumFunctor =
typename NestedSumFunctorHelper<F0, F1>::Type;
224 template<
class Operation,
class SFINAE =
void>
236 struct IsReciprocalExpression
237 : std::is_same<Expressions::Operation<T>, ReciprocalOperation>
241 struct IsSqrtExpression
242 : std::is_same<Expressions::Operation<T>, SqrtOperation>
246 struct IsSquareExpression
247 : std::is_same<Expressions::Operation<T>, SquareOperation>
251 struct IsPowExpression
252 : std::is_same<Expressions::Operation<T>, PowOperation>
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
265 struct IsExponentiationExpression
267 || IsSqrtExpression<T>::value
268 || IsSquareExpression<T>::value
269 || IsReciprocalExpression<T>::value)>
272 template<class T, std::enable_if_t<IsPowExpression<T>::value,
int> = 0>
273 constexpr decltype(
auto) exponent(T&& t)
275 return std::forward<T>(t).template operand<1>();
278 template<class T, std::enable_if_t<IsSqrtExpression<T>::value,
int> = 0>
279 constexpr
auto exponent(T&& t)
281 return IntFraction<1, 2>{};
284 template<class T, std::enable_if_t<IsSquareExpression<T>::value,
int> = 0>
285 constexpr
auto exponent(T&& t)
287 return IntFraction<2>{};
290 template<class T, std::enable_if_t<IsReciprocalExpression<T>::value,
int> = 0>
291 constexpr
auto exponent(T&& t)
293 return IntFraction<-1>{};
296 constexpr
auto exponent(SqrtOperation)
298 return IntFraction<1, 2>{};
301 constexpr
auto exponent(SquareOperation)
303 return IntFraction<2>{};
306 constexpr
auto exponent(ReciprocalOperation)
308 return IntFraction<-1>{};
311 template<
class Operation>
312 constexpr
auto exponent(OperationTraits<Operation>)
314 return exponent(Operation{});
317 template<
class WhatEver>
318 constexpr
auto exponent()
320 return exponent(WhatEver{});
323 template<
class T,
class SFINAE =
void>
324 struct ExponentiationTraits
328 struct ExponentiationTraits<T, std::enable_if_t<IsExponentiationExpression<T>::value> >
330 using BaseType = Expressions::Operand<0, T>;
331 using ExponentType = std::decay_t<decltype(exponent(std::declval<T>()))>;
335 using ExponentOfPower =
typename ExponentiationTraits<T>::ExponentType;
338 using BaseOfPower =
typename ExponentiationTraits<T>::BaseType;
340 using SquareFunctor = OperationTraits<SquareOperation>;
342 template<
class T,
class SFINAE =
void>
352 struct IsAssumeOperation
356 template<
class... Properties>
357 struct IsAssumeOperation<AssumeOperation<Properties...> >
362 using IsAssumeExpression = IsAssumeOperation<Expressions::Operation<T> >;
367 using Properties = void;
370 template<
class... Property>
371 struct AssumeTraits<AssumeOperation<Property...> >
373 using Properties = MPL::TagContainer<Property...>;
376 template<
class... Properties>
377 struct AssumeTraits<OperationTraits<AssumeOperation<Properties...> > >
378 : AssumeTraits<AssumeOperation<Properties...> >
388 struct IsIndeterminateOperation
392 template<std::
size_t Id>
393 struct IsIndeterminateOperation<IndeterminateOperation<Id> >
398 using IsIndeterminateExpression = IsIndeterminateOperation<Expressions::Operation<T> >;
400 template<
class T,
class SFINAE =
void>
401 struct IndeterminateTraits;
403 template<std::
size_t Id>
404 struct IndeterminateTraits<IndeterminateOperation<Id> >
406 static constexpr std::size_t id_ = Id;
407 using IdType = IndexConstant<Id>;
410 template<std::
size_t Id>
411 struct IndeterminateTraits<OperationTraits<IndeterminateOperation<Id> > >
412 : IndeterminateTraits<IndeterminateOperation<Id> >
416 struct IndeterminateTraits<
418 std::enable_if_t<IsIndeterminateOperation<Expressions::Operation<T> >::value> >
419 : IndeterminateTraits<Expressions::Operation<T> >
422 template<
class Cand
idate,
class Id,
class SFINAE =
void>
423 struct IndeterminateMatch
427 template<
class Cand
idate,
class Id>
428 struct IndeterminateMatch<
430 std::enable_if_t<IndeterminateTraits<Candidate>::id_ == Id::value> >
434 template<std::
size_t Id,
class T>
435 constexpr
bool indeterminateMatch(T&& t, IndexConstant<Id> = IndexConstant<Id>::value)
437 return IndeterminateMatch<T, IndexConstant<Id> >::value;
447 struct IsPlaceholderOperation
451 template<
class Placeholder>
452 struct IsPlaceholderOperation<PlaceholderOperation<Placeholder> >
457 using IsPlaceholderExpression = IsPlaceholderOperation<Expressions::Operation<T> >;
459 template<
class T,
class SFINAE =
void>
460 struct PlaceholderTraits;
462 template<
class Placeholder>
463 struct PlaceholderTraits<PlaceholderOperation<Placeholder> >
465 using PlaceholderType = Placeholder;
468 template<
class Placeholder>
469 struct PlaceholderTraits<OperationTraits<PlaceholderOperation<Placeholder> > >
470 : PlaceholderTraits<PlaceholderOperation<Placeholder> >
474 struct PlaceholderTraits<
476 std::enable_if_t<IsPlaceholderOperation<Expressions::Operation<T> >::value> >
477 : PlaceholderTraits<Expressions::Operation<T> >
480 template<
class Cand
idate,
class Placeholder,
class SFINAE =
void>
481 struct PlaceholderMatch
485 template<
class Cand
idate,
class Placeholder>
486 struct PlaceholderMatch<
487 Candidate, Placeholder,
488 std::enable_if_t<std::is_same<typename PlaceholderTraits<Candidate>::PlaceholderType, Placeholder>::value> >
492 template<
class Placeholder,
class T>
493 constexpr
bool placeholderMatch(T&& t, Placeholder&&)
495 return PlaceholderMatch<T, Placeholder>::value;
498 template<
class Placeholder,
class T>
499 constexpr
bool placeholderMatch(T&& t)
501 return PlaceholderMatch<T, Placeholder>::value;
511 struct IsSubExpressionOperation
516 struct IsSubExpressionOperation<SubExpressionOperation<Id> >
521 using IsSubExpressionExpression = IsSubExpressionOperation<Expressions::Operation<T> >;
523 template<
class T,
class SFINAE =
void>
524 struct SubExpressionTraits;
526 template<std::size_t... OperandPos>
527 struct SubExpressionTraits<SubExpressionOperation<
IndexSequence<OperandPos...> > >
532 template<std::size_t... OperandPos>
533 struct SubExpressionTraits<OperationTraits<SubExpressionOperation<
IndexSequence<OperandPos...> > > >
534 : SubExpressionTraits<SubExpressionOperation<IndexSequence<OperandPos...> > >
538 struct SubExpressionTraits<
540 std::enable_if_t<IsSubExpressionOperation<Expressions::Operation<T> >::value> >
541 : SubExpressionTraits<Expressions::Operation<T> >
553 struct IsVolatileOperation
560 template<
class Placeholder>
566 template<std::
size_t Id>
586 template<
class T,
class SFINAE =
void>
588 : IsVolatileOperation<T>
593 namespace Expressions
595 template<
class Operation>
596 using F = OperationTraits<Operation>;
603 return std::forward<F>(f).name() +
"(" + arg +
")";
608 std::string
operationName(F&& f,
const std::string& left,
const std::string& right)
610 return "(" + left +
" " + std::forward<F>(f).name() +
" " + right +
")";
615 template<
class String>
616 std::string operationNameHelper(String&& last)
618 return std::forward<String>(last);
621 template<
class... Strings>
622 std::string operationNameHelper(
const std::string& s0,
const std::string& s1, Strings&&... rest)
624 return s0 +
", " + operationNameHelper(s1, std::forward<Strings>(rest)...);
629 template<
class F,
class... Strings, std::enable_if_t<(
sizeof...(Strings) > 2),
int> = 0>
632 return (std::forward<F>(f).name()
634 "(" + operationNameHelper(std::forward<Strings>(strings)...) +
")"
639 struct OperationTraits<IdentityOperation>
641 using InvertibleOperation = IdentityOperation;
642 using OperationType = IdentityOperation;
644 template<
class Value>
645 using ResultType = Value;
647 template<
class Order>
648 static constexpr
auto polynomialOrder(Order oldOrder)
654 static constexpr
auto signPropagation(Sign)
659 static std::string name()
665 constexpr decltype(
auto) operator()(T&& arg)
const
667 return std::forward<T>(arg);
676 template<
class... Property>
677 struct OperationTraits<AssumeOperation<Property...> >
679 using InvertibleOperation = void;
680 using OperationType = AssumeOperation<Property...>;
681 using Properties =
typename AssumeOperation<Property...>::Properties;
683 template<
class T,
class SFINAE =
void>
688 using ResultType = FloatingPointClosure<T>;
692 struct HasOperation<T, std::enable_if_t<(sizeof(decltype(assume(std::declval<T>(), Properties{}))) >= 0)> >
695 using ResultType = std::decay_t<decltype(assume(std::declval<T>(), Properties{}))>;
699 using ResultType =
typename HasOperation<T>::ResultType;
702 template<
class Order>
703 static constexpr
auto polynomialOrder(Order oldOrder)
710 static constexpr
auto signPropagation(Sign)
715 static std::string name()
718 auto str = (std::string(
"assume<") + ... + toString(Property{}));
719 str += str.back() ==
'>' ?
" >" :
">";
724 template<class T, std::enable_if_t<HasOperation<T>::value,
int> = 0>
725 constexpr
auto operator()(T&& t)
const
727 return assume(std::forward<T>(t), Properties{});
734 template<class T, std::enable_if_t<!HasOperation<T>::value,
int> = 0>
735 constexpr decltype(
auto) operator()(T&& t)
const
737 return forwardReturnValue<T>(t);
742 template<std::
size_t Id>
743 struct OperationTraits<IndeterminateOperation<Id> >
745 using InvertibleOperation = void;
746 using OperationType = IndeterminateOperation<Id>;
748 template<
class T,
class SFINAE =
void>
753 using ResultType = FloatingPointClosure<T>;
757 struct HasOperation<T, std::enable_if_t<(sizeof(decltype(indeterminate(std::declval<T>(), IndexConstant<Id>{}))) >= 0)> >
760 using ResultType = std::decay_t<decltype(indeterminate(std::declval<T>(), IndexConstant<Id>{}))>;
764 using ResultType =
typename HasOperation<T>::ResultType;
766 template<
class Order>
767 static constexpr
auto polynomialOrder(Order oldOrder)
773 static constexpr
auto signPropagation(Sign)
778 static std::string name()
781 return "X["+std::to_string(Id)+
"]";
785 template<class T, std::enable_if_t<HasOperation<T>::value,
int> = 0>
786 auto operator()(T&& t)
const
788 return indeterminate(std::forward<T>(t), IndexConstant<Id>{});
795 template<class T, std::enable_if_t<!HasOperation<T>::value,
int> = 0>
796 constexpr FloatingPointClosure<T> operator()(T&& t)
const
803 template<
class Placeholder>
804 struct OperationTraits<PlaceholderOperation<Placeholder> >
806 using InvertibleOperation = void;
807 using OperationType = PlaceholderOperation<Placeholder>;
809 template<
class T,
class SFINAE =
void>
814 using ResultType = T;
818 struct HasOperation<T,
VoidType<decltype(placeholder(std::declval<T>(), OperationType{}))> >
821 using ResultType = std::decay_t<decltype(placeholder(std::declval<T>(), OperationType{}))>;
825 using ResultType =
typename HasOperation<T>::ResultType;
827 template<
class Order>
828 static constexpr
auto polynomialOrder(Order oldOrder)
834 static constexpr
auto signPropagation(Sign)
839 template<class T, std::enable_if_t<HasOperation<T>::value,
int> = 0>
840 constexpr
auto operator()(T&& t)
const
842 return placeholder(std::forward<T>(t), OperationType{});
849 template<class T, std::enable_if_t<!HasOperation<T>::value,
int> = 0>
850 constexpr T operator()(T&& t)
const
852 return std::forward<T>(t);
855 static std::string name()
862 static std::string idString(UnknownExpression<>)
869 static std::string idString(T)
871 return toString(T{});
875 template<std::size_t... OperandPos>
876 struct OperationTraits<SubExpressionOperation<
IndexSequence<OperandPos...> > >
879 using InvertibleOperation = void;
880 using OperationType = SubExpressionOperation<TreePos>;
882 template<
class T1,
class T2,
class SFINAE =
void>
887 using ResultType = FloatingPointClosure<T1>;
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)> >
894 using ResultType = std::decay_t<decltype(subExpression(std::declval<T1>(), std::declval<T2>(), TreePos{}))>;
897 template<
class T1,
class T2>
898 using ResultType =
typename HasOperation<T1, T2>::ResultType;
900 template<
class Order>
901 static constexpr
auto polynomialOrder(std::size_t order1, Order order2)
906 template<
class S1,
class S2>
907 static constexpr
auto signPropagation(
const S1&,
const S2&)
912 static std::string name()
914 return "SExp"+(size<TreePos>() > 0 ?
"{" + toString(TreePos{}) +
"}" :
"");
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
921 return subExpression(std::forward<T1>(t1), std::forward<T2>(t2), TreePos{});
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
944 struct OperationTraits<EqOperation>
946 using InvertibleOperation = void;
947 using OperationType = EqOperation;
949 template<
class T0,
class T1>
950 using ResultType = bool;
952 template<
class Order0,
class Order1>
953 static constexpr
auto polynomialOrder(Order0, Order1)
955 using namespace Literals;
959 template<
class Sign0,
class Sign1>
960 static constexpr
auto signPropagation(Sign0, Sign1)
962 return SemiPositiveExpressionSign{};
965 static std::string name()
970 template<
class T0,
class T1>
971 constexpr
auto operator()(T0&& t0, T1&& t1)
const
973 return std::forward<T0>(t0) == std::forward<T1>(t1);
978 struct OperationTraits<NeOperation>
980 using InvertibleOperation = void;
981 using OperationType = NeOperation;
983 template<
class T0,
class T1>
984 using ResultType = bool;
986 template<
class Order0,
class Order1>
987 static constexpr
auto polynomialOrder(Order0, Order1)
989 using namespace Literals;
993 template<
class Sign0,
class Sign1>
994 static constexpr
auto signPropagation(Sign0, Sign1)
996 return SemiPositiveExpressionSign{};
999 static std::string name()
1004 template<
class T0,
class T1>
1005 constexpr
auto operator()(T0&& t0, T1&& t1)
const
1007 return std::forward<T0>(t0) != std::forward<T1>(t1);
1012 struct OperationTraits<GtOperation>
1014 using InvertibleOperation = void;
1015 using OperationType = GtOperation;
1017 template<
class T0,
class T1>
1018 using ResultType = bool;
1020 template<
class Order0,
class Order1>
1021 static constexpr
auto polynomialOrder(Order0, Order1)
1023 using namespace Literals;
1027 template<
class Sign0,
class Sign1>
1028 static constexpr
auto signPropagation(Sign0, Sign1)
1030 return SemiPositiveExpressionSign{};
1033 static std::string name()
1038 template<
class T0,
class T1>
1039 constexpr
auto operator()(T0&& t0, T1&& t1)
const
1041 return std::forward<T0>(t0) > std::forward<T1>(t1);
1046 struct OperationTraits<GeOperation>
1048 using InvertibleOperation = void;
1049 using OperationType = GeOperation;
1051 template<
class T0,
class T1>
1052 using ResultType = bool;
1054 template<
class Order0,
class Order1>
1055 static constexpr
auto polynomialOrder(Order0, Order1)
1057 using namespace Literals;
1061 template<
class Sign0,
class Sign1>
1062 static constexpr
auto signPropagation(Sign0, Sign1)
1064 return SemiPositiveExpressionSign{};
1067 static std::string name()
1072 template<
class T0,
class T1>
1073 constexpr
auto operator()(T0&& t0, T1&& t1)
const
1075 return std::forward<T0>(t0) >= std::forward<T1>(t1);
1080 struct OperationTraits<LtOperation>
1082 using InvertibleOperation = void;
1083 using OperationType = LtOperation;
1085 template<
class T0,
class T1>
1086 using ResultType = bool;
1088 template<
class Order0,
class Order1>
1089 static constexpr
auto polynomialOrder(Order0, Order1)
1091 using namespace Literals;
1095 template<
class Sign0,
class Sign1>
1096 static constexpr
auto signPropagation(Sign0, Sign1)
1098 return SemiPositiveExpressionSign{};
1101 static std::string name()
1106 template<
class T0,
class T1>
1107 constexpr
auto operator()(T0&& t0, T1&& t1)
const
1109 return std::forward<T0>(t0) < std::forward<T1>(t1);
1114 struct OperationTraits<LeOperation>
1116 using InvertibleOperation = void;
1117 using OperationType = LeOperation;
1119 template<
class T0,
class T1>
1120 using ResultType = bool;
1122 template<
class Order0,
class Order1>
1123 static constexpr
auto polynomialOrder(Order0, Order1)
1125 using namespace Literals;
1129 template<
class Sign0,
class Sign1>
1130 static constexpr
auto signPropagation(Sign0, Sign1)
1132 return SemiPositiveExpressionSign{};
1135 static std::string name()
1140 template<
class T0,
class T1>
1141 constexpr
auto operator()(T0&& t0, T1&& t1)
const
1143 return std::forward<T0>(t0) <= std::forward<T1>(t1);
1155 struct OperationTraits<LogicalNotOperation>
1157 using InvertibleOperation = LogicalNotOperation;
1158 using OperationType = LogicalNotOperation;
1161 using ResultType = std::decay_t<decltype(!std::declval<T>())>;
1163 template<
class Order>
1164 static constexpr
auto polynomialOrder(Order oldOrder)
1166 using namespace Literals;
1170 template<
class Sign>
1171 static constexpr
auto signPropagation(Sign)
1173 return ExpressionSign<!Sign::isNonSingular,
1179 static std::string name()
1185 constexpr
auto operator()(T&& arg)
const
1187 return !std::forward<T>(arg);
1192 struct OperationTraits<LogicalOrOperation>
1194 using InvertibleOperation = void;
1195 using OperationType = LogicalOrOperation;
1197 template<
class T1,
class T2>
1198 using ResultType = std::decay_t<decltype(std::declval<T1>() || std::declval<T2>())>;
1200 static constexpr
auto polynomialOrder(
unsigned order1,
unsigned order2)
1202 using namespace Literals;
1206 template<
class S1,
class S2>
1207 static constexpr
auto signPropagation(
const S1&,
const S2&)
1209 return ExpressionSign<(S1::isNonSingular || S2::isNonSingular),
true,
false, 0>{};
1212 static std::string name()
1217 template<
class T1,
class T2>
1218 constexpr
auto operator()(T1&& t1, T2&& t2)
const
1220 return std::forward<T1>(t1) || std::forward<T2>(t2);
1225 struct OperationTraits<LogicalAndOperation>
1227 using InvertibleOperation = void;
1228 using OperationType = LogicalAndOperation;
1230 template<
class T1,
class T2>
1231 using ResultType = std::decay_t<decltype(std::declval<T1>() && std::declval<T2>())>;
1233 static constexpr
auto polynomialOrder(
unsigned order1,
unsigned order2)
1235 using namespace Literals;
1239 template<
class S1,
class S2>
1240 static constexpr
auto signPropagation(
const S1&,
const S2&)
1242 return ExpressionSign<(S1::isNonSingular && S2::isNonSingular),
true,
false, 0>{};
1245 static std::string name()
1250 template<
class T1,
class T2>
1251 constexpr
auto operator()(T1&& t1, T2&& t2)
const
1253 return std::forward<T1>(t1) && std::forward<T2>(t2);
1265 struct OperationTraits<PlusOperation>
1267 using InvertibleOperation = void;
1268 using OperationType = PlusOperation;
1270 template<
class T1,
class T2>
1273 using Type = std::decay_t<decltype(std::declval<T1>() + std::declval<T2>())>;
1277 struct ResultHelper<T, void>
1279 using Type = OperationTraits<IdentityOperation>::template ResultType<T>;
1284 template<
class T1,
class T2 =
void>
1285 using ResultType =
typename ResultHelper<T1, T2>::Type;
1287 static constexpr
auto polynomialOrder(
unsigned order1,
unsigned order2)
1289 return max(order1, order2);
1293 static constexpr
auto signPropagation(S)
1298 template<
class S1,
class S2>
1299 static constexpr
auto signPropagation(
const S1&,
const S2&)
1301 return ExpressionSign<(S1::isNonSingular || S2::isNonSingular)
1303 ((S1::isSemiPositive && S2::isSemiPositive)
1305 (S1::isSemiNegative && S2::isSemiNegative)),
1306 S1::isSemiPositive && S2::isSemiPositive,
1307 S1::isSemiNegative && S2::isSemiNegative,
1308 S1::reference + S2::reference>{};
1312 constexpr decltype(
auto) operator()(T&& arg)
const
1314 return std::forward<T>(arg);
1317 template<
class T1,
class T2>
1318 constexpr
auto operator()(T1&& t1, T2&& t2)
const
1320 return std::forward<T1>(t1) + std::forward<T2>(t2);
1323 static std::string name()
1330 struct OperationTraits<PlusEqOperation>
1332 using InvertibleOperation = void;
1333 using OperationType = PlusEqOperation;
1335 template<
class T1,
class T2>
1336 using ResultType = std::decay_t<decltype(std::declval<T1>() += std::declval<T2>())>;
1338 static constexpr
auto polynomialOrder(
unsigned order1,
unsigned order2)
1340 return max(order1, order2);
1343 template<
class S1,
class S2>
1344 static constexpr
auto signPropagation(
const S1&,
const S2&)
1346 return ExpressionSign<(S1::isNonSingular || S2::isNonSingular)
1348 ((S1::isSemiPositive && S2::isSemiPositive)
1350 (S1::isSemiNegative && S2::isSemiNegative)),
1351 S1::isSemiPositive && S2::isSemiPositive,
1352 S1::isSemiNegative && S2::isSemiNegative,
1353 S1::reference + S2::reference>{};
1356 template<
class T1,
class T2>
1357 constexpr decltype(
auto) operator()(T1&& t1, T2&& t2)
const
1359 return std::forward<T1>(t1) += std::forward<T2>(t2);
1362 static std::string name()
1369 struct OperationTraits<MinusOperation>
1371 using ThisType = OperationTraits<MinusOperation>;
1372 using InvertibleOperation = MinusOperation;
1373 using OperationType = MinusOperation;
1375 template<
class T1,
class T2>
1378 using Type = std::decay_t<decltype(std::declval<T1>() - std::declval<T2>())>;
1382 struct ResultHelper<T, std::enable_if_t<HasUnaryMinus<T>::value> >
1384 using Type = std::decay_t<decltype(-std::declval<T>())>;
1388 struct ResultHelper<T, std::enable_if_t<!HasUnaryMinus<T>::value> >
1390 using Type = std::decay_t<decltype(std::declval<T>())>;
1395 template<
class T1,
class T2 =
void>
1396 using ResultType =
typename ResultHelper<T1, T2>::Type;
1398 static constexpr
auto polynomialOrder(
unsigned order1,
unsigned order2)
1400 return max(order1, order2);
1403 template<
class Order>
1404 static constexpr
auto polynomialOrder(Order order)
1409 template<
class Sign>
1410 static constexpr
auto signPropagation(
const Sign&)
1413 return ExpressionSign<Sign::isNonSingular,
1414 Sign::isSemiNegative,
1415 Sign::isSemiPositive,
1416 -Sign::reference>{};
1419 template<
class S1,
class S2>
1420 static constexpr
auto signPropagation(
const S1&,
const S2&)
1422 return ExpressionSign<((S1::isNonSingular || S2::isNonSingular)
1424 ((S1::isSemiPositive && S2::isSemiNegative)
1426 (S1::isSemiNegative && S2::isSemiPositive))),
1427 S1::isSemiPositive && S2::isSemiNegative,
1428 S1::isSemiNegative && S2::isSemiPositive,
1429 S1::reference - S2::reference>{};
1432 static std::string name()
1437 template<class T, std::enable_if_t<HasUnaryMinus<T>::value,
int> = 0>
1438 constexpr
auto operator()(T&& t)
const
1440 return -std::forward<T>(t);
1443 template<class T, std::enable_if_t<!HasUnaryMinus<T>::value,
int> = 0>
1444 constexpr
auto operator()(T&& t)
const
1446 std::decay_t<T> tmp(t);
1450 template<
class T1,
class T2>
1451 constexpr
auto operator()(T1&& t1, T2&& t2)
const
1453 return std::forward<T1>(t1) - std::forward<T2>(t2);
1458 struct OperationTraits<MinusEqOperation>
1460 using InvertibleOperation = void;
1461 using OperationType = MinusEqOperation;
1463 template<
class T1,
class T2>
1464 using ResultType = std::decay_t<decltype(std::declval<T1>() -= std::declval<T2>())>;
1466 static constexpr
auto polynomialOrder(
unsigned order1,
unsigned order2)
1468 return max(order1, order2);
1471 template<
class S1,
class S2>
1472 static constexpr
auto signPropagation(
const S1&,
const S2&)
1474 return ExpressionSign<(S1::isNonSingular || S2::isNonSingular)
1476 ((S1::isSemiPositive && S2::isSemiPositive)
1478 (S1::isSemiNegative && S2::isSemiNegative)),
1479 S1::isSemiPositive && S2::isSemiPositive,
1480 S1::isSemiNegative && S2::isSemiNegative,
1481 S1::reference + S2::reference>{};
1484 template<
class T1,
class T2>
1485 constexpr decltype(
auto) operator()(T1&& t1, T2&& t2)
const
1487 return std::forward<T1>(t1) -= std::forward<T2>(t2);
1490 static std::string name()
1497 struct OperationTraits<ReciprocalOperation>
1499 using InvertibleOperation = ReciprocalOperation;
1500 using OperationType = ReciprocalOperation;
1502 template<
class T,
class SFINAE =
void>
1507 using ResultType = FloatingPointClosure<T>;
1511 struct HasOperation<T, std::enable_if_t<(sizeof(decltype(reciprocal(std::declval<T>()))) >= 0)> >
1514 using ResultType = std::decay_t<decltype(reciprocal(std::declval<T>()))>;
1518 using ResultType =
typename HasOperation<T>::ResultType;
1520 static std::size_t polynomialOrder(std::size_t oldOrder)
1525 template<
class Sign, std::enable_if_t<Sign::reference == 0,
int> = 0>
1526 static constexpr
auto signPropagation(
const Sign&)
1531 template<
class Sign, std::enable_if_t<(Sign::reference >= 1),
int> = 0>
1532 static constexpr
auto signPropagation(
const Sign&)
1535 return ExpressionSign<Sign::isNonSingular,
1537 Sign::isSemiPositive,
1541 template<
class Sign, std::enable_if_t<(Sign::reference <= -1),
int> = 0>
1542 static constexpr
auto signPropagation(
const Sign&)
1545 return ExpressionSign<Sign::isNonSingular,
1546 Sign::isSemiNegative,
1551 static std::string name()
1557 template<class T, std::enable_if_t<HasOperation<T>::value,
int> = 0>
1558 auto operator()(T&& t)
const
1560 return reciprocal(std::forward<T>(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
1571 return 1./FloatingPointClosure<T>(t);
1578 std::enable_if_t<(!HasOperation<T>::value
1579 && !std::numeric_limits<std::decay_t<T> >::is_integer
1581 constexpr
auto operator()(T&& t)
const
1583 return one(std::forward<T>(t))/std::forward<T>(t);
1588 struct OperationTraits<SquareOperation>
1590 using InvertibleOperation = SqrtOperation;
1591 using OperationType = SquareOperation;
1593 template<
class T,
class SFINAE =
void>
1598 using ResultType = FloatingPointClosure<T>;
1602 struct HasOperation<T, std::enable_if_t<(sizeof(decltype(sqr(std::declval<T>()))) >= 0)> >
1605 using ResultType = std::decay_t<decltype(sqr(std::declval<T>()))>;
1609 using ResultType =
typename HasOperation<T>::ResultType;
1612 template<
class Sign>
1613 static constexpr
auto signPropagation(
const Sign&)
1615 constexpr ssize_t reference = Sign::reference*Sign::reference;
1616 constexpr
bool goodCase = ((Sign::reference >= 0 && Sign::isSemiPositive)
1618 (Sign::reference <= 0 && Sign::isSemiNegative));
1619 return ExpressionSign<goodCase && Sign::isNonSingular, true, false, goodCase*reference>{};
1622 static std::string name()
1627 template<
class Order>
1628 static constexpr
auto polynomialOrder(Order oldOrder)
1630 using namespace Literals;
1631 return 2_f*oldOrder;
1635 template<class T, std::enable_if_t<HasOperation<T>::value,
int> = 0>
1636 auto operator()(T&& t)
const
1638 return sqr(std::forward<T>(t));
1641 template<class T, std::enable_if_t<!HasOperation<T>::value,
int> = 0>
1642 constexpr
auto operator()(T&& t)
const
1644 return std::forward<T>(t)*std::forward<T>(t);
1649 struct OperationTraits<SMultiplyOperation>
1651 using OperationType = SMultiplyOperation;
1652 using InvertibleOperation = void;
1654 template<
class T1,
class T2,
class Enable =
void>
1655 struct ResultHelper;
1657 template<
class T1,
class T2>
1658 struct ResultHelper<T1, T2,
1659 std::enable_if_t<IsFieldVector<T2>::value && (T2::dimension > 1)> >
1661 using ResultType = std::decay_t<T2>;
1664 template<
class T1,
class T2>
1665 struct ResultHelper<T1, T2,
1666 std::enable_if_t<IsFieldVector<T1>::value && (T1::dimension > 1)> >
1668 using ResultType = std::decay_t<T1>;
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> >
1676 using ResultType = std::decay_t<decltype(std::declval<T1>() * std::declval<T2>())>;
1679 template<
class T1,
class T2>
1680 using ResultType =
typename ResultHelper<T1, T2>::ResultType;
1682 template<
class Order1,
class Order2>
1683 static constexpr
auto polynomialOrder(Order1 order1, Order2 order2)
1685 return order1 + order2;
1689 template<
class S1,
class S2>
1690 static constexpr
auto signPropagation(
const S1&,
const S2&)
1692 return ExpressionSign<
1693 (S1::isNonSingular && S2::isNonSingular
1695 (((S1::reference >= 0) && S1::isSemiPositive)
1697 ((S1::reference <= 0) && S1::isSemiNegative))
1699 (((S2::reference >= 0) && S2::isSemiPositive)
1701 ((S2::reference <= 0) && S2::isSemiNegative))),
1703 ((S1::reference*S2::reference >= 0)
1705 ((S1::isSemiPositive && S2::isSemiPositive)
1707 (S1::isSemiNegative && S2::isSemiNegative))),
1709 ((S1::reference*S2::reference <= 0)
1711 ((S1::isSemiPositive && S2::isSemiNegative)
1713 (S1::isSemiNegative && S2::isSemiPositive))),
1715 S1::reference * S2::reference>{};
1718 static std::string name()
1723 template<
class T1,
class T2>
1724 constexpr
auto operator()(T1&& t1, T2&& t2)
const
1726 return std::forward<T1>(t1) * std::forward<T2>(t2);
1731 struct OperationTraits<SMultiplyEqOperation>
1733 using OperationType = SMultiplyEqOperation;
1734 using InvertibleOperation = void;
1736 template<
class T1,
class T2>
1737 using ResultType = std::decay_t<decltype(std::declval<T1>() *= std::declval<T2>())>;
1739 template<
class Order1,
class Order2>
1740 static constexpr
auto polynomialOrder(Order1 order1, Order2 order2)
1742 return order1 + order2;
1746 template<
class S1,
class S2>
1747 static constexpr
auto signPropagation(
const S1&,
const S2&)
1749 return ExpressionSign<
1750 (S1::isNonSingular && S2::isNonSingular
1752 (((S1::reference >= 0) && S1::isSemiPositive)
1754 ((S1::reference <= 0) && S1::isSemiNegative))
1756 (((S2::reference >= 0) && S2::isSemiPositive)
1758 ((S2::reference <= 0) && S2::isSemiNegative))),
1760 ((S1::reference*S2::reference >= 0)
1762 ((S1::isSemiPositive && S2::isSemiPositive)
1764 (S1::isSemiNegative && S2::isSemiNegative))),
1766 ((S1::reference*S2::reference <= 0)
1768 ((S1::isSemiPositive && S2::isSemiNegative)
1770 (S1::isSemiNegative && S2::isSemiPositive))),
1772 S1::reference * S2::reference>{};
1775 static std::string name()
1780 template<
class T1,
class T2>
1781 constexpr decltype(
auto) operator()(T1&& t1, T2&& t2)
const
1783 return std::forward<T1>(t1) *= std::forward<T2>(t2);
1795 struct OperationTraits<SqrtOperation>
1797 using InvertibleOperation = SquareOperation;
1798 using OperationType = SqrtOperation;
1800 template<
class Value>
1801 using ResultType = FloatingPointClosure<Value>;
1804 static std::size_t polynomialOrder(std::size_t oldOrder)
1806 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
1810 template<
class Sign>
1811 static constexpr
auto signPropagation(
const Sign&)
1813 return ExpressionSign<Sign::reference >= 0 && Sign::isNonSingular,
true,
false>{};
1816 static std::string name()
1821 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
1822 constexpr
auto operator()(T&& t)
const
1824 return sqrt(std::forward<T>(t));
1827 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
1828 constexpr
auto operator()(T&& t)
const
1835 struct OperationTraits<ExpOperation>
1837 using InvertibleOperation = LogOperation;
1838 using OperationType = ExpOperation;
1840 template<
class Value>
1841 using ResultType = FloatingPointClosure<Value>;
1843 template<
class Sign>
1844 static constexpr
auto signPropagation(
const Sign&)
1846 return ExpressionSign<Sign::isNonSingular,
true,
false,
1847 std::max(0L, (ssize_t)Sign::isSemiPositive * (Sign::reference + 1L))>{};
1850 template<
class Sign, std::enable_if_t<(Sign::reference < 0),
int> = 0>
1851 static constexpr auto signPropagation(const Sign&)
1853 return ExpressionSign<Sign::isNonSingular, true, false, 0>{};
1856 static std::
string name()
1862 static std::
size_t polynomialOrder(std::
size_t oldOrder)
1864 return oldOrder == 0 ? 0 : std::numeric_limits<std::
size_t>::max();
1867 template<
class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
1868 constexpr
auto operator()(T&& t)
const
1870 return exp(std::forward<T>(t));
1873 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
1874 constexpr
auto operator()(T&& t)
const
1881 struct OperationTraits<LogOperation>
1883 using InvertibleOperation = ExpOperation;
1884 using OperationType = LogOperation;
1886 template<
class Value>
1887 using ResultType = FloatingPointClosure<Value>;
1890 static std::size_t polynomialOrder(std::size_t oldOrder)
1892 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
1895 template<
class Sign>
1896 static constexpr
auto signPropagation(
const Sign&)
1898 return ExpressionSign<!(Sign::reference == 1 && Sign::isZero),
1899 (Sign::reference >= 1) && Sign::isSemiPositive,
1900 (Sign::reference == 1) && Sign::isSemiNegative, 0>{};
1903 static std::string name()
1908 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
1909 constexpr
auto operator()(T&& t)
const
1911 return log(std::forward<T>(t));
1914 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
1915 constexpr
auto operator()(T&& t)
const
1922 struct OperationTraits<ErfOperation>
1924 using InvertibleOperation = void;
1925 using OperationType = ErfOperation;
1927 template<
class Value>
1928 using ResultType = FloatingPointClosure<Value>;
1930 template<
class Sign>
1931 static constexpr
auto signPropagation(Sign)
1936 static std::string name()
1941 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
1943 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
1946 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
1947 constexpr
auto operator()(T&& t)
const
1949 return erf(std::forward<T>(t));
1952 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
1953 constexpr
auto operator()(T&& t)
const
1960 struct OperationTraits<LGammaOperation>
1962 using InvertibleOperation = void;
1963 using OperationType = LGammaOperation;
1965 template<
class Value>
1966 using ResultType = FloatingPointClosure<Value>;
1968 template<
class Sign>
1969 static constexpr
auto signPropagation(Sign)
1971 return SemiPositiveExpressionSign{};
1974 static std::string name()
1979 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
1981 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
1984 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
1985 constexpr
auto operator()(T&& t)
const
1987 return lgamma(std::forward<T>(t));
1990 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
1991 constexpr
auto operator()(T&& t)
const
1998 struct OperationTraits<TGammaOperation>
2000 using InvertibleOperation = void;
2001 using OperationType = TGammaOperation;
2003 template<
class Value>
2004 using ResultType = FloatingPointClosure<Value>;
2006 template<
class Sign>
2007 static constexpr
auto signPropagation(Sign)
2009 return PositiveExpressionSign{};
2012 static std::string name()
2017 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2019 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2022 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2023 constexpr
auto operator()(T&& t)
const
2025 return tgamma(std::forward<T>(t));
2028 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2029 constexpr
auto operator()(T&& t)
const
2036 struct OperationTraits<CoshOperation>
2038 using InvertibleOperation = AcoshOperation;
2039 using OperationType = CoshOperation;
2041 template<
class Value>
2042 using ResultType = FloatingPointClosure<Value>;
2044 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2046 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2049 template<
class Sign>
2050 static constexpr
auto signPropagation(
const Sign&)
2052 return ExpressionSign<
false,
2058 static std::string name()
2063 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2064 constexpr
auto operator()(T&& t)
const
2066 return cosh(std::forward<T>(t));
2069 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2070 constexpr
auto operator()(T&& t)
const
2077 struct OperationTraits<SinhOperation>
2079 using InvertibleOperation = AsinhOperation;
2080 using OperationType = SinhOperation;
2082 template<
class Value>
2083 using ResultType = FloatingPointClosure<Value>;
2085 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2087 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2090 template<
class Sign>
2091 static constexpr
auto signPropagation(
const Sign&)
2096 static std::string name()
2101 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2102 constexpr
auto operator()(T&& t)
const
2104 return sinh(std::forward<T>(t));
2107 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2108 constexpr
auto operator()(T&& t)
const
2115 struct OperationTraits<TanhOperation>
2117 using InvertibleOperation = AtanhOperation;
2118 using OperationType = TanhOperation;
2120 template<
class Value>
2121 using ResultType = FloatingPointClosure<Value>;
2123 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2125 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2128 template<
class Sign>
2129 static constexpr
auto signPropagation(
const Sign&)
2134 static std::string name()
2139 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2140 constexpr
auto operator()(T&& t)
const
2142 return tanh(std::forward<T>(t));
2145 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2146 constexpr
auto operator()(T&& t)
const
2153 struct OperationTraits<AcoshOperation>
2155 using InvertibleOperation = void;
2156 using OperationType = AcoshOperation;
2158 template<
class Value>
2159 using ResultType = FloatingPointClosure<Value>;
2161 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2163 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2166 template<
class Sign>
2167 static constexpr
auto signPropagation(
const Sign&)
2169 return ExpressionSign<
false,
2175 static std::string name()
2180 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2181 constexpr
auto operator()(T&& t)
const
2183 return acosh(std::forward<T>(t));
2186 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2187 constexpr
auto operator()(T&& t)
const
2194 struct OperationTraits<AsinhOperation>
2196 using InvertibleOperation = SinhOperation;
2197 using OperationType = AsinhOperation;
2199 template<
class Value>
2200 using ResultType = FloatingPointClosure<Value>;
2202 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2204 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2207 template<
class Sign>
2208 static constexpr
auto signPropagation(
const Sign&)
2213 static std::string name()
2218 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2219 constexpr
auto operator()(T&& t)
const
2221 return asinh(std::forward<T>(t));
2224 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2225 constexpr
auto operator()(T&& t)
const
2232 struct OperationTraits<AtanhOperation>
2234 using InvertibleOperation = TanhOperation;
2235 using OperationType = AtanhOperation;
2237 template<
class Value>
2238 using ResultType = FloatingPointClosure<Value>;
2240 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2242 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2245 template<
class Sign>
2246 static constexpr
auto signPropagation(
const Sign&)
2251 static std::string name()
2256 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2257 constexpr
auto operator()(T&& t)
const
2259 return atanh(std::forward<T>(t));
2262 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2263 constexpr
auto operator()(T&& t)
const
2270 struct OperationTraits<SinOperation>
2272 using InvertibleOperation = AsinOperation;
2273 using OperationType = SinOperation;
2275 template<
class Value>
2276 using ResultType = FloatingPointClosure<Value>;
2278 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2280 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2284 template<
class Sign>
2285 static constexpr
auto signPropagation(
const Sign&)
2290 static std::string name()
2295 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2296 constexpr
auto operator()(T&& t)
const
2298 return sin(std::forward<T>(t));
2301 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2302 constexpr
auto operator()(T&& t)
const
2309 struct OperationTraits<CosOperation>
2311 using InvertibleOperation = AcosOperation;
2312 using OperationType = CosOperation;
2314 template<
class Value>
2315 using ResultType = FloatingPointClosure<Value>;
2317 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2319 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2323 template<
class Sign>
2324 static constexpr
auto signPropagation(
const Sign&)
2329 static std::string name()
2334 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2335 constexpr
auto operator()(T&& t)
const
2337 return cos(std::forward<T>(t));
2340 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2341 constexpr
auto operator()(T&& t)
const
2348 struct OperationTraits<TanOperation>
2350 using InvertibleOperation = AtanOperation;
2351 using OperationType = TanOperation;
2353 template<
class Value>
2354 using ResultType = FloatingPointClosure<Value>;
2356 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2358 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2361 template<
class Sign>
2362 static constexpr
auto signPropagation(
const Sign&)
2367 static std::string name()
2372 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2373 constexpr
auto operator()(T&& t)
const
2375 return tan(std::forward<T>(t));
2378 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2379 constexpr
auto operator()(T&& t)
const
2386 struct OperationTraits<AsinOperation>
2388 using InvertibleOperation = void;
2389 using OperationType = AsinOperation;
2391 template<
class Value>
2392 using ResultType = FloatingPointClosure<Value>;
2394 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2396 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2399 template<
class Sign>
2400 static constexpr
auto signPropagation(
const Sign&)
2402 return ExpressionSign<((Sign::reference >= 2 || Sign::reference <= -2)
2404 (Sign::reference == 0 && Sign::isNonSingular)
2406 (Sign::reference > 0 && Sign::isSemiPositive)
2408 (Sign::reference < 0 && Sign::isSemiNegative)),
2409 (Sign::reference >= 0 && Sign::isSemiPositive),
2410 (Sign::reference <= 0 && Sign::isSemiNegative),
2414 static std::string name()
2419 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2420 constexpr
auto operator()(T&& t)
const
2422 return asin(std::forward<T>(t));
2425 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2426 constexpr
auto operator()(T&& t)
const
2433 struct OperationTraits<AcosOperation>
2435 using InvertibleOperation = void;
2436 using OperationType = AcosOperation;
2438 template<
class Value>
2439 using ResultType = FloatingPointClosure<Value>;
2441 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2443 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2446 template<
class Sign>
2447 static constexpr
auto signPropagation(
const Sign&)
2450 return ExpressionSign<(Sign::reference == 0 && Sign::isSemiNegative)
2452 (Sign::reference == 1 && Sign::isNonSingular),
2456 static std::string name()
2461 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2462 constexpr
auto operator()(T&& t)
const
2464 return acos(std::forward<T>(t));
2467 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2468 constexpr
auto operator()(T&& t)
const
2475 struct OperationTraits<AtanOperation>
2477 using InvertibleOperation = void;
2478 using OperationType = AtanOperation;
2480 template<
class Value>
2481 using ResultType = FloatingPointClosure<Value>;
2483 static constexpr std::size_t polynomialOrder(std::size_t oldOrder)
2485 return oldOrder == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2488 template<
class Sign>
2489 static constexpr
auto signPropagation(
const Sign&)
2491 return ExpressionSign<((Sign::reference >= 2 || Sign::reference <= -2)
2493 (Sign::reference == 0 && Sign::isNonSingular)
2495 (Sign::reference == 1 && Sign::isSemiPositive)
2497 (Sign::reference == -1 && Sign::isSemiNegative)),
2498 (Sign::reference >= 0 && Sign::isSemiPositive),
2499 (Sign::reference <= 0 && Sign::isSemiNegative),
2503 static std::string name()
2508 template<class T, std::enable_if_t<!IsScalar<T>::value,
int> = 0>
2509 constexpr
auto operator()(T&& t)
const
2511 return atan(std::forward<T>(t));
2514 template<class T, std::enable_if_t<IsScalar<T>::value,
int> = 0>
2515 constexpr
auto operator()(T&& t)
const
2522 struct OperationTraits<PowOperation>
2524 using InvertibleOperation = void;
2525 using OperationType = PowOperation;
2527 template<
class T1,
class T2>
2528 using ResultType =
typename FieldPromotion<T1, FloatingPointClosure<T2> >::Type;
2530 static constexpr std::size_t polynomialOrder(
unsigned order1,
unsigned order2)
2532 return order2 == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2536 template<
class S1,
class S2>
2537 static constexpr
auto signPropagation(
const S1&,
const S2&)
2539 return ExpressionSign<S1::reference >= 0 && S1::isNonSingular,
true,
false>{};
2542 static std::string name()
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
2550 return pow(std::forward<T1>(t1), std::forward<T2>(t2));
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
2559 template<
class T,
class I, I N,
2560 std::enable_if_t<(N % 2 == 1
2563 && IsScalar<T>::value
2565 constexpr
auto operator()(T&& t, TypedValue::FractionConstant<I, N, 2>)
const
2567 using namespace Literals;
2569 return 1_f / sqrt(multiplyLoop<-N>(1_f, [&](
auto i) {
return std::forward<T>(t); }));
2572 template<
class T,
class I, I N,
2573 std::enable_if_t<(N < 0
2575 && IsScalar<T>::value
2577 constexpr
auto operator()(T&& t, TypedValue::FractionConstant<I, N, 1>)
const
2579 using namespace Literals;
2581 return 1_f /
multiplyLoop<-N>(1_f, [&](
auto i) {
return std::forward<T>(t); });
2584 template<
class T,
class I, I N,
2585 std::enable_if_t<(N > 0
2587 && IsScalar<T>::value
2589 constexpr
auto operator()(T&& t, TypedValue::FractionConstant<I, N, 1>)
const
2591 using namespace Literals;
2593 return multiplyLoop<N>(1_f, [&](
auto i) {
return std::forward<T>(t); });
2599 struct OperationTraits<Atan2Operation>
2601 using InvertibleOperation = void;
2602 using OperationType = Atan2Operation;
2604 template<
class T1,
class T2>
2605 using ResultType =
typename FieldPromotion<T1, T2>::Type;
2607 static constexpr std::size_t polynomialOrder(
unsigned order1,
unsigned order2)
2609 return order1 == 0 && order2 == 0 ? 0 : std::numeric_limits<std::size_t>::max();
2613 template<
class S1,
class S2>
2614 static constexpr
auto signPropagation(
const S1&,
const S2&)
2616 return ExpressionSign<((S1::reference >= 0 && S1::isPositive)
2618 (S1::reference <= 0 && S1::isNegative)),
2619 S1::reference >= 0 && S1::isSemiPositive,
2620 S1::reference <= 0 && S1::isSemiNegative>{};
2623 static std::string name()
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
2631 return atan2(std::forward<T1>(t1), std::forward<T2>(t2));
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
2642 struct OperationTraits<MinOperation>
2644 using InvertibleOperation = void;
2645 using OperationType = MinOperation;
2647 template<
class T1,
class T2>
2648 using ResultType = std::decay_t<decltype(min(std::declval<T1>(), std::declval<T2>()))>;
2650 static constexpr std::size_t polynomialOrder(
unsigned order1,
unsigned order2)
2652 return std::max(order1, order2);
2656 template<
class S1,
class S2>
2657 static constexpr
auto signPropagation(
const S1&,
const S2&)
2659 return ExpressionSign<(S1::reference == S2::reference
2661 ((S1::isNonSingular && S1::isNegative)
2663 (S2::isNonSingular && S2::isNegative))),
2664 (S1::reference == S2::reference
2668 S2::isSemiPositive),
2669 (S1::reference == S2::reference
2673 S2::isSemiNegative)>{};
2676 static std::string name()
2681 template<
class T1,
class T2>
2682 constexpr
auto operator()(T1&& t1, T2&& t2)
const
2684 return min(std::forward<T1>(t1), std::forward<T2>(t2));
2689 struct OperationTraits<MaxOperation>
2691 using InvertibleOperation = void;
2692 using OperationType = MaxOperation;
2694 template<
class T1,
class T2>
2695 using ResultType = std::decay_t<decltype(max(std::declval<T1>(), std::declval<T2>()))>;
2697 static constexpr std::size_t polynomialOrder(
unsigned order1,
unsigned order2)
2699 return std::max(order1, order2);
2703 template<
class S1,
class S2>
2704 static constexpr
auto signPropagation(
const S1&,
const S2&)
2706 return ExpressionSign<(S1::reference == S2::reference
2708 ((S1::isNonSingular && S1::isNegative)
2710 (S2::isNonSingular && S2::isNegative))),
2711 (S1::reference == S2::reference
2715 S2::isSemiPositive),
2716 (S1::reference == S2::reference
2720 S2::isSemiNegative)>{};
2723 static std::string name()
2728 template<
class T1,
class T2>
2729 constexpr
auto operator()(T1&& t1, T2&& t2)
const
2731 return max(std::forward<T1>(t1), std::forward<T2>(t2));
2736 struct OperationTraits<TernaryOperation>
2738 using InvertibleOperation = void;
2739 using OperationType = TernaryOperation;
2742 using ResultType = double;
2744 template<
class Order>
2745 static constexpr
auto polynomialOrder(Order)
2747 using namespace Literals;
2754 static constexpr
auto signPropagation(
const S1&)
2756 return SemiPositiveExpressionSign{};
2759 static std::string name()
2765 constexpr
auto operator()(T1&& t1)
const
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
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