5#ifndef LINE_API_MAM_MMPP2_FITC_H
6#define LINE_API_MAM_MMPP2_FITC_H
52T lambertw0(
const T& z,
unsigned max_iter) {
53 const T zero = num_traits<T>::from_int(0);
54 const T one = num_traits<T>::from_int(1);
55 const T two = num_traits<T>::from_int(2);
56 const T e = num_exp(one);
57 const T ez1 = e * z + one;
58 if (ez1 < zero)
throw NumericError(
"lambertw0: argument below the branch point -1/e");
59 if (z == zero)
return zero;
61 if (ez1 < num_traits<T>::from_double(0.3)) {
62 const T p = num_sqrt(T(two * ez1));
63 w = -one + p - p * p / num_traits<T>::from_int(3) +
64 num_traits<T>::from_int(11) * p * p * p / num_traits<T>::from_int(72);
65 }
else if (z > zero) {
66 w = num_log(T(one + z));
70 for (
unsigned it = 0; it < max_iter; ++it) {
71 const T ew = num_exp(w);
72 const T f = w * ew - z;
74 const T d1 = ew * (w + one);
76 const T dd = two * w + two;
78 if (dd != zero) den = d1 - (w + two) * f / dd;
79 if (den == zero || !(den == den))
break;
80 const T step = f / den;
82 if (
num_abs(step) <= num_traits<T>::from_double(1e-40) * (one +
num_abs(w)))
break;
103 const T& t1,
const T& t2) {
105 "mmpp2_fitc requires transcendental arithmetic");
106 using fitdetail::lambertw0;
107 using fitdetail::num_exp;
108 using fitdetail::num_sqrt;
119 if (mu <= zero)
throw InputError(
"mmpp2_fitc: non-positive arrival rate");
120 if (t1 <= zero || t2 <= zero)
throw InputError(
"mmpp2_fitc: non-positive time scale");
126 if ((
num_abs(T(binf - one)) < tiny &&
num_abs(T(binf - bt1)) < tiny) ||
127 !(binf > bt1 && bt1 > one)) {
133 const T c = (binf - one) / (binf - bt1);
134 const T zarg = -c * num_exp(T(-c));
135 const T w0 = lambertw0(zarg, 200u);
136 const T x = (w0 + c) / t1;
137 if (x <= zero)
throw NumericError(
"mmpp2_fitc: non-positive switching rate");
139 const T k1 = pw(mu, 3) * pw(t2, 3);
140 const T k2 = three * mu * mu * (binf - one) * t2 * t2;
141 const T k3 = three * mu * (binf - one) / x * t2;
142 const T k4 = three * mu / (x * x) * (binf - one) * t2 * num_exp(T(-x * t2));
143 const T k5 = six * mu / pw(x, 3) * (binf - one) * (one - num_exp(T(-x * t2)));
144 const T g1t2 = m3t2 + three * mu * t2 * (mu * t2 - one) * bt2 +
145 mu * t2 * (mu * t2 - one) * (mu * t2 - two);
146 const T hden = (k3 / x) + k4 - k5;
147 if (hden == zero)
throw NumericError(
"mmpp2_fitc: degenerate third-moment equation");
148 const T h = (g1t2 - k1 - k2 - k3 * (-mu) - k4 * mu * x) / hden;
154 const T d = half * num_sqrt(T(two * (binf - one) * mu * x));
158 const T y = (binf - one) * mu * pw(x, 3) / (two * h * h);
166 if (r1 == r2)
throw NumericError(
"mmpp2_fitc: degenerate switching rates");
167 const T wv = h / (r1 - r2);
168 const T w_min = -mu / r1 * (r1 + r2);
169 const T w_max = mu / r2 * (r1 + r2);
170 if (wv < w_min || wv > w_max) {
173 const T zz = (binf - one) * pw(x, 3) * mu;
174 const T u = x * zz / (two * mu * mu * x * x + zz);
175 r1 = u + (x - u) / two;
177 const T delta = num_sqrt(T(zz / (two * r1 * r2)));
178 l2 = mu - r2 / x * delta;
181 l2 = mu - h / (r1 - r2) * (r2 / (r1 + r2));
182 l1 = h / (r1 - r2) + l2;
189 m.
D0(0, 0) = -(r1 + l1);
192 m.
D0(1, 1) = -(r2 + l2);
NumericError(const std::string &what)
The exception types the port throws.
Scalar helpers shared by the MAP/PH moment-matching headers.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
Mmpp2FitcResult< T > mmpp2_fitc(const T &mu, const T &bt1, const T &bt2, const T &binf, const T &m3t2, const T &t1, const T &t2)
MMPP(2) from the arrival rate, the IDC at t1, t2 and infinity, and the third central moment of the co...
Map< T > map_exponential(const T &lambda)
Two-phase MAP constructor for a Poisson process of rate lambda.
Number-type abstraction for the templated API port.
A MAP as the pair of matrices (D0, D1).
bool degenerate
true when a Poisson process was returned instead
bool third_moment_ok
false when the third moment had to be dropped for feasibility