Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 13:33:31

0001 #ifndef PhysicsTools_Utilities_SimplifyProduct_h
0002 #define PhysicsTools_Utilities_SimplifyProduct_h
0003 
0004 #include "PhysicsTools/Utilities/interface/Product.h"
0005 #include "PhysicsTools/Utilities/interface/Fraction.h"
0006 #include "PhysicsTools/Utilities/interface/DecomposePower.h"
0007 #include "PhysicsTools/Utilities/interface/ParametricTrait.h"
0008 #include <type_traits>
0009 
0010 #include "PhysicsTools/Utilities/interface/Simplify_begin.h"
0011 
0012 namespace funct {
0013 
0014   // a * ( b * c ) = ( a * b ) * c
0015   PROD_RULE(TYPT3, A, PROD_S(B, C), PROD(PROD(A, B), C), (_1 * _2._1) * _2._2);
0016 
0017   // 0 * a = 0
0018   PROD_RULE(TYPT1, NUM(0), A, NUM(0), num<0>());
0019 
0020   // 0 * n = 0
0021   PROD_RULE(TYPN1, NUM(0), NUM(n), NUM(0), num<0>());
0022 
0023   // 0 * ( a * b ) => 0
0024   PROD_RULE(TYPT2, NUM(0), PROD_S(A, B), NUM(0), num<0>());
0025 
0026   // 1 * a = a
0027   PROD_RULE(TYPT1, NUM(1), A, A, _2);
0028 
0029   // avoid template ambiguities
0030   // 1 * n = n
0031   PROD_RULE(TYPN1, NUM(1), NUM(n), NUM(n), _2);
0032 
0033   // 1 * (n/m) = (n/m)
0034   PROD_RULE(TYPN2, NUM(1), FRACT_S(n, m), FRACT_S(n, m), _2);
0035 
0036   // 1 * 1 = 1
0037   PROD_RULE(TYP0, NUM(1), NUM(1), NUM(1), num<1>());
0038 
0039   // ( - 1 ) * a = - a
0040   PROD_RULE(TYPT1, NUM(-1), A, MINUS_S(A), -_2);
0041 
0042   // ( - 1 ) * n = -n
0043   PROD_RULE(TYPN1, NUM(-1), NUM(n), NUM(-n), num<-n>());
0044 
0045   // 1 * ( a * b ) => ( a * b )
0046   PROD_RULE(TYPT2, NUM(1), PROD_S(A, B), PROD_S(A, B), _2);
0047 
0048   // a * ( -b ) =  - ( a * b )
0049   PROD_RULE(TYPT2, A, MINUS_S(B), MINUS(PROD(A, B)), -(_1* _2._));
0050 
0051   // n * ( -a ) =  - ( n * a )
0052   PROD_RULE(TYPN1T1, NUM(n), MINUS_S(A), MINUS(PROD(NUM(n), A)), -(_1* _2._));
0053 
0054   // ( a * b ) * ( -c )=  - ( ( a * b ) * c )
0055   PROD_RULE(TYPT3, PROD_S(A, B), MINUS_S(C), MINUS(PROD(PROD(A, B), C)), -(_1* _2._));
0056 
0057   // 1 * ( -a ) = -a
0058   PROD_RULE(TYPT1, NUM(1), MINUS_S(A), MINUS(A), _2);
0059 
0060   // ( - a ) * ( - b ) = a * b
0061   PROD_RULE(TYPT2, MINUS_S(A), MINUS_S(B), PROD(A, B), _1._* _2._);
0062 
0063   // ( -a ) * b = -( a * b )
0064   PROD_RULE(TYPT2, MINUS_S(A), B, MINUS(PROD(A, B)), -(_1._* _2));
0065 
0066   // a * ( b / c ) = ( a * b ) / c
0067   PROD_RULE(TYPT3, A, RATIO_S(B, C), RATIO(PROD(A, B), C), (_1 * _2._1) / _2._2);
0068 
0069   // n * ( a / b ) = ( n * a ) / b
0070   PROD_RULE(TYPN1T2, NUM(n), RATIO_S(A, B), RATIO(PROD(NUM(n), A), B), (_1 * _2._1) / _2._2);
0071 
0072   // 1 * ( a / b ) = a / b
0073   PROD_RULE(TYPT2, NUM(1), RATIO_S(A, B), RATIO(A, B), _2);
0074 
0075   // 0 * ( a / b ) = 0
0076   PROD_RULE(TYPT2, NUM(0), RATIO_S(A, B), NUM(0), num<0>());
0077 
0078   // a * n = n * a
0079   PROD_RULE(TYPN1T1, A, NUM(n), PROD(NUM(n), A), _2* _1);
0080 
0081   // ( a * b ) n = ( n * a ) * b
0082   PROD_RULE(TYPN1T2, PROD_S(A, B), NUM(n), PROD(PROD(NUM(n), A), B), (_2 * _1._1) * _1._2);
0083 
0084   // ( a * b ) * ( c * d ) => ( ( a * b ) * c ) * d
0085   PROD_RULE(TYPT4, PROD_S(A, B), PROD_S(C, D), PROD(PROD(PROD(A, B), C), D), (_1 * _2._1) * _2._2);
0086 
0087   // n/m * ( a / k ) = n/(m+k) * a
0088   PROD_RULE(TYPN3T1, FRACT_S(n, m), RATIO_S(A, NUM(k)), PROD(FRACT(n, m + k), A), (fract<n, m + k>() * _2._1));
0089 
0090   // ( a / b ) * n = ( n a ) / b
0091   PROD_RULE(TYPN1T2, RATIO_S(A, B), NUM(n), RATIO(PROD(NUM(n), A), B), (_2 * _1._1) / _1._2);
0092 
0093   // ( a / b ) * c = ( a * c ) / b
0094   PROD_RULE(TYPT3, RATIO_S(A, B), C, RATIO(PROD(A, C), B), (_1._1 * _2) / _1._2);
0095 
0096   // 0 * 1 = 0  ( avoid template ambiguity )
0097   PROD_RULE(TYP0, NUM(0), NUM(1), NUM(0), num<0>());
0098 
0099   // ( a / b ) * ( c / d )= a * c / ( b * d )
0100   PROD_RULE(TYPT4, RATIO_S(A, B), RATIO_S(C, D), RATIO(PROD(A, C), PROD(B, D)), (_1._1 * _2._1) / (_1._2 * _2._2));
0101 
0102   // a^b * a^c => a^( b + c )
0103   template <TYPT3, bool parametric = Parametric<A>::value>
0104   struct SimplifyPowerProduct {
0105     typedef POWER(A, B) arg1;
0106     typedef POWER(A, C) arg2;
0107     typedef PROD_S(arg1, arg2) type;
0108     COMBINE(arg1, arg2, type(_1, _2));
0109   };
0110 
0111   TEMPL(T3)
0112   struct SimplifyPowerProduct<A, B, C, false> {
0113     typedef POWER(A, B) arg1;
0114     typedef POWER(A, C) arg2;
0115     typedef POWER(A, SUM(B, C)) type;
0116     inline static type combine(const arg1& _1, const arg2& _2) {
0117       return pow(DecomposePower<A, B>::getBase(_1),
0118                  (DecomposePower<A, B>::getExp(_1) + DecomposePower<A, C>::getExp(_2)));
0119     }
0120   };
0121 
0122   TEMPL(T3) struct Product<POWER_S(A, B), POWER_S(A, C)> : public SimplifyPowerProduct<A, B, C> {};
0123 
0124   TEMPL(T2) struct Product<POWER_S(A, B), POWER_S(A, B)> : public SimplifyPowerProduct<A, B, B> {};
0125 
0126   TEMPL(T2) struct Product<A, POWER_S(A, B)> : public SimplifyPowerProduct<A, NUM(1), B> {};
0127 
0128   TEMPL(N1T1) struct Product<A, POWER_S(A, NUM(n))> : public SimplifyPowerProduct<A, NUM(1), NUM(n)> {};
0129 
0130   TEMPL(T2) struct Product<POWER_S(A, B), A> : public SimplifyPowerProduct<A, B, NUM(1)> {};
0131 
0132   TEMPL(N1T1) struct Product<POWER_S(A, NUM(n)), A> : public SimplifyPowerProduct<A, NUM(n), NUM(1)> {};
0133 
0134   TEMPL(T1) struct Product<A, A> : public SimplifyPowerProduct<A, NUM(1), NUM(1)> {};
0135 
0136   TEMPL(T2) struct Product<PROD_S(A, B), PROD_S(A, B)> : public SimplifyPowerProduct<PROD(A, B), NUM(1), NUM(1)> {};
0137 
0138   TEMPL(T1) struct Product<MINUS_S(A), MINUS_S(A)> : public SimplifyPowerProduct<MINUS_S(A), NUM(1), NUM(1)> {};
0139 
0140   // n * n = n ^ 2
0141   PROD_RULE(TYPN1, NUM(n), NUM(n), NUM(n* n), num<n * n>());
0142 
0143   // a/ b * ( c * d ) = ( a * c * d ) / b
0144   PROD_RULE(TYPT4, RATIO_S(A, B), PROD_S(C, D), RATIO(PROD(PROD(A, C), D), B), ((_1._1 * _2._1) * _2._2) / _1._2);
0145 
0146   // simplify f * g * h regardless of the order
0147   template <typename Prod, bool simplify = Prod::value>
0148   struct AuxProduct {
0149     typedef PROD(typename Prod::AB, typename Prod::C) type;
0150     COMBINE(typename Prod::AB, typename Prod::C, _1* _2);
0151   };
0152 
0153   template <typename Prod>
0154   struct AuxProduct<Prod, false> {
0155     typedef PROD_S(typename Prod::AB, typename Prod::C) type;
0156     COMBINE(typename Prod::AB, typename Prod::C, type(_1, _2));
0157   };
0158 
0159   template <typename F, typename G, typename H>
0160   struct Product<PROD_S(F, G), H> {
0161     struct prod0 {
0162       typedef F A;
0163       typedef G B;
0164       typedef H C;
0165       typedef PROD_S(A, B) AB;
0166       inline static const A& a(const F& f, const G& g, const H& h) { return f; }
0167       inline static const B& b(const F& f, const G& g, const H& h) { return g; }
0168       inline static const C& c(const F& f, const G& g, const H& h) { return h; }
0169       enum { value = false };
0170     };
0171     struct prod1 {
0172       typedef F A;
0173       typedef H B;
0174       typedef G C;
0175       typedef PROD_S(A, B) base;
0176       typedef PROD(A, B) AB;
0177       inline static const A& a(const F& f, const G& g, const H& h) { return f; }
0178       inline static const B& b(const F& f, const G& g, const H& h) { return h; }
0179       inline static const C& c(const F& f, const G& g, const H& h) { return g; }
0180       enum { value = not ::std::is_same<AB, base>::value };
0181     };
0182     struct prod2 {
0183       typedef G A;
0184       typedef H B;
0185       typedef F C;
0186       typedef PROD_S(A, B) base;
0187       typedef PROD(A, B) AB;
0188       inline static const A& a(const F& f, const G& g, const H& h) { return g; }
0189       inline static const B& b(const F& f, const G& g, const H& h) { return h; }
0190       inline static const C& c(const F& f, const G& g, const H& h) { return f; }
0191       enum { value = not ::std::is_same<AB, base>::value };
0192     };
0193 
0194     typedef
0195         typename std::conditional<prod1::value, prod1, typename std::conditional<prod2::value, prod2, prod0>::type>::type
0196             prod;
0197     typedef typename AuxProduct<prod>::type type;
0198     inline static type combine(const ProductStruct<F, G>& fg, const H& h) {
0199       const F& f = fg._1;
0200       const G& g = fg._2;
0201       const typename prod::A& a = prod::a(f, g, h);
0202       const typename prod::B& b = prod::b(f, g, h);
0203       const typename prod::C& c = prod::c(f, g, h);
0204       return AuxProduct<prod>::combine(a * b, c);
0205     }
0206   };
0207 
0208 }  // namespace funct
0209 
0210 #include "PhysicsTools/Utilities/interface/Simplify_end.h"
0211 
0212 #endif