numerics 0.1.0
Loading...
Searching...
No Matches
math.hpp
Go to the documentation of this file.
1/// @file math.hpp
2/// @brief Thin wrappers around `<cmath>` and `<numeric>` with readable
3/// names.
4///
5/// The standard library names for special functions (cyl_bessel_j,
6/// comp_ellint_1, cyl_neumann, etc.) are accurate but opaque. This header
7/// re-exports them under the names used in textbooks and mathematical
8/// literature.
9///
10/// Random number generation wraps the mt19937 boilerplate into a plain struct.
11///
12/// Include this header instead of pulling `<cmath>` special functions directly.
13#pragma once
14
15#include "core/types.hpp"
16#include <cassert>
17#include <cmath>
18#include <numeric>
19#include <random>
20#include <vector>
21
22// Apple libc++ does not implement C++17 special math functions.
23// Use Boost.Math as a drop-in replacement when building on macOS.
24#ifdef NUMERICS_USE_BOOST_MATH
25 #include <boost/math/special_functions/bessel.hpp>
26 #include <boost/math/special_functions/beta.hpp>
27 #include <boost/math/special_functions/ellint_1.hpp>
28 #include <boost/math/special_functions/ellint_2.hpp>
29 #include <boost/math/special_functions/ellint_3.hpp>
30 #include <boost/math/special_functions/expint.hpp>
31 #include <boost/math/special_functions/hermite.hpp>
32 #include <boost/math/special_functions/laguerre.hpp>
33 #include <boost/math/special_functions/legendre.hpp>
34 #include <boost/math/special_functions/spherical_harmonic.hpp>
35 #include <boost/math/special_functions/zeta.hpp>
36#endif
37
38namespace num {
39
40// Mathematical constants kept local to avoid depending on <numbers> at call
41// sites.
42
43constexpr real pi = 3.14159265358979323846;
44constexpr real e = 2.71828182845904523536;
45constexpr real phi = 1.61803398874989484820; ///< Golden ratio
46constexpr real sqrt2 = 1.41421356237309504880;
47constexpr real sqrt3 = 1.73205080756887729353;
48constexpr real ln2 = 0.69314718055994530942;
49constexpr real inv_pi = 0.31830988618379067154; ///< 1/pi
50constexpr real two_pi = 6.28318530717958647692; ///< 2pi
51constexpr real half_pi = 1.57079632679489661923; ///< pi/2
52
53// Cylindrical Bessel functions (C++17, <cmath>)
54
55/// @brief J_nu(x) -- Bessel function of the first kind
56inline real bessel_j(real nu, real x) {
57#ifdef NUMERICS_USE_BOOST_MATH
58 return boost::math::cyl_bessel_j(nu, x);
59#else
60 return std::cyl_bessel_j(nu, x);
61#endif
62}
63
64/// @brief Y_nu(x) -- Bessel function of the second kind (Neumann function)
65inline real bessel_y(real nu, real x) {
66#ifdef NUMERICS_USE_BOOST_MATH
67 return boost::math::cyl_neumann(nu, x);
68#else
69 return std::cyl_neumann(nu, x);
70#endif
71}
72
73/// @brief I_nu(x) -- modified Bessel function of the first kind
74inline real bessel_i(real nu, real x) {
75#ifdef NUMERICS_USE_BOOST_MATH
76 return boost::math::cyl_bessel_i(nu, x);
77#else
78 return std::cyl_bessel_i(nu, x);
79#endif
80}
81
82/// @brief K_nu(x) -- modified Bessel function of the second kind
83inline real bessel_k(real nu, real x) {
84#ifdef NUMERICS_USE_BOOST_MATH
85 return boost::math::cyl_bessel_k(nu, x);
86#else
87 return std::cyl_bessel_k(nu, x);
88#endif
89}
90
91// Spherical Bessel functions (C++17, <cmath>)
92
93/// @brief j_n(x) -- spherical Bessel function of the first kind
94inline real sph_bessel_j(unsigned int n, real x) {
95#ifdef NUMERICS_USE_BOOST_MATH
96 return boost::math::sph_bessel(n, x);
97#else
98 return std::sph_bessel(n, x);
99#endif
100}
101
102/// @brief y_n(x) -- spherical Neumann function (spherical Bessel of the second
103/// kind)
104inline real sph_bessel_y(unsigned int n, real x) {
105#ifdef NUMERICS_USE_BOOST_MATH
106 return boost::math::sph_neumann(n, x);
107#else
108 return std::sph_neumann(n, x);
109#endif
110}
111
112// Orthogonal polynomials (C++17, <cmath>)
113
114/// @brief P_n(x) -- Legendre polynomial of degree n
115inline real legendre(unsigned int n, real x) {
116#ifdef NUMERICS_USE_BOOST_MATH
117 return boost::math::legendre_p(static_cast<int>(n), x);
118#else
119 return std::legendre(n, x);
120#endif
121}
122
123/// @brief P_n^m(x) -- associated Legendre polynomial
124inline real assoc_legendre(unsigned int n, unsigned int m, real x) {
125#ifdef NUMERICS_USE_BOOST_MATH
126 return boost::math::legendre_p(static_cast<int>(n), static_cast<int>(m), x);
127#else
128 return std::assoc_legendre(n, m, x);
129#endif
130}
131
132/// @brief Y_l^m(theta) -- spherical harmonic (real part, theta in radians)
133inline real sph_legendre(unsigned int l, unsigned int m, real theta) {
134#ifdef NUMERICS_USE_BOOST_MATH
135 return boost::math::spherical_harmonic_r(l, static_cast<int>(m), theta, real(0));
136#else
137 return std::sph_legendre(l, m, theta);
138#endif
139}
140
141/// @brief H_n(x) -- (physicists') Hermite polynomial
142inline real hermite(unsigned int n, real x) {
143#ifdef NUMERICS_USE_BOOST_MATH
144 return boost::math::hermite(n, x);
145#else
146 return std::hermite(n, x);
147#endif
148}
149
150/// @brief L_n(x) -- Laguerre polynomial
151inline real laguerre(unsigned int n, real x) {
152#ifdef NUMERICS_USE_BOOST_MATH
153 return boost::math::laguerre(n, x);
154#else
155 return std::laguerre(n, x);
156#endif
157}
158
159/// @brief L_n^m(x) -- associated Laguerre polynomial
160inline real assoc_laguerre(unsigned int n, unsigned int m, real x) {
161#ifdef NUMERICS_USE_BOOST_MATH
162 return boost::math::laguerre(n, m, x);
163#else
164 return std::assoc_laguerre(n, m, x);
165#endif
166}
167
168// Elliptic integrals (C++17, <cmath>)
169// Names: K(k), E(k), Pi(n,k) for complete; F(k,phi), E(k,phi), Pi(n,k,phi) for
170// incomplete
171
172/// @brief K(k) -- complete elliptic integral of the first kind
173inline real ellint_K(real k) {
174#ifdef NUMERICS_USE_BOOST_MATH
175 return boost::math::ellint_1(k);
176#else
177 return std::comp_ellint_1(k);
178#endif
179}
180
181/// @brief E(k) -- complete elliptic integral of the second kind
182inline real ellint_E(real k) {
183#ifdef NUMERICS_USE_BOOST_MATH
184 return boost::math::ellint_2(k);
185#else
186 return std::comp_ellint_2(k);
187#endif
188}
189
190/// @brief Pi(n, k) -- complete elliptic integral of the third kind
191inline real ellint_Pi(real n, real k) {
192#ifdef NUMERICS_USE_BOOST_MATH
193 return boost::math::ellint_3(k, n); // boost: (k, n); std: (n, k)
194#else
195 return std::comp_ellint_3(n, k);
196#endif
197}
198
199/// @brief F(k, phi) -- incomplete elliptic integral of the first kind
201#ifdef NUMERICS_USE_BOOST_MATH
202 return boost::math::ellint_1(k, phi);
203#else
204 return std::ellint_1(k, phi);
205#endif
206}
207
208/// @brief E(k, phi) -- incomplete elliptic integral of the second kind
210#ifdef NUMERICS_USE_BOOST_MATH
211 return boost::math::ellint_2(k, phi);
212#else
213 return std::ellint_2(k, phi);
214#endif
215}
216
217/// @brief Pi(n, k, phi) -- incomplete elliptic integral of the third kind
219#ifdef NUMERICS_USE_BOOST_MATH
220 return boost::math::ellint_3(k, n,
221 phi); // boost: (k, n, phi); std: (n, k, phi)
222#else
223 return std::ellint_3(n, k, phi);
224#endif
225}
226
227// Other special functions (C++17, <cmath>)
228
229/// @brief Ei(x) -- exponential integral
230inline real expint(real x) {
231#ifdef NUMERICS_USE_BOOST_MATH
232 return boost::math::expint(x);
233#else
234 return std::expint(x);
235#endif
236}
237
238/// @brief zeta(x) -- Riemann zeta function
239inline real zeta(real x) {
240#ifdef NUMERICS_USE_BOOST_MATH
241 return boost::math::zeta(x);
242#else
243 return std::riemann_zeta(x);
244#endif
245}
246
247/// @brief B(a, b) -- beta function
248inline real beta(real a, real b) {
249#ifdef NUMERICS_USE_BOOST_MATH
250 return boost::math::beta(a, b);
251#else
252 return std::beta(a, b);
253#endif
254}
255
256// Sequence utilities (wrapping <numeric>)
257
258/// @brief Evenly spaced values from start to stop, inclusive. MATLAB/NumPy
259/// linspace.
260inline std::vector<real> linspace(real start, real stop, idx n) {
261 assert(n >= 2);
262 std::vector<real> out(n);
263 real step = (stop - start) / static_cast<real>(n - 1);
264 for (idx i = 0; i < n; ++i)
265 out[i] = start + static_cast<real>(i) * step;
266 return out;
267}
268
269/// @brief Integer sequence [start, start+1, ..., start+n-1]. Wraps std::iota.
270inline std::vector<int> int_range(int start, int n) {
271 assert(n >= 0);
272 std::vector<int> out(static_cast<idx>(n));
273 std::iota(out.begin(), out.end(), start);
274 return out;
275}
276
277// Random number generation (wrapping the mt19937 boilerplate)
278
279/// @brief Seeded pseudo-random number generator (Mersenne Twister).
280/// Pass a pointer to rng_* functions to draw samples.
281struct Rng {
282 std::mt19937 engine;
283
284 explicit Rng(uint32_t seed)
285 : engine(seed) {}
286
287 /// Seed from hardware entropy.
289 : engine(std::random_device{}()) {}
290};
291
292/// @brief Uniform real in [lo, hi).
293inline real rng_uniform(Rng* r, real lo, real hi) {
294 return std::uniform_real_distribution<real>{lo, hi}(r->engine);
295}
296
297/// @brief Normal (Gaussian) sample with given mean and standard deviation.
298inline real rng_normal(Rng* r, real mean, real stddev) {
299 return std::normal_distribution<real>{mean, stddev}(r->engine);
300}
301
302/// @brief Uniform integer in [lo, hi] (inclusive on both ends).
303inline int rng_int(Rng* r, int lo, int hi) {
304 return std::uniform_int_distribution<int>{lo, hi}(r->engine);
305}
306
307// Spatial distributions
308
309/// @brief 2D isotropic Gaussian centred at \f$(c_x, c_y)\f$ with width
310/// \f$\sigma\f$:
311/// \f$\exp\!\bigl(-\tfrac{(x-c_x)^2+(y-c_y)^2}{2\sigma^2}\bigr)\f$
312inline real gaussian2d(real x, real y, real cx, real cy, real sigma) {
313 real dx = x - cx, dy = y - cy;
314 return std::exp(-((dx * dx) + (dy * dy)) / (2.0 * sigma * sigma));
315}
316
317} // namespace num
Core type definitions.
real gaussian2d(real x, real y, real cx, real cy, real sigma)
2D isotropic Gaussian centred at with width :
Definition math.hpp:312
double real
Definition types.hpp:10
constexpr real phi
Golden ratio.
Definition math.hpp:45
constexpr real inv_pi
1/pi
Definition math.hpp:49
constexpr real sqrt3
Definition math.hpp:47
real ellint_F(real k, real phi)
F(k, phi) – incomplete elliptic integral of the first kind.
Definition math.hpp:200
std::vector< real > linspace(real start, real stop, idx n)
Evenly spaced values from start to stop, inclusive. MATLAB/NumPy linspace.
Definition math.hpp:260
real bessel_j(real nu, real x)
J_nu(x) – Bessel function of the first kind.
Definition math.hpp:56
real expint(real x)
Ei(x) – exponential integral.
Definition math.hpp:230
int rng_int(Rng *r, int lo, int hi)
Uniform integer in [lo, hi] (inclusive on both ends).
Definition math.hpp:303
real sph_legendre(unsigned int l, unsigned int m, real theta)
Y_l^m(theta) – spherical harmonic (real part, theta in radians)
Definition math.hpp:133
real ellint_E(real k)
E(k) – complete elliptic integral of the second kind.
Definition math.hpp:182
real rng_uniform(Rng *r, real lo, real hi)
Uniform real in [lo, hi).
Definition math.hpp:293
real beta(real a, real b)
B(a, b) – beta function.
Definition math.hpp:248
std::size_t idx
Definition types.hpp:11
real legendre(unsigned int n, real x)
P_n(x) – Legendre polynomial of degree n.
Definition math.hpp:115
real rng_normal(Rng *r, real mean, real stddev)
Normal (Gaussian) sample with given mean and standard deviation.
Definition math.hpp:298
constexpr real pi
Definition math.hpp:43
real assoc_legendre(unsigned int n, unsigned int m, real x)
P_n^m(x) – associated Legendre polynomial.
Definition math.hpp:124
real bessel_k(real nu, real x)
K_nu(x) – modified Bessel function of the second kind.
Definition math.hpp:83
constexpr real ln2
Definition math.hpp:48
constexpr real e
Definition math.hpp:44
constexpr real two_pi
2pi
Definition math.hpp:50
real ellint_K(real k)
K(k) – complete elliptic integral of the first kind.
Definition math.hpp:173
std::vector< int > int_range(int start, int n)
Integer sequence [start, start+1, ..., start+n-1]. Wraps std::iota.
Definition math.hpp:270
real zeta(real x)
zeta(x) – Riemann zeta function
Definition math.hpp:239
real laguerre(unsigned int n, real x)
L_n(x) – Laguerre polynomial.
Definition math.hpp:151
constexpr real half_pi
pi/2
Definition math.hpp:51
real hermite(unsigned int n, real x)
H_n(x) – (physicists') Hermite polynomial.
Definition math.hpp:142
real bessel_i(real nu, real x)
I_nu(x) – modified Bessel function of the first kind.
Definition math.hpp:74
real bessel_y(real nu, real x)
Y_nu(x) – Bessel function of the second kind (Neumann function)
Definition math.hpp:65
real assoc_laguerre(unsigned int n, unsigned int m, real x)
L_n^m(x) – associated Laguerre polynomial.
Definition math.hpp:160
real ellint_Pi(real n, real k)
Pi(n, k) – complete elliptic integral of the third kind.
Definition math.hpp:191
real sph_bessel_j(unsigned int n, real x)
j_n(x) – spherical Bessel function of the first kind
Definition math.hpp:94
real sph_bessel_y(unsigned int n, real x)
y_n(x) – spherical Neumann function (spherical Bessel of the second kind)
Definition math.hpp:104
real ellint_Pi_inc(real n, real k, real phi)
Pi(n, k, phi) – incomplete elliptic integral of the third kind.
Definition math.hpp:218
real ellint_Ei(real k, real phi)
E(k, phi) – incomplete elliptic integral of the second kind.
Definition math.hpp:209
constexpr real sqrt2
Definition math.hpp:46
Seeded pseudo-random number generator (Mersenne Twister). Pass a pointer to rng_* functions to draw s...
Definition math.hpp:281
std::mt19937 engine
Definition math.hpp:282
Rng()
Seed from hardware entropy.
Definition math.hpp:288
Rng(uint32_t seed)
Definition math.hpp:284