LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
sim_dist.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_SIM_SIM_DIST_H
6#define LINE_API_SIM_SIM_DIST_H
7
8/**
9 * @file
10 * @ingroup api_sim
11 * Normal and Student t quantiles used by the output-analysis routines.
12 *
13 * Port of matlab/src/api/sim/sim_normcdf.m, sim_norminv.m and sim_tinv.m, which are
14 * grouped here as the JAR groups them in jline.api.sim.SimDist and native Python
15 * in line_solver.api.sim.dist. The four codebases reach the same values through
16 * four different libraries -- MATLAB through erfc/erfinv/betaincinv to avoid a
17 * toolbox dependency, the JAR through commons-math3, Python through SciPy and
18 * this port through Boost.Math -- and agree to within 1e-10.
19 *
20 * These are deliberately plain doubles rather than templates on T. A quantile
21 * order p and a significance level alpha are doubles at every call site in this
22 * family, so the quantile they determine carries double information and no
23 * more; see the arithmetic note in sim_types.h.
24 *
25 * The t quantile follows the MATLAB identity rather than a distribution object,
26 * so the branch structure is comparable line by line with the reference:
27 * P(|T| > t) = betainc(nu/(nu+t^2), nu/2, 1/2),
28 * inverted for the two-sided tail 2(1-p) and mapped back with
29 * t = sqrt(nu (1-z)/z), z = betaincinv(2(1-p), nu/2, 1/2).
30 * MATLAB's betaincinv(y, a, b) is Boost's ibeta_inv(a, b, y): both invert the
31 * REGULARIZED incomplete beta, and getting the argument order wrong here is a
32 * silently plausible wrong number rather than an error.
33 */
34
35#include <cmath>
36#include <limits>
37
38#include <boost/math/special_functions/beta.hpp>
39#include <boost/math/special_functions/erf.hpp>
40
41#include "line/util/error.h"
42
43namespace line {
44namespace sim {
45
46/**
47 * Standard normal cumulative distribution function.
48 *
49 * @param z the argument
50 * @return Phi(z)
51 */
52inline double sim_normcdf(double z) {
53 return 0.5 * boost::math::erfc(-z / std::sqrt(2.0));
54}
55
56/**
57 * Standard normal quantile function.
58 *
59 * @param p probability in [0,1]
60 * @return Phi^{-1}(p), infinite at the endpoints
61 */
62inline double sim_norminv(double p) {
63 if (!(p >= 0.0) || !(p <= 1.0))
64 throw InputError("sim_norminv: the probability must lie in [0,1]");
65 if (p == 0.0) return -std::numeric_limits<double>::infinity();
66 if (p == 1.0) return std::numeric_limits<double>::infinity();
67 return std::sqrt(2.0) * boost::math::erf_inv(2.0 * p - 1.0);
68}
69
70/**
71 * Quantile function of Student's t distribution.
72 *
73 * @param p probability in [0,1]
74 * @param nu degrees of freedom, positive
75 * @return the p-quantile of t with nu degrees of freedom
76 */
77inline double sim_tinv(double p, double nu) {
78 if (!(nu > 0.0)) throw InputError("sim_tinv: nu must be a positive real scalar");
79 if (!(p >= 0.0) || !(p <= 1.0))
80 throw InputError("sim_tinv: the probability must lie in [0,1]");
81 if (p == 0.5) return 0.0;
82 if (p <= 0.0) return -std::numeric_limits<double>::infinity();
83 if (p >= 1.0) return std::numeric_limits<double>::infinity();
84
85 // reflect the lower half onto the upper half, the law is symmetric
86 const bool flip = p < 0.5;
87 const double pu = flip ? 1.0 - p : p;
88 const double z = boost::math::ibeta_inv(0.5 * nu, 0.5, 2.0 * (1.0 - pu));
89 const double t = std::sqrt(nu * (1.0 - z) / z);
90 return flip ? -t : t;
91}
92
93} // namespace sim
94} // namespace line
95
96#endif // LINE_API_SIM_SIM_DIST_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
double sim_norminv(double p)
Standard normal quantile function.
Definition sim_dist.h:62
double sim_normcdf(double z)
Standard normal cumulative distribution function.
Definition sim_dist.h:52
double sim_tinv(double p, double nu)
Quantile function of Student's t distribution.
Definition sim_dist.h:77