LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_mm1k_loss.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_MM1K_LOSS_H
6#define LINE_API_QSYS_QSYS_MM1K_LOSS_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * Blocking probability of the M/M/1/K queue.
12 *
13 * Templated port of matlab/src/api/qsys/qsys_mm1k_loss.m, cross-checked
14 * against jar/src/main/java/jline/api/qsys/Qsys_mm1k_loss.java (identical).
15 *
16 * rho = lambda/mu
17 * Ploss = (1-rho)/(1-rho^(K+1)) * rho^K
18 *
19 * Only integer powers appear, so this is exact for T = Rational. It is the
20 * closed form the Niu-Cooper transform-free M/G/1/K analysis collapses onto
21 * when the service is exponential, and qsys_mg1k_loss must reproduce it.
22 *
23 * The formula has a removable singularity at rho = 1, where the true value is
24 * 1/(K+1): the stationary law is uniform over 0..K, so the full state carries
25 * 1/(K+1) like every other. This port RAISED there until 2026-09-13, while
26 * MATLAB, the JAR and python all returned the limit, so the one caller that
27 * reaches a saturated M/M/1/K got an exception from C++ and a number from the
28 * other three. The limit is a rational, not an approximation, so it is exact
29 * for T = Rational as well.
30 */
31
32#include <cmath>
33
36#include "line/num/number.h"
37#include "line/util/error.h"
38
39namespace line {
40namespace qsys {
41
42template <class T>
45 T utilization; ///< rho = lambda/mu, the offered load (not the carried one)
46};
47
48/**
49 * @brief Blocking probability of the M/M/1/K queue.
50 *
51 * @param lambda arrival rate
52 * @param mu service rate
53 * @param K system capacity, jobs in service included, K >= 1
54 */
55template <class T>
56Mm1kLossResult<T> qsys_mm1k_loss(const T& lambda, const T& mu, unsigned K) {
57 if (K == 0) throw InputError("qsys_mm1k_loss: K must be at least 1");
58 const T one = num_traits<T>::from_int(1);
59 const T rho = lambda / mu;
61 r.utilization = rho;
62 // The removable singularity, taken as the reference takes it. The tolerance
63 // matches qsys_mm1k_loss.m; on an exact T the subtraction is exact and the
64 // test fires only at rho = 1 itself.
65 if (std::fabs(num_traits<T>::to_double(rho) - 1.0) < lang::GlobalConstants::FineTol) {
66 r.lossProbability = one / num_traits<T>::from_int(static_cast<int>(K) + 1);
67 return r;
68 }
69 r.lossProbability = (one - rho) / (one - num_pow_int(rho, K + 1)) * num_pow_int(rho, K);
70 return r;
71}
72
73} // namespace qsys
74} // namespace line
75
76#endif // LINE_API_QSYS_QSYS_MM1K_LOSS_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Mm1kLossResult< T > qsys_mm1k_loss(const T &lambda, const T &mu, unsigned K)
Blocking probability of the M/M/1/K queue.
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
T num_pow_int(const T &base, unsigned e)
Integer power, valid in any field (no transcendental requirement).
Definition number.h:218
Number-type abstraction for the templated API port.
Shared return type and arithmetic helpers for the templated qsys port.
static constexpr double FineTol
Definition lang_types.h:760
T utilization
rho = lambda/mu, the offered load (not the carried one)