Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #ifndef PhysicsTools_Utilities_SimplifyRatio_h
0002 #define PhysicsTools_Utilities_SimplifyRatio_h
0003 
0004 #include "PhysicsTools/Utilities/interface/Ratio.h"
0005 #include "PhysicsTools/Utilities/interface/Product.h"
0006 #include "PhysicsTools/Utilities/interface/Power.h"
0007 #include "PhysicsTools/Utilities/interface/Minus.h"
0008 #include "PhysicsTools/Utilities/interface/Fraction.h"
0009 #include "PhysicsTools/Utilities/interface/DecomposePower.h"
0010 #include "PhysicsTools/Utilities/interface/ParametricTrait.h"
0011 
0012 #include "PhysicsTools/Utilities/interface/Simplify_begin.h"
0013 
0014 #include <type_traits>
0015 
0016 namespace funct {
0017 
0018   // 0 / a = 0
0019   RATIO_RULE(TYPT1, NUM(0), A, NUM(0), num<0>());
0020 
0021   // a / 1 = a
0022   RATIO_RULE(TYPT1, A, NUM(1), A, _1);
0023 
0024   // ( a * b )/ 1 = a * b
0025   RATIO_RULE(TYPT2, PROD_S(A, B), NUM(1), PROD(A, B), _1);
0026 
0027   // a / ( -n ) = - ( a / n )
0028   template <int n, typename A, bool positive = (n >= 0)>
0029   struct SimplifyNegativeRatio {
0030     typedef RATIO_S(A, NUM(n)) type;
0031     COMBINE(A, NUM(n), type(_1, _2));
0032   };
0033 
0034   TEMPL(N1T1)
0035   struct SimplifyNegativeRatio<n, A, false> {
0036     typedef MINUS(RATIO(A, NUM(-n))) type;
0037     COMBINE(A, NUM(n), -(_1 / num<-n>()));
0038   };
0039 
0040   TEMPL(N1T1) struct Ratio<A, NUM(n)> : public SimplifyNegativeRatio<n, A> {};
0041 
0042   // ( -a ) / b = - ( a / b )
0043   RATIO_RULE(TYPT2, MINUS_S(A), B, MINUS(RATIO(A, B)), -(_1._ / _2));
0044 
0045   // ( -a ) / n = - ( a / n )
0046   RATIO_RULE(TYPN1T1, MINUS_S(A), NUM(n), MINUS(RATIO(A, NUM(n))), -(_1._ / _2));
0047 
0048   //TEMPL( N1T2 struct Ratio<PROD_S( A, B ), NUM( n )> :
0049   //  public SimplifyNegativeRatio<n, PROD_S( A, B )> { };
0050 
0051   // n / ( m * a ) = (n/m) * a
0052   /* WRONG!!
0053   RATIO_RULE(TYPN2T1, NUM(n), PROD_S(NUM(m), A), \
0054          PROD(FRACT(n, m), A), (fract<n, m>() * _2._2));
0055   */
0056   // ( a / b ) / c = a / ( b * c )
0057   RATIO_RULE(TYPT3, RATIO_S(A, B), C, RATIO(A, PROD(B, C)), _1._1 / (_1._2 * _2));
0058 
0059   // ( a / b ) / n = a / ( n * b )
0060   RATIO_RULE(TYPN1T2, RATIO_S(A, B), NUM(n), RATIO(A, PROD(NUM(n), B)), _1._1 / (_2 * _1._2));
0061 
0062   // ( a / b ) / ( c * d ) = a / ( b * c * d )
0063   RATIO_RULE(TYPT4, RATIO_S(A, B), PROD_S(C, D), RATIO(A, PROD(PROD(B, C), D)), _1._1 / (_1._2 * _2));
0064 
0065   // ( a * b ) / ( c / d ) = ( a * b * d ) / c
0066   RATIO_RULE(TYPT4, PROD_S(A, B), RATIO_S(C, D), RATIO(PROD(PROD(A, B), D), C), (_1 * _2._2) / _2._1);
0067 
0068   // ( n * a ) / ( m * b ) = ( n/m ) ( a / b )
0069   RATIO_RULE(TYPN2T2,
0070              PROD_S(NUM(n), A),
0071              PROD_S(NUM(m), B),
0072              PROD_S(FRACT(n, m), RATIO(A, B)),
0073              (PROD_S(FRACT(n, m), RATIO(A, B))((fract<n, m>()), (_1._2 / _2._2))));
0074 
0075   //  a / ( b / c ) = a * c / b
0076   RATIO_RULE(TYPT3, A, RATIO_S(B, C), RATIO(PROD(A, C), B), (_1 * _2._2) / _2._1);
0077 
0078   //  ( a + b ) / ( c / d ) = ( a + b ) * d / c
0079   RATIO_RULE(TYPT4, SUM_S(A, B), RATIO_S(C, D), RATIO(PROD(SUM(A, B), D), C), (_1 * _2._2) / _2._1);
0080 
0081   // ( a / b ) / ( c / d )= a * d / ( b * c )
0082   RATIO_RULE(TYPT4, RATIO_S(A, B), RATIO_S(C, D), RATIO(PROD(A, D), PROD(B, C)), (_1._1 * _2._2) / (_1._2 * _2._1));
0083 
0084   // ( a + b ) / ( b + a ) = 1
0085   template <TYPT2, bool parametric = (Parametric<A>::value == 1) || (Parametric<B>::value == 1)>
0086   struct SimplifyRatioSum {
0087     typedef RATIO_S(SUM(A, B), SUM(B, A)) type;
0088     COMBINE(SUM(A, B), SUM(B, A), type(_1, _2));
0089   };
0090 
0091   TEMPL(T2) struct SimplifyRatioSum<A, B, false> {
0092     typedef NUM(1) type;
0093     COMBINE(SUM(A, B), SUM(B, A), num<1>());
0094   };
0095 
0096   TEMPL(T2) struct Ratio<SUM_S(A, B), SUM_S(B, A)> : public SimplifyRatioSum<A, B> {};
0097 
0098   // a^b / a^c => a^( b - c)
0099   template <TYPT3, bool parametric = (Parametric<A>::value == 1)>
0100   struct SimplifyPowerRatio {
0101     typedef POWER(A, B) arg1;
0102     typedef POWER(A, C) arg2;
0103     typedef RATIO_S(arg1, arg2) type;
0104     COMBINE(arg1, arg2, type(_1, _2));
0105   };
0106 
0107   TEMPL(T3)
0108   struct SimplifyPowerRatio<A, B, C, false> {
0109     typedef POWER(A, B) arg1;
0110     typedef POWER(A, C) arg2;
0111     typedef POWER(A, DIFF(B, C)) type;
0112     inline static type combine(const arg1& _1, const arg2& _2) {
0113       return pow(DecomposePower<A, B>::getBase(_1),
0114                  (DecomposePower<A, B>::getExp(_1) - DecomposePower<A, C>::getExp(_2)));
0115     }
0116   };
0117 
0118   TEMPL(T3) struct Ratio<POWER_S(A, B), POWER_S(A, C)> : public SimplifyPowerRatio<A, B, C> {};
0119 
0120   TEMPL(T2) struct Ratio<POWER_S(A, B), POWER_S(A, B)> : public SimplifyPowerRatio<A, B, B> {};
0121 
0122   TEMPL(T2) struct Ratio<A, POWER_S(A, B)> : public SimplifyPowerRatio<A, NUM(1), B> {};
0123 
0124   TEMPL(N1T1) struct Ratio<A, POWER_S(A, NUM(n))> : public SimplifyPowerRatio<A, NUM(1), NUM(n)> {};
0125 
0126   TEMPL(T2) struct Ratio<POWER_S(A, B), A> : public SimplifyPowerRatio<A, B, NUM(1)> {};
0127 
0128   TEMPL(N1T1) struct Ratio<POWER_S(A, NUM(n)), A> : public SimplifyPowerRatio<A, NUM(n), NUM(1)> {};
0129 
0130   TEMPL(T1) struct Ratio<A, A> : public SimplifyPowerRatio<A, NUM(1), NUM(1)> {};
0131 
0132   TEMPL(T2) struct Ratio<PROD_S(A, B), PROD_S(A, B)> : public SimplifyPowerRatio<PROD_S(A, B), NUM(1), NUM(1)> {};
0133 
0134   TEMPL(N1T1)
0135   struct Ratio<PROD_S(NUM(n), A), PROD_S(NUM(n), A)> : public SimplifyPowerRatio<PROD_S(NUM(n), A), NUM(1), NUM(1)> {};
0136 
0137   RATIO_RULE(TYPN1, NUM(n), NUM(n), NUM(1), num<1>());
0138 
0139   // simplify ( f * g ) / h
0140   // try ( f / h ) * g and ( g / h ) * f, otherwise leave ( f * g ) / h
0141 
0142   template <typename Prod, bool simplify = Prod::value>
0143   struct AuxProductRatio {
0144     typedef PROD(typename Prod::AB, typename Prod::C) type;
0145     inline static type combine(const typename Prod::A& a, const typename Prod::B& b, const typename Prod::C& c) {
0146       return (a / b) * c;
0147     }
0148   };
0149 
0150   template <typename Prod>
0151   struct AuxProductRatio<Prod, false> {
0152     typedef RATIO_S(typename Prod::AB, typename Prod::C) type;
0153     inline static type combine(const typename Prod::A& a, const typename Prod::B& b, const typename Prod::C& c) {
0154       return type(a * b, c);
0155     }
0156   };
0157 
0158   template <typename F, typename G, typename H>
0159   struct RatioP1 {
0160     struct prod0 {
0161       typedef F A;
0162       typedef G B;
0163       typedef H C;
0164       typedef PROD_S(A, B) AB;
0165       inline static const A& a(const F& f, const G& g, const H& h) { return f; }
0166       inline static const B& b(const F& f, const G& g, const H& h) { return g; }
0167       inline static const C& c(const F& f, const G& g, const H& h) { return h; }
0168       enum { value = false };
0169     };
0170     struct prod1 {
0171       typedef F A;
0172       typedef H B;
0173       typedef G C;
0174       typedef RATIO_S(A, B) base;
0175       typedef RATIO(A, B) AB;
0176       inline static const A& a(const F& f, const G& g, const H& h) { return f; }
0177       inline static const B& b(const F& f, const G& g, const H& h) { return h; }
0178       inline static const C& c(const F& f, const G& g, const H& h) { return g; }
0179       enum { value = not ::std::is_same<AB, base>::value };
0180     };
0181     struct prod2 {
0182       typedef G A;
0183       typedef H B;
0184       typedef F C;
0185       typedef RATIO_S(A, B) base;
0186       typedef RATIO(A, B) AB;
0187       inline static const A& a(const F& f, const G& g, const H& h) { return g; }
0188       inline static const B& b(const F& f, const G& g, const H& h) { return h; }
0189       inline static const C& c(const F& f, const G& g, const H& h) { return f; }
0190       enum { value = not ::std::is_same<AB, base>::value };
0191     };
0192 
0193     typedef
0194         typename std::conditional<prod1::value, prod1, typename std::conditional<prod2::value, prod2, prod0>::type>::type
0195             prod;
0196     typedef typename AuxProductRatio<prod>::type type;
0197     inline static type combine(const PROD_S(F, G) & fg, const H& h) {
0198       const F& f = fg._1;
0199       const G& g = fg._2;
0200       const typename prod::A& a = prod::a(f, g, h);
0201       const typename prod::B& b = prod::b(f, g, h);
0202       const typename prod::C& c = prod::c(f, g, h);
0203       return AuxProductRatio<prod>::combine(a, b, c);
0204     }
0205   };
0206 
0207   // simplify c / ( a * b )
0208   // try ( c / a ) / b and ( c / b ) / a, otherwise leave c / ( a * b )
0209 
0210   template <typename Prod, bool simplify = Prod::value>
0211   struct AuxProductRatio2 {
0212     typedef RATIO(typename Prod::AB, typename Prod::C) type;
0213     inline static type combine(const typename Prod::A& a, const typename Prod::B& b, const typename Prod::C& c) {
0214       return (b / a) / c;
0215     }
0216   };
0217 
0218   template <typename Prod>
0219   struct AuxProductRatio2<Prod, false> {
0220     typedef RATIO_S(typename Prod::C, typename Prod::AB) type;
0221     inline static type combine(const typename Prod::A& a, const typename Prod::B& b, const typename Prod::C& c) {
0222       return type(c, a * b);
0223     }
0224   };
0225 
0226   template <typename F, typename G, typename H>
0227   struct RatioP2 {
0228     struct prod0 {
0229       typedef F A;
0230       typedef G B;
0231       typedef H C;
0232       typedef PROD_S(A, B) AB;
0233       inline static const A& a(const F& f, const G& g, const H& h) { return f; }
0234       inline static const B& b(const F& f, const G& g, const H& h) { return g; }
0235       inline static const C& c(const F& f, const G& g, const H& h) { return h; }
0236       enum { value = false };
0237     };
0238     struct prod1 {
0239       typedef F A;
0240       typedef H B;
0241       typedef G C;
0242       typedef RATIO_S(B, A) base;
0243       typedef RATIO(B, A) AB;
0244       inline static const A& a(const F& f, const G& g, const H& h) { return f; }
0245       inline static const B& b(const F& f, const G& g, const H& h) { return h; }
0246       inline static const C& c(const F& f, const G& g, const H& h) { return g; }
0247       enum { value = not ::std::is_same<AB, base>::value };
0248     };
0249     struct prod2 {
0250       typedef G A;
0251       typedef H B;
0252       typedef F C;
0253       typedef RATIO_S(B, A) base;
0254       typedef RATIO(B, A) AB;
0255       inline static const A& a(const F& f, const G& g, const H& h) { return g; }
0256       inline static const B& b(const F& f, const G& g, const H& h) { return h; }
0257       inline static const C& c(const F& f, const G& g, const H& h) { return f; }
0258       enum { value = not ::std::is_same<AB, base>::value };
0259     };
0260 
0261     typedef
0262         typename std::conditional<prod1::value, prod1, typename std::conditional<prod2::value, prod2, prod0>::type>::type
0263             prod;
0264     typedef typename AuxProductRatio2<prod>::type type;
0265     inline static type combine(const H& h, const PROD_S(F, G) & fg) {
0266       const F& f = fg._1;
0267       const G& g = fg._2;
0268       const typename prod::A& a = prod::a(f, g, h);
0269       const typename prod::B& b = prod::b(f, g, h);
0270       const typename prod::C& c = prod::c(f, g, h);
0271       return AuxProductRatio2<prod>::combine(a, b, c);
0272     }
0273   };
0274 
0275   TEMPL(T3) struct Ratio<PROD_S(A, B), C> : public RatioP1<A, B, C> {};
0276 
0277   TEMPL(N1T2) struct Ratio<PROD_S(A, B), NUM(n)> : public RatioP1<A, B, NUM(n)> {};
0278 
0279   TEMPL(T3) struct Ratio<C, PROD_S(A, B)> : public RatioP2<A, B, C> {};
0280 
0281   TEMPL(T4) struct Ratio<PROD_S(C, D), PROD_S(A, B)> : public RatioP2<A, B, PROD_S(C, D)> {};
0282 
0283   // simplify ( a + b ) / c trying to simplify ( a / c ) and ( b / c )
0284   template <TYPT3, bool simplify = false>
0285   struct AuxSumRatio {
0286     typedef RATIO_S(SUM_S(A, B), C) type;
0287     COMBINE(SUM_S(A, B), C, type(_1, _2));
0288   };
0289 
0290   TEMPL(T3) struct AuxSumRatio<A, B, C, true> {
0291     typedef SUM(RATIO(A, C), RATIO(B, C)) type;
0292     COMBINE(SUM_S(A, B), C, (_1._1 / _2) + (_1._2 / _2));
0293   };
0294 
0295   TEMPL(T3) struct RatioSimpl {
0296     struct ratio1 {
0297       typedef RATIO_S(A, C) base;
0298       typedef RATIO(A, C) type;
0299       enum { value = not ::std::is_same<type, base>::value };
0300     };
0301     struct ratio2 {
0302       typedef RATIO_S(B, C) base;
0303       typedef RATIO(B, C) type;
0304       enum { value = not ::std::is_same<type, base>::value };
0305     };
0306     typedef AuxSumRatio<A, B, C, ratio1::value or ratio2::value> aux;
0307     typedef typename aux::type type;
0308     COMBINE(SUM_S(A, B), C, aux::combine(_1, _2));
0309   };
0310 
0311   TEMPL(T3) struct Ratio<SUM_S(A, B), C> : public RatioSimpl<A, B, C> {};
0312 
0313   TEMPL(T4) struct Ratio<SUM_S(A, B), PROD_S(C, D)> : public RatioSimpl<A, B, PROD_S(C, D)> {};
0314 
0315   TEMPL(N1T2) struct Ratio<SUM_S(A, B), NUM(n)> : public RatioSimpl<A, B, NUM(n)> {};
0316 
0317 }  // namespace funct
0318 
0319 #include "PhysicsTools/Utilities/interface/Simplify_end.h"
0320 
0321 #endif