LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_mgc_ps.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_QSYS_MGC_PS_H
6#define LINE_API_QSYS_QSYS_MGC_PS_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * Exact analysis of the M/G/c processor-sharing queue.
12 *
13 * Port of matlab/src/api/qsys/qsys_mgc_ps.m. The queue-length law is
14 * insensitive and equals that of M/M/c: with A = lambda/mu, a = A/c and the
15 * Erlang C probability C,
16 *
17 * E[N] = C a/(1 - a) + A, Var[N] = a C (1 + a - a C)/(1 - a)^2 + A (1 + C),
18 *
19 * and E[T] = E[N]/lambda by Little's law. The distribution is the M/M/c law,
20 * normalized in log space and truncated where its geometric tail falls below
21 * 1e-14.
22 *
23 * ARITHMETIC: double, as the reference.
24 */
25
26#include <algorithm>
27#include <cmath>
28#include <string>
29#include <vector>
30
32#include "line/util/error.h"
33
34namespace line {
35namespace qsys {
36
37/**
38 * @brief Exact M/G/c-PS queue.
39 *
40 * @param lambda arrival rate
41 * @param mu service rate of one server
42 * @param c number of servers
43 */
44inline QsysRes qsys_mgc_ps(double lambda, double mu, unsigned c) {
45 using namespace resdetail;
46 if (!(lambda > 0.0)) throw Error("qsys_mgc_ps: lambda must be a positive scalar");
47 if (!(mu > 0.0)) throw Error("qsys_mgc_ps: mu must be a positive scalar");
48 if (c < 1) throw Error("qsys_mgc_ps: c must be a positive integer");
49 const double A = lambda / mu;
50 const double a = A / c;
51 if (a >= 1.0) throw_unstable("qsys_mgc_ps", "lambda/(c mu)", a);
52 double B = 1.0;
53 for (unsigned k = 1; k <= c; ++k) B = A * B / (k + A * B);
54 const double C = c * B / (c - A * (1.0 - B));
55 const double EQ = C * a / (1.0 - a);
56 const double VQ = a * C * (1.0 + a - a * C) / ((1.0 - a) * (1.0 - a));
57 const double EN = EQ + A;
58 const double VN = VQ + A * (1.0 + C);
59 std::vector<double> logp(c + 1);
60 for (unsigned n = 0; n <= c; ++n) logp[n] = n * std::log(A) - gammaln(n + 1.0);
61 const double logpc = logp[c];
62 const double ntail = std::max(0.0, std::ceil(std::log(1e-14 * (1.0 - a)) / std::log(a)));
63 for (long j = 1; j <= static_cast<long>(ntail); ++j) logp.push_back(logpc + j * std::log(a));
64 std::vector<double> lognorm(logp.begin(), logp.begin() + c);
65 lognorm.push_back(logpc - std::log(1.0 - a));
66 double mx = lognorm[0];
67 for (double v : lognorm) mx = std::max(mx, v);
68 double s = 0.0;
69 for (double v : lognorm) s += std::exp(v - mx);
70 const double logP0 = -(mx + std::log(s));
71 std::vector<double> pn(logp.size());
72 for (std::size_t i = 0; i < logp.size(); ++i) pn[i] = std::exp(logp[i] + logP0);
73 QsysRes r;
74 r.set("meanQueueLength", EN);
75 r.set("varQueueLength", VN);
76 r.set("meanSojournTime", EN / lambda);
77 r.set("throughput", lambda);
78 r.set("utilization", a);
79 r.set("queueLengthDist", pn);
80 r.set("tailRatio", a);
81 r.analyzer = "exact:M/G/" + std::to_string(c) + "-PS";
82 return r;
83}
84
85} // namespace qsys
86} // namespace line
87
88#endif // LINE_API_QSYS_QSYS_MGC_PS_H
Error(const std::string &what)
Definition error.h:75
The exception types the port throws.
QsysResT< double > QsysRes
Definition qsys_res.h:96
QsysRes qsys_mgc_ps(double lambda, double mu, unsigned c)
Exact M/G/c-PS queue.
Definition qsys_mgc_ps.h:44
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
The res struct the exact queueing-system functions return, and the numeric helpers those functions sh...
std::string analyzer
Definition qsys_res.h:59
void set(const std::string &name, const T &v)
Sets (or overwrites) a scalar field.
Definition qsys_res.h:62