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;
83 if (alpha <= 0.0 || beta <= 0.0)
84 throw InputError(
"ssj::pareto_inverse: alpha and beta must be positive");
85 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
86 return beta * std::pow(1.0 - u, -1.0 / alpha);
94inline double weibull_inverse(
double alpha,
double lambda,
double delta,
double u) {
95 if (alpha <= 0.0 || lambda <= 0.0)
96 throw InputError(
"ssj::weibull_inverse: alpha and lambda must be positive");
97 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
98 if (u <= 0.0)
return delta;
99 return delta + std::pow(-line::fdlibm::log1p(-u), 1.0 / alpha) / lambda;
104 if (p < 0.0 || p > 1.0)
throw InputError(
"ssj::bernoulli_inverse: p must lie in [0,1]");
105 return (u <= 1.0 - p) ? 0.0 : 1.0;
119 if (u <= 0.0)
return -std::numeric_limits<double>::infinity();
120 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
122 const double q = u - 0.5;
124 if (std::fabs(q) <= 0.425) {
125 r = 0.180625 - q * q;
127 (((((((2509.0809287301226727 * r + 33430.575583588128105) * r +
128 67265.770927008700853) * r + 45921.953931549871457) * r +
129 13731.693765509461125) * r + 1971.5909503065514427) * r +
130 133.14166789178437745) * r + 3.387132872796366608) /
131 (((((((5226.495278852854561 * r + 28729.085735721942674) * r +
132 39307.89580009271061) * r + 21213.794301586595867) * r +
133 5394.1960214247511077) * r + 687.1870074920579083) * r +
134 42.313330701600911252) * r + 1.0);
136 r = (q < 0.0) ? u : 1.0 - u;
137 r = std::sqrt(-std::log(r));
141 x = (((((((7.7454501427834140764e-4 * r + 0.0227238449892691845833) * r +
142 0.24178072517745061177) * r + 1.27045825245236838258) * r +
143 3.64784832476320460504) * r + 5.7694972214606914055) * r +
144 4.6303378461565452959) * r + 1.42343711074968357734) /
145 (((((((1.05075007164441684324e-9 * r + 5.475938084995344946e-4) * r +
146 0.0151986665636164571966) * r + 0.14810397642748007459) * r +
147 0.68976733498510000455) * r + 1.6763848301838038494) * r +
148 2.05319162663775882187) * r + 1.0);
151 x = (((((((2.01033439929228813265e-7 * r + 2.71155556874348757815e-5) * r +
152 0.0012426609473880784386) * r + 0.026532189526576123093) * r +
153 0.29656057182850489123) * r + 1.7848265399172913358) * r +
154 5.4637849111641143699) * r + 6.6579046435011037772) /
155 (((((((2.04426310338993978564e-15 * r + 1.4215117583164458887e-7) * r +
156 1.8463183175100546818e-5) * r + 7.868691311456132591e-4) * r +
157 0.0148753612908506148525) * r + 0.13692988092273580531) * r +
158 0.59983220655588793769) * r + 1.0);
160 return (q < 0.0) ? -x : x;
165 if (sigma <= 0.0)
throw InputError(
"ssj::normal_inverse: sigma must be positive");
171 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
172 if (u <= 0.0)
return 0.0;
183inline double gamma_p(
double a,
double x) {
184 if (x <= 0.0)
return 0.0;
185 const double lg = std::lgamma(a);
188 double ap = a,
sum = 1.0 / a, del =
sum;
189 for (
int n = 0; n < 1000; ++n) {
193 if (std::fabs(del) < std::fabs(
sum) * 1e-16)
break;
195 return sum * std::exp(-x + a * std::log(x) - lg);
198 const double tiny = 1e-300;
199 double b = x + 1.0 - a, c = 1.0 / tiny, d = 1.0 / b, h = d;
200 for (
int i = 1; i <= 1000; ++i) {
201 const double an = -
static_cast<double>(i) * (
static_cast<double>(i) - a);
204 if (std::fabs(d) < tiny) d = tiny;
206 if (std::fabs(c) < tiny) c = tiny;
208 const double del = d * c;
210 if (std::fabs(del - 1.0) < 1e-16)
break;
212 return 1.0 - std::exp(-x + a * std::log(x) - lg) * h;
227 if (alpha <= 0.0 || lambda <= 0.0)
228 throw InputError(
"ssj::gamma_inverse: alpha and lambda must be positive");
229 if (u <= 0.0)
return 0.0;
230 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
234 const double wh = alpha * std::pow(1.0 - 1.0 / (9.0 * alpha) + z / (3.0 * std::sqrt(alpha)), 3.0);
235 double x = (wh > 0.0) ? wh : alpha * 0.5;
237 double lo = 0.0, hi = 0.0;
238 const double lg = std::lgamma(alpha);
239 for (
int it = 0; it < 200; ++it) {
240 const double p = detail::gamma_p(alpha, x);
246 const double logpdf = (alpha - 1.0) * std::log(x) - x - lg;
247 const double pdf = std::exp(logpdf);
248 double step = (pdf > 0.0) ? (p - u) / pdf : 0.0;
249 double next = x - step;
250 if (!(next > lo) || (hi > 0.0 && !(next < hi)) || !(next > 0.0) || !std::isfinite(next)) {
251 next = (hi > 0.0) ? 0.5 * (lo + hi) : 2.0 * x;
253 const double rel = std::fabs(next - x) / (std::fabs(x) + 1e-300);
255 if (rel < 1e-15)
break;
266 if (k <= 0)
throw InputError(
"ssj::erlang_inverse: k must be positive");
282 if (lambda <= 0.0)
throw InputError(
"ssj::poisson_inverse: lambda must be positive");
283 if (u <= 0.0)
return 0.0;
284 if (u >= 1.0)
return std::numeric_limits<double>::infinity();
285 double p = std::exp(-lambda), cdf = p;
287 const int guard =
static_cast<int>(lambda + 20.0 * std::sqrt(lambda) + 1000.0);
288 while (cdf < u && k < guard) {
290 p *= lambda /
static_cast<double>(k);
293 return static_cast<double>(k);
298 if (n < 0)
throw InputError(
"ssj::binomial_inverse: n must be non-negative");
299 if (p < 0.0 || p > 1.0)
throw InputError(
"ssj::binomial_inverse: p must lie in [0,1]");
300 if (u <= 0.0)
return 0.0;
301 if (p <= 0.0)
return 0.0;
302 if (p >= 1.0)
return static_cast<double>(n);
303 double pk = std::pow(1.0 - p,
static_cast<double>(n)), cdf = pk;
305 while (cdf < u && k < n) {
306 pk *= (
static_cast<double>(n - k) /
static_cast<double>(k + 1)) * (p / (1.0 - p));
310 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 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.