|
YODA - Yet more Objects for Data Analysis 2.0.3
|
Go to the documentation of this file.
6#ifndef YODA_MathUtils_H
7#define YODA_MathUtils_H
39 const static double MAXINT = INT_MAX;
42 static const double PI = M_PI;
45 static const double TWOPI = 2*M_PI;
61 template < typename NUM>
62 inline typename std::enable_if_t<std::is_floating_point_v<NUM>, bool>
63 isZero(NUM val, double tolerance=1e-5) {
64 return fabs(val) < tolerance;
71 template < typename NUM>
72 inline typename std::enable_if_t<std::is_integral_v<NUM>, bool>
78 template < typename NUM>
79 inline typename std::enable_if_t<std::is_floating_point_v<NUM>, bool>
80 isNaN(NUM val) { return std::isnan(val); }
83 template < typename NUM>
84 inline typename std::enable_if_t<std::is_floating_point_v<NUM>, bool>
85 notNaN(NUM val) { return !std::isnan(val); }
92 template < typename N1, typename N2>
93 inline typename std::enable_if_t<
94 std::is_arithmetic_v<N1> && std::is_arithmetic_v<N2> &&
95 (std::is_floating_point_v<N1> || std::is_floating_point_v<N2>), bool>
97 const double absavg = (std::abs(a) + std::abs(b))/2.0;
98 const double absdiff = std::abs(a - b);
99 const bool rtn = ( isZero(a) && isZero(b)) || absdiff < tolerance*absavg;
107 template < typename N1, typename N2>
108 inline typename std::enable_if_t<
109 std::is_integral_v<N1> && std::is_integral_v<N2>, bool>
115 static std::function<bool( const double, const double)> fuzzyEqComp =
116 []( const double& lhs, const double& rhs) { return fuzzyEquals(lhs, rhs); };
122 template < typename N1, typename N2>
123 inline typename std::enable_if_t<
124 std::is_arithmetic_v<N1> && std::is_arithmetic_v<N2>, bool>
132 template < typename N1, typename N2>
133 inline typename std::enable_if_t<
134 std::is_arithmetic_v<N1> && std::is_arithmetic_v<N2>, bool>
140 inline double approx( double a, int n = 5) {
141 double roundTo = pow(10.0,n);
163 template< typename NUM>
164 inline bool inRange(NUM value, NUM low, NUM high,
166 if (lowbound == OPEN && highbound == OPEN) {
167 return (value > low && value < high);
168 } else if (lowbound == OPEN && highbound == CLOSED) {
169 return (value > low && value <= high);
170 } else if (lowbound == CLOSED && highbound == OPEN) {
171 return (value >= low && value < high);
173 return (value >= low && value <= high);
178 template< typename NUM>
179 inline bool inRange(NUM value, std::pair<NUM, NUM> lowhigh,
181 return inRange(value, lowhigh.first, lowhigh.second, lowbound, highbound);
189 inline bool inRange( int value, int low, int high,
191 if (lowbound == OPEN && highbound == OPEN) {
192 return (value > low && value < high);
193 } else if (lowbound == OPEN && highbound == CLOSED) {
194 return (value > low && value <= high);
195 } else if (lowbound == CLOSED && highbound == OPEN) {
196 return (value >= low && value < high);
198 return (value >= low && value <= high);
203 inline bool inRange( int value, std::pair<int, int> lowhigh,
205 return inRange(value, lowhigh.first, lowhigh.second, lowbound, highbound);
215 template < typename NUM>
221 template < typename... Num>
222 inline std::enable_if_t<std::conjunction_v<std::is_arithmetic<Num>...>, double>
224 return sqrt((0.0 + ... + sqr(vals)));
230 const int valsign = (val > 0) ? PLUS : MINUS;
236 if (val == 0) return ZERO;
242 if (val == 0) return ZERO;
247 inline double subtract( double a, double b, double tolerance = 1e-5) {
253 inline double add( double a, double b, double tolerance = 1e-5) {
267 inline std::vector<double> linspace( size_t nbins, double xmin, double xmax, bool include_end= true) {
268 if (xmax < xmin) throw RangeError( "xmax should not be smaller than xmin!");
269 if (nbins == 0) throw RangeError( "Requested number of bins is 0!");
270 std::vector<double> rtn;
271 const double interval = (xmax-xmin)/ static_cast<double>(nbins);
272 for ( size_t i = 0; i < nbins; ++i) {
273 rtn.push_back(xmin + i*interval);
275 assert(rtn.size() == nbins);
276 if (include_end) rtn.push_back(xmax);
286 inline std::vector<double> logspace( size_t nbins, double xmin, double xmax, bool include_end= true) {
287 if (xmax < xmin) throw RangeError( "xmax should not be smaller than xmin!");
288 if (xmin < 0) throw RangeError( "xmin should not be negative!");
289 if (nbins == 0) throw RangeError( "Requested number of bins is 0!");
290 const double logxmin = std::log(xmin);
291 const double logxmax = std::log(xmax);
292 const std::vector<double> logvals = linspace(nbins, logxmin, logxmax);
293 assert(logvals.size() == nbins+1);
294 std::vector<double> rtn; rtn.reserve(logvals.size());
296 for ( size_t i = 1; i < logvals.size()-1; ++i) {
297 rtn.push_back(std::exp(logvals[i]));
299 assert(rtn.size() == nbins);
300 if (include_end) rtn.push_back(xmax);
328 inline std::vector<double> pdfspace( size_t nbins, double xmin, double xmax, std::function< double( double)>& fn, size_t nsample=10000) {
329 const double dx = (xmax-xmin)/( double)nsample;
330 const std::vector<double> xs = linspace(nsample, xmin, xmax);
331 std::vector<double> ys(0, nsample);
332 auto posfn = [&]( double x){ return std::max(fn(x), 0.0);};
333 std::transform(xs.begin(), xs.end(), ys.begin(), posfn);
334 std::vector<double> areas; areas.reserve(nsample);
336 for ( size_t i = 0; i < ys.size()-1; ++i) {
337 const double area = (ys[i] + ys[i+1])*dx/2.0;
341 const double df = areasum/(double)nbins;
342 std::vector<double> xedges{xmin}; xedges.reserve(nbins+1);
344 for ( size_t i = 0; i < nsample-1; ++i) {
348 xedges.push_back(xs[i+1]);
351 xedges.push_back(xmax);
352 assert(xedges.size() == nbins+1);
360 template < typename NUM>
361 inline int index_between( const NUM& val, const std::vector<NUM>& binedges) {
362 if (! inRange(val, binedges.front(), binedges.back())) return -1;
364 for ( size_t i = 1; i < binedges.size(); ++i) {
365 if (val < binedges[i]) {
370 assert( inRange(index, -1, binedges.size()-1));
382 if ( isZero(sumW2)) return 0;
383 return sqr(sumW) / sumW2;
388 double sumW = 0.0, sumW2 = 0.0;
389 for ( size_t i = 0; i < weights.size(); ++i) {
391 sumW2 += sqr(weights[i]);
397 inline double mean( const std::vector<int>& sample) {
399 for ( size_t i=0; i<sample.size(); ++i) {
402 return mean/sample.size();
406 inline double mean( const double sumWX, const double sumW) {
407 return sumW? sumWX / sumW : std::numeric_limits<double>::quiet_NaN();
411 inline double mean( const std::vector<double>& sample,
412 const std::vector<double>& weights) {
413 if (sample.size() != weights.size()) throw RangeError( "Inputs should have equal length!");
414 double sumWX = 0., sumW = 0.;
415 for ( size_t i = 0; i < sample.size(); ++i) {
417 sumWX += weights[i]*sample[i];
419 return mean(sumWX, sumW);
427 inline double variance( const double sumWX, const double sumW,
428 const double sumWX2, const double sumW2) {
429 const double num = subtract(sumWX2*sumW, sqr(sumWX));
441 return den? fabs(num/den): std::numeric_limits<double>::quiet_NaN();
445 inline double variance( const std::vector<double>& sample,
446 const std::vector<double>& weights) {
447 if (sample.size() != weights.size()) throw RangeError( "Inputs should have equal length!");
450 return std::numeric_limits<double>::quiet_NaN();
452 double sumWX = 0., sumW = 0.;
453 double sumWX2 = 0., sumW2 = 0.;
454 for ( size_t i = 0; i < sample.size(); ++i) {
456 sumWX += weights[i]*sample[i];
457 sumW2 += sqr(weights[i]);
458 sumWX2 += weights[i]* sqr(sample[i]);
460 return variance(sumWX, sumW, sumWX2, sumW2);
464 inline double stdDev( const double sumWX, const double sumW,
465 const double sumWX2, const double sumW2) {
466 return std::sqrt( variance(sumWX, sumW, sumWX2, sumW2));
470 inline double stdDev( const std::vector<double>& sample,
471 const std::vector<double>& weights) {
472 return std::sqrt( variance(sample, weights));
476 inline double stdErr( const double sumWX, const double sumW,
477 const double sumWX2, const double sumW2) {
479 if (effN == 0) return std::numeric_limits<double>::quiet_NaN();
480 const double var = variance(sumWX, sumW, sumWX2, sumW2);
481 return std::sqrt(var / effN);
485 inline double stdErr( const std::vector<double>& sample,
486 const std::vector<double>& weights) {
487 if (sample.size() != weights.size()) throw RangeError( "Inputs should have equal length!");
489 if (effN == 0) return std::numeric_limits<double>::quiet_NaN();
490 const double var = variance(sample, weights);
491 return std::sqrt(var / effN);
495 inline double RMS( const double sumWX2, const double sumW, const double sumW2) {
499 if (effN == 0) return std::numeric_limits<double>::quiet_NaN();
500 const double meanSq = sumWX2 / sumW;
501 return std::sqrt(meanSq);
505 inline double RMS( const std::vector<double>& sample,
506 const std::vector<double>& weights) {
507 if (sample.size() != weights.size()) throw RangeError( "Inputs should have equal length!");
508 double sumWX2 = 0., sumW = 0., sumW2 = 0.;
509 for ( size_t i = 0; i < sample.size(); ++i) {
511 sumW2 += sqr(weights[i]);
512 sumWX2 += weights[i]* sqr(sample[i]);
514 return RMS(sumWX2, sumW, sumW2);
518 inline double covariance( const std::vector<int>& sample1, const std::vector<int>& sample2) {
519 const double mean1 = mean(sample1);
520 const double mean2 = mean(sample2);
521 const size_t N = sample1.size();
523 for ( size_t i = 0; i < N; i++) {
524 const double cov_i = (sample1[i] - mean1)*(sample2[i] - mean2);
527 if (N > 1) return cov/(N-1);
533 inline double correlation( const std::vector<int>& sample1, const std::vector<int>& sample2) {
534 const double cov = covariance(sample1, sample2);
535 const double var1 = covariance(sample1, sample1);
536 const double var2 = covariance(sample2, sample2);
538 const double corr_strength = correlation*sqrt(var2/var1);
539 return corr_strength;
549 inline double naiveChi2( const std::vector<double>& sample1, const std::vector<double>& sample2,
550 const std::vector<double>& s1errors = std::vector<double>{},
551 const std::vector<double>& s2errors = std::vector<double>{}) {
552 if (sample1.size() != sample2.size()) {
553 throw RangeError( "Inputs should have equal length!");
555 if (s1errors.size() && sample1.size() != s1errors.size()) {
556 throw RangeError( "Inputs should have equal length!");
558 if (s2errors.size() && sample2.size() != s2errors.size()) {
559 throw RangeError( "Inputs should have equal length!");
561 const size_t N = sample1.size();
563 for ( size_t i = 0; i < N; ++i) {
564 double temp = sqr(sample1[i] - sample2[i]);
565 if (s1errors.size()) {
566 temp /= sqr(s1errors[i]) + sqr(s2errors[i]);
579 inline double naiveChi2reduced( const std::vector<double>& sample1, const std::vector<double>& sample2,
580 const std::vector<double>& s1errors = std::vector<double>{},
581 const std::vector<double>& s2errors = std::vector<double>{}) {
582 if (sample1.empty()) throw RangeError( "Inputs should not have 0 length!");
583 return naiveChi2(sample1, sample2, s1errors, s2errors)/sample1.size();
Error for e.g. use of invalid bin ranges.
Anonymous namespace to limit visibility.
double stdErr(const double sumWX, const double sumW, const double sumWX2, const double sumW2) Calculate the weighted standard error of a sample.
static const double HALFPI A pre-defined value of .
double RMS(const double sumWX2, const double sumW, const double sumW2) Calculate the weighted RMS of a sample.
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 >, bool > fuzzyLessEquals(N1 a, N2 b, double tolerance=1e-5) Compare two floating point numbers for <= with a degree of fuzziness.
std::vector< double > logspace(size_t nbins, double xmin, double xmax, bool include_end=true) Make a list of nbins + 1 values uniformly spaced in log(x) between xmin and xmax inclusive.
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 >, bool > fuzzyGtrEquals(N1 a, N2 b, double tolerance=1e-5) Compare two numbers for >= with a degree of fuzziness.
int index_between(const NUM &val, const std::vector< NUM > &binedges) Return the bin index of the given value, val, given a vector of bin edges.
std::enable_if_t< std::is_floating_point_v< NUM >, bool > isNaN(NUM val) Check if a number is NaN.
std::vector< double > linspace(size_t nbins, double xmin, double xmax, bool include_end=true) Make a list of nbins + 1 values uniformly spaced between xmin and xmax inclusive.
double covariance(const std::vector< int > &sample1, const std::vector< int > &sample2) Calculate the covariance (variance) between two samples.
double naiveChi2(const std::vector< double > &sample1, const std::vector< double > &sample2, const std::vector< double > &s1errors=std::vector< double >{}, const std::vector< double > &s2errors=std::vector< double >{}) Calculate the error-weighted chi2 statistic between two samples.
double approx(double a, int n=5) Returns a number floored at the nth decimal place.
double correlation(const std::vector< int > &sample1, const std::vector< int > &sample2) Calculate the correlation strength between two samples.
std::enable_if_t< std::conjunction_v< std::is_arithmetic< Num >... >, double > add_quad(Num ... vals) Named number-type addition in quadrature operation.
static const double TWOPI A pre-defined value of .
NUM sqr(NUM a) Named number-type squaring operation.
static const double PI A pre-defined value of .
double stdDev(const double sumWX, const double sumW, const double sumWX2, const double sumW2) Calculate the weighted standard deviation of a sample.
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 > &&(std::is_floating_point_v< N1 >||std::is_floating_point_v< N2 >), bool > fuzzyEquals(N1 a, N2 b, double tolerance=1e-5) Compare two numbers for equality with a degree of fuzziness.
std::enable_if_t< std::is_floating_point_v< NUM >, bool > notNaN(NUM val) Check if a number is non-NaN.
double naiveChi2reduced(const std::vector< double > &sample1, const std::vector< double > &sample2, const std::vector< double > &s1errors=std::vector< double >{}, const std::vector< double > &s2errors=std::vector< double >{}) Calculate the error-weighted reduced chi2 statistic between two samples.
BinnedEstimate< AxisT... > add(const BinnedDbn< DbnN, AxisT... > &dbn, const BinnedEstimate< AxisT... > &est) Calculate the addition of a BinnedDbn with a BinnedEstimate.
int sign(double val) Find the sign of a number.
BinnedEstimate< AxisT... > subtract(const BinnedDbn< DbnN, AxisT... > &dbn, const BinnedEstimate< AxisT... > &est) Calculate the subtraction of a BinnedEstimate from a BinnedDbn.
static std::function< bool(const double, const double)> fuzzyEqComp Comparator wrapper to use with STL algorithms, e.g. std::equal etc.
static const double MAXDOUBLE
static const double MAXINT
double variance(const double sumWX, const double sumW, const double sumWX2, const double sumW2) Calculate the weighted variance of a sample.
std::vector< double > pdfspace(size_t nbins, double xmin, double xmax, std::function< double(double)> &fn, size_t nsample=10000) Make a list of nbins + 1 values spaced with density ~ f(x) between xmin and end inclusive.
std::enable_if_t< std::is_floating_point_v< NUM >, bool > isZero(NUM val, double tolerance=1e-5) Compare a number to zero.
double mean(const std::vector< int > &sample) Calculate the mean of a sample.
double effNumEntries(const double sumW, const double sumW2) Calculate the effective number of entries of a sample.
Sign Enum for signs of numbers.
bool inRange(NUM value, NUM low, NUM high, RangeBoundary lowbound=CLOSED, RangeBoundary highbound=OPEN) Determine if value is in the range low to high, for floating point numbers.
|