5#ifndef LINE_API_QSYS_GGNM_DIFFUSION_H
6#define LINE_API_QSYS_GGNM_DIFFUSION_H
88T ggnm_phi(
const T& x) {
97T ggnm_Phi(
const T& x) {
107template <
class T,
class Ccdf>
108T ggnm_omega(Ccdf&& ccdf,
const T& ES,
double tol, std::size_t panels) {
109 T hi = num_traits<T>::from_int(1);
110 const T tolT = num_traits<T>::from_double(tol);
111 while (ccdf(hi) > tolT) {
112 hi *= num_traits<T>::from_int(2);
113 if (hi > num_traits<T>::from_double(1e12))
114 throw InputError(
"qsys_ggnm_diffusion: the service ccdf does not decay, so its "
115 "peakedness is undefined");
117 const T h = hi / num_traits<T>::from_int(
static_cast<long>(panels));
118 const T g0 = ccdf(num_traits<T>::from_int(0));
119 const T gn = ccdf(hi);
120 T sum = g0 * g0 + gn * gn;
121 for (std::size_t i = 1; i < panels; ++i) {
122 const T g = ccdf(T(num_traits<T>::from_int(
static_cast<long>(i)) * h));
123 sum += num_traits<T>::from_int(i % 2 == 1 ? 4 : 2) * g * g;
125 return (h / num_traits<T>::from_int(3) * sum) / ES;
145 const T& lambda,
const T& mu,
unsigned n,
double m,
const T& ca,
const T& cs,
146 const std::function<T(
const T&)>& serviceCcdf = std::function<T(
const T&)>(),
147 double tol = 1e-12, std::size_t panels = 4000) {
149 "qsys_ggnm_diffusion needs erfc, exp and a quadrature");
156 if (lambda <= zero || mu <= zero)
157 throw InputError(
"qsys_ggnm_diffusion: the arrival and service rates must be positive");
158 if (n < 1)
throw InputError(
"qsys_ggnm_diffusion: the number of servers n must be at least 1");
160 throw InputError(
"qsys_ggnm_diffusion: the number of extra waiting spaces m must be "
164 const T ca2 = ca * ca;
165 const T cs2 = cs * cs;
166 const T ES = one / mu;
167 const T rho = lambda / (nT * mu);
168 const T beta = sqrt(nT) * (one - rho);
169 const bool finiteRoom = std::isfinite(m);
173 const T omega = serviceCcdf ? detail::ggnm_omega<T>(serviceCcdf, ES, tol, panels)
175 const T z = one + (ca2 - one) * omega;
177 throw InputError(
"qsys_ggnm_diffusion: the asymptotic peakedness came out non-positive; "
178 "check ca and the service ccdf");
179 const T v = (ca2 + cs2) / two;
180 const T b = beta / sqrt(z);
181 const T r = beta / v;
185 const T tail = finiteRoom ? T(-expm1(-r * gamma)) : one;
186 T alpha, meanAbove, densityAtTop;
190 throw InputError(
"qsys_ggnm_diffusion: with beta = 0 the queue needs a finite waiting "
191 "room to be stable");
192 alpha = one / (one + detail::ggnm_Phi(b) / (detail::ggnm_phi(b) * gamma / sqrt(z)));
193 meanAbove = gamma / two;
194 densityAtTop = alpha / gamma;
196 alpha = one / (one + b * detail::ggnm_Phi(b) / (detail::ggnm_phi(b) * tail));
198 const T e = exp(-r * gamma);
199 meanAbove = (one / r - (gamma + one / r) * e) / tail;
200 densityAtTop = alpha * r * e / tail;
208 const T meanBelow = -beta - sqrt(z) * detail::ggnm_phi(b) / detail::ggnm_Phi(b);
209 const T meanScaled = (one - alpha) * meanBelow + alpha * meanAbove;
222 T pb = densityAtTop * v / sqrt(nT);
223 if (pb < zero) pb = zero;
224 if (pb > one) pb = one;
The exception types the port throws.
QsysGgnmResult< T > qsys_ggnm_diffusion(const T &lambda, const T &mu, unsigned n, double m, const T &ca, const T &cs, const std::function< T(const T &)> &serviceCcdf=std::function< T(const T &)>(), double tol=1e-12, std::size_t panels=4000)
Diffusion approximation for the G/GI/n/m queue.
Conservation laws of a layered queueing network, enumerated from its structure.
Number-type abstraction for the templated API port.
Shared return type and arithmetic helpers for the templated qsys port.
Steady-state measures of the G/GI/n/m diffusion approximation.
T throughput
lambda(1-P(block))
T trafficIntensity
rho = lambda/(n mu)
T meanWait
mean wait of an admitted arrival
T peakedness
z, the asymptotic peakedness
T variability
v = (ca^2+cs^2)/2
T meanQueueLength
mean number waiting
T peakednessWeight
omega_G
T probBlock
P(an arrival is blocked).
T probDelay
P(an arrival waits).
T gamma
the scaled waiting room m/sqrt(n)
T beta
the QED server slack sqrt(n)(1-rho)
T meanNumber
mean number in system