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
CubicSplineclass that assumes evenly spaced nodes for fast evaluation. - A
NIGclass 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
norminvgausswithin 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.