5#ifndef LINE_SOLVERS_LDES_LDES_SSJ_VARIATES_H
6#define LINE_SOLVERS_LDES_LDES_SSJ_VARIATES_H
70 if (lambda <= 0.0)
throw InputError(
"ssj::exponential_inverse: lambda must be positive");
71 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
72 if (u <= 0.0)
return 0.0;
73 return -line::fdlibm::log1p(-u) / lambda;
78 return a + (b - a) * u;
89 if (!(width >= 1.0))
throw InputError(
"ssj::uniform_int_inverse: the width must be at least 1");
90 if (u <= 0.0)
return lo;
91 if (u >= 1.0)
return lo + width - 1.0;
92 return lo + std::floor(u * width);
97 if (alpha <= 0.0 || beta <= 0.0)
98 throw InputError(
"ssj::pareto_inverse: alpha and beta must be positive");
99 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
100 return beta * std::pow(1.0 - u, -1.0 / alpha);
109 if (alpha <= 0.0 || lambda <= 0.0)
110 throw InputError(
"ssj::weibull_inverse: alpha and lambda must be positive");
111 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
112 if (u <= 0.0)
return delta;
113 return delta + std::pow(-line::fdlibm::log1p(-u), 1.0 / alpha) / lambda;
118 if (p < 0.0 || p > 1.0)
throw InputError(
"ssj::bernoulli_inverse: p must lie in [0,1]");
119 return (u <= 1.0 - p) ? 0.0 : 1.0;
133 if (u <= 0.0)
return -std::numeric_limits<double>::infinity();
134 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
136 const double q = u - 0.5;
138 if (std::fabs(q) <= 0.425) {
139 r = 0.180625 - q * q;
141 (((((((2509.0809287301226727 * r + 33430.575583588128105) * r +
142 67265.770927008700853) * r + 45921.953931549871457) * r +
143 13731.693765509461125) * r + 1971.5909503065514427) * r +
144 133.14166789178437745) * r + 3.387132872796366608) /
145 (((((((5226.495278852854561 * r + 28729.085735721942674) * r +
146 39307.89580009271061) * r + 21213.794301586595867) * r +
147 5394.1960214247511077) * r + 687.1870074920579083) * r +
148 42.313330701600911252) * r + 1.0);
150 r = (q < 0.0) ? u : 1.0 - u;
151 r = std::sqrt(-std::log(r));
155 x = (((((((7.7454501427834140764e-4 * r + 0.0227238449892691845833) * r +
156 0.24178072517745061177) * r + 1.27045825245236838258) * r +
157 3.64784832476320460504) * r + 5.7694972214606914055) * r +
158 4.6303378461565452959) * r + 1.42343711074968357734) /
159 (((((((1.05075007164441684324e-9 * r + 5.475938084995344946e-4) * r +
160 0.0151986665636164571966) * r + 0.14810397642748007459) * r +
161 0.68976733498510000455) * r + 1.6763848301838038494) * r +
162 2.05319162663775882187) * r + 1.0);
165 x = (((((((2.01033439929228813265e-7 * r + 2.71155556874348757815e-5) * r +
166 0.0012426609473880784386) * r + 0.026532189526576123093) * r +
167 0.29656057182850489123) * r + 1.7848265399172913358) * r +
168 5.4637849111641143699) * r + 6.6579046435011037772) /
169 (((((((2.04426310338993978564e-15 * r + 1.4215117583164458887e-7) * r +
170 1.8463183175100546818e-5) * r + 7.868691311456132591e-4) * r +
171 0.0148753612908506148525) * r + 0.13692988092273580531) * r +
172 0.59983220655588793769) * r + 1.0);
174 return (q < 0.0) ? -x : x;
179 if (sigma <= 0.0)
throw InputError(
"ssj::normal_inverse: sigma must be positive");
185 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
186 if (u <= 0.0)
return 0.0;
197inline double gamma_p(
double a,
double x) {
198 if (x <= 0.0)
return 0.0;
199 const double lg = std::lgamma(a);
202 double ap = a,
sum = 1.0 / a, del =
sum;
203 for (
int n = 0; n < 1000; ++n) {
207 if (std::fabs(del) < std::fabs(
sum) * 1e-16)
break;
209 return sum * std::exp(-x + a * std::log(x) - lg);
212 const double tiny = 1e-300;
213 double b = x + 1.0 - a, c = 1.0 / tiny, d = 1.0 / b, h = d;
214 for (
int i = 1; i <= 1000; ++i) {
215 const double an = -
static_cast<double>(i) * (
static_cast<double>(i) - a);
218 if (std::fabs(d) < tiny) d = tiny;
220 if (std::fabs(c) < tiny) c = tiny;
222 const double del = d * c;
224 if (std::fabs(del - 1.0) < 1e-16)
break;
226 return 1.0 - std::exp(-x + a * std::log(x) - lg) * h;
241 if (alpha <= 0.0 || lambda <= 0.0)
242 throw InputError(
"ssj::gamma_inverse: alpha and lambda must be positive");
243 if (u <= 0.0)
return 0.0;
244 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
248 const double wh = alpha * std::pow(1.0 - 1.0 / (9.0 * alpha) + z / (3.0 * std::sqrt(alpha)), 3.0);
249 double x = (wh > 0.0) ? wh : alpha * 0.5;
251 double lo = 0.0, hi = 0.0;
252 const double lg = std::lgamma(alpha);
253 for (
int it = 0; it < 200; ++it) {
254 const double p = detail::gamma_p(alpha, x);
260 const double logpdf = (alpha - 1.0) * std::log(x) - x - lg;
261 const double pdf = std::exp(logpdf);
262 double step = (pdf > 0.0) ? (p - u) / pdf : 0.0;
263 double next = x - step;
264 if (!(next > lo) || (hi > 0.0 && !(next < hi)) || !(next > 0.0) || !std::isfinite(next)) {
265 next = (hi > 0.0) ? 0.5 * (lo + hi) : 2.0 * x;
267 const double rel = std::fabs(next - x) / (std::fabs(x) + 1e-300);
269 if (rel < 1e-15)
break;
280 if (k <= 0)
throw InputError(
"ssj::erlang_inverse: k must be positive");
296 if (lambda <= 0.0)
throw InputError(
"ssj::poisson_inverse: lambda must be positive");
297 if (u <= 0.0)
return 0.0;
298 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
299 double p = std::exp(-lambda), cdf = p;
301 const int guard =
static_cast<int>(lambda + 20.0 * std::sqrt(lambda) + 1000.0);
302 while (cdf < u && k < guard) {
304 p *= lambda /
static_cast<double>(k);
307 return static_cast<double>(k);
312 if (n < 0)
throw InputError(
"ssj::binomial_inverse: n must be non-negative");
313 if (p < 0.0 || p > 1.0)
throw InputError(
"ssj::binomial_inverse: p must lie in [0,1]");
314 if (u <= 0.0)
return 0.0;
315 if (p <= 0.0)
return 0.0;
316 if (p >= 1.0)
return static_cast<double>(n);
317 double pk = std::pow(1.0 - p,
static_cast<double>(n)), cdf = pk;
319 while (cdf < u && k < n) {
320 pk *= (
static_cast<double>(n - k) /
static_cast<double>(k + 1)) * (p / (1.0 - p));
324 return static_cast<double>(k);
The exception types the port throws.
double exponential_inverse(double lambda, double u)
ExponentialDist.inverseF(lambda, u), SSJ's log1p spelling.
double uniform_int_inverse(double lo, double width, double u)
UniformIntDist.inverseF(i, j, u), written over the lower bound and the WIDTH w = j - i + 1 so that a ...
double binomial_inverse(int n, double p, double u)
BinomialDist.inverseF(n, p, u), by the same forward inversion.
double erlang_inverse(int k, double lambda, double u)
ErlangGen(k, lambda): the Gamma of integer shape k and rate lambda.
double uniform_inverse(double a, double b, double u)
UniformDist.inverseF(a, b, u).
double weibull_inverse(double alpha, double lambda, double delta, double u)
WeibullDist.inverseF(alpha, lambda, delta, u).
double pareto_inverse(double alpha, double beta, double u)
ParetoDist.inverseF(alpha, beta, u) = beta (1-u)^(-1/alpha).
double gamma_inverse(double alpha, double lambda, double u)
GammaDist.inverseF(alpha, lambda, u): the quantile of a Gamma of shape alpha and RATE lambda,...
double normal_inverse01(double u)
NormalDist.inverseF(0, 1, u) by Wichura's AS 241 (Applied Statistics 37, 1988), the algorithm SSJ's i...
double bernoulli_inverse(double p, double u)
BernoulliDist.inverseF(p, u): 1 when u exceeds 1 - p.
double normal_inverse(double mu, double sigma, double u)
NormalDist.inverseF(mu, sigma, u).
double lognormal_inverse(double mu, double sigma, double u)
LognormalDist.inverseF(mu, sigma, u) = exp(mu + sigma Phi^-1(u)).
double poisson_inverse(double lambda, double u)
PoissonDist.inverseF(lambda, u): the smallest k whose cdf reaches u.
Conservation laws of a layered queueing network, enumerated from its structure.