A library for working with phylogenetic and population genetic data.
v0.27.0
common.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_MATH_COMMON_H_
2 #define GENESIS_UTILS_MATH_COMMON_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2021 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lczech@carnegiescience.edu>
23  Department of Plant Biology, Carnegie Institution For Science
24  260 Panama Street, Stanford, CA 94305, USA
25 */
26 
34 #include <algorithm>
35 #include <cassert>
36 #include <cmath>
37 #include <cstdint>
38 #include <functional>
39 #include <limits>
40 #include <stdexcept>
41 #include <type_traits>
42 #include <utility>
43 #include <vector>
44 
45 namespace genesis {
46 namespace utils {
47 
48 // =================================================================================================
49 // Constants and General Functions
50 // =================================================================================================
51 
55 constexpr double PI = 3.141592653589793238463;
56 
57 inline double circumference( double radius )
58 {
59  return 2.0 * PI * radius;
60 }
61 
70 double log_factorial( size_t n );
71 
78 size_t binomial_coefficient( size_t n, size_t k );
79 
102 double binomial_coefficient_approx( size_t n, size_t k, bool lenient = false );
103 
113 inline double binomial_distribution( size_t k, size_t n, double p, bool lenient = false )
114 {
115  if( ! std::isfinite(p) || p < 0.0 || p > 1.0 ) {
116  throw std::invalid_argument(
117  "Cannot compute binomial distribution with p outside of [ 0, 1 ]"
118  );
119  }
120  double const coeff = binomial_coefficient_approx( n, k, lenient );
121  return coeff * std::pow( p, k ) * std::pow( 1.0 - p, n - k );
122 }
123 
124 // =================================================================================================
125 // Number Handling
126 // =================================================================================================
127 
134 template< typename T > inline constexpr
135 T abs_diff( T const& lhs, T const& rhs )
136 {
137  return ((lhs > rhs) ? (lhs - rhs) : (rhs - lhs));
138 }
139 
143 template <typename T> inline constexpr
144 int signum(T x, std::false_type )
145 {
146  // The tag type `std::false_type` is unnamed in order to avoid compiler warnings about an
147  // unused parameter. As this function is `constexpr`, we cannot shut this warning down by
148  // using `(void) param`, so making it unnamed is a reasonable solution in this case.
149  return T(0) < x;
150 }
151 
155 template <typename T> inline constexpr
156 int signum(T x, std::true_type )
157 {
158  // The tag type `std::false_type` is unnamed in order to avoid compiler warnings about an
159  // unused parameter. As this function is `constexpr`, we cannot shut this warning down by
160  // using `(void) param`, so making it unnamed is a reasonable solution in this case.
161  return (T(0) < x) - (x < T(0));
162 }
163 
172 template <typename T> inline constexpr
173 int signum(T x)
174 {
175  return signum( x, std::is_signed<T>() );
176 }
177 
182  double lhs,
183  double rhs,
184  double max_rel_diff = std::numeric_limits<double>::epsilon()
185 ) {
186  // Calculate the difference.
187  auto diff = std::abs( lhs - rhs );
188 
189  // Find the larger number.
190  auto largest = std::max( std::abs( lhs ), std::abs( rhs ));
191 
192  // Do the comparison.
193  return ( diff <= largest * max_rel_diff );
194 }
195 
199 inline double round_to( double x, size_t accuracy_order )
200 {
201  double factor = std::pow( 10, accuracy_order );
202  return std::round( x * factor ) / factor;
203 }
204 
215 inline size_t int_pow( size_t base, size_t exp )
216 {
217  // Using Exponentiation by squaring, see
218  // http://stackoverflow.com/a/101613/4184258
219  size_t result = 1;
220  while( exp ) {
221  if( exp & 1 ) {
222  result *= base;
223  }
224  exp >>= 1;
225  base *= base;
226  }
227  return result;
228 }
229 
235 inline bool is_valid_int_pow( size_t base, size_t exp )
236 {
237  return std::pow( base, exp ) < static_cast<double>( std::numeric_limits<size_t>::max() );
238 }
239 
247 inline constexpr double squared( double x )
248 {
249  return x * x;
250 }
251 
259 inline constexpr double cubed( double x )
260 {
261  return x * x * x;
262 }
263 
264 // =================================================================================================
265 // Helper Functions
266 // =================================================================================================
267 
275 template <class ForwardIteratorA, class ForwardIteratorB>
276 std::pair<std::vector<double>, std::vector<double>> finite_pairs(
277  ForwardIteratorA first_a, ForwardIteratorA last_a,
278  ForwardIteratorB first_b, ForwardIteratorB last_b
279 ) {
280  // Prepare result.
281  std::vector<double> vec_a;
282  std::vector<double> vec_b;
283 
284  // Iterate in parallel.
285  while( first_a != last_a && first_b != last_b ) {
286  if( std::isfinite( *first_a ) && std::isfinite( *first_b ) ) {
287  vec_a.push_back( *first_a );
288  vec_b.push_back( *first_b );
289  }
290  ++first_a;
291  ++first_b;
292  }
293  if( first_a != last_a || first_b != last_b ) {
294  throw std::runtime_error(
295  "Ranges need to have same length."
296  );
297  }
298 
299  assert( vec_a.size() == vec_b.size() );
300  return { vec_a, vec_b };
301 }
302 
309 template <class ForwardIteratorA, class ForwardIteratorB>
311  ForwardIteratorA first_a, ForwardIteratorA last_a,
312  ForwardIteratorB first_b, ForwardIteratorB last_b,
313  std::function<void( double value_a, double value_b )> execute
314 ) {
315  // Iterate in parallel.
316  while( first_a != last_a && first_b != last_b ) {
317  if( std::isfinite( *first_a ) && std::isfinite( *first_b ) ) {
318  execute( *first_a, *first_b );
319  }
320  ++first_a;
321  ++first_b;
322  }
323 
324  // Check if the ranges have the same length.
325  if( first_a != last_a || first_b != last_b ) {
326  throw std::runtime_error( "Ranges need to have same length." );
327  }
328 }
329 
330 } // namespace utils
331 } // namespace genesis
332 
333 #endif // include guard
genesis::utils::log_factorial
double log_factorial(size_t n)
Return the logarithm (base e) of the factorial of n, that is log(n!).
Definition: common.cpp:348
genesis::utils::abs_diff
constexpr T abs_diff(T const &lhs, T const &rhs)
Calculate the absolute differenence between two values.
Definition: common.hpp:135
genesis::utils::signum
constexpr int signum(T x, std::false_type)
Implementation of signum(T x) for unsigned types. See there for details.
Definition: common.hpp:144
genesis::utils::almost_equal_relative
bool almost_equal_relative(double lhs, double rhs, double max_rel_diff=std::numeric_limits< double >::epsilon())
Check whether two doubles are almost equal, using a relative epsilon to compare them.
Definition: common.hpp:181
genesis::utils::cubed
constexpr double cubed(double x)
Cube of a number.
Definition: common.hpp:259
genesis::utils::circumference
double circumference(double radius)
Definition: common.hpp:57
genesis::utils::binomial_coefficient
size_t binomial_coefficient(size_t n, size_t k)
Compute the binomial coefficient, that is n choose k, for two integer numbers.
Definition: common.cpp:361
genesis::utils::int_pow
size_t int_pow(size_t base, size_t exp)
Calculate the power base^exp for positive integer values.
Definition: common.hpp:215
genesis::utils::binomial_distribution
double binomial_distribution(size_t k, size_t n, double p, bool lenient=false)
Compute the probability mass function for a binomial distribution.
Definition: common.hpp:113
genesis::utils::finite_pairs
std::pair< std::vector< double >, std::vector< double > > finite_pairs(ForwardIteratorA first_a, ForwardIteratorA last_a, ForwardIteratorB first_b, ForwardIteratorB last_b)
Helper function that cleans two ranges of double of the same length from non-finite values.
Definition: common.hpp:276
genesis::utils::PI
constexpr double PI
Make the world go round.
Definition: common.hpp:55
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::binomial_coefficient_approx
double binomial_coefficient_approx(size_t n, size_t k, bool lenient)
Compute the binomial coefficient, that is n choose k, for two integer numbers, for large numbers.
Definition: common.cpp:408
genesis::utils::is_valid_int_pow
bool is_valid_int_pow(size_t base, size_t exp)
Return whether the given power can be stored within a size_t.
Definition: common.hpp:235
genesis::utils::for_each_finite_pair
void for_each_finite_pair(ForwardIteratorA first_a, ForwardIteratorA last_a, ForwardIteratorB first_b, ForwardIteratorB last_b, std::function< void(double value_a, double value_b)> execute)
Iterate two ranges of double values in parallel, and execute a function for each pair of values from ...
Definition: common.hpp:310
genesis::utils::squared
constexpr double squared(double x)
Square of a number.
Definition: common.hpp:247
genesis::utils::round_to
double round_to(double x, size_t accuracy_order)
Retun the value of x, rounded to the decimal digit given by accuracy_order.
Definition: common.hpp:199