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