LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
qsys_phm1.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_PHM1_H
6
#define LINE_API_QSYS_QSYS_PHM1_H
7
8
/**
9
* @file
10
* @ingroup api_qsys
11
* Exact PH/M/1, the GI/M/1 queue with phase-type interarrival times.
12
*
13
* Templated port of matlab/src/api/qsys/qsys_phm1.m, cross-checked against
14
* jar/src/main/java/jline/api/qsys/Qsys_phm1.java.
15
*
16
* With psi_A(s) = alpha (sI - T)^-1 (-T e) the interarrival LST, sigma is the
17
* root in (0,1) of the GI/M/1 equation
18
*
19
* sigma = psi_A(mu(1 - sigma)),
20
*
21
* and then L = rho/(1-sigma), Lq = rho sigma/(1-sigma), Wq = Lq/lambda,
22
* W = Wq + 1/mu. Since psi_A is completely monotone and psi_A(0) = 1, the
23
* function f(sigma) = sigma - psi_A(mu(1-sigma)) is negative just above zero
24
* and positive just below one whenever rho < 1, so the bracket [0,1] always
25
* contains the root and bisection is unconditional. MATLAB brackets on
26
* [1e-12, 1-1e-12] with fzero and falls back to fixed-point iteration; the
27
* port bisects on the same bracket, which reaches the same root -- f is
28
* strictly increasing there -- without the fallback.
29
*
30
* ARITHMETIC. sigma is defined by a transcendental equation and reached by a
31
* tolerance-driven iteration, so the function is gated.
32
*
33
* At k = 1 with T = [-lambda] the arrival process is Poisson, psi_A is
34
* lambda/(s+lambda), the root is sigma = rho and every metric collapses onto
35
* the M/M/1 values. That identity is the sharpest available check on the port.
36
*/
37
38
#include <cstddef>
39
#include <vector>
40
41
#include "
line/api/qsys/qsys_types.h
"
42
#include "
line/num/number.h
"
43
#include "
line/util/error.h
"
44
#include "
line/util/linalg.h
"
45
#include "
line/util/lu.h
"
46
#include "
line/util/matrix.h
"
47
48
namespace
line
{
49
namespace
qsys
{
50
51
template
<
class
T>
52
struct
PhM1Result
{
53
T
meanQueueLength
;
///< L
54
T
meanWaitingQueue
;
///< Lq
55
T
meanWaitingTime
;
///< Wq
56
T
meanSojournTime
;
///< W
57
T
utilization
;
///< rho = lambda/mu
58
T
sigma
;
///< GI/M/1 root in (0,1)
59
};
60
61
namespace
detail {
62
63
/** psi_A(s) = alpha (sI - T)^-1 (-T e), the interarrival LST. */
64
template
<
class
T>
65
T ph_lst(
const
std::vector<T>& alpha,
const
Matrix<T>
& Tm,
const
T& s) {
66
const
std::size_t k = Tm.
rows
();
67
Matrix<T>
A(k, k);
68
for
(std::size_t i = 0; i < k; ++i)
69
for
(std::size_t j = 0; j < k; ++j) A(i, j) = (i == j ? s :
num_traits<T>::from_int
(0)) - Tm(i, j);
70
std::vector<T> t_vec(k,
num_traits<T>::from_int
(0));
71
for
(std::size_t i = 0; i < k; ++i)
72
for
(std::size_t j = 0; j < k; ++j) t_vec[i] -= Tm(i, j);
73
const
std::vector<T> y =
line::solve
(A, t_vec);
74
T out =
num_traits<T>::from_int
(0);
75
for
(std::size_t i = 0; i < k; ++i) out += alpha[i] * y[i];
76
return
out;
77
}
78
79
}
// namespace detail
80
81
/**
82
* @brief Exact PH/M/1, the GI/M/1 queue with phase-type interarrival times.
83
*
84
* @param alpha PH entry probability vector, length k
85
* @param Tm PH sub-generator, k x k
86
* @param mu exponential service rate
87
* @param tol width of the bisection bracket at which to stop (MATLAB's
88
* fzero stops at the double round-off level, so 1e-16 is the
89
* matching default)
90
*/
91
template
<
class
T>
92
PhM1Result<T>
qsys_phm1
(
const
std::vector<T>& alpha,
const
Matrix<T>
& Tm,
const
T& mu,
93
const
T& tol) {
94
static_assert
(
num_traits<T>::has_transcendental
,
95
"qsys_phm1 requires transcendental arithmetic"
);
96
const
T zero =
num_traits<T>::from_int
(0), one =
num_traits<T>::from_int
(1);
97
if
(mu <= zero)
throw
InputError
(
"qsys_phm1: service rate mu must be positive"
);
98
const
std::size_t k = Tm.
rows
();
99
if
(Tm.
cols
() != k)
throw
InputError
(
"qsys_phm1: T must be square"
);
100
if
(alpha.size() != k)
throw
InputError
(
"qsys_phm1: alpha length must match T dimension"
);
101
102
// Mean interarrival time = alpha (-T)^-1 e.
103
Matrix<T>
negT(k, k);
104
for
(std::size_t i = 0; i < k; ++i)
105
for
(std::size_t j = 0; j < k; ++j) negT(i, j) = -Tm(i, j);
106
const
std::vector<T> m =
line::solve
(negT,
ones<T>
(k));
107
T mean_ia = zero;
108
for
(std::size_t i = 0; i < k; ++i) mean_ia += alpha[i] * m[i];
109
if
(mean_ia <= zero)
throw
InputError
(
"qsys_phm1: non-positive mean interarrival time"
);
110
const
T lambda = one / mean_ia;
111
const
T rho = lambda / mu;
112
if
(rho >= one)
throw
InputError
(
"qsys_phm1: load rho must be strictly less than 1"
);
113
114
T a = T(
num_traits<T>::from_double
(1e-12));
115
T b = one - T(
num_traits<T>::from_double
(1e-12));
116
for
(
unsigned
it = 0; it < 4000u; ++it) {
117
if
(b - a <= tol)
break
;
118
const
T mid = (a + b) /
num_traits<T>::from_int
(2);
119
const
T f = mid - detail::ph_lst(alpha, Tm, T(mu * (one - mid)));
120
if
(f < zero)
121
a = mid;
122
else
123
b = mid;
124
}
125
const
T sigma = (a + b) /
num_traits<T>::from_int
(2);
126
127
PhM1Result<T>
r;
128
r.
sigma
= sigma;
129
r.
utilization
= rho;
130
r.
meanQueueLength
= rho / (one - sigma);
131
r.
meanWaitingQueue
= rho * sigma / (one - sigma);
132
r.
meanWaitingTime
= r.
meanWaitingQueue
/ lambda;
133
r.
meanSojournTime
= r.
meanWaitingTime
+ one / mu;
134
return
r;
135
}
136
137
/** qsys_phm1 with the fzero-equivalent default bracket tolerance. */
138
template
<
class
T>
139
PhM1Result<T>
qsys_phm1
(
const
std::vector<T>& alpha,
const
Matrix<T>
& Tm,
const
T& mu) {
140
return
qsys_phm1
(alpha, Tm, mu, T(
num_traits<T>::from_double
(1e-16)));
141
}
142
143
}
// namespace qsys
144
}
// namespace line
145
146
#endif
// LINE_API_QSYS_QSYS_PHM1_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
error.h
The exception types the port throws.
linalg.h
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
lu.h
LU factorization with partial pivoting, templated on the number type.
matrix.h
Dense matrix and non-owning view.
line::qsys
Definition
qsys_bmapm1.h:58
line::qsys::qsys_phm1
PhM1Result< T > qsys_phm1(const std::vector< T > &alpha, const Matrix< T > &Tm, const T &mu, const T &tol)
Exact PH/M/1, the GI/M/1 queue with phase-type interarrival times.
Definition
qsys_phm1.h:92
line
Definition
aoi_dist2ph.h:52
line::solve
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.
Definition
lu.h:158
line::ones
std::vector< T > ones(std::size_t n)
Column vector of ones, the ubiquitous e in MAP algebra.
Definition
linalg.h:104
number.h
Number-type abstraction for the templated API port.
qsys_types.h
Shared return type and arithmetic helpers for the templated qsys port.
line::num_traits
Definition
number.h:111
line::qsys::PhM1Result
Definition
qsys_phm1.h:52
line::qsys::PhM1Result::sigma
T sigma
GI/M/1 root in (0,1).
Definition
qsys_phm1.h:58
line::qsys::PhM1Result::meanWaitingTime
T meanWaitingTime
Wq.
Definition
qsys_phm1.h:55
line::qsys::PhM1Result::utilization
T utilization
rho = lambda/mu
Definition
qsys_phm1.h:57
line::qsys::PhM1Result::meanSojournTime
T meanSojournTime
W.
Definition
qsys_phm1.h:56
line::qsys::PhM1Result::meanQueueLength
T meanQueueLength
L.
Definition
qsys_phm1.h:53
line::qsys::PhM1Result::meanWaitingQueue
T meanWaitingQueue
Lq.
Definition
qsys_phm1.h:54
include
line
api
qsys
qsys_phm1.h
Generated by
1.18.0