LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
qsys_mg1k_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_MG1K_LOSS_H
6
#define LINE_API_QSYS_QSYS_MG1K_LOSS_H
7
8
/**
9
* @file
10
* @ingroup api_qsys
11
* Exact M/G/1/K loss probability, via the chain embedded at service-start
12
* epochs.
13
*
14
* Templated port of matlab/src/api/qsys/qsys_mg1k_loss.m, cross-checked
15
* against jar/src/main/java/jline/api/qsys/Qsys_mg1k_loss.java.
16
*
17
* The state is the number waiting immediately after a service start,
18
* q in {0,...,K-2}, and a_j is the probability of j Poisson arrivals during
19
* one service:
20
*
21
* q = 0 : both a_0 and a_1 lead to q' = 0, because after an empty departure
22
* the next service starts with the next arrival; j >= 2 gives
23
* q' = j-1;
24
* q >= 1: q' = q-1+j, with arrivals past the free capacity lost and
25
* aggregated in the last column.
26
*
27
* The loss probability then follows from renewal-reward,
28
*
29
* E[cycle] = E[S] + sigma_0 a_0/lambda, P_loss = 1 - 1/(rho + sigma_0 a_0),
30
*
31
* with sigma the stationary vector at service-start epochs.
32
*
33
* The service law is supplied as its density. Both the mean service time and
34
* the a_j are obtained by adaptive quadrature on [0, 1e4/lambda], exactly the
35
* truncation and the tolerances MATLAB's integral() is given (RelTol 1e-6,
36
* AbsTol 1e-10), and the a_j series is stopped at 1e-12 or after 1000 terms as
37
* in the reference. For an exponential density the result must reproduce
38
* qsys_mm1k_loss, and that identity is the sharpest available check on the
39
* embedded chain.
40
*
41
* ARITHMETIC. The quadrature and the exp in the Poisson weights make this
42
* transcendental. The chain itself -- row normalization and the stationary
43
* solve -- is finite field arithmetic, but it is fed by the quadrature, so the
44
* gate applies to the whole function.
45
*/
46
47
#include <cstddef>
48
#include <vector>
49
50
#include "
line/api/mc/dtmc_solve.h
"
51
#include "
line/api/qsys/qsys_quadrature.h
"
52
#include "
line/api/qsys/qsys_types.h
"
53
#include "
line/num/number.h
"
54
#include "
line/util/error.h
"
55
#include "
line/util/matrix.h
"
56
57
namespace
line
{
58
namespace
qsys
{
59
60
template
<
class
T>
61
struct
Mg1kLossResult
{
62
T
lossProbability
;
63
T
utilization
;
///< rho = lambda/mu with mu the reciprocal mean service time
64
};
65
66
namespace
detail {
67
68
/**
69
* Row-normalize P and repair the diagonal, MATLAB's dtmc_makestochastic. A row
70
* that sums to zero is replaced by a self-loop.
71
*/
72
template
<
class
T>
73
void
dtmc_makestochastic_inplace(
Matrix<T>
& P) {
74
const
T zero =
num_traits<T>::from_int
(0), one =
num_traits<T>::from_int
(1);
75
for
(std::size_t i = 0; i < P.
rows
(); ++i) {
76
T s = zero;
77
for
(std::size_t j = 0; j < P.
cols
(); ++j) s += P(i, j);
78
if
(s > zero) {
79
for
(std::size_t j = 0; j < P.
cols
(); ++j) P(i, j) /= s;
80
T off = zero;
81
for
(std::size_t j = 0; j < P.
cols
(); ++j)
82
if
(j != i) off += P(i, j);
83
T d = one - off;
84
if
(d < zero) d = zero;
85
if
(d > one) d = one;
86
P(i, i) = d;
87
}
else
{
88
for
(std::size_t j = 0; j < P.
cols
(); ++j) P(i, j) = zero;
89
P(i, i) = one;
90
}
91
}
92
}
93
94
}
// namespace detail
95
96
/**
97
* @brief Exact M/G/1/K loss probability, via the chain embedded at
98
* service-start epochs.
99
*
100
* @param lambda Poisson arrival rate
101
* @param density service-time density, callable as density(t) -> T
102
* @param K system capacity, jobs in service included, K >= 2
103
*/
104
template
<
class
T,
class
Density>
105
Mg1kLossResult<T>
qsys_mg1k_loss
(
const
T& lambda, Density&& density,
unsigned
K) {
106
static_assert
(
num_traits<T>::has_transcendental
,
107
"qsys_mg1k_loss requires transcendental arithmetic"
);
108
if
(K < 2)
throw
InputError
(
"qsys_mg1k_loss: K must be at least 2"
);
109
const
T zero =
num_traits<T>::from_int
(0), one =
num_traits<T>::from_int
(1);
110
const
T reltol = T(
num_traits<T>::from_double
(1e-6));
111
const
T abstol = T(
num_traits<T>::from_double
(1e-10));
112
const
T tmax = T(
num_traits<T>::from_double
(1e4)) / lambda;
113
114
const
T meanS = detail::num_integral<T>([&](
const
T& t) {
return
t * density(t); }, zero, tmax,
115
reltol, abstol);
116
if
(meanS <= zero)
throw
NumericError
(
"qsys_mg1k_loss: non-positive mean service time"
);
117
const
T mu = one / meanS;
118
119
// a_j = P(j Poisson arrivals during one service), j = 0, 1, ...
120
std::vector<T> a(K - 1, zero);
121
const
T stop = T(
num_traits<T>::from_double
(1e-12));
122
for
(
unsigned
j = 0; j <= 1000u; ++j) {
123
const
T aj = detail::num_integral<T>(
124
[&](
const
T& t) {
125
return
detail::num_exp(T(-lambda * t)) *
126
num_pow_int
(T(lambda * t), j) * density(t);
127
},
128
zero, tmax, reltol, abstol) /
129
num_factorial<T>
(j);
130
if
(j < a.size())
131
a[j] = aj;
132
else
133
a.push_back(aj);
134
if
(aj < stop)
break
;
135
}
136
137
// Embedded chain at service-start epochs, states q = 0..K-2.
138
const
std::size_t n = K - 1;
139
Matrix<T>
P(n, n, zero);
140
const
std::size_t last = n - 1;
141
P(0, 0) = a[0] + (a.size() > 1 ? a[1] : zero);
142
for
(std::size_t i = 1; i + 2 <= n; ++i) P(0, i) = i + 1 < a.size() ? a[i + 1] : zero;
143
if
(n >= 2) {
144
for
(std::size_t i = 0; i + 1 < n; ++i) P(1, i) = i < a.size() ? a[i] : zero;
145
}
146
for
(std::size_t r = 2; r < n; ++r)
147
for
(std::size_t col = r - 1; col + 1 < n; ++col) {
148
const
std::size_t j = col - r + 1;
149
P(r, col) = j < a.size() ? a[j] : zero;
150
}
151
// Last column absorbs everything the free capacity cannot take.
152
for
(std::size_t r = 0; r < n; ++r) {
153
T s = zero;
154
for
(std::size_t col = 0; col + 1 < n; ++col) s += P(r, col);
155
P(r, last) = one - s;
156
}
157
detail::dtmc_makestochastic_inplace(P);
158
const
std::vector<T> sigma =
mc::dtmc_solve
(P);
159
160
Mg1kLossResult<T>
r;
161
r.
utilization
= lambda / mu;
162
const
T carried = sigma[0] * a[0] + r.
utilization
;
163
if
(carried == zero)
throw
NumericError
(
"qsys_mg1k_loss: degenerate renewal cycle"
);
164
r.
lossProbability
= one - one / carried;
165
return
r;
166
}
167
168
}
// namespace qsys
169
}
// namespace line
170
171
#endif
// LINE_API_QSYS_QSYS_MG1K_LOSS_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
line::Matrix
Definition
matrix.h:56
line::Matrix::cols
std::size_t cols() const
Definition
matrix.h:90
line::Matrix::rows
std::size_t rows() const
Definition
matrix.h:89
line::NumericError::NumericError
NumericError(const std::string &what)
Definition
error.h:45
dtmc_solve.h
Equilibrium distribution of a discrete-time Markov chain, and stochastic complementation.
error.h
The exception types the port throws.
matrix.h
Dense matrix and non-owning view.
line::mc::dtmc_solve
std::vector< T > dtmc_solve(const Matrix< T > &P)
Stationary distribution of a stochastic matrix P.
Definition
dtmc_solve.h:106
line::qsys
Definition
qsys_bmapm1.h:58
line::qsys::qsys_mg1k_loss
Mg1kLossResult< T > qsys_mg1k_loss(const T &lambda, Density &&density, unsigned K)
Exact M/G/1/K loss probability, via the chain embedded at service-start epochs.
Definition
qsys_mg1k_loss.h:105
line
Definition
aoi_dist2ph.h:52
line::num_factorial
T num_factorial(unsigned n)
Factorial as a value of T.
Definition
number.h:184
line::num_pow_int
T num_pow_int(const T &base, unsigned e)
Integer power, valid in any field (no transcendental requirement).
Definition
number.h:192
number.h
Number-type abstraction for the templated API port.
qsys_quadrature.h
Adaptive quadrature for the qsys functions whose MATLAB originals call integral(),...
qsys_types.h
Shared return type and arithmetic helpers for the templated qsys port.
line::num_traits
Definition
number.h:111
line::qsys::Mg1kLossResult
Definition
qsys_mg1k_loss.h:61
line::qsys::Mg1kLossResult::utilization
T utilization
rho = lambda/mu with mu the reciprocal mean service time
Definition
qsys_mg1k_loss.h:63
line::qsys::Mg1kLossResult::lossProbability
T lossProbability
Definition
qsys_mg1k_loss.h:62
include
line
api
qsys
qsys_mg1k_loss.h
Generated by
1.18.0