5#ifndef LINE_API_FJ_FJ_TAIL_ORDSTAT_H
6#define LINE_API_FJ_FJ_TAIL_ORDSTAT_H
69T ge_cdf(
const T& x,
const T& alpha,
const T& beta) {
72 const T zero = num_traits<T>::from_int(0);
73 const T one = num_traits<T>::from_int(1);
74 if (!(x > zero))
return zero;
75 const T u = exp(alpha * log1p(-exp(-x / beta)));
76 if (!std::isfinite(num_traits<T>::to_double(u)))
return zero;
77 if (u < zero)
return zero;
78 if (u > one)
return one;
87T poissbin_upper(
const std::vector<T>& u, std::size_t kreq) {
88 const T zero = num_traits<T>::from_int(0);
89 const T one = num_traits<T>::from_int(1);
90 const std::size_t n = u.size();
91 std::vector<T> pmf(n + 1, zero);
93 for (std::size_t i = 0; i < n; ++i) {
94 for (std::size_t j = i + 1; j >= 1; --j)
95 pmf[j] = T(pmf[j] * (one - u[i]) + pmf[j - 1] * u[i]);
96 pmf[0] = T(pmf[0] * (one - u[i]));
99 for (std::size_t j = kreq; j <= n; ++j) acc += pmf[j];
118 std::size_t kreq = 0) {
120 "fj_tail_ordstat requires transcendental arithmetic: the generalized "
121 "exponential fit inverts a ratio of digamma and trigamma values");
130 if (ET.size() != VT.size())
131 throw InputError(
"fj_tail_ordstat: ET and VT must have the same number of entries");
132 if (ET.empty())
throw InputError(
"fj_tail_ordstat: ET must be nonempty");
135 if (p > one) p = T(p / hundred);
136 if (!(p > zero) || !(p < one))
137 throw InputError(
"fj_tail_ordstat: the percentile must lie strictly between 0 and 1");
138 for (std::size_t i = 0; i < ET.size(); ++i)
139 if (!(ET[i] > zero) || !(VT[i] > zero))
141 "fj_tail_ordstat: the task response time mean and variance must be positive");
143 const std::size_t nbranch = ET.size();
144 const std::size_t nsib = (nbranch == 1) ? (K < 1 ? 1 : K) : nbranch;
145 if (kreq == 0) kreq = nsib;
147 throw InputError(
"fj_tail_ordstat: the quorum must not exceed the branch count");
152 std::vector<T> et = ET, vt = VT;
153 if (nbranch == 1 && nsib > 1) {
154 et.assign(nsib, ET[0]);
155 vt.assign(nsib, VT[0]);
159 r.
alpha.assign(et.size(), zero);
160 r.
beta.assign(et.size(), zero);
161 for (std::size_t i = 0; i < et.size(); ++i)
162 detail::ge_fit(et[i], vt[i], r.
alpha[i], r.
beta[i]);
168 if (kreq == nsib)
return andjoin;
169 const T xhi = andjoin.
xp;
172 for (std::size_t i = 0; i < r.
alpha.size(); ++i) {
173 const T cand = -r.
beta[i] * log1p(-exp(log(p) / r.
alpha[i]));
174 if (!(xlo > zero) || cand < xlo) xlo = cand;
177 auto residual = [&](
const T& x) {
178 std::vector<T> u(r.
alpha.size(), zero);
179 for (std::size_t i = 0; i < r.
alpha.size(); ++i)
180 u[i] = detail::ge_cdf(x, r.
alpha[i], r.
beta[i]);
181 return T(detail::poissbin_upper(u, kreq) - p);
186 while (residual(xlo) > zero && xlo > tiny) xlo = T(xlo / two);
ForkTail black-box tail-latency approximation for fork-join requests.
ForkTailResult< T > fj_tail_forktail(const std::vector< T > &ET, const std::vector< T > &VT, const std::vector< T > &K=std::vector< T >(), const T &p_in=num_traits< T >::from_int(99), const std::vector< T > &P=std::vector< T >())
ForkTail black-box tail-latency approximation for fork-join requests.
ForkTailResult< T > fj_tail_ordstat(const std::vector< T > &ET, const std::vector< T > &VT, std::size_t K=1, const T &p_in=num_traits< T >::from_int(99), std::size_t kreq=0)
Tail latency of a k-of-n (QUORUM) fork-join request.
RootResult< T > root_brent(F f, const T &a0, const T &b0, const T &tol, unsigned maxiter=200)
Brent's method on a bracket with a sign change.
Outcome of a scalar solve.
T root
best estimate of the root
Mirrors MATLAB's [xp, alpha, beta] return list.
std::vector< T > beta
fitted scale parameters, one per branch
T xp
predicted p-th percentile of the request response time
std::vector< T > alpha
fitted shape parameters, one per branch