OpenMS
Loading...
Searching...
No Matches
MathFunctions.h
Go to the documentation of this file.
1// Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin
2// SPDX-License-Identifier: BSD-3-Clause
3//
4// --------------------------------------------------------------------------
5// $Maintainer: Timo Sachsenberg$
6// $Authors: Marc Sturm $
7// --------------------------------------------------------------------------
8
9#pragma once
10
15
16#include <boost/random/mersenne_twister.hpp> // for mt19937_64
17#include <boost/random/uniform_int.hpp>
18#include <cmath>
19#include <boost/math/special_functions/binomial.hpp>
20#include <boost/math/special_functions/gamma.hpp>
21#include <boost/math/special_functions/log1p.hpp>
22#include <boost/math/distributions/binomial.hpp>
23#include <boost/math/distributions/complement.hpp>
24#include <limits>
25#include <utility> // for std::pair
26#include <vector>
27
28namespace OpenMS
29{
37namespace Math
38{
39
48 template<typename T>
49 bool extendRange(T& min, T& max, const T& value)
50 {
51 if (value < min)
52 {
53 min = value;
54 return true;
55 }
56 if (value > max)
57 {
58 max = value;
59 return true;
60 }
61 return false;
62 }
63
69 template<typename T>
70 bool contains(T value, T min, T max)
71 {
72 return min <= value && value <= max;
73 }
74
95 inline std::pair<double, double> zoomIn(const double left, const double right, const float factor, const float align)
96 {
97 OPENMS_PRECONDITION(factor >= 0, "Factor must be >=0")
98 OPENMS_PRECONDITION(align >= 0, "align must be >=0")
99 OPENMS_PRECONDITION(align <= 1, "align must be <=1")
100 std::pair<double, double> res;
101 auto old_width = right - left;
102 auto offset_left = (1.0f - factor) * old_width * align;
103 res.first = left + offset_left;
104 res.second = res.first + old_width * factor;
105 return res;
106 }
107
108 using BinContainer = std::vector<RangeBase>;
124 inline BinContainer createBins(double min, double max, uint32_t number_of_bins, double extend_margin = 0)
125 {
126 OPENMS_PRECONDITION(number_of_bins >= 1, "Number of bins must be >= 1")
127 OPENMS_PRECONDITION(min < max, "Require min < max");
128 std::vector<RangeBase> res(number_of_bins);
129 const double bin_width = (max - min) / number_of_bins;
130 for (uint32_t i = 0; i < number_of_bins; ++i)
131 {
132 res[i] = RangeBase(min + i * bin_width, min + (i + 1) * bin_width);
133 res[i].extendLeftRight(extend_margin);
134 }
135 res.front().setMin(min); // undo potential margin
136 res.back().setMax(max); // undo potential margin
137
138 return res;
139 }
140
141
153 inline double ceilDecimal(double x, int decPow)
154 {
155 return (ceil(x / pow(10.0, decPow))) * pow(10.0, decPow); // decimal shift right, ceiling, decimal shift left
156 }
157
168 inline double roundDecimal(double x, int decPow)
169 {
170 if (x > 0) return (floor(0.5 + x / pow(10.0, decPow))) * pow(10.0, decPow);
171
172 return -((floor(0.5 + fabs(x) / pow(10.0, decPow))) * pow(10.0, decPow));
173 }
174
180 inline double intervalTransformation(double x, double left1, double right1, double left2, double right2)
181 {
182 return left2 + (x - left1) * (right2 - left2) / (right1 - left1);
183 }
184
192 inline double linear2log(double x)
193 {
194 return log10(x + 1); //+1 to avoid negative logarithms
195 }
196
204 inline double log2linear(double x)
205 {
206 return pow(10, x) - 1;
207 }
208
214 inline bool isOdd(UInt x)
215 {
216 return (x & 1) != 0;
217 }
218
224 template<typename T>
225 T round(T x)
226 {
227 return std::round(x);
228 }
229
244 template<typename T>
245 T roundTo(const T value, int digits)
246 {
247 T factor = 1.0;
248 if (digits > 0)
249 {
250 for (int i = 0; i < digits; ++i)
251 factor *= 10.0;
252 }
253 else if (digits < 0)
254 {
255 for (int i = 0; i < -digits; ++i)
256 factor /= 10.0;
257 }
258
259 return std::round(value * factor) / factor;
260 }
261
279 template<typename T>
280 double percentOf(T value, T total, int digits)
281 {
282 if (value < 0) { throw Exception::InvalidValue(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Value must be non-negative", String(value)); }
283 if (total < 0) { throw Exception::InvalidValue(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Total must be non-negative", String(total)); }
284 if (total <= 0) // avoid float equality compare
285 {
286 return 0.0; // avoid division by zero
287 }
288 return roundTo(value * 100.0 / total, digits);
289 }
290
296 inline bool approximatelyEqual(double a, double b, double tol)
297 {
298 return std::fabs(a - b) <= tol;
299 }
300
309 template<typename T>
310 T gcd(T a, T b)
311 {
312 T c;
313 while (b != 0)
314 {
315 c = a % b;
316 a = b;
317 b = c;
318 }
319 return a;
320 }
321
334 template<typename T>
335 T gcd(T a, T b, T& u1, T& u2)
336 {
337 u1 = 1;
338 u2 = 0;
339 T u3 = a;
340
341 T v1 = 0;
342 T v2 = 1;
343 T v3 = b;
344
345 while (v3 != 0)
346 {
347 T q = u3 / v3;
348 T t1 = u1 - v1 * q;
349 T t2 = u2 - v2 * q;
350 T t3 = u3 - v3 * q;
351
352 u1 = v1;
353 u2 = v2;
354 u3 = v3;
355
356 v1 = t1;
357 v2 = t2;
358 v3 = t3;
359 }
360
361 return u3;
362 }
363
373 template<typename T>
374 T getPPM(T mz_obs, T mz_ref)
375 {
376 return (mz_obs - mz_ref) / mz_ref * 1e6;
377 }
378
388 template<typename T>
389 T getPPMAbs(T mz_obs, T mz_ref)
390 {
391 return std::fabs(getPPM(mz_obs, mz_ref));
392 }
393
403 template<typename T>
404 T ppmToMass(T ppm, T mz_ref)
405 {
406 return (ppm / T(1e6)) * mz_ref;
407 }
408
409 /*
410 @brief Compute the absolute mass diff in [Th], given a ppm value and a reference point.
411
412 The returned mass diff is always positive!
413
414 @param[in] ppm Parts-per-million error
415 @param[in] mz_ref Reference m/z
416 @return The absolute mass diff in [Th]
417 */
418 template<typename T>
419 T ppmToMassAbs(T ppm, T mz_ref)
420 {
421 return std::fabs(ppmToMass(ppm, mz_ref));
422 }
423
437 inline std::pair<double, double> getTolWindow(double val, double tol, bool ppm)
438 {
439 double left, right;
440
441 if (ppm)
442 {
443 left = val - val * tol * 1e-6;
444 right = val / (1.0 - tol * 1e-6);
445 }
446 else
447 {
448 left = val - tol;
449 right = val + tol;
450 }
451
452 return std::make_pair(left, right);
453 }
454
458 template<typename T1>
459 typename T1::value_type quantile(const T1& x, double q)
460 {
461 if (x.empty()) throw Exception::InvalidParameter(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Quantile requested from empty container.");
462 if (q < 0.0) q = 0.;
463 if (q > 1.0) q = 1.;
464
465 const auto n = x.size();
466 const auto id = std::max(0., n * q - 1); // -1 for c++ index starting at 0
467 const auto lo = floor(id);
468 const auto hi = ceil(id);
469 const auto qs = x[lo];
470 const auto h = (id - lo);
471
472 return (1.0 - h) * qs + h * x[hi];
473 }
474
475 // portable random shuffle
476 class OPENMS_DLLAPI RandomShuffler
477 {
478 public:
479 explicit RandomShuffler(int seed): rng_(boost::mt19937_64(seed))
480 {
481 }
482
483 explicit RandomShuffler(const boost::mt19937_64& mt_rng): rng_(mt_rng)
484 {
485 }
486
487 RandomShuffler() = default;
488 ~RandomShuffler() = default;
489
490 boost::mt19937_64 rng_;
491 template<class RandomAccessIterator>
492 void portable_random_shuffle(RandomAccessIterator first, RandomAccessIterator last)
493 {
494 for (auto i = (last - first) - 1; i > 0; --i) // OMS_CODING_TEST_EXCLUDE
495 {
496 boost::uniform_int<decltype(i)> d(0, i);
497 std::swap(first[i], first[d(rng_)]);
498 }
499 }
500
501 void seed(uint64_t val)
502 {
503 rng_.seed(val);
504 }
505 };
506
515 inline double log_binomial_coef(unsigned n, unsigned k)
516 {
517 // Handle edge cases for improved numerical stability
518 if (k > n)
519 {
520 throw std::invalid_argument("k cannot be greater than n in binomial coefficient");
521 }
522
523 if (k == 0 || k == n)
524 {
525 return 0.0; // log(1) = 0
526 }
527
528 // Use symmetry to minimize computation for large k
529 if (k > n / 2)
530 {
531 k = n - k;
532 }
533
534 return boost::math::lgamma(n + 1.0) - boost::math::lgamma(k + 1.0) - boost::math::lgamma(n - k + 1.0);
535 }
536
544 inline double log_sum_exp(double x, double y)
545 {
546 // Handle infinite cases
547 if (std::isinf(x) && x < 0) return y;
548 if (std::isinf(y) && y < 0) return x;
549
550 // Use the maximum value for numerical stability
551 double max_val = std::max(x, y);
552 return max_val + std::log(std::exp(x - max_val) + std::exp(y - max_val));
553 }
554
567 inline double binomial_cdf_complement(unsigned N, unsigned n, double p)
568 {
569 if (p < 0.0 || p > 1.0)
570 {
571 throw std::invalid_argument("Probability p must be between 0 and 1");
572 }
573 if (n > N)
574 {
575 throw std::invalid_argument("n cannot be greater than N");
576 }
577
578 if (n == 0) return 1.0; // P(X ≥ 0) = 1
579 if (p == 0.0) return (n == 0) ? 1.0 : 0.0;
580 if (p == 1.0) return 1.0; // all mass at N
581
582 const boost::math::binomial_distribution<double> dist(N, p);
583 return boost::math::cdf(boost::math::complement(dist, n - 1));
584 }
585} // namespace Math
586} // namespace OpenMS
Exception indicating that an invalid parameter was handed over to an algorithm.
Definition Exception.h:317
Invalid value exception.
Definition Exception.h:306
Definition MathFunctions.h:477
RandomShuffler(int seed)
Definition MathFunctions.h:479
boost::mt19937_64 rng_
Definition MathFunctions.h:490
void seed(uint64_t val)
Definition MathFunctions.h:501
RandomShuffler(const boost::mt19937_64 &mt_rng)
Definition MathFunctions.h:483
void portable_random_shuffle(RandomAccessIterator first, RandomAccessIterator last)
Definition MathFunctions.h:492
A more convenient string class.
Definition String.h:34
unsigned int UInt
Unsigned integer type.
Definition Types.h:64
#define OPENMS_PRECONDITION(condition, message)
Precondition macro.
Definition openms/include/OpenMS/CONCEPT/Macros.h:94
bool approximatelyEqual(double a, double b, double tol)
Returns if a is approximately equal b , allowing a tolerance of tol.
Definition MathFunctions.h:296
bool isOdd(UInt x)
Returns true if the given integer is odd.
Definition MathFunctions.h:214
T gcd(T a, T b)
Returns the greatest common divisor (gcd) of two numbers by applying the Euclidean algorithm.
Definition MathFunctions.h:310
double log2linear(double x)
Transforms a number from log10 to to linear scale. Subtracts the 1 added by linear2log(double)
Definition MathFunctions.h:204
double roundDecimal(double x, int decPow)
rounds x to the next decimal power 10 ^ decPow
Definition MathFunctions.h:168
double linear2log(double x)
Transforms a number from linear to log10 scale. Avoids negative logarithms by adding 1.
Definition MathFunctions.h:192
T round(T x)
Rounds the value.
Definition MathFunctions.h:225
double ceilDecimal(double x, int decPow)
rounds x up to the next decimal power 10 ^ decPow
Definition MathFunctions.h:153
double intervalTransformation(double x, double left1, double right1, double left2, double right2)
transforms point x of interval [left1,right1] into interval [left2,right2]
Definition MathFunctions.h:180
double log_sum_exp(double x, double y)
Log-sum-exp operation for numerical stability.
Definition MathFunctions.h:544
T getPPMAbs(T mz_obs, T mz_ref)
Compute absolute parts-per-million of two m/z values.
Definition MathFunctions.h:389
BinContainer createBins(double min, double max, uint32_t number_of_bins, double extend_margin=0)
Split a range [min,max] into number_of_bins (with optional overlap) and return the ranges of each bin...
Definition MathFunctions.h:124
T1::value_type quantile(const T1 &x, double q)
Returns the value of the q th quantile (0-1) in a sorted non-empty vector x.
Definition MathFunctions.h:459
double binomial_cdf_complement(unsigned N, unsigned n, double p)
Calculate binomial cumulative distribution function P(X ≥ n)
Definition MathFunctions.h:567
std::pair< double, double > zoomIn(const double left, const double right, const float factor, const float align)
Zoom into an interval [left, right], decreasing its width by factor (which must be in [0,...
Definition MathFunctions.h:95
double log_binomial_coef(unsigned n, unsigned k)
Calculate logarithm of binomial coefficient C(n,k) using log-gamma function.
Definition MathFunctions.h:515
T getPPM(T mz_obs, T mz_ref)
Compute parts-per-million of two m/z values.
Definition MathFunctions.h:374
std::pair< double, double > getTolWindow(double val, double tol, bool ppm)
Return tolerance window around val given tolerance tol.
Definition MathFunctions.h:437
T roundTo(const T value, int digits)
Definition MathFunctions.h:245
T ppmToMass(T ppm, T mz_ref)
Compute the mass diff in [Th], given a ppm value and a reference point.
Definition MathFunctions.h:404
T ppmToMassAbs(T ppm, T mz_ref)
Definition MathFunctions.h:419
double percentOf(T value, T total, int digits)
Definition MathFunctions.h:280
bool contains(T value, T min, T max)
Is a value contained in [min, max] ?
Definition MathFunctions.h:70
std::vector< RangeBase > BinContainer
Definition MathFunctions.h:108
bool extendRange(T &min, T &max, const T &value)
Given an interval/range and a new value, extend the range to include the new value if needed.
Definition MathFunctions.h:49
Main OpenMS namespace.
Definition openswathalgo/include/OpenMS/OPENSWATHALGO/DATAACCESS/ISpectrumAccess.h:19
Base class for a simple range with minimum and maximum.
Definition RangeManager.h:37