5#ifndef LINE_API_QSYS_QSYS_MG1_SRPT_H
6#define LINE_API_QSYS_QSYS_MG1_SRPT_H
60 enum Kind { EXPONENTIAL, HYPEREXP2, ERLANG_MIX } kind = EXPONENTIAL;
69SrptFit<T> srpt_fit(
const T& mu,
const T& cs) {
70 const T one = num_traits<T>::from_int(1);
71 const T two = num_traits<T>::from_int(2);
72 const T half = num_traits<T>::from_rational(1, 2);
75 if (
num_abs(T(c2 - one)) < T(num_traits<T>::from_double(1e-9))) {
76 f.kind = SrptFit<T>::EXPONENTIAL;
80 }
else if (c2 > one) {
81 const T pr = half * (one + num_sqrt(T((c2 - one) / (c2 + one))));
82 f.kind = SrptFit<T>::HYPEREXP2;
85 f.r2 = two * (one - pr) * mu;
86 f.rate_min = num_min(f.r1, f.r2);
87 f.rate_max = f.r1 < f.r2 ? f.r2 : f.r1;
89 const double inv = 1.0 / num_traits<T>::to_double(c2);
90 const unsigned k =
static_cast<unsigned>(std::ceil(inv));
91 const T kt = num_traits<T>::from_int(
static_cast<long>(k));
92 const T pr = (one / (one + c2)) * (kt * c2 - num_sqrt(T(kt * (one + c2) - kt * kt * c2)));
93 f.kind = SrptFit<T>::ERLANG_MIX;
96 f.rate = (kt - pr) * mu;
105T log_factorial(
unsigned m) {
106 T s = num_traits<T>::from_int(0);
107 for (
unsigned j = 2; j <= m; ++j) {
109 s += log(num_traits<T>::from_int(
static_cast<long>(j)));
116T erlang_pdf(
unsigned n,
const T& rate,
const T& x) {
117 const T zero = num_traits<T>::from_int(0);
118 if (n == 0)
return zero;
119 const T t = rate * x;
120 const unsigned m = n - 1;
121 if (t <= zero)
return m == 0 ? rate : zero;
123 const T logp = num_traits<T>::from_int(
static_cast<long>(m)) * log(t) - t - log_factorial<T>(m);
124 return rate * num_exp(logp);
129T erlang_tail(
unsigned n,
const T& rate,
const T& x) {
130 const T zero = num_traits<T>::from_int(0);
131 if (n == 0)
return zero;
132 const T t = rate * x;
133 if (t <= zero)
return num_traits<T>::from_int(1);
136 const T logt = log(t);
137 for (
unsigned j = 0; j < n; ++j)
138 y += num_exp(T(num_traits<T>::from_int(
static_cast<long>(j)) * logt - t -
139 log_factorial<T>(j)));
144T srpt_pdf(
const SrptFit<T>& f,
const T& x) {
145 const T one = num_traits<T>::from_int(1);
147 case SrptFit<T>::EXPONENTIAL:
148 return f.rate * num_exp(T(-f.rate * x));
149 case SrptFit<T>::HYPEREXP2:
150 return f.p * f.r1 * num_exp(T(-f.r1 * x)) +
151 (one - f.p) * f.r2 * num_exp(T(-f.r2 * x));
153 return f.p * erlang_pdf(f.k - 1, f.rate, x) +
154 (one - f.p) * erlang_pdf(f.k, f.rate, x);
159T srpt_tail(
const SrptFit<T>& f,
const T& x) {
160 const T one = num_traits<T>::from_int(1);
162 case SrptFit<T>::EXPONENTIAL:
163 return num_exp(T(-f.rate * x));
164 case SrptFit<T>::HYPEREXP2:
165 return f.p * num_exp(T(-f.r1 * x)) + (one - f.p) * num_exp(T(-f.r2 * x));
167 return f.p * erlang_tail(f.k - 1, f.rate, x) +
168 (one - f.p) * erlang_tail(f.k, f.rate, x);
184 const std::vector<T>& cs) {
186 "qsys_mg1_srpt requires transcendental arithmetic");
187 detail::mg1_discipline_check(
"qsys_mg1_srpt", lambda, mu, cs);
188 const std::size_t K = lambda.size();
192 T lambda_total = zero;
193 for (
const T& v : lambda) lambda_total += v;
195 for (std::size_t i = 0; i < K; ++i) p[i] = lambda[i] / lambda_total;
197 std::vector<detail::SrptFit<T>> fits;
199 T rate_min = zero, rate_max = zero;
200 for (std::size_t r = 0; r < K; ++r) {
201 fits.push_back(detail::srpt_fit(mu[r], cs[r]));
202 if (r == 0 || fits[r].rate_min < rate_min) rate_min = fits[r].rate_min;
203 if (r == 0 || fits[r].rate_max > rate_max) rate_max = fits[r].rate_max;
205 if (rate_min <= zero)
throw NumericError(
"qsys_mg1_srpt: degenerate phase rate");
210 std::size_t N =
static_cast<std::size_t
>(std::ceil(200.0 * ratio));
211 if (N < 20000u) N = 20000u;
212 if (N > 2000000u) N = 2000000u;
214 std::vector<T> x(N + 1), fmix(N + 1, zero), Fbar(N + 1, zero);
215 for (std::size_t i = 0; i <= N; ++i)
218 for (std::size_t r = 0; r < K; ++r)
219 for (std::size_t i = 0; i <= N; ++i) {
220 fmix[i] += p[r] * detail::srpt_pdf(fits[r], x[i]);
221 Fbar[i] += p[r] * detail::srpt_tail(fits[r], x[i]);
224 std::vector<T> xf(N + 1), x2f(N + 1);
225 for (std::size_t i = 0; i <= N; ++i) {
226 xf[i] = x[i] * fmix[i];
227 x2f[i] = x[i] * x[i] * fmix[i];
229 std::vector<T> rho_x = detail::num_cumtrapz(x, xf);
230 for (T& v : rho_x) v *= lambda_total;
231 const std::vector<T> m2_x = detail::num_cumtrapz(x, x2f);
235 std::vector<T> denom(N + 1), invden(N + 1), ET(N + 1);
236 for (std::size_t i = 0; i <= N; ++i) {
237 const T d = one - rho_x[i];
238 denom[i] = d > floor_ ? d : floor_;
239 invden[i] = one / denom[i];
241 const std::vector<T> Res = detail::num_cumtrapz(x, invden);
242 for (std::size_t i = 0; i <= N; ++i)
243 ET[i] = lambda_total * (m2_x[i] + x[i] * x[i] * Fbar[i]) / (two * denom[i] * denom[i]) +
248 std::vector<T> integrand(N + 1);
249 for (std::size_t c = 0; c < K; ++c) {
250 for (std::size_t i = 0; i <= N; ++i) integrand[i] = ET[i] * detail::srpt_pdf(fits[c], x[i]);
251 r.
W[c] = detail::num_trapz(x, integrand);
253 r.
rhohat = detail::mg1_discipline_rhohat(lambda, r.
W);
NumericError(const std::string &what)
The exception types the port throws.
Mg1DisciplineResult< T > qsys_mg1_srpt(const std::vector< T > &lambda, const std::vector< T > &mu, const std::vector< T > &cs)
M/G/1 under SRPT (shortest remaining processing time), by the Schrage-Miller formula.
Number-type abstraction for the templated API port.
M/G/1 under SETF (shortest elapsed time first), the non-preemptive counterpart of FB/LAS.
Adaptive quadrature for the qsys functions whose MATLAB originals call integral(),...
Shared return type and arithmetic helpers for the templated qsys port.
std::vector< T > W
per-class mean response time
T rhohat
Q/(1+Q) with Q = sum_k lambda_k W_k.