LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_gigk_approx_whitt.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_QSYS_GIGK_APPROX_WHITT_H
6#define LINE_API_QSYS_GIGK_APPROX_WHITT_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * Whitt (1993) approximation for the GI/G/k queue, eqs. (2.16)-(2.25).
12 *
13 * Templated port of matlab/src/api/qsys/qsys_gigk_approx_whitt.m.
14 *
15 * gamma = min(0.24, (1-rho)(k-1)(sqrt(4+5k)-2)/(16 k rho)) (2.17)
16 * phi1 = 1 + gamma (2.16)
17 * phi2 = 1 - 4 gamma (2.18)
18 * phi3 = phi2 exp(-2(1-rho)/(3 rho)) (2.20)
19 * phi4 = min(1, (phi1+phi3)/2) (2.21)
20 * psi = 1 if c2 >= 1 else phi4^(2(1-c2)) (2.22)
21 * phi = psi if ca^2 == cs^2
22 * = 4(ca^2-cs^2)/(4ca^2-3cs^2) phi1 + cs^2/(4ca^2-3cs^2) psi
23 * if ca^2 > cs^2 (2.25)
24 * = (cs^2-ca^2)/(2(ca^2+cs^2)) phi3 + (cs^2+3ca^2)/(2(ca^2+cs^2)) psi
25 * otherwise
26 * Wq = phi c2 Wq(M/M/k), c2 = (ca^2+cs^2)/2 (2.24)
27 *
28 * The equality branch is taken when |ca^2-cs^2| < 1e-12, exactly as in MATLAB
29 * and the JAR, so the port keeps that literal tolerance.
30 *
31 * DIVERGENCE: jar/.../Qsys_gigk_approx_whitt.java names its arguments ca2 and
32 * cs2 and uses them unsquared, i.e. it expects squared coefficients of
33 * variation, whereas MATLAB takes ca, cs and squares them internally. MATLAB
34 * is ground truth, so this port takes ca, cs. The JAR also returns {L,W,Q,U}
35 * instead of [W,rhohat].
36 *
37 * Reference: Whitt, W. (1993). Approximations for the GI/G/m queue.
38 * Production and Operations Management 2(2), 114-161.
39 *
40 * Carries sqrt, exp and a real-valued power, so it requires transcendental
41 * arithmetic and cannot be instantiated at T = Rational.
42 */
43
46#include "line/num/number.h"
47
48namespace line {
49namespace qsys {
50
51/**
52 * @brief Whitt (1993) approximation for the GI/G/k queue, eqs. (2.16)-(2.25).
53 *
54 * @param lambda arrival rate
55 * @param mu service rate of a single server
56 * @param ca coefficient of variation of the interarrival time
57 * @param cs coefficient of variation of the service time
58 * @param k number of servers, k >= 1
59 */
60template <class T>
61QsysResult<T> qsys_gigk_approx_whitt(const T& lambda, const T& mu, const T& ca, const T& cs,
62 unsigned k) {
64 "qsys_gigk_approx_whitt requires transcendental arithmetic");
65 const T one = num_traits<T>::from_int(1);
66 const T two = num_traits<T>::from_int(2);
67 const T three = num_traits<T>::from_int(3);
68 const T four = num_traits<T>::from_int(4);
69 const T kT = num_traits<T>::from_int(static_cast<long>(k));
70 const T ca2 = num_pow_int(ca, 2);
71 const T cs2 = num_pow_int(cs, 2);
72 const T rho = lambda / (kT * mu);
73
74 const T Wq_mmk = qsys_mmk(lambda, mu, k).W - one / mu;
75
76 const T gamma = detail::num_min(
78 (one - rho) * (kT - one) *
79 (detail::num_sqrt(T(four + num_traits<T>::from_int(5) * kT)) - two) /
80 (num_traits<T>::from_int(16) * kT * rho));
81 const T phi1 = one + gamma;
82 const T phi2 = one - four * gamma;
83 const T phi3 = phi2 * detail::num_exp(T(-two * (one - rho) / (three * rho)));
84 const T phi4 = detail::num_min(one, T((phi1 + phi3) / two));
85
86 const T c2 = (ca2 + cs2) / two;
87 T psi;
88 if (c2 >= one) {
89 psi = one;
90 } else {
91 psi = detail::num_pow(phi4, T(two * (one - c2)));
92 }
93
94 T phi;
95 if (num_abs(T(ca2 - cs2)) < num_traits<T>::from_double(1e-12)) {
96 phi = psi;
97 } else if (ca2 > cs2) {
98 phi = (four * (ca2 - cs2) / (four * ca2 - three * cs2)) * phi1 +
99 (cs2 / (four * ca2 - three * cs2)) * psi;
100 } else {
101 phi = ((cs2 - ca2) / (two * (ca2 + cs2))) * phi3 +
102 ((cs2 + three * ca2) / (two * (ca2 + cs2))) * psi;
103 }
104
105 const T Wq = phi * c2 * Wq_mmk;
106 const T W = Wq + one / mu;
107 return {W, detail::rhohat_from_W(W, lambda)};
108}
109
110} // namespace qsys
111} // namespace line
112
113#endif // LINE_API_QSYS_GIGK_APPROX_WHITT_H
QsysResult< T > qsys_gigk_approx_whitt(const T &lambda, const T &mu, const T &ca, const T &cs, unsigned k)
Whitt (1993) approximation for the GI/G/k queue, eqs.
QsysResult< T > qsys_mmk(const T &lambda, const T &mu, unsigned k)
Exact mean response time of the M/M/k queue (Erlang-C).
Definition qsys_mmk.h:60
T num_abs(const T &v)
Definition number.h:172
T num_pow_int(const T &base, unsigned e)
Integer power, valid in any field (no transcendental requirement).
Definition number.h:192
Number-type abstraction for the templated API port.
Exact mean response time of the M/M/k queue (Erlang-C).
Shared return type and arithmetic helpers for the templated qsys port.
Return value of the qsys family, mirroring MATLAB's [W,rhohat] and the JAR's Ret.qsys.
Definition qsys_types.h:37