LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
qsys_tandem_lindley.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_TANDEM_LINDLEY_H
6
#define LINE_API_QSYS_QSYS_TANDEM_LINDLEY_H
7
8
/**
9
* @file
10
* @ingroup api_qsys
11
* Sample-path Lindley recursion along a tandem of single-server FCFS queues.
12
*
13
* Templated port of matlab/src/api/qsys/qsys_tandem_lindley.m. No JAR
14
* counterpart. Given the interarrival times A of N customers at the first
15
* station and the (N x K) service times S, it replays
16
*
17
* W(n+1,k) = max(W(n,k) + S(n,k) - G(n,k), 0)
18
*
19
* where G(n,k) is the interarrival gap SEEN AT STATION k. The coupling that
20
* makes this a tandem rather than K independent queues is the gap update
21
*
22
* G(n,k+1) = max(G(n,k) - W(n,k) - S(n,k), 0) + S(n+1,k),
23
*
24
* the interdeparture time of station k: customer n+1 either catches up with
25
* customer n, in which case the gap collapses to the service time of n+1 at
26
* station k, or it does not, and the residual gap survives. Nothing here is
27
* distributional, so the recursion holds for arbitrary service laws and is
28
* the reference any conditional-moment approximation is checked against.
29
*
30
* The last customer has no successor, so its row of G stays unset; MATLAB
31
* leaves it NaN and the port does the same rather than filling it with a
32
* value that has no meaning.
33
*
34
* Reference: S. Palomo, J. Pender, "Learning the Tandem Network Lindley
35
* Recursion", Proc. Winter Simulation Conference, 2021. Registered in
36
* .citations() as 'tandemlindley'.
37
*
38
* ARITHMETIC: additions, subtractions and comparisons only, so the exact
39
* instantiation replays the same sample path with no rounding at all.
40
*/
41
42
#include <cstddef>
43
#include <limits>
44
#include <string>
45
#include <vector>
46
47
#include "
line/num/number.h
"
48
#include "
line/util/error.h
"
49
#include "
line/util/matrix.h
"
50
51
namespace
line
{
52
namespace
qsys
{
53
54
/** Mirrors the struct MATLAB returns from qsys_tandem_lindley. */
55
template
<
class
T>
56
struct
TandemLindleyResult
{
57
Matrix<T>
W
;
///< (N x K) waiting time of each customer at each station
58
Matrix<T>
G
;
///< (N x K) gap seen at each station, last row unset (NaN)
59
Matrix<T>
T_
;
///< (N x K) sojourn time W + S
60
Matrix<T>
departure
;
///< (N x K) departure epoch from each station
61
std::string
analyzer
;
62
};
63
64
/**
65
* @brief Sample-path Lindley recursion along a tandem of single-server FCFS
66
* queues.
67
*
68
* @param A (N) interarrival times at the first station, finite nonnegative
69
* @param S (N x K) service times, finite nonnegative
70
* @param W0 (K) initial waiting times, one per station; empty means all zero
71
*/
72
template
<
class
T>
73
TandemLindleyResult<T>
qsys_tandem_lindley
(
const
std::vector<T>& A,
const
Matrix<T>
& S,
74
const
std::vector<T>& W0 = std::vector<T>()) {
75
const
T zero =
num_traits<T>::from_int
(0);
76
const
std::size_t N = A.size();
77
if
(N < 1)
throw
InputError
(
"qsys_tandem_lindley: A must hold at least one interarrival time"
);
78
if
(S.
rows
() != N)
79
throw
InputError
(
"qsys_tandem_lindley: S must have one row per interarrival time"
);
80
const
std::size_t K = S.
cols
();
81
if
(K < 1)
throw
InputError
(
"qsys_tandem_lindley: S must have at least one column"
);
82
for
(std::size_t n = 0; n < N; ++n) {
83
if
(A[n] < zero)
84
throw
InputError
(
"qsys_tandem_lindley: A must hold nonnegative interarrival times"
);
85
for
(std::size_t k = 0; k < K; ++k)
86
if
(S(n, k) < zero)
87
throw
InputError
(
"qsys_tandem_lindley: S must hold nonnegative service times"
);
88
}
89
std::vector<T> w0 = W0;
90
if
(w0.empty()) w0.assign(K, zero);
91
if
(w0.size() != K)
92
throw
InputError
(
"qsys_tandem_lindley: W0 must hold one waiting time per station"
);
93
for
(std::size_t k = 0; k < K; ++k)
94
if
(w0[k] < zero)
95
throw
InputError
(
"qsys_tandem_lindley: W0 must hold nonnegative waiting times"
);
96
97
TandemLindleyResult<T>
r;
98
r.
analyzer
=
"qsys_tandem_lindley"
;
99
r.
W
=
Matrix<T>
(N, K, zero);
100
// the last customer has no successor, so its gap row is undefined
101
r.
G
=
Matrix<T>
(N, K,
num_traits<T>::from_double
(std::numeric_limits<double>::quiet_NaN()));
102
for
(std::size_t k = 0; k < K; ++k) r.
W
(0, k) = w0[k];
103
104
for
(std::size_t n = 0; n + 1 < N; ++n) {
105
T gap = A[n];
106
for
(std::size_t k = 0; k < K; ++k) {
107
r.
G
(n, k) = gap;
108
const
T adv = r.
W
(n, k) + S(n, k);
109
r.
W
(n + 1, k) = (adv > gap) ? T(adv - gap) : zero;
110
const
T residual = (gap > adv) ? T(gap - adv) : zero;
111
gap = residual + S(n + 1, k);
112
}
113
}
114
115
r.
T_
=
Matrix<T>
(N, K, zero);
116
for
(std::size_t n = 0; n < N; ++n)
117
for
(std::size_t k = 0; k < K; ++k) r.
T_
(n, k) = r.
W
(n, k) + S(n, k);
118
119
r.
departure
=
Matrix<T>
(N, K, zero);
120
T epoch = zero;
121
for
(std::size_t n = 0; n < N; ++n) {
122
if
(n > 0) epoch += A[n - 1];
123
r.
departure
(n, 0) = epoch + r.
T_
(n, 0);
124
for
(std::size_t k = 1; k < K; ++k)
125
r.
departure
(n, k) = r.
departure
(n, k - 1) + r.
T_
(n, k);
126
}
127
return
r;
128
}
129
130
}
// namespace qsys
131
}
// namespace line
132
133
#endif
// LINE_API_QSYS_QSYS_TANDEM_LINDLEY_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::Matrix
Matrix()
Definition
matrix.h:58
line::Matrix::rows
std::size_t rows() const
Definition
matrix.h:89
error.h
The exception types the port throws.
matrix.h
Dense matrix and non-owning view.
line::qsys
Definition
qsys_bmapm1.h:58
line::qsys::qsys_tandem_lindley
TandemLindleyResult< T > qsys_tandem_lindley(const std::vector< T > &A, const Matrix< T > &S, const std::vector< T > &W0=std::vector< T >())
Sample-path Lindley recursion along a tandem of single-server FCFS queues.
Definition
qsys_tandem_lindley.h:73
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
line::num_traits
Definition
number.h:111
line::qsys::TandemLindleyResult
Mirrors the struct MATLAB returns from qsys_tandem_lindley.
Definition
qsys_tandem_lindley.h:56
line::qsys::TandemLindleyResult::T_
Matrix< T > T_
(N x K) sojourn time W + S
Definition
qsys_tandem_lindley.h:59
line::qsys::TandemLindleyResult::departure
Matrix< T > departure
(N x K) departure epoch from each station
Definition
qsys_tandem_lindley.h:60
line::qsys::TandemLindleyResult::G
Matrix< T > G
(N x K) gap seen at each station, last row unset (NaN)
Definition
qsys_tandem_lindley.h:58
line::qsys::TandemLindleyResult::W
Matrix< T > W
(N x K) waiting time of each customer at each station
Definition
qsys_tandem_lindley.h:57
line::qsys::TandemLindleyResult::analyzer
std::string analyzer
Definition
qsys_tandem_lindley.h:61
include
line
api
qsys
qsys_tandem_lindley.h
Generated by
1.18.0