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 
18 namespace 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
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.80.0 (May 1, 22:29, 2024)