00001
00002 #ifndef RIVET_MathUtils_HH
00003 #define RIVET_MathUtils_HH
00004
00005 #include "Rivet/Math/MathHeader.hh"
00006 #include "Rivet/RivetBoost.hh"
00007 #include <cassert>
00008
00009 namespace Rivet {
00010
00011
00012
00013
00014
00015
00016
00017 inline bool isZero(double val, double tolerance=1E-8) {
00018 return (fabs(val) < tolerance);
00019 }
00020
00021
00022
00023
00024
00025 inline bool isZero(long val, double UNUSED(tolerance)=1E-8) {
00026 return val == 0;
00027 }
00028
00029
00030
00031
00032 inline bool fuzzyEquals(double a, double b, double tolerance=1E-5) {
00033 const double absavg = fabs(a + b)/2.0;
00034 const double absdiff = fabs(a - b);
00035 const bool rtn = (absavg == 0.0 && absdiff == 0.0) || absdiff < tolerance*absavg;
00036 return rtn;
00037 }
00038
00039
00040
00041
00042
00043
00044
00045 inline bool fuzzyEquals(long a, long b, double UNUSED(tolerance)=1E-5) {
00046 return a == b;
00047 }
00048
00049
00050
00051
00052 inline bool fuzzyGtrEquals(double a, double b, double tolerance=1E-5) {
00053 return a > b || fuzzyEquals(a, b, tolerance);
00054 }
00055
00056
00057
00058
00059
00060
00061
00062 inline bool fuzzyGtrEquals(long a, long b, double UNUSED(tolerance)=1E-5) {
00063 return a >= b;
00064 }
00065
00066
00067
00068
00069 inline bool fuzzyLessEquals(double a, double b, double tolerance=1E-5) {
00070 return a < b || fuzzyEquals(a, b, tolerance);
00071 }
00072
00073
00074
00075
00076
00077
00078
00079 inline bool fuzzyLessEquals(long a, long b, double UNUSED(tolerance)=1E-5) {
00080 return a <= b;
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 enum RangeBoundary { OPEN=0, SOFT=0, CLOSED=1, HARD=1 };
00093
00094
00095
00096
00097
00098 template<typename NUM>
00099 inline bool inRange(NUM value, NUM low, NUM high,
00100 RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN) {
00101 if (lowbound == OPEN && highbound == OPEN) {
00102 return (value > low && value < high);
00103 } else if (lowbound == OPEN && highbound == CLOSED) {
00104 return (value > low && (value < high || fuzzyEquals(value, high)));
00105 } else if (lowbound == CLOSED && highbound == OPEN) {
00106 return ((value > low || fuzzyEquals(value, low)) && value < high);
00107 } else {
00108 return ((value > low || fuzzyEquals(value, low)) && (value < high || fuzzyEquals(value, high)));
00109 }
00110 }
00111
00112
00113 template<typename NUM>
00114 inline bool inRange(NUM value, pair<NUM, NUM> lowhigh,
00115 RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN) {
00116 return inRange(value, lowhigh.first, lowhigh.second, lowbound, highbound);
00117 }
00118
00119
00120
00121
00122
00123 inline bool inRange(int value, int low, int high,
00124 RangeBoundary lowbound=CLOSED, RangeBoundary highbound=CLOSED) {
00125 if (lowbound == OPEN && highbound == OPEN) {
00126 return (value > low && value < high);
00127 } else if (lowbound == OPEN && highbound == CLOSED) {
00128 return (value > low && value <= high);
00129 } else if (lowbound == CLOSED && highbound == OPEN) {
00130 return (value >= low && value < high);
00131 } else {
00132 return (value >= low && value <= high);
00133 }
00134 }
00135
00136
00137 inline bool inRange(int value, pair<int, int> lowhigh,
00138 RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN) {
00139 return inRange(value, lowhigh.first, lowhigh.second, lowbound, highbound);
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149 template <typename NUM>
00150 inline NUM sqr(NUM a) {
00151 return a*a;
00152 }
00153
00154
00155 template <typename Num>
00156 inline Num add_quad(Num a, Num b) {
00157 return sqrt(a*a + b*b);
00158 }
00159
00160
00161 template <typename Num>
00162 inline Num add_quad(Num a, Num b, Num c) {
00163 return sqrt(a*a + b*b + c*c);
00164 }
00165
00166
00167 template <typename Num>
00168 inline Num intpow(Num val, unsigned int exp) {
00169 assert(exp >= 0);
00170 if (exp == 0) return (Num) 1;
00171 else if (exp == 1) return val;
00172 else return val * intpow(val, exp-1);
00173 }
00174
00175
00176 inline int sign(double val) {
00177 if (isZero(val)) return ZERO;
00178 const int valsign = (val > 0) ? PLUS : MINUS;
00179 return valsign;
00180 }
00181
00182
00183 inline int sign(int val) {
00184 if (val == 0) return ZERO;
00185 return (val > 0) ? PLUS : MINUS;
00186 }
00187
00188
00189 inline int sign(long val) {
00190 if (val == 0) return ZERO;
00191 return (val > 0) ? PLUS : MINUS;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201 inline vector<double> linspace(double start, double end, size_t nbins) {
00202 assert(end >= start);
00203 assert(nbins > 0);
00204 vector<double> rtn;
00205 const double interval = (end-start)/static_cast<double>(nbins);
00206 double edge = start;
00207 while (inRange(edge, start, end, CLOSED, CLOSED)) {
00208 rtn.push_back(edge);
00209 edge += interval;
00210 }
00211 assert(rtn.size() == nbins+1);
00212 return rtn;
00213 }
00214
00215
00216
00217 inline vector<double> logspace(double start, double end, size_t nbins) {
00218 assert(end >= start);
00219 assert(start > 0);
00220 assert(nbins > 0);
00221 const double logstart = std::log(start);
00222 const double logend = std::log(end);
00223 const vector<double> logvals = linspace(logstart, logend, nbins);
00224 vector<double> rtn;
00225 foreach (double logval, logvals) {
00226 rtn.push_back(std::exp(logval));
00227 }
00228 assert(rtn.size() == nbins+1);
00229 return rtn;
00230 }
00231
00232
00233
00234
00235 template <typename NUM>
00236 inline int index_between(const NUM& val, const vector<NUM>& binedges) {
00237 if (!inRange(val, binedges.front(), binedges.back())) return -1;
00238 int index = -1;
00239 for (size_t i = 1; i < binedges.size(); ++i) {
00240 if (val < binedges[i]) {
00241 index = i-1;
00242 break;
00243 }
00244 }
00245 assert(inRange(index, -1, binedges.size()-1));
00246 return index;
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256 inline double mean(const vector<int>& sample) {
00257 double mean = 0.0;
00258 for (size_t i=0; i<sample.size(); ++i) {
00259 mean += sample[i];
00260 }
00261 return mean/sample.size();
00262 }
00263
00264
00265 inline double mean_err(const vector<int>& sample) {
00266 double mean_e = 0.0;
00267 for (size_t i=0; i<sample.size(); ++i) {
00268 mean_e += sqrt(sample[i]);
00269 }
00270 return mean_e/sample.size();
00271 }
00272
00273
00274 inline double covariance(const vector<int>& sample1, const vector<int>& sample2) {
00275 const double mean1 = mean(sample1);
00276 const double mean2 = mean(sample2);
00277 const int N = sample1.size();
00278 double cov = 0.0;
00279 for (int i = 0; i < N; i++) {
00280 const double cov_i = (sample1[i] - mean1)*(sample2[i] - mean2);
00281 cov += cov_i;
00282 }
00283 if (N > 1) return cov/(N-1);
00284 else return 0.0;
00285 }
00286
00287
00288 inline double covariance_err(const vector<int>& sample1, const vector<int>& sample2) {
00289 const double mean1 = mean(sample1);
00290 const double mean2 = mean(sample2);
00291 const double mean1_e = mean_err(sample1);
00292 const double mean2_e = mean_err(sample2);
00293 const int N = sample1.size();
00294 double cov_e = 0.0;
00295 for (int i = 0; i < N; i++) {
00296 const double cov_i = (sqrt(sample1[i]) - mean1_e)*(sample2[i] - mean2) +
00297 (sample1[i] - mean1)*(sqrt(sample2[i]) - mean2_e);
00298 cov_e += cov_i;
00299 }
00300 if (N > 1) return cov_e/(N-1);
00301 else return 0.0;
00302 }
00303
00304
00305
00306 inline double correlation(const vector<int>& sample1, const vector<int>& sample2) {
00307 const double cov = covariance(sample1, sample2);
00308 const double var1 = covariance(sample1, sample1);
00309 const double var2 = covariance(sample2, sample2);
00310 const double correlation = cov/sqrt(var1*var2);
00311 const double corr_strength = correlation*sqrt(var2/var1);
00312 return corr_strength;
00313 }
00314
00315
00316 inline double correlation_err(const vector<int>& sample1, const vector<int>& sample2) {
00317 const double cov = covariance(sample1, sample2);
00318 const double var1 = covariance(sample1, sample1);
00319 const double var2 = covariance(sample2, sample2);
00320 const double cov_e = covariance_err(sample1, sample2);
00321 const double var1_e = covariance_err(sample1, sample1);
00322 const double var2_e = covariance_err(sample2, sample2);
00323
00324
00325 const double correlation = cov/sqrt(var1*var2);
00326
00327 const double correlation_err = cov_e/sqrt(var1*var2) -
00328 cov/(2*pow(3./2., var1*var2)) * (var1_e * var2 + var1 * var2_e);
00329
00330
00331
00332 const double corr_strength_err = correlation_err*sqrt(var2/var1) +
00333 correlation/(2*sqrt(var2/var1)) * (var2_e/var1 - var2*var1_e/pow(2, var2));
00334
00335 return corr_strength_err;
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345 inline double _mapAngleM2PITo2Pi(double angle) {
00346 double rtn = fmod(angle, TWOPI);
00347 if (isZero(rtn)) return 0;
00348 assert(rtn >= -TWOPI && rtn <= TWOPI);
00349 return rtn;
00350 }
00351
00352
00353 inline double mapAngleMPiToPi(double angle) {
00354 double rtn = _mapAngleM2PITo2Pi(angle);
00355 if (isZero(rtn)) return 0;
00356 rtn = (rtn > PI ? rtn-TWOPI :
00357 rtn <= -PI ? rtn+TWOPI : rtn);
00358 assert(rtn > -PI && rtn <= PI);
00359 return rtn;
00360 }
00361
00362
00363 inline double mapAngle0To2Pi(double angle) {
00364 double rtn = _mapAngleM2PITo2Pi(angle);
00365 if (isZero(rtn)) return 0;
00366 if (rtn < 0) rtn += TWOPI;
00367 if (rtn == TWOPI) rtn = 0;
00368 assert(rtn >= 0 && rtn < TWOPI);
00369 return rtn;
00370 }
00371
00372
00373 inline double mapAngle0ToPi(double angle) {
00374 double rtn = fabs(mapAngleMPiToPi(angle));
00375 if (isZero(rtn)) return 0;
00376 assert(rtn > 0 && rtn <= PI);
00377 return rtn;
00378 }
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 inline double deltaPhi(double phi1, double phi2) {
00389 return mapAngle0ToPi(phi1 - phi2);
00390 }
00391
00392
00393
00394 inline double deltaEta(double eta1, double eta2) {
00395 return fabs(eta1 - eta2);
00396 }
00397
00398
00399
00400 inline double deltaR(double rap1, double phi1, double rap2, double phi2) {
00401 const double dphi = deltaPhi(phi1, phi2);
00402 return sqrt( sqr(rap1-rap2) + sqr(dphi) );
00403 }
00404
00405
00406 inline double rapidity(double E, double pz) {
00407 if (isZero(E - pz)) {
00408 throw std::runtime_error("Divergent positive rapidity");
00409 return MAXDOUBLE;
00410 }
00411 if (isZero(E + pz)) {
00412 throw std::runtime_error("Divergent negative rapidity");
00413 return -MAXDOUBLE;
00414 }
00415 return 0.5*log((E+pz)/(E-pz));
00416 }
00417
00418
00419
00420
00421 }
00422
00423
00424 #endif