5#ifndef LINE_API_MAM_HYPEREXP_FIT_LONGTAIL_H
6#define LINE_API_MAM_HYPEREXP_FIT_LONGTAIL_H
72template <
class T,
class Ccdf>
73T hefit_quantile(Ccdf&& ccdf,
const T& prob) {
76 while (ccdf(hi) > prob) {
79 throw InputError(
"hyperexp_fit_longtail: the ccdf does not decay, so there is no tail "
83 for (
int i = 0; i < 200; ++i) {
84 const T mid = (lo + hi) / two;
85 if (ccdf(mid) > prob) {
91 return (lo + hi) / two;
105template <
class T,
class Ccdf>
109 "hyperexp_fit_longtail needs logarithms and exponentials");
114 const std::size_t k = cs.size();
115 if (k < 1)
throw InputError(
"hyperexp_fit_longtail: at least one component is required");
116 if (b <= one)
throw InputError(
"hyperexp_fit_longtail: the spacing b must exceed 1");
117 for (std::size_t i = 1; i < k; ++i)
118 if (!(cs[i] < cs[i - 1]))
119 throw InputError(
"hyperexp_fit_longtail: the fitting arguments must be strictly "
122 std::vector<T> p(k, zero), lam(k, zero);
123 for (std::size_t i = 0; i < k; ++i) {
126 T residC = ccdf(ci), residBC = ccdf(T(b * ci));
127 for (std::size_t j = 0; j < i; ++j) {
128 residC -= p[j] * exp(-lam[j] * ci);
129 residBC -= p[j] * exp(-lam[j] * b * ci);
132 if (residC <= zero || residBC <= zero || residC <= residBC)
133 throw InputError(
"hyperexp_fit_longtail: the residual ccdf is not positive and "
134 "decreasing at a fitting argument. The recursion needs the "
135 "arguments well separated, c_i/c_(i+1) >> b; widen decade, lower "
136 "k, or move c1 further into the tail");
137 lam[i] = log(residC / residBC) / ((b - one) * ci);
138 p[i] = residC * exp(lam[i] * ci);
142 for (std::size_t j = 0; j < i; ++j) rest -= p[j];
144 throw InputError(
"hyperexp_fit_longtail: the fitted components already carry all "
145 "the probability, so the last one has none left");
147 throw InputError(
"hyperexp_fit_longtail: the residual ccdf has gone non-positive "
148 "at the last fitting argument");
150 lam[i] = log(p[i] / residC) / ci;
153 throw InputError(
"hyperexp_fit_longtail: a non-positive rate came out of the fit; the "
154 "ccdf is not decaying fast enough for this many components");
157 auto fitted = [&](
const T& t) {
159 for (std::size_t j = 0; j < k; ++j) v += p[j] * exp(-lam[j] * t);
167 for (std::size_t j = 0; j < k; ++j) r.
mean += p[j] / lam[j];
172 const std::size_t gn = 20000;
175 for (std::size_t i = 1; i < gn; ++i)
179 for (std::size_t i = 0; i < k; ++i) {
180 for (
int j = 0; j < 2; ++j) {
181 const T t = j == 0 ? cs[i] : T(b * cs[i]);
182 const T target = ccdf(t);
184 const T e =
num_abs(T(fitted(t) - target)) / target;
193 for (
int i = 0; i < 200; ++i) {
195 const T target = ccdf(t);
197 const T e =
num_abs(T(fitted(t) - target)) / target;
213template <
class T,
class Ccdf>
215 const T& b,
const T& decade) {
217 if (k < 1)
throw InputError(
"hyperexp_fit_longtail: at least one component is required");
218 if (b <= one)
throw InputError(
"hyperexp_fit_longtail: the spacing b must exceed 1");
220 throw InputError(
"hyperexp_fit_longtail: the decade ratio must exceed the spacing b, or "
221 "the fitting arguments would interleave");
222 std::vector<T> cs(k);
224 for (std::size_t i = 1; i < k; ++i) cs[i] = cs[i - 1] / decade;
232template <
class T,
class Ccdf>
251template <
class T,
class Ccdf>
258 if (b <= one)
throw InputError(
"hyperexp_fit_longtail: the spacing b must exceed 1");
260 throw InputError(
"hyperexp_fit_longtail: the decade ratio must exceed the spacing b, or "
261 "the fitting arguments would interleave");
267 throw InputError(
"hyperexp_fit_longtail: the ccdf gives no usable range of time scales");
273 for (
long k = k0; k >= 2; --k) {
280 throw InputError(
"hyperexp_fit_longtail: no component count admits the recursion; the ccdf may "
281 "not be long-tailed enough for this scheme");
299template <
class T,
class Ccdf>
302 if (
opt.b <= one)
throw InputError(
"hyperexp_fit_longtail: the spacing b must exceed 1");
304 throw InputError(
"hyperexp_fit_longtail: the decade ratio must exceed the spacing b, or "
305 "the fitting arguments would interleave");
The exception types the port throws.
HyperexpLongtailResult< T > hyperexp_fit_longtail_k(Ccdf &&ccdf, std::size_t k, const T &c1, const T &b, const T &decade)
The recursion at a fixed component count.
HyperexpLongtailResult< T > hyperexp_fit_longtail_points(Ccdf &&ccdf, const std::vector< T > &cs, const T &b)
The recursion on GIVEN fitting arguments, the reference's hyperexp_fit_longtail_core with its points ...
HyperexpLongtailResult< T > hyperexp_fit_longtail(Ccdf &&ccdf, const T &b=num_traits< T >::from_rational(3, 2), const T &decade=num_traits< T >::from_int(4), const T &c1=num_traits< T >::from_int(0))
The fit with the component count chosen automatically: one per decade between the 0....
Conservation laws of a layered queueing network, enumerated from its structure.
Number-type abstraction for the templated API port.
The reference's name-value options: k, c1, b, decade, points (empty = unset).
std::size_t k
'k': component count, 0 = automatic
T c1
'c1': largest argument, <= 0 = 1e-6 quantile
std::vector< T > points
'points': explicit fitting arguments
Outcome of the long-tail hyperexponential fit.
T mean
mean of the fitted law
std::vector< T > lambda
rates, increasing
T coverageLow
c_k, the smallest constrained argument
T coverageHigh
b c_1, the largest
std::vector< T > points
the fitting arguments c_i
T maxRelError
worst relative error at the fitting arguments
std::vector< T > p
mixing probabilities, summing to 1
T maxRelErrorGrid
worst relative error on a log grid across the coverage
T targetMean
mean of the original law over the covered range