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 C++17 `<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 (C++20 <numbers> not available in C++17)
41
42constexpr real pi = 3.14159265358979323846;
43constexpr real e = 2.71828182845904523536;
44constexpr real phi = 1.61803398874989484820; ///< Golden ratio
45constexpr real sqrt2 = 1.41421356237309504880;
46constexpr real sqrt3 = 1.73205080756887729353;
47constexpr real ln2 = 0.69314718055994530942;
48constexpr real inv_pi = 0.31830988618379067154; ///< 1/pi
49constexpr real two_pi = 6.28318530717958647692; ///< 2pi
50constexpr real half_pi = 1.57079632679489661923; ///< pi/2
51
52// Cylindrical Bessel functions (C++17, <cmath>)
53
54/// @brief J_nu(x) -- Bessel function of the first kind
55inline real bessel_j(real nu, real x) {
56#ifdef NUMERICS_USE_BOOST_MATH
57 return boost::math::cyl_bessel_j(nu, x);
58#else
59 return std::cyl_bessel_j(nu, x);
60#endif
61}
62
63/// @brief Y_nu(x) -- Bessel function of the second kind (Neumann function)
64inline real bessel_y(real nu, real x) {
65#ifdef NUMERICS_USE_BOOST_MATH
66 return boost::math::cyl_neumann(nu, x);
67#else
68 return std::cyl_neumann(nu, x);
69#endif
70}
71
72/// @brief I_nu(x) -- modified Bessel function of the first kind
73inline real bessel_i(real nu, real x) {
74#ifdef NUMERICS_USE_BOOST_MATH
75 return boost::math::cyl_bessel_i(nu, x);
76#else
77 return std::cyl_bessel_i(nu, x);
78#endif
79}
80
81/// @brief K_nu(x) -- modified Bessel function of the second kind
82inline real bessel_k(real nu, real x) {
83#ifdef NUMERICS_USE_BOOST_MATH
84 return boost::math::cyl_bessel_k(nu, x);
85#else
86 return std::cyl_bessel_k(nu, x);
87#endif
88}
89
90// Spherical Bessel functions (C++17, <cmath>)
91
92/// @brief j_n(x) -- spherical Bessel function of the first kind
93inline real sph_bessel_j(unsigned int n, real x) {
94#ifdef NUMERICS_USE_BOOST_MATH
95 return boost::math::sph_bessel(n, x);
96#else
97 return std::sph_bessel(n, x);
98#endif
99}
100
101/// @brief y_n(x) -- spherical Neumann function (spherical Bessel of the second
102/// kind)
103inline real sph_bessel_y(unsigned int n, real x) {
104#ifdef NUMERICS_USE_BOOST_MATH
105 return boost::math::sph_neumann(n, x);
106#else
107 return std::sph_neumann(n, x);
108#endif
109}
110
111// Orthogonal polynomials (C++17, <cmath>)
112
113/// @brief P_n(x) -- Legendre polynomial of degree n
114inline real legendre(unsigned int n, real x) {
115#ifdef NUMERICS_USE_BOOST_MATH
116 return boost::math::legendre_p(static_cast<int>(n), x);
117#else
118 return std::legendre(n, x);
119#endif
120}
121
122/// @brief P_n^m(x) -- associated Legendre polynomial
123inline real assoc_legendre(unsigned int n, unsigned int m, real x) {
124#ifdef NUMERICS_USE_BOOST_MATH
125 return boost::math::legendre_p(static_cast<int>(n), static_cast<int>(m), x);
126#else
127 return std::assoc_legendre(n, m, x);
128#endif
129}
130
131/// @brief Y_l^m(theta) -- spherical harmonic (real part, theta in radians)
132inline real sph_legendre(unsigned int l, unsigned int m, real theta) {
133#ifdef NUMERICS_USE_BOOST_MATH
134 return boost::math::spherical_harmonic_r(l, static_cast<int>(m), theta,
135 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) : engine(seed) {}
285
286 /// Seed from hardware entropy.
287 Rng() : engine(std::random_device{}()) {}
288};
289
290/// @brief Uniform real in [lo, hi).
291inline real rng_uniform(Rng *r, real lo, real hi) {
292 return std::uniform_real_distribution<real>{lo, hi}(r->engine);
293}
294
295/// @brief Normal (Gaussian) sample with given mean and standard deviation.
296inline real rng_normal(Rng *r, real mean, real stddev) {
297 return std::normal_distribution<real>{mean, stddev}(r->engine);
298}
299
300/// @brief Uniform integer in [lo, hi] (inclusive on both ends).
301inline int rng_int(Rng *r, int lo, int hi) {
302 return std::uniform_int_distribution<int>{lo, hi}(r->engine);
303}
304
305// Spatial distributions
306
307/// @brief 2D isotropic Gaussian centred at \f$(c_x, c_y)\f$ with width
308/// \f$\sigma\f$:
309/// \f$\exp\!\bigl(-\tfrac{(x-c_x)^2+(y-c_y)^2}{2\sigma^2}\bigr)\f$
310inline real gaussian2d(real x, real y, real cx, real cy, real sigma) {
311 real dx = x - cx, dy = y - cy;
312 return std::exp(-((dx * dx) + (dy * dy)) / (2.0 * sigma * sigma));
313}
314
315} // 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:310
double real
Definition types.hpp:10
constexpr real phi
Golden ratio.
Definition math.hpp:44
constexpr real inv_pi
1/pi
Definition math.hpp:48
constexpr real sqrt3
Definition math.hpp:46
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:55
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:301
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:132
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:291
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:114
real rng_normal(Rng *r, real mean, real stddev)
Normal (Gaussian) sample with given mean and standard deviation.
Definition math.hpp:296
constexpr real pi
Definition math.hpp:42
real assoc_legendre(unsigned int n, unsigned int m, real x)
P_n^m(x) – associated Legendre polynomial.
Definition math.hpp:123
real bessel_k(real nu, real x)
K_nu(x) – modified Bessel function of the second kind.
Definition math.hpp:82
constexpr real ln2
Definition math.hpp:47
constexpr real e
Definition math.hpp:43
constexpr real two_pi
2pi
Definition math.hpp:49
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:50
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:73
real bessel_y(real nu, real x)
Y_nu(x) – Bessel function of the second kind (Neumann function)
Definition math.hpp:64
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:93
real sph_bessel_y(unsigned int n, real x)
y_n(x) – spherical Neumann function (spherical Bessel of the second kind)
Definition math.hpp:103
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:45
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:287
Rng(uint32_t seed)
Definition math.hpp:284