LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_mmk.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_MMK_H
6#define LINE_API_QSYS_MMK_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * Exact mean response time of the M/M/k queue (Erlang-C).
12 *
13 * Templated port of matlab/src/api/qsys/qsys_mmk.m, cross-checked against
14 * jar/src/main/java/jline/api/qsys/Qsys_mmk.java. The JAR accumulates the
15 * factorials incrementally and writes C = 1/(1+(1-rho)*(C*(C-1)!)/(C rho)^C*S),
16 * which is the same k! as MATLAB's factorial(k); the two agree.
17 *
18 * rho = lambda/(mu k)
19 * S = sum_{j=0}^{k-1} (k rho)^j / j!
20 * C = 1 / (1 + (1-rho) k! / (k rho)^k * S)
21 * Q = rho/(1-rho) C + k rho, W = Q/lambda
22 *
23 * Every exponent is an integer, so this stays in the field of the inputs and
24 * is exact for T = Rational.
25 */
26
28#include "line/num/number.h"
29#include "line/util/error.h"
30
31namespace line {
32namespace qsys {
33
34namespace detail {
35
36/**
37 * Erlang-C: the probability that an arriving customer finds all k servers
38 * busy. Argument rho is the per-server utilization lambda/(mu k).
39 */
40template <class T>
41T erlang_c(unsigned k, const T& rho) {
42 const T one = num_traits<T>::from_int(1);
43 const T krho = num_traits<T>::from_int(static_cast<long>(k)) * rho;
44 T S = num_traits<T>::from_int(0);
45 for (unsigned j = 0; j < k; ++j) S += num_pow_int(krho, j) / num_factorial<T>(j);
46 return one / (one + (one - rho) * num_factorial<T>(k) / num_pow_int(krho, k) * S);
47}
48
49} // namespace detail
50
51/**
52 * @brief Exact mean response time of the M/M/k queue (Erlang-C).
53 *
54 * @param lambda arrival rate
55 * @param mu service rate of a single server
56 * @param k number of servers, k >= 1
57 * @return W = mean response time, rhohat = rho = lambda/(mu k)
58 */
59template <class T>
60QsysResult<T> qsys_mmk(const T& lambda, const T& mu, unsigned k) {
61 if (k == 0) throw InputError("qsys_mmk: k must be at least 1");
62 const T one = num_traits<T>::from_int(1);
63 const T rho = lambda / mu / num_traits<T>::from_int(static_cast<long>(k));
64 detail::require_no_pole(T(one - rho), "qsys_mmk");
65 const T Q = rho / (one - rho) * detail::erlang_c(k, rho) +
66 num_traits<T>::from_int(static_cast<long>(k)) * rho;
67 const T W = Q / lambda;
68 return {W, rho};
69}
70
71} // namespace qsys
72} // namespace line
73
74#endif // LINE_API_QSYS_MMK_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
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_factorial(unsigned n)
Factorial as a value of T.
Definition number.h:184
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.
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