LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_mmcc.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_MMCC_H
6#define LINE_API_QSYS_QSYS_MMCC_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * Exact analysis of the M/M/c/c (Erlang loss) system.
12 *
13 * Port of matlab/src/api/qsys/qsys_mmcc.m. The blocking probability is the
14 * Erlang B formula by its stable recursion B_k = A B_{k-1} / (k + A B_{k-1});
15 * the occupancy is the truncated Poisson law, normalized in log space. The
16 * result is insensitive to the service law beyond its mean.
17 *
18 * ARITHMETIC: double (gammaln, log-space normalization), as the reference.
19 */
20
21#include <cmath>
22#include <string>
23#include <vector>
24
26#include "line/util/error.h"
27
28namespace line {
29namespace qsys {
30
31/**
32 * @brief Exact M/M/c/c Erlang loss system.
33 *
34 * @param lambda arrival rate
35 * @param mu service rate of one server
36 * @param c number of servers
37 */
38inline QsysRes qsys_mmcc(double lambda, double mu, unsigned c) {
39 using namespace resdetail;
40 if (!(lambda > 0.0)) throw Error("qsys_mmcc: lambda must be a positive scalar");
41 if (!(mu > 0.0)) throw Error("qsys_mmcc: mu must be a positive scalar");
42 if (c < 1) throw Error("qsys_mmcc: c must be a positive integer");
43 const double A = lambda / mu;
44 double B = 1.0;
45 for (unsigned k = 1; k <= c; ++k) B = A * B / (k + A * B);
46 std::vector<double> logp(c + 1);
47 for (unsigned n = 0; n <= c; ++n) logp[n] = n * std::log(A) - gammaln(n + 1.0);
48 double mx = logp[0];
49 for (double v : logp) mx = std::max(mx, v);
50 std::vector<double> p(c + 1);
51 double s = 0.0;
52 for (unsigned n = 0; n <= c; ++n) s += (p[n] = std::exp(logp[n] - mx));
53 double EN2 = 0.0;
54 for (unsigned n = 0; n <= c; ++n) {
55 p[n] /= s;
56 EN2 += static_cast<double>(n) * n * p[n];
57 }
58 const double EN = A * (1.0 - B);
59 QsysRes r;
60 r.set("blockingProb", B);
61 r.set("throughput", lambda * (1.0 - B));
62 r.set("lostRate", lambda * B);
63 r.set("offeredTraffic", A);
64 r.set("carriedTraffic", EN);
65 r.set("overflowTraffic", A * B);
66 r.set("meanQueueLength", EN);
67 r.set("varQueueLength", EN2 - EN * EN);
68 r.set("utilization", EN / c);
69 r.set("meanSojournTime", 1.0 / mu);
70 r.set("queueLengthDist", p);
71 r.analyzer = "exact:M/M/" + std::to_string(c) + "/" + std::to_string(c);
72 return r;
73}
74
75} // namespace qsys
76} // namespace line
77
78#endif // LINE_API_QSYS_QSYS_MMCC_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_mmcc(double lambda, double mu, unsigned c)
Exact M/M/c/c Erlang loss system.
Definition qsys_mmcc.h:38
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...
void set(const std::string &name, const T &v)
Sets (or overwrites) a scalar field.
Definition qsys_res.h:62