LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
mfq_ld_mean.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_MAM_MFQ_LD_MEAN_H
6#define LINE_API_MAM_MFQ_LD_MEAN_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * Stationary mean fluid level E[X] of a first- or second-order level-dependent
12 * (multi-regime) Markovian fluid queue, in closed form from the
13 * matrix-exponential building blocks.
14 *
15 * Port of matlab/src/api/mam/mfq_ld_mean.m and the BUTools
16 * LevelDependentFluidStationaryMean it wraps. Its inputs are exactly the
17 * outputs of mfq_ld_solve, and it calls nothing else, so it is complete on its
18 * own terms: a caller holding the blocks from any source can use it.
19 *
20 * THE DENSITY. Over regime k, that is over the level interval
21 * [T(k), T(k+1)], the stationary density is the sum of a forward and a backward
22 * matrix exponential,
23 *
24 * pi_k(x) = iniF_k exp(KF_k (x - T(k))) cloF_k
25 * + iniB_k exp(KB_k (T(k+1) - x)) cloB_k,
26 *
27 * one anchored at each end of the regime, plus point masses at the K+1
28 * thresholds. E[X] is then the mass contribution sum_j T(j) masses_j e plus
29 * the integral of x pi_k(x) over each regime.
30 *
31 * THE INTEGRALS. Both regime integrals reduce to
32 * J0 = int_0^L exp(M u) du and J1 = int_0^L u exp(M u) du,
33 * which are read off ONE matrix exponential of the nilpotent augmentation
34 *
35 * A = [ M I 0 ; 0 0 I ; 0 0 0 ], W = exp(A L),
36 * J0 = W(1:n, n+1:2n), J1 = L J0 - W(1:n, 2n+1:3n).
37 *
38 * That form is used rather than the obvious M^-1 (exp(M L) - I) because KF and
39 * KB are SINGULAR whenever a regime has a zero-drift direction, which is the
40 * normal case and not an edge case; the augmentation never inverts anything and
41 * is exact for a singular M. The forward integral is anchored at T(k), giving
42 * the weight T(k) J0 + J1, and the backward one runs the other way, giving
43 * T(k+1) J0 - J1.
44 *
45 * ARITHMETIC. Gated on num_traits<T>::has_transcendental because it calls expm,
46 * which is a tolerance-controlled Pade approximation in any arithmetic. The
47 * rest is finite exact linear algebra.
48 */
49
50#include <cstddef>
51#include <vector>
52
53#include "line/num/number.h"
54#include "line/util/error.h"
55#include "line/util/expm.h"
56#include "line/util/linalg.h"
57#include "line/util/matrix.h"
58
59namespace line {
60namespace mam {
61
62/**
63 * The matrix-exponential building blocks of a multi-regime fluid queue, the
64 * output of mfq_ld_solve. With K regimes there are K+1 point-mass vectors, at
65 * the levels 0 = T(0), T(1), ..., T(K).
66 */
67template <class T>
69 std::vector<std::vector<T>> masses; ///< K+1 point-mass vectors of length N
70 std::vector<std::vector<T>> iniF; ///< K forward initial vectors
71 std::vector<Matrix<T>> KF; ///< K forward matrix exponents
72 std::vector<Matrix<T>> cloF; ///< K forward closing matrices
73 std::vector<std::vector<T>> iniB; ///< K backward initial vectors
74 std::vector<Matrix<T>> KB; ///< K backward matrix exponents
75 std::vector<Matrix<T>> cloB; ///< K backward closing matrices
76 std::vector<T> Thr; ///< K regime thresholds T(1)..T(K)
77};
78
79namespace mfq_ld_detail {
80
81/**
82 * J0 = int_0^L exp(M u) du and J1 = int_0^L u exp(M u) du, from one matrix
83 * exponential of a nilpotent block augmentation. Valid for a singular M.
84 */
85template <class T>
86void exp_int_moments(const Matrix<T>& M, const T& L, Matrix<T>& J0, Matrix<T>& J1) {
87 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
88 const std::size_t n = M.rows();
89 Matrix<T> A(3 * n, 3 * n, zero);
90 for (std::size_t i = 0; i < n; ++i) {
91 for (std::size_t j = 0; j < n; ++j) A(i, j) = M(i, j);
92 A(i, n + i) = one;
93 A(n + i, 2 * n + i) = one;
94 }
95 const Matrix<T> W = expm(A, L);
96 J0 = Matrix<T>(n, n, zero);
97 J1 = Matrix<T>(n, n, zero);
98 for (std::size_t i = 0; i < n; ++i)
99 for (std::size_t j = 0; j < n; ++j) {
100 J0(i, j) = W(i, n + j);
101 J1(i, j) = L * W(i, n + j) - W(i, 2 * n + j);
102 }
103}
104
105} // namespace mfq_ld_detail
106
107/**
108 * Stationary mean fluid level of a level-dependent fluid queue.
109 *
110 * @param b the building blocks returned by mfq_ld_solve
111 */
112template <class T>
115 "mfq_ld_mean evaluates matrix exponentials");
116 const T zero = num_traits<T>::from_int(0);
117 const std::size_t K = b.Thr.size();
118 if (K == 0) throw InputError("mfq_ld_mean: at least one regime is required");
119 if (b.masses.size() != K + 1)
120 throw InputError("mfq_ld_mean: expected K+1 point-mass vectors");
121 if (b.iniF.size() != K || b.KF.size() != K || b.cloF.size() != K || b.iniB.size() != K ||
122 b.KB.size() != K || b.cloB.size() != K)
123 throw InputError("mfq_ld_mean: expected K forward and K backward blocks");
124 const std::size_t N = b.masses[0].size();
125
126 // Thresholds with the implicit zero at the front: T(0) = 0.
127 std::vector<T> Tv(K + 1, zero);
128 for (std::size_t k = 0; k < K; ++k) Tv[k + 1] = b.Thr[k];
129
130 T res = zero;
131 // Contribution of the point masses, located at the levels T(0..K).
132 for (std::size_t j = 0; j <= K; ++j) {
133 if (b.masses[j].size() != N)
134 throw InputError("mfq_ld_mean: the point-mass vectors have different lengths");
135 T s = zero;
136 for (const T& v : b.masses[j]) s += v;
137 res += Tv[j] * s;
138 }
139 // Contribution of the continuous density in each regime.
140 const std::vector<T> h = ones<T>(N);
141 for (std::size_t k = 0; k < K; ++k) {
142 const T L = Tv[k + 1] - Tv[k];
143 Matrix<T> J0F, J1F, J0B, J1B;
144 mfq_ld_detail::exp_int_moments(b.KF[k], L, J0F, J1F);
145 mfq_ld_detail::exp_int_moments(b.KB[k], L, J0B, J1B);
146 Matrix<T> WF = J1F, WB = J1B;
147 for (std::size_t i = 0; i < WF.rows(); ++i)
148 for (std::size_t j = 0; j < WF.cols(); ++j) WF(i, j) += Tv[k] * J0F(i, j);
149 for (std::size_t i = 0; i < WB.rows(); ++i)
150 for (std::size_t j = 0; j < WB.cols(); ++j)
151 WB(i, j) = Tv[k + 1] * J0B(i, j) - WB(i, j);
152 {
153 const std::vector<T> t = vecmul(vecmul(b.iniF[k], WF), b.cloF[k]);
154 for (std::size_t j = 0; j < N; ++j) res += t[j] * h[j];
155 }
156 {
157 const std::vector<T> t = vecmul(vecmul(b.iniB[k], WB), b.cloB[k]);
158 for (std::size_t j = 0; j < N; ++j) res += t[j] * h[j];
159 }
160 }
161 return res;
162}
163
164} // namespace mam
165} // namespace line
166
167#endif // LINE_API_MAM_MFQ_LD_MEAN_H
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
The exception types the port throws.
Matrix exponential by scaling and squaring with a diagonal Pade approximant.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
Dense matrix and non-owning view.
T mfq_ld_mean(const LevelDependentFluidBlocks< T > &b)
Stationary mean fluid level of a level-dependent fluid queue.
std::vector< T > vecmul(const std::vector< T > &v, const Matrix< T > &A)
Row vector times matrix, v A.
Definition linalg.h:50
std::vector< T > ones(std::size_t n)
Column vector of ones, the ubiquitous e in MAP algebra.
Definition linalg.h:104
Matrix< T > expm(const Matrix< T > &A)
Matrix exponential exp(A).
Definition expm.h:141
Number-type abstraction for the templated API port.
The matrix-exponential building blocks of a multi-regime fluid queue, the output of mfq_ld_solve.
Definition mfq_ld_mean.h:68
std::vector< std::vector< T > > masses
K+1 point-mass vectors of length N.
Definition mfq_ld_mean.h:69
std::vector< T > Thr
K regime thresholds T(1)..T(K).
Definition mfq_ld_mean.h:76
std::vector< Matrix< T > > KF
K forward matrix exponents.
Definition mfq_ld_mean.h:71
std::vector< std::vector< T > > iniB
K backward initial vectors.
Definition mfq_ld_mean.h:73
std::vector< Matrix< T > > KB
K backward matrix exponents.
Definition mfq_ld_mean.h:74
std::vector< std::vector< T > > iniF
K forward initial vectors.
Definition mfq_ld_mean.h:70
std::vector< Matrix< T > > cloF
K forward closing matrices.
Definition mfq_ld_mean.h:72
std::vector< Matrix< T > > cloB
K backward closing matrices.
Definition mfq_ld_mean.h:75