This repository implements the Normal Inverse Gaussian (NIG) distribution in C++ using pybind11, Boost and OpenMP. It includes a specialized function for mapping standard normal values to NIG quantiles using a cubic spline approximation.
A small script to evaluate the time spent for the different computations is provided. The function nig_values_from_normal_values
processes 1 billion values in approximately 1.2 seconds.
Make sure to change the path to boost and OpenMP in your setup.py
!!
-
nig.cpp
Implements the NIG distribution in C++ with:- A
CubicSpline
class that assumes evenly spaced nodes for fast evaluation. - A
NIG
class with methods for:pdf
: Compute the probability density function.cdf
: Compute the cumulative distribution function.ppf
: Compute the inverse CDF using a cubic spline approximation.nig_values_from_normal_values
: Maps standard normal values to NIG quantiles by computingnig.ppf(norm.cdf(x))
.
- A
-
setup.py
The build script for compiling the C++ extension using pybind11. It also configures Boost include paths. -
run_timing.py
A benchmarking script that:- Measures the performance of the pdf, cdf, and ppf routines compared to SciPy’s
norminvgauss
. - Benchmarks the copula mapping function (
nig_values_from_normal_values
) against the equivalent operationppf(norm.cdf(x))
. - Repeats measurements multiple times (at least 10 per test) and reports both average timings and speedup ratios.
- Measures the performance of the pdf, cdf, and ppf routines compared to SciPy’s
-
tests/test_nig.py
A set of pytest-based tests verifying that:- The C++ implementation’s pdf, cdf, and ppf match those from SciPy’s
norminvgauss
within acceptable tolerances. - The copula mapping function (
nig_values_from_normal_values
) produces equivalent results toppf(norm.cdf(x))
and is monotonic.
- The C++ implementation’s pdf, cdf, and ppf match those from SciPy’s
All benchmarks were run on a MacOS machine with 8 cores and 8 threads. The file run_timings.py
will reproduce the results.
-
PDF Function:
Achieves roughly a 10x speedup compared to SciPy's implementation (varying with NIG parameters). -
CDF and PPF Functions:
CDF has a 200x–230x speedup and PPF a 120x-140x speedup, again depending on parameter settings. -
Cubic Spline PPF Evaluation:
After a one-time initialization, evaluating the PPF for 1 billion values takes approximately 1 second. This is about 40,000x faster than our C++ NIG PPF implementation and around 4.5 million times faster than using SciPy'snorminvgauss
. Of course they didn't optimise for this so it is not entirely fair to compare. Also, we test it only to 1e-7 accuracy. To increase accuracy, increase the spline points to maybe 10k? It should not really decrease computation speed.