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
46#include "line/num/number.h"
47#include "line/util/error.h"
48#include "line/util/linalg.h"
49#include "line/util/matrix.h"
50
51namespace line {
52namespace fes {
53
54/** System metrics of the delay plus flow-equivalent server model. */
55template <class T>
57 T X; ///< system throughput
58 T R; ///< response time of the aggregated subnetwork, N/X - E[Z]
59 T Q; ///< mean jobs held by the flow-equivalent server
60 std::vector<T> pk; ///< law of the jobs held by the flow-equivalent server
61};
62
63/** Per-station metrics an aggregate stands for. */
64template <class T>
66 std::vector<T> Q;
67 std::vector<T> U;
68 std::vector<T> X;
69 std::vector<T> R;
70};
71
72/**
73 * @brief Closed model left by a MAP flow-equivalent server, and the
74 * per-station metrics behind it.
75 *
76 * @param fes flow-equivalent server, one MAP per level
77 * @param think_map think time process (Z0,Z1)
78 * @param n number of jobs in the closed model
79 */
80template <class T>
82 const mam::Map<T>& think_map, std::size_t n) {
83 if (n < 1) throw InputError("fes_map_solve: the population must be at least 1");
84 const std::vector<mam::Map<T>> fesLev = fes_map_levels(fes, n);
85 const std::vector<mam::Map<T>> think =
86 fes_map_levels(think_map, n, std::numeric_limits<double>::infinity());
87
88 const mam::Map<T> T01 = fes_map_interdeparture(think, fesLev, n);
89 const Matrix<T> Q = mam::map_infgen(T01);
90 const std::size_t dim = Q.rows();
91 const T zero = num_traits<T>::from_int(0);
92
93 const std::vector<T> phi = mc::ctmc_solve(Q);
94 const std::vector<T> phiT1 = vecmul(phi, T01.D1);
95
97 out.X = zero;
98 for (const T& v : phiT1) out.X += v;
99
100 const std::size_t blk = dim / (n + 1);
101 out.pk.assign(n + 1, zero);
102 out.Q = zero;
103 for (std::size_t k = 0; k <= n; ++k) {
104 T s = zero;
105 for (std::size_t j = 0; j < blk; ++j) s += phi[k * blk + j];
106 out.pk[k] = s;
107 out.Q += num_traits<T>::from_int(static_cast<long>(k)) * s;
108 }
109 out.R = num_traits<T>::from_int(static_cast<long>(n)) / out.X - mam::map_moment(think_map, 1);
110 return out;
111}
112
113/**
114 * @param pk law of the jobs held by the aggregate, index k = P(k jobs)
115 * @param L service demands of the isolated subnetwork
116 * @param mi servers per station, ignored where isDelay
117 * @param isDelay true where the station is a pure delay
118 */
119template <class T>
120FesMapDeaggregateResult<T> fes_map_deaggregate(const std::vector<T>& pk, const std::vector<T>& L,
121 const std::vector<int>& mi,
122 const std::vector<bool>& isDelay) {
123 const std::size_t M = L.size();
124 const std::size_t n = pk.size() - 1;
125 const T zero = num_traits<T>::from_int(0);
126
128 out.Q.assign(M, zero);
129 out.U.assign(M, zero);
130 out.X.assign(M, zero);
131 out.R.assign(M, zero);
132
133 std::vector<std::size_t> queueIdx;
134 T Z = zero;
135 for (std::size_t i = 0; i < M; ++i) {
136 if (isDelay[i]) {
137 Z += L[i];
138 } else {
139 queueIdx.push_back(i);
140 }
141 }
142 Matrix<T> Lq(queueIdx.size(), 1, zero);
143 std::vector<int> miq(queueIdx.size(), 1);
144 for (std::size_t j = 0; j < queueIdx.size(); ++j) {
145 Lq(j, 0) = L[queueIdx[j]];
146 miq[j] = mi[queueIdx[j]];
147 }
148 Matrix<T> Zm(1, 1, Z);
149
150 for (std::size_t k = 1; k <= n; ++k) {
151 if (pk[k] == zero) continue;
152 const std::vector<int> N(1, static_cast<int>(k));
153 const pfqn::MvaResult<T> r = pfqn::pfqn_mva(Lq, N, Zm, miq);
154 const T Xk = r.XN[0];
155 for (std::size_t j = 0; j < queueIdx.size(); ++j) {
156 out.Q[queueIdx[j]] += pk[k] * r.QN(j, 0);
157 out.U[queueIdx[j]] += pk[k] * r.UN(j, 0);
158 out.X[queueIdx[j]] += pk[k] * Xk;
159 }
160 for (std::size_t i = 0; i < M; ++i) {
161 if (isDelay[i]) {
162 out.Q[i] += pk[k] * Xk * L[i];
163 out.U[i] += pk[k] * Xk * L[i];
164 out.X[i] += pk[k] * Xk;
165 }
166 }
167 }
168
169 for (std::size_t i = 0; i < M; ++i)
170 if (out.X[i] != zero) out.R[i] = out.Q[i] / out.X[i];
171 return out;
172}
173
174} // namespace fes
175} // namespace line
176
177#endif // LINE_API_FES_MAP_SOLVE_H
InputError(const std::string &what)
Definition error.h:39
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.
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_mva(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &mi)
Exact Mean Value Analysis for closed product-form networks (Reiser and Lavenberg 1980).
Definition pfqn_mva.h:71
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).
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
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
Matrix< T > UN
(M x R) utilization
Definition pfqn_mva.h:47