5#ifndef LINE_LANG_DISTRIBUTION_H
6#define LINE_LANG_DISTRIBUTION_H
64 const double n = std::ceil(1.0 / scv);
65 const double capped = n < 1.0 ? 1.0 : (n > 100.0 ? 100.0 : n);
66 return static_cast<unsigned>(capped);
89 ": the distribution is a Prior, which is a weighted set of alternative "
90 "MODELS rather than one law; solve the model with SolverUQ, which "
91 "replaces each Prior by one alternative per design point");
114 const std::size_t n = d.
D0.rows();
117 for (std::size_t i = 0; i < n; ++i)
118 for (std::size_t j = 0; j < n; ++j) ImD0(i, j) = T((i == j ? one : T(0)) - d.
D0(i, j));
122 const std::vector<std::size_t> piv =
lu_factor(LU);
124 for (std::size_t j = 0; j < n; ++j) {
125 std::vector<T> col(n);
126 for (std::size_t i = 0; i < n; ++i) col[i] = d.
D1(i, j);
128 for (std::size_t i = 0; i < n; ++i) P(i, j) = col[i];
131 std::vector<T> y(n, one);
133 std::vector<T> z = y;
136 for (std::size_t i = 0; i < n; ++i) {
137 m1 += T(alpha[i] * y[i]);
139 for (std::size_t j = 0; j < n; ++j) dz += T(d.
D0(i, j) * z[j]);
140 fac2 += T(alpha[i] * dz);
142 fac2 = T(two * fac2);
143 const T m2 = T(fac2 + m1);
145 d.
scv = T((m2 - m1 * m1) / (m1 * m1));
154 "dist_to_map: a Normal puts mass below zero, so it is not the law of any duration and "
155 "has no Markovian representation. The default arm of this function would hand back the "
156 "Erlang fit of its mean, which is a positive law with the same mean and nothing else "
157 "in common; refusing instead. A Normal reaches this port only as the parameter density "
158 "of a continuous Prior");
175 for (
const T& x : d.
trace) {
180 return mam::aph_fit(T(m1 / n), T(m2 / n), T(m3 / n)).aph;
183 "dist_to_map: fitting a Replayer trace to an acyclic phase-type needs "
184 "transcendental arithmetic, which exact rational arithmetic does not provide; "
185 "solve in double or Real<n>, or replace the trace by a fitted distribution");
231 if (s == zero)
return one;
245 "dist_lst: the transform of a Replayer trace is a mean of exp, which exact "
246 "arithmetic has no representation for; use the double or real backend");
257 "dist_lst: the transform of a Det is exp(-s m), which exact arithmetic has "
258 "no representation for; use the double or real backend");
267 "dist_lst: the transform of a Uniform evaluates exp, which exact arithmetic "
268 "has no representation for; use the double or real backend");
280 "dist_lst: the transform of a Normal is a value of exp, which exact arithmetic "
281 "has no representation for; use the double or real backend");
302 "dist_lst: the transform of a Pareto is an integral of exp, which exact "
303 "arithmetic has no representation for; use the double or real backend");
309 auto g = [&alpha, &k, &s, &tiny, &one](
const T& u) -> T {
311 const T uu = u > tiny ? u : tiny;
317 const T val = qsys::detail::num_integral<T>(g, zero, one,
320 return T(alpha * val);
326 "dist_lst: the transform of a Weibull is a numerical integral, which exact "
327 "arithmetic has no representation for; use the double or real backend");
333 const double upper = a * std::pow(-std::log(1e-10), 1.0 / r);
335 const double dx = upper / n;
337 for (
int i = 1; i <= n; ++i) {
338 const double x = i * dx;
340 (r / a) * std::pow(x / a, r - 1.0) * std::exp(-std::pow(x / a, r));
341 acc += std::exp(-sv * x) * pdf;
349 "dist_lst: the transform of a Lognormal is a numerical integral, which exact "
350 "arithmetic has no representation for; use the double or real backend");
355 const double upper = std::exp(mu + 5.0 * sg);
357 const double dx = upper / n;
359 for (
int i = 1; i <= n; ++i) {
360 const double x = i * dx;
361 const double lx = std::log(x);
362 const double pdf = std::exp(-(lx - mu) * (lx - mu) / (2.0 * sg * sg)) /
363 (x * sg * std::sqrt(2.0 * M_PI));
364 acc += std::exp(-sv * x) * pdf;
372 "dist_lst: the transform of a Gamma is (1 + s theta)^-k, which exact "
373 "arithmetic has no representation for; use the double or real backend");
389 const std::size_t n = m.
D0.rows();
391 for (std::size_t i = 0; i < n; ++i)
392 for (std::size_t j = 0; j < n; ++j) A(i, j) = T((i == j ? s : zero) - m.
D0(i, j));
394 std::vector<T> rhs(n, zero);
395 for (std::size_t i = 0; i < n; ++i) {
397 for (std::size_t j = 0; j < n; ++j) acc += m.
D0(i, j);
401 std::vector<T> x = rhs;
402 for (std::size_t col = 0; col < n; ++col) {
403 std::size_t best = col;
405 for (std::size_t r = col + 1; r < n; ++r) {
413 for (std::size_t j = 0; j < n; ++j) std::swap(A(col, j), A(best, j));
414 std::swap(x[col], x[best]);
416 if (A(col, col) == zero)
throw NumericError(
"dist_lst: singular transform matrix");
417 for (std::size_t r = 0; r < n; ++r) {
418 if (r == col)
continue;
419 const T f = T(A(r, col) / A(col, col));
420 if (f == zero)
continue;
421 for (std::size_t j = 0; j < n; ++j) A(r, j) = T(A(r, j) - f * A(col, j));
422 x[r] = T(x[r] - f * x[col]);
426 for (std::size_t i = 0; i < n; ++i) out += pie[i] * T(x[i] / A(i, i));
434T
dist_cdf(
const Distrib<T>& d,
const T& x);
460 "dist_lst at a complex argument requires transcendental arithmetic");
463 if (std::abs(s) == 0.0)
return std::complex<double>(1.0, 0.0);
467 return std::complex<double>(1.0, 0.0);
469 std::complex<double> acc(0.0, 0.0);
471 return acc /
static_cast<double>(d.
trace.size());
478 return (std::exp(-s * a) - std::exp(-s * b)) / (s * (b - a));
483 return std::exp(-mu * s + sg * sg * s * s / 2.0);
488 return std::pow(std::complex<double>(1.0, 0.0) + s * scale, -shape);
499 const std::size_t n = m.
D0.rows();
500 std::vector<std::vector<std::complex<double> > > A(
501 n, std::vector<std::complex<double> >(n, std::complex<double>(0.0, 0.0)));
502 std::vector<std::complex<double> > x(n, std::complex<double>(0.0, 0.0));
503 for (std::size_t i = 0; i < n; ++i) {
505 for (std::size_t j = 0; j < n; ++j) {
507 A[i][j] = (i == j ? s : std::complex<double>(0.0, 0.0)) - d0;
510 x[i] = std::complex<double>(-exit, 0.0);
512 for (std::size_t col = 0; col < n; ++col) {
513 std::size_t piv = col;
514 double bv = std::abs(A[col][col]);
515 for (std::size_t r = col + 1; r < n; ++r) {
516 if (std::abs(A[r][col]) > bv) { bv = std::abs(A[r][col]); piv = r; }
518 if (piv != col) { std::swap(A[piv], A[col]); std::swap(x[piv], x[col]); }
519 if (std::abs(A[col][col]) == 0.0)
520 throw NumericError(
"dist_lst: singular transform matrix");
521 for (std::size_t r = col + 1; r < n; ++r) {
522 const std::complex<double> f = A[r][col] / A[col][col];
523 for (std::size_t c = col; c < n; ++c) A[r][c] -= f * A[col][c];
527 for (std::size_t row = n; row-- > 0;) {
528 std::complex<double> acc = x[row];
529 for (std::size_t c = row + 1; c < n; ++c) acc -= A[row][c] * x[c];
530 x[row] = acc / A[row][row];
532 std::complex<double> out(0.0, 0.0);
533 for (std::size_t i = 0; i < n; ++i) out += num_traits<T>::to_double(pie[i]) * x[i];
539 const std::size_t n_grid = 2400;
541 double hi = mean * 60.0;
543 const double var = m2 - mean * mean;
544 if (std::isfinite(var) && var > 0.0) hi = std::max(hi, mean + 12.0 * std::sqrt(var));
545 if (!std::isfinite(hi) || hi <= 0.0)
return std::complex<double>(1.0, 0.0);
546 const double step = hi /
static_cast<double>(n_grid);
547 std::complex<double> acc(0.0, 0.0);
550 for (std::size_t i = 0; i < n_grid; ++i) {
551 const double right =
static_cast<double>(i + 1) * step;
553 const double w = cur - prev;
555 if (w == 0.0)
continue;
557 acc += w * std::exp(-s * ((
static_cast<double>(i) + 0.5) * step));
559 return mass > 0.0 ? acc / mass : std::complex<double>(1.0, 0.0);
572 if (k == 0)
return one;
580 for (
unsigned i = 0; i < k; ++i) v = T(v * d.
mean);
586 T pa = one, pb = one;
587 for (
unsigned i = 0; i <= k; ++i) {
598 throw NumericError(
"dist_moment: the Pareto moment of this order is infinite");
600 for (
unsigned i = 0; i < k; ++i) ps = T(ps * scale);
601 return T(alpha * ps / (alpha - m));
606 for (
const T& x : d.
trace) {
608 for (
unsigned i = 0; i < k; ++i) v = T(v * x);
616 "dist_moment: the moments of a Gamma are values of the gamma function, which "
617 "exact arithmetic has no representation for");
622 std::pow(scale,
static_cast<double>(k)));
628 "dist_moment: the moments of a Weibull are values of the gamma function, "
629 "which exact arithmetic has no representation for");
634 std::tgamma(1.0 + k / r));
640 "dist_moment: the moments of a Lognormal are values of exp, which exact "
641 "arithmetic has no representation for");
653 T prev2 = one, prev1 = mu;
654 if (k == 1)
return prev1;
655 for (
unsigned i = 2; i <= k; ++i) {
656 const T next = T(mu * prev1 +
698 "dist_cdf: a Prior's law is the mixture over its alternatives, which lives with the "
699 "Prior; call prior_cdf (lang/prior.h)");
706 return x < d.
params[0] ? zero : one;
709 if (x <= a)
return zero;
710 if (x >= b)
return one;
711 return T((x - a) / (b - a));
716 "dist_cdf: the Gaussian CDF is a value of erf, which exact arithmetic has no "
717 "representation for");
724 (sg * std::sqrt(2.0)))));
729 if (d.
trace.empty())
throw InputError(
"dist_cdf: the Replayer carries no samples");
730 std::size_t below = 0;
731 for (
const T& v : d.
trace)
732 if (!(v > x)) ++below;
741 "dist_cdf: the law of this family is an exponential, which exact arithmetic has no "
742 "representation for; use the double or real backend");
744 if (!(x > zero))
return zero;
755 const double z = alpha * xv;
756 double term = std::exp(-z), acc = term;
757 for (
long j = 1; j < r; ++j) {
758 term *= z /
static_cast<double>(j);
768 (1.0 - p) * (1.0 - std::exp(-m2 * xv)));
773 if (xv <= scale)
return zero;
790 0.5 * std::erfc(-(std::log(xv) - mu) / (sg * std::sqrt(2.0))));
799 for (std::size_t i = 0; i < A.
rows(); ++i)
800 for (std::size_t j = 0; j < A.
cols(); ++j) A(i, j) = T(m.
D0(i, j) * x);
803 for (std::size_t i = 0; i < E.
rows(); ++i)
804 for (std::size_t j = 0; j < E.
cols(); ++j) acc += T(pie[i] * E(i, j));
823 if (!(p > zero) || !(p < one))
824 throw InputError(
"dist_quantile: p must lie strictly between 0 and 1");
829 const int max_expand = 200;
838 lo = T(d.
mean - step);
839 hi = T(d.
mean + step);
841 for (; j < max_expand; ++j) {
843 if (low_ok && high_ok)
break;
844 step = T(step * two);
845 if (!low_ok) lo = T(d.
mean - step);
846 if (!high_ok) hi = T(d.
mean + step);
848 if (j == max_expand)
throw NumericError(
"dist_quantile: failed to bracket the quantile");
851 for (; i < max_expand; ++i) {
855 if (i == max_expand)
throw NumericError(
"dist_quantile: failed to bracket the quantile");
858 for (
int k = 0; k < 200; ++k) {
859 const T mid = T((lo + hi) / two);
864 const T scale = hi > one ? hi : one;
865 if (T(hi - lo) <= T(tol * scale))
break;
867 return T((lo + hi) / two);
889 if (d.
trace.size() < 2)
890 throw InputError(
"dist_is_nhpp: the trace needs at least two inter-arrival times to test");
891 std::vector<T> epochs;
892 epochs.reserve(d.
trace.size());
894 for (std::size_t i = 0; i < d.
trace.size(); ++i) {
895 acc = T(acc + d.
trace[i]);
896 epochs.push_back(acc);
Minimal-order acyclic phase-type fit of the first three moments (matlab/lib/kpctoolbox/aph/aph_fit....
NumericError(const std::string &what)
UnsupportedError(const std::string &what)
Equilibrium distribution of a discrete-time Markov chain, and stochastic complementation.
The exception types the port throws.
Matrix exponential by scaling and squaring with a diagonal Pade approximant.
Kolmogorov-Smirnov tests for a non-homogeneous Poisson arrival process.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Transient distribution of a level-independent-in-the-tail QBD by an adaptive Taylor series (libQBD QB...
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
NhppKsResult< Tv > infer_nhpp_ks(const std::vector< Tv > ×, const Tv &T, const std::function< Tv(const Tv &)> &cumRate=std::function< Tv(const Tv &)>(), NhppKsMethod method=NhppKsMethod::Lewis, const Tv &T0=num_traits< Tv >::from_int(0))
Kolmogorov-Smirnov tests for a non-homogeneous Poisson arrival process.
mam::Map< T > dist_to_map(const Distrib< T > &d)
T dist_quantile(const Distrib< T > &d, const T &p)
The p-quantile, by bisection on dist_cdf.
infer::NhppKsResult< T > dist_is_nhpp(const Distrib< T > &d)
Port of Replayer.isNHPP: test whether a trace is a sample path of a NON-HOMOGENEOUS POISSON process,...
T dist_lst(const Distrib< T > &d, const T &s)
sn.lst: the Laplace-Stieltjes transform E[exp(-sX)].
unsigned convert_to_map_phases(double scv)
The number of Erlang phases convertToMAP picks for a non-Markovian distribution: 20 when the SCV is b...
T dist_cdf(const Distrib< T > &d, const T &x)
F(x) = P{X <= x}, MATLAB's Distribution.evalCDF.
std::vector< T > dist_pie(const Distrib< T > &d)
sn.pie: the phase distribution seen by an arriving job.
@ NORMAL
A Gaussian, and the ONE family whose value is not MATLAB's, because MATLAB has none to copy: ProcessT...
void dmap_refresh_moments(Distrib< T > &d)
The first two moments of a DISCRETE-time MAP, from its own law.
bool process_is_markovian(ProcessType p)
ProcessType.isMarkovian: true when sn.proc carries an exact matrix representation of the law,...
void dist_refresh_moments(Distrib< T > &d)
Fill in the first two moments of a distribution given by its matrices.
void reject_prior(const char *who)
The (D0,D1) pair that reaches sn.proc.
T dist_moment(const Distrib< T > &d, unsigned k)
The k-th raw moment.
double gammainc_lower(double a, double x)
Regularized lower incomplete gamma P(a, x), MATLAB's gammainc(x, a, 'lower').
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
AphFitResult< T > aph_fit(const T &e1, const T &e2, const T &e3, unsigned nmax, const T &tol)
Fit an APH(n) with n <= nmax to the raw moments e1, e2, e3.
Map< T > map_erlang(const T &mean, unsigned k)
Erlang-k renewal MAP with the given mean (map_erlang.m).
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
T map_scv(const Map< T > &m)
Squared coefficient of variation.
T map_moment(const Map< T > &m, unsigned k)
Raw moment of order k of the inter-arrival time: k!
std::vector< T > dtmc_solve(const Matrix< T > &P)
Stationary distribution of a stochastic matrix P.
void lu_solve(const Matrix< T > &LU, const std::vector< std::size_t > &piv, std::vector< T > &b)
Solve LUx = Pb in place on b, using the factors from lu_factor.
std::vector< std::size_t > lu_factor(Matrix< T > &A)
In-place LU of A (n x n).
Matrix< T > expm(const Matrix< T > &A)
Matrix exponential exp(A).
Number-type abstraction for the templated API port.
Adaptive quadrature for the qsys functions whose MATLAB originals call integral(),...
bool has_map() const
True when the type carries a (D0,D1) pair of its own.
Matrix< T > D0
The (D0,D1) pair when the type carries one directly.
std::vector< T > params
Constructor arguments, in MATLAB getParam order.
std::vector< T > trace
Replayer / Trace samples; empty for every other type.
static constexpr double FineTol
static constexpr double CoarseTol
A MAP as the pair of matrices (D0, D1).