5#ifndef LINE_API_QSYS_GGINGI_TGA_H
6#define LINE_API_QSYS_GGINGI_TGA_H
76T tga_phi(
const T& x) {
85T tga_Phi(
const T& x) {
92template <
class T,
class Fn>
93T tga_simpson(Fn&& f,
const T& a,
const T& b, std::size_t m = 2000) {
94 const T zero = num_traits<T>::from_int(0);
95 if (b <= a)
return zero;
96 const T h = (b - a) / num_traits<T>::from_int(
static_cast<long>(m));
98 for (std::size_t i = 1; i < m; ++i)
99 sum += num_traits<T>::from_int(i % 2 == 1 ? 4 : 2) *
100 f(T(a + num_traits<T>::from_int(
static_cast<long>(i)) * h));
101 return h / num_traits<T>::from_int(3) * sum;
105template <
class T,
class Ccdf>
106T tga_inv_ccdf(Ccdf&& ccdf,
const T& target) {
107 const T two = num_traits<T>::from_int(2);
108 T lo = num_traits<T>::from_int(0), hi = num_traits<T>::from_int(1);
109 while (ccdf(hi) > target) {
111 if (hi > num_traits<T>::from_double(1e12))
112 throw InputError(
"qsys_ggingi_tga: the patience ccdf never falls to 1/rho, so the "
113 "overloaded model has no fluid equilibrium");
115 const T one = num_traits<T>::from_int(1);
116 const T tol = num_traits<T>::from_double(1e-12);
117 while (hi - lo > tol * (hi > one ? hi : one)) {
118 const T mid = (lo + hi) / two;
119 if (ccdf(mid) > target) {
125 return (lo + hi) / two;
130void tga_trunc_moments(
const T& a, T& m1, T& v) {
131 const T one = num_traits<T>::from_int(1);
132 const T Pa = tga_Phi(a);
133 const T pa = tga_phi(a);
134 m1 = pa - a * (one - Pa);
135 const T m2 = Pa - a * pa + a * a * (one - Pa);
137 if (v < num_traits<T>::from_int(0)) v = num_traits<T>::from_int(0);
156 const T& lambda,
const T& mu,
unsigned n,
const T& ca,
const T& cs,
157 const std::function<T(
const T&)>& patienceCcdf,
158 const std::function<T(
const T&)>& patiencePdf = std::function<T(
const T&)>(),
159 const std::function<T(
const T&)>& serviceCcdf = std::function<T(
const T&)>()) {
165 if (lambda <= zero || mu <= zero)
166 throw InputError(
"qsys_ggingi_tga: the arrival and service rates must be positive");
167 if (n < 1)
throw InputError(
"qsys_ggingi_tga: the number of servers n must be at least 1");
170 const T ca2 = ca * ca;
171 const T rho = lambda / (nT * mu);
172 const T lamPn = lambda / nT;
174 std::function<T(
const T&)> pdf = patiencePdf;
176 pdf = [&patienceCcdf](
const T& x) {
192 omega = detail::tga_simpson<T>([&](
const T& x) {
return T(serviceCcdf(x) * serviceCcdf(x)); },
200 r.
sigmaX = sqrt((lambda / mu) * (one + (ca2 - one) * omega));
205 const T w = detail::tga_inv_ccdf<T>(patienceCcdf, T(one / rho));
208 throw InputError(
"qsys_ggingi_tga: the patience density vanishes at the fluid waiting "
209 "time, so the Gaussian correction is undefined there");
210 const T qPerServer = lamPn * detail::tga_simpson<T>(patienceCcdf, zero, w);
213 const T sigmaW2 = ((ca2 - one) + (cs + one) * rho) / (two * mu * rho * rho * fw);
216 lamPn * detail::tga_simpson<T>(
217 [&](
const T& x) {
return T(patienceCcdf(x) * (one + (ca2 - one) * patienceCcdf(x))); },
219 r.
sigmaW = sqrt(sigmaW2 < zero ? zero : sigmaW2);
220 r.
sigmaX = sqrt(sigmaX2 < zero ? zero : sigmaX2);
222 const T aW = sqrt(nT) * w / r.
sigmaW;
223 const T aX = sqrt(nT) * qPerServer / r.
sigmaX;
225 detail::tga_trunc_moments(aW, m1W, vW);
226 detail::tga_trunc_moments(aX, m1X, vX);
231 r.
meanWait = w * (detail::tga_Phi(aW) + detail::tga_phi(aW) / aW);
233 r.
meanQueueLength = nT * qPerServer * (detail::tga_Phi(aX) + detail::tga_phi(aX) / aX);
237 nT - sqrt(nT) * r.
sigmaX * (detail::tga_phi(aX) - aX * (one - detail::tga_Phi(aX)));
244 T pa = detail::tga_simpson<T>(
245 [&](
const T& x) {
return T((one - detail::tga_Phi(T(aW * (x / w - one)))) * pdf(x)); }, zero,
247 if (pa < zero) pa = zero;
248 if (pa > one) pa = one;
The exception types the port throws.
QsysTgaResult< T > qsys_ggingi_tga(const T &lambda, const T &mu, unsigned n, const T &ca, const T &cs, const std::function< T(const T &)> &patienceCcdf, const std::function< T(const T &)> &patiencePdf=std::function< T(const T &)>(), const std::function< T(const T &)> &serviceCcdf=std::function< T(const T &)>())
Truncated Gaussian approximation (TGA-G) for the G/GI/n+GI queue.
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+GI truncated Gaussian approximation.
T sigmaW
the CLT scale of the wait
std::string regime
"underloaded" or "overloaded"
T meanNumberInService
E[B].
T trafficIntensity
rho = lambda/(n mu)
T meanNumber
E[X] = E[B] + E[Q].
T probAbandon
P(patience < wait).
T fluidWait
w, the fluid waiting time
T fluidQueueLength
the fluid queue content
T meanWait
E[W] after truncation.
T sigmaX
the CLT scale of the content
T meanQueueLength
E[Q] after truncation.