LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_gig1_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_GIG1_APPROX_WHITT_H
6#define LINE_API_QSYS_GIG1_APPROX_WHITT_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * Whitt's approximation of the G/G/1 mean response time.
12 *
13 * Port of `qsys_gig1_approx_whitt` in
14 * python/line_solver/api/qsys/approximations.py. PYTHON-ONLY, and its own
15 * docstring says so: there is no `qsys_gig1_approx_whitt.m`.
16 *
17 * It is the Kingman diffusion form `Lq = rho^2 (ca^2 + cs^2) / (2 (1 - rho))`
18 * multiplied by a CORRECTION FACTOR phi. The correction is what distinguishes
19 * it: Kingman's form is an upper bound that is loose when the arrival stream is
20 * more regular than Poisson, and phi discounts it exactly there.
21 *
22 * PHI IS PIECEWISE AND ONLY TWO OF ITS FOUR ARMS DO ANYTHING. With both
23 * variability parameters at or below one -- the regular regime where Kingman is
24 * loosest -- phi is an exponential discount in `(1 - ca^2)^2`. With a bursty
25 * arrival stream and regular service it is a milder discount. In the two arms
26 * where the SERVICE is bursty, `cs^2 > 1`, phi is exactly one and the
27 * approximation falls back to Kingman: the correction has nothing to offer
28 * there, and pretending otherwise would be an invented formula.
29 *
30 * An unstable queue returns an infinite response time and a unit utilization
31 * rather than dividing by a non-positive `1 - rho`.
32 *
33 * ARITHMETIC: transcendental (phi is an exponential).
34 */
35
36#include <cmath>
37#include <limits>
38
40#include "line/num/number.h"
41
42namespace line {
43namespace qsys {
44
45/**
46 * @brief Whitt's approximation of the G/G/1 mean response time.
47 *
48 * @param lambda arrival rate
49 * @param mu service rate
50 * @param ca coefficient of variation of the interarrival time
51 * @param cs coefficient of variation of the service time
52 */
53template <class T>
54QsysResult<T> qsys_gig1_approx_whitt(const T& lambda, const T& mu, const T& ca, const T& cs) {
56 "qsys_gig1_approx_whitt needs exp() for the correction factor");
57 const T one = num_traits<T>::from_int(1);
58 const T two = num_traits<T>::from_int(2);
59 const T three = num_traits<T>::from_int(3);
60 const T four = num_traits<T>::from_int(4);
61 const T rho = lambda / mu;
62 if (!(num_traits<T>::to_double(one - rho) > 0.0)) {
63 // Unstable: the queue has no stationary response time, and the
64 // reference reports that rather than dividing.
65 return {num_traits<T>::from_double(std::numeric_limits<double>::infinity()), one};
66 }
67
68 const T ca2 = ca * ca, cs2 = cs * cs;
69 const double ca2d = num_traits<T>::to_double(ca2), cs2d = num_traits<T>::to_double(cs2);
70 T phi = one;
71 if (ca2d <= 1.0 && cs2d <= 1.0) {
72 const T e = T(-two * (one - rho) * (one - ca2) * (one - ca2) / (three * rho * (ca2 + cs2)));
74 } else if (ca2d > 1.0 && cs2d <= 1.0) {
75 const T e = T(-(one - rho) * (ca2 - one) / (ca2 + four * cs2));
77 }
78 // Both remaining arms leave phi at one: with bursty service the correction
79 // has nothing to add and this IS Kingman.
80
81 const T Lq = T(phi * rho * rho * (ca2 + cs2) / (two * (one - rho)));
82 const T L = T(Lq + rho);
83 const T W = T(L / lambda);
84 return {W, detail::rhohat_from_W(W, lambda)};
85}
86
87} // namespace qsys
88} // namespace line
89
90#endif // LINE_API_QSYS_GIG1_APPROX_WHITT_H
QsysResult< T > qsys_gig1_approx_whitt(const T &lambda, const T &mu, const T &ca, const T &cs)
Whitt's approximation of the G/G/1 mean response time.
Number-type abstraction for the templated API port.
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