LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
fes_map_solve.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_FES_MAP_SOLVE_H
6#define LINE_API_FES_MAP_SOLVE_H
7
8/**
9 * @file
10 * @ingroup api_fes
11 * Closed model left by a MAP flow-equivalent server, and the per-station metrics
12 * behind it.
13 *
14 * Templated port of matlab/src/api/fes/fes_map_solve.m and
15 * fes_map_deaggregate.m, mirrored by the JAR and native Python.
16 *
17 * Closes the aggregation of Section 5.2.1 of Casale, Mi, Cherkasova and Smirni,
18 * IEEE Trans. Soft. Eng. 37(5), 2011. Once a subnetwork has been replaced by the
19 * load-dependent MAP of `fes_map_aggregate`, the model left is a delay holding the
20 * think times and one station, which is a finite level-dependent quasi birth-death
21 * process: level k is the number of jobs held by the flow-equivalent server and
22 * N-k jobs are thinking. The chain is the same block bidiagonal pair used to
23 * measure the inter-departure times, now read as a generator rather than as a MAP,
24 * so the delay is a station whose process is scaled by the number of jobs it holds
25 * and the marked transitions are the arrivals into the flow-equivalent server. The
26 * think time may itself be a MAP, which is how Section 5.3.1 models a bounded
27 * flash crowd.
28 *
29 * The de-aggregation conditions on the population of the aggregate,
30 * E[Y_i] = sum_k pk(k) Y_i(k), which is the decomposition step of Chandy, Herzog
31 * and Woo, IBM J. Res. Dev. 19(1), 1975: exact for a product-form subnetwork, an
32 * approximation when the burstiness the flow-equivalent server carries also
33 * matters inside it. The aggregate metrics do not rely on it.
34 *
35 * ARITHMETIC: field operations only, exact at T = Rational.
36 */
37
38#include <cstddef>
39#include <vector>
40
48#include "line/num/number.h"
49#include "line/util/error.h"
50#include "line/util/linalg.h"
51#include "line/util/matrix.h"
52
53namespace line {
54namespace fes {
55
56/** System metrics of the delay plus flow-equivalent server model. */
57template <class T>
59 T X; ///< system throughput
60 T R; ///< response time of the aggregated subnetwork, N/X - E[Z]
61 T Q; ///< mean jobs held by the flow-equivalent server
62 std::vector<T> pk; ///< law of the jobs held by the flow-equivalent server
63};
64
65/** Per-station metrics an aggregate stands for. */
66template <class T>
68 std::vector<T> Q;
69 std::vector<T> U;
70 std::vector<T> X;
71 std::vector<T> R;
72};
73
74/**
75 * @brief Closed model left by a MAP flow-equivalent server, and the
76 * per-station metrics behind it.
77 *
78 * @param fes flow-equivalent server, one MAP per level
79 * @param think_map think time process (Z0,Z1)
80 * @param n number of jobs in the closed model
81 */
82template <class T>
84 const mam::Map<T>& think_map, std::size_t n) {
85 if (n < 1) throw InputError("fes_map_solve: the population must be at least 1");
86 const std::vector<mam::Map<T>> fesLev = fes_map_levels(fes, n);
87 const std::vector<mam::Map<T>> think =
88 fes_map_levels(think_map, n, std::numeric_limits<double>::infinity());
89
90 const mam::Map<T> T01 = fes_map_interdeparture(think, fesLev, n);
91 const Matrix<T> Q = mam::map_infgen(T01);
92 const std::size_t dim = Q.rows();
93 const T zero = num_traits<T>::from_int(0);
94
95 const std::vector<T> phi = mc::ctmc_solve(Q);
96 const std::vector<T> phiT1 = vecmul(phi, T01.D1);
97
99 out.X = zero;
100 for (const T& v : phiT1) out.X += v;
101
102 const std::size_t blk = dim / (n + 1);
103 out.pk.assign(n + 1, zero);
104 out.Q = zero;
105 for (std::size_t k = 0; k <= n; ++k) {
106 T s = zero;
107 for (std::size_t j = 0; j < blk; ++j) s += phi[k * blk + j];
108 out.pk[k] = s;
109 out.Q += num_traits<T>::from_int(static_cast<long>(k)) * s;
110 }
111 out.R = num_traits<T>::from_int(static_cast<long>(n)) / out.X - mam::map_moment(think_map, 1);
112 return out;
113}
114
115/**
116 * @param pk law of the jobs held by the aggregate, index k = P(k jobs)
117 * @param L service demands of the isolated subnetwork
118 * @param mi servers per station, ignored where isDelay
119 * @param isDelay true where the station is a pure delay
120 */
121template <class T>
122FesMapDeaggregateResult<T> fes_map_deaggregate(const std::vector<T>& pk, const std::vector<T>& L,
123 const std::vector<int>& mi,
124 const std::vector<bool>& isDelay) {
125 const std::size_t M = L.size();
126 const std::size_t n = pk.size() - 1;
127 const T zero = num_traits<T>::from_int(0);
128
130 out.Q.assign(M, zero);
131 out.U.assign(M, zero);
132 out.X.assign(M, zero);
133 out.R.assign(M, zero);
134
135 std::vector<std::size_t> queueIdx;
136 T Z = zero;
137 for (std::size_t i = 0; i < M; ++i) {
138 if (isDelay[i]) {
139 Z += L[i];
140 } else {
141 queueIdx.push_back(i);
142 }
143 }
144 Matrix<T> Lq(queueIdx.size(), 1, zero);
145 std::vector<int> miq(queueIdx.size(), 1);
146 for (std::size_t j = 0; j < queueIdx.size(); ++j) {
147 Lq(j, 0) = L[queueIdx[j]];
148 miq[j] = mi[queueIdx[j]];
149 }
150 Matrix<T> Zm(1, 1, Z);
151
152 // The reference: pfqn_mvams(0, Lq, k, Z, ones, miq), i.e. the server
153 // counts go in the S slot (pfqn_mva's mi is a multiplicity, not a server
154 // count), and Uk = Xk Lq ./ max(1, miq).
155 const std::vector<T> lambda0(1, zero);
156 const std::vector<int> ones_m(queueIdx.size(), 1);
158 for (std::size_t k = 1; k <= n; ++k) {
159 if (pk[k] <= gzero) continue;
160 const std::vector<int> N(1, static_cast<int>(k));
161 const pfqn::MvaResult<T> r = pfqn::pfqn_mvams(lambda0, Lq, N, Zm, ones_m, miq);
162 const T Xk = r.XN[0];
163 for (std::size_t j = 0; j < queueIdx.size(); ++j) {
164 const int mj = miq[j] > 1 ? miq[j] : 1;
165 const T Uk = Xk * Lq(j, 0) / num_traits<T>::from_int(mj);
166 out.Q[queueIdx[j]] += pk[k] * r.QN(j, 0);
167 out.U[queueIdx[j]] += pk[k] * Uk;
168 out.X[queueIdx[j]] += pk[k] * Xk;
169 }
170 for (std::size_t i = 0; i < M; ++i) {
171 if (isDelay[i]) {
172 out.Q[i] += pk[k] * Xk * L[i];
173 out.U[i] += pk[k] * Xk * L[i];
174 out.X[i] += pk[k] * Xk;
175 }
176 }
177 }
178
179 for (std::size_t i = 0; i < M; ++i)
180 if (out.X[i] > gzero) out.R[i] = out.Q[i] / out.X[i];
181 return out;
182}
183
184} // namespace fes
185} // namespace line
186
187#endif // LINE_API_FES_MAP_SOLVE_H
InputError(const std::string &what)
Definition error.h:105
std::size_t rows() const
Definition matrix.h:89
Steady-state distribution of a continuous-time Markov chain.
The exception types the port throws.
Inter-departure MAP of a closed subnetwork made of one MAP station and one MAP flow-equivalent server...
Per-level processes of a load-dependent flow-equivalent server.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
FesMapDeaggregateResult< T > fes_map_deaggregate(const std::vector< T > &pk, const std::vector< T > &L, const std::vector< int > &mi, const std::vector< bool > &isDelay)
std::vector< mam::Map< T > > fes_map_levels(const mam::Map< T > &map, std::size_t n, double mi=1.0)
Replicate a load independent MAP over n levels, scaling level k by min(k, mi).
mam::Map< T > fes_map_interdeparture(const std::vector< mam::Map< T > > &maps, const std::vector< mam::Map< T > > &fes, std::size_t n)
Inter-departure MAP of a closed subnetwork made of one MAP station and one MAP flow-equivalent server...
FesMapSolveResult< T > fes_map_solve(const std::vector< mam::Map< T > > &fes, const mam::Map< T > &think_map, std::size_t n)
Closed model left by a MAP flow-equivalent server, and the per-station metrics behind it.
Matrix< T > map_infgen(const Map< T > &m)
Generator of the underlying phase process, D0 + D1.
Definition map_moment.h:62
T map_moment(const Map< T > &m, unsigned k)
Raw moment of order k of the inter-arrival time: k!
Definition map_moment.h:118
std::vector< T > ctmc_solve(const Matrix< T > &Qin)
Steady-state distribution of a continuous-time Markov chain.
Definition ctmc_solve.h:122
MvaResult< T > pfqn_mvams(const std::vector< T > &lambda, const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &mi, const std::vector< int > &S)
General-purpose exact MVA for mixed networks with multiserver stations.
Definition pfqn_mvams.h:852
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
std::vector< T > vecmul(const std::vector< T > &v, const Matrix< T > &A)
Row vector times matrix, v A.
Definition linalg.h:50
Number-type abstraction for the templated API port.
Exact Mean Value Analysis for closed product-form networks (Reiser and Lavenberg 1980).
Exact Mean Value Analysis for mixed open/closed networks with multiserver stations.
Per-station metrics an aggregate stands for.
System metrics of the delay plus flow-equivalent server model.
std::vector< T > pk
law of the jobs held by the flow-equivalent server
T R
response time of the aggregated subnetwork, N/X - E[Z]
T Q
mean jobs held by the flow-equivalent server
static constexpr double Zero
Definition lang_types.h:767
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
Matrix< T > D1
Definition map_moment.h:55
std::vector< T > XN
(R) per-class throughput
Definition pfqn_mva.h:45
Matrix< T > QN
(M x R) mean queue length
Definition pfqn_mva.h:46