MathUtils.hh

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #ifndef RIVET_MathUtils_HH
00003 #define RIVET_MathUtils_HH
00004 
00005 #include "Rivet/Math/MathHeader.hh"
00006 #include <cassert>
00007 
00008 namespace Rivet {
00009 
00010 
00011   /// @name Number comparisons etc.
00012   //@{
00013 
00014   /// Compare a floating point number to zero with a degree
00015   /// of fuzziness expressed by the absolute @a tolerance parameter.
00016   inline bool isZero(double val, double tolerance=1E-8) {
00017     return (fabs(val) < tolerance);
00018   }
00019 
00020   /// Compare an integral-type number to zero. Since there is no
00021   /// risk of floating point error, this function just exists in
00022   /// case @c isZero is accidentally used on an integer type, to avoid
00023   /// implicit type conversion. The @a tolerance parameter is ignored.
00024   inline bool isZero(long val, double UNUSED(tolerance)=1E-8) {
00025     return val == 0;
00026   }
00027 
00028   /// Find the sign of a number
00029   inline int sign(double val) {
00030     if (isZero(val)) return ZERO;
00031     const int valsign = (val > 0) ? PLUS : MINUS;
00032     return valsign;
00033   }
00034 
00035   /// Find the sign of a number
00036   inline int sign(int val) {
00037     if (val == 0) return ZERO;
00038     return (val > 0) ? PLUS : MINUS;
00039   }
00040 
00041   /// Find the sign of a number
00042   inline int sign(long val) {
00043     if (val == 0) return ZERO;
00044     return (val > 0) ? PLUS : MINUS;
00045   }
00046 
00047   /// Compare two floating point numbers with a degree of fuzziness
00048   /// expressed by the fractional @a tolerance parameter.
00049   inline bool fuzzyEquals(double a, double b, double tolerance=1E-5) {
00050     const double absavg = fabs(a + b)/2.0;
00051     const double absdiff = fabs(a - b);
00052     const bool rtn = (absavg == 0.0 && absdiff == 0.0) || absdiff < tolerance*absavg;
00053     return rtn;
00054   }
00055 
00056   /// Compare two integral-type numbers with a degree of fuzziness.
00057   /// Since there is no risk of floating point error with integral types,
00058   /// this function just exists in case @c fuzzyEquals is accidentally
00059   /// used on an integer type, to avoid implicit type conversion. The @a
00060   /// tolerance parameter is ignored, even if it would have an
00061   /// absolute magnitude greater than 1.
00062   inline bool fuzzyEquals(long a, long b, double UNUSED(tolerance)=1E-5) {
00063     return a == b;
00064   }
00065 
00066   /// Represents whether an interval is open (non-inclusive) or closed
00067   /// (inclusive). For example, the interval \f$ [0, \pi) \f$ is closed (an inclusive
00068   /// boundary) at 0, and open (a non-inclusive boundary) at \f$ \pi \f$.
00069   enum RangeBoundary { OPEN=0, SOFT=0, CLOSED=1, HARD=1 };
00070 
00071   /// Determine if @a value is in the range @a low to @a high, with boundary
00072   /// types defined by @a lowbound and @a highbound.
00073   /// @todo Optimise to one-line at compile time?
00074   template<typename NUM>
00075   inline bool inRange(NUM value, NUM low, NUM high,
00076                       RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN) {
00077     if (lowbound == OPEN && highbound == OPEN) {
00078       return (value > low && value < high);
00079     } else if (lowbound == OPEN && highbound == CLOSED) {
00080       return (value > low && value <= high);
00081     } else if (lowbound == CLOSED && highbound == OPEN) {
00082       return (value >= low && value < high);
00083     } else { // if (lowbound == CLOSED && highbound == CLOSED) {
00084       return (value >= low && value <= high);
00085     }
00086   }
00087 
00088 
00089   /// Determine if @a value is in the range @a low to @a high, with boundary
00090   /// types defined by @a lowbound and @a highbound.
00091   /// @todo Optimise to one-line at compile time?
00092   inline bool inRange(int value, int low, int high,
00093                       RangeBoundary lowbound=CLOSED, RangeBoundary highbound=CLOSED) {
00094     if (lowbound == OPEN && highbound == OPEN) {
00095       return (value > low && value < high);
00096     } else if (lowbound == OPEN && highbound == CLOSED) {
00097       return (value > low && value <= high);
00098     } else if (lowbound == CLOSED && highbound == OPEN) {
00099       return (value >= low && value < high);
00100     } else { // if (lowbound == CLOSED && highbound == CLOSED) {
00101       return (value >= low && value <= high);
00102     }
00103   }
00104 
00105 
00106   /// Named number-type squaring operation.
00107   template <typename Num>
00108   inline Num sqr(Num a) {
00109     return a*a;
00110   }
00111 
00112   //@}
00113 
00114 
00115 
00116   /// @name Statistics functions
00117   //@{
00118 
00119   /// Calculate the mean of a sample
00120   inline double mean(const vector<int>& sample) {
00121     double mean = 0.0;
00122     for (size_t i=0; i<sample.size(); ++i) {
00123       mean += sample[i];
00124     }
00125     return mean/sample.size();
00126   }
00127 
00128 
00129   /// Calculate the covariance (variance) between two samples
00130   inline double covariance(const vector<int>& sample1, const vector<int>& sample2) {
00131     double mean1 = mean(sample1);
00132     double mean2 = mean(sample2);
00133     int N = sample1.size();
00134     double cov = 0.0;
00135     for (int i = 0; i < N; i++) {
00136       double cov_i = (sample1[i] - mean1)*(sample2[i] - mean2);
00137       cov += cov_i;
00138     }
00139     if (N > 1) return cov/(N-1);
00140     else return 0.0;
00141   }
00142 
00143 
00144   /// Calculate the correlation strength between two samples
00145   inline double correlation(const vector<int>& sample1, const vector<int>& sample2) {
00146     const double cov = covariance(sample1, sample2);
00147     const double var1 = covariance(sample1, sample1);
00148     const double var2 = covariance(sample2, sample2);
00149     const double correlation = cov/sqrt(var1*var2);
00150     const double corr_strength = correlation*sqrt(var2/var1);
00151     return corr_strength;
00152   }
00153 
00154   //@}
00155 
00156 
00157   /// @name Angle range mappings
00158   //@{
00159 
00160   /// Reduce any number to the range [-2PI, 2PI] by repeated addition or
00161   /// subtraction of 2PI as required. Used to normalise angular measures.
00162   inline double _mapAngleM2PITo2Pi(double angle) {
00163     double rtn = fmod(angle, TWOPI);
00164     if (isZero(rtn)) return 0;
00165     assert(rtn >= -TWOPI && rtn <= TWOPI);
00166     return rtn;
00167   }
00168 
00169   /// Map an angle into the range (-PI, PI].
00170   inline double mapAngleMPiToPi(double angle) {
00171     double rtn = _mapAngleM2PITo2Pi(angle);
00172     if (isZero(rtn)) return 0;
00173     rtn = (rtn >   PI ? rtn-TWOPI :
00174            rtn <= -PI ? rtn+TWOPI : rtn);
00175     assert(rtn > -PI && rtn <= PI);
00176     return rtn;
00177   }
00178 
00179   /// Map an angle into the range [0, 2PI).
00180   inline double mapAngle0To2Pi(double angle) {
00181     double rtn = _mapAngleM2PITo2Pi(angle);
00182     if (isZero(rtn)) return 0;
00183     if (rtn < 0) rtn += TWOPI;
00184     if (rtn == TWOPI) rtn = 0;
00185     assert(rtn >= 0 && rtn < TWOPI);
00186     return rtn;
00187   }
00188 
00189   /// Map an angle into the range [0, PI].
00190   inline double mapAngle0ToPi(double angle) {
00191     double rtn = fabs(mapAngleMPiToPi(angle));
00192     if (isZero(rtn)) return 0;
00193     assert(rtn > 0 && rtn <= PI);
00194     return rtn;
00195   }
00196 
00197   //@}
00198 
00199 
00200   /// @name Phase space measure helpers
00201   //@{
00202 
00203   /// Calculate the difference between two angles in radians,
00204   /// returning in the range [0, PI].
00205   inline double deltaPhi(double phi1, double phi2) {
00206     return mapAngle0ToPi(phi1 - phi2);
00207   }
00208 
00209   /// Calculate the distance between two points in 2D rapidity-azimuthal
00210   /// ("eta-phi") space. The phi values are given in radians.
00211   inline double deltaR(double y1, double phi1, double y2, double phi2) {
00212     const double dphi = deltaPhi(phi1, phi2);
00213     return sqrt( sqr(y1-y2) + sqr(dphi) );
00214   }
00215 
00216   /// Calculate a rapidity value from the supplied energy @a E and longitudinal momentum @pz.
00217   inline double rapidity(double E, double pz) {
00218     if (isZero(E - pz)) {
00219       throw std::runtime_error("Divergent positive rapidity");
00220       return MAXDOUBLE;
00221     }
00222     if (isZero(E + pz)) {
00223       throw std::runtime_error("Divergent negative rapidity");
00224       return -MAXDOUBLE;
00225     }
00226     return 0.5*log((E+pz)/(E-pz));
00227   }
00228 
00229 
00230 }
00231 
00232 //@}
00233 
00234 #endif