LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_mapg1k_perflow.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_MAPG1K_PERFLOW_H
6#define LINE_API_QSYS_QSYS_MAPG1K_PERFLOW_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * Per-flow throughput and loss ratio of a tail-drop FIFO buffer fed by N flows
12 * of mutually different statistical character. Port of
13 * matlab/src/api/qsys/qsys_mapg1k_perflow.m, Theorem 1 of [1].
14 *
15 * Flow n has its own MAP, so two flows may share an arrival rate and still
16 * differ in the shape and the autocorrelation of their interarrival times.
17 *
18 * METHOD, AND WHY IT IS AN APPROXIMATION. The exact model would track the
19 * modulating state of every flow jointly with the buffer, prod_n M_n (K+1)
20 * states, which [1] notes is already out of reach at N = 10, M_n = 3, K = 10.
21 * Instead ONE model is solved per flow: flow n is kept exactly and the other
22 * N-1 flows are replaced by a single Poisson stream of rate lambda - lambda_n,
23 * which the Palm-Khinchin limiting theorem on superposed point processes
24 * justifies as N grows. The substitution is applied N times, once per flow, so
25 * no flow is ever the Poissonized one when its own throughput is computed.
26 * Superposing MAP_n with the Poisson background gives ([1], eq. 5)
27 *
28 * D0 = D0n - lambdaBar I, D1 = D1n + lambdaBar I,
29 *
30 * and the flow throughput is read off the aggregate ([1], eq. 20)
31 *
32 * T_n = (1 - p0)/S + pK lambdaBar - lambdaBar,
33 *
34 * the aggregate departure rate less the background throughput
35 * lambdaBar (1 - pK), the background loss ratio being pK by PASTA BECAUSE the
36 * background is Poisson. PASTA is used for the background only, never for the
37 * flow being measured. Cost is O(N (K M)^3) against O(M^(3N) K^3): linear
38 * rather than exponential in the flow count.
39 *
40 * ACCURACY. [1] reports errors against simulation of the exact model below
41 * about 8% for N >= 9 with K >= 20, falling to 2.1% at K = 50, 0.5% at K = 100
42 * and 1.2% at N = 900. Errors are largest when flows are few, highly variable
43 * and the buffer is small. This is a property of the method, not of the port:
44 * the port reproduces the reference's numbers, and the two agree with the
45 * published Table 2 of [1] to the precision at which it is printed.
46 *
47 * ARITHMETIC. Inherits the transcendental gate from qsys_mapg1k.
48 *
49 * Reference: [1] Chydzinski, A. Per-Flow Throughput of a FIFO Buffer. Applied
50 * System Innovation 2026, 9, 112.
51 */
52
53#include <cstddef>
54#include <vector>
55
58#include "line/num/number.h"
59#include "line/util/error.h"
60#include "line/util/matrix.h"
61
62namespace line {
63namespace qsys {
64
65/** Return value of qsys_mapg1k_perflow, mirroring the MATLAB result struct. */
66template <class T>
68 std::vector<T> throughput; ///< per-flow throughput
69 std::vector<T> lossRatio; ///< per-flow loss ratio
70 std::vector<T> lambda; ///< per-flow arrival rate
73 T lossAggregate; ///< sum_n L_n lambda_n / lambda
74 std::vector<T> p0; ///< empty-buffer probability of the n-th model
75 std::vector<T> pK; ///< full-buffer probability of the n-th model
77 T rho; ///< offered load lambdaAggregate * S
78};
79
80/**
81 * Per-flow analysis of a MAP-fed tail-drop buffer.
82 *
83 * @param flows the N arrival MAPs, whose modulating orders may differ
84 * @param svc service law, shared by all flows
85 * @param K buffer size in packets, the one in transmission included
86 * @param tol convergence tolerance
87 * @param nmaxCap cap on the level truncation
88 */
89template <class T>
91 const ServiceLaw<T>& svc, std::size_t K, const T& tol,
92 std::size_t nmaxCap) {
94 "qsys_mapg1k_perflow requires transcendental arithmetic");
95 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
96 const std::size_t N = flows.size();
97 if (N == 0) throw InputError("qsys_mapg1k_perflow: at least one flow is required");
98
99 std::vector<T> lam(N);
100 T lamTot = zero;
101 for (std::size_t n = 0; n < N; ++n) {
102 lam[n] = mam::map_lambda(flows[n]);
103 if (lam[n] <= zero)
104 throw InputError("qsys_mapg1k_perflow: every flow must have a positive arrival rate");
105 lamTot += lam[n];
106 }
107
109 out.throughput.assign(N, zero);
110 out.lossRatio.assign(N, zero);
111 out.lambda = lam;
112 out.lambdaAggregate = lamTot;
113 out.p0.assign(N, zero);
114 out.pK.assign(N, zero);
115 out.throughputAggregate = zero;
116 T Smean = zero;
117 T lossWeighted = zero;
118 for (std::size_t n = 0; n < N; ++n) {
119 const T lamBar = lamTot - lam[n];
120 const std::size_t Mn = flows[n].D0.rows();
121 mam::Map<T> sup;
122 sup.D0 = flows[n].D0;
123 sup.D1 = flows[n].D1;
124 for (std::size_t i = 0; i < Mn; ++i) {
125 sup.D0(i, i) -= lamBar;
126 sup.D1(i, i) += lamBar;
127 }
128 const MapG1kResult<T> r = qsys_mapg1k(sup, svc, K, tol, nmaxCap);
129 Smean = r.meanServiceTime;
130 out.p0[n] = r.p0;
131 out.pK[n] = r.pK;
132 out.throughput[n] = (one - r.p0) / Smean + r.pK * lamBar - lamBar;
133 out.lossRatio[n] = one - out.throughput[n] / lam[n];
134 out.throughputAggregate += out.throughput[n];
135 lossWeighted += out.lossRatio[n] * lam[n];
136 }
137 out.lossAggregate = lossWeighted / lamTot;
138 out.meanServiceTime = Smean;
139 out.rho = lamTot * Smean;
140 return out;
141}
142
143/** qsys_mapg1k_perflow with the qsys_mapg1k defaults tol = 1e-12, nmax = 200000. */
144template <class T>
146 const ServiceLaw<T>& svc, std::size_t K) {
147 return qsys_mapg1k_perflow(flows, svc, K, T(num_traits<T>::from_double(1e-12)),
148 static_cast<std::size_t>(200000));
149}
150
151} // namespace qsys
152} // namespace line
153
154#endif // LINE_API_QSYS_QSYS_MAPG1K_PERFLOW_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
T map_lambda(const Map< T > &m)
Stationary arrival rate, lambda = pi D1 e.
Definition map_moment.h:79
MapG1kResult< T > qsys_mapg1k(const mam::Map< T > &arrival, const ServiceLaw< T > &svc, std::size_t K, const T &tol, std::size_t nmaxCap)
MAP/G/1/K with tail drop.
MapG1kPerflowResult< T > qsys_mapg1k_perflow(const std::vector< mam::Map< T > > &flows, const ServiceLaw< T > &svc, std::size_t K, const T &tol, std::size_t nmaxCap)
Per-flow analysis of a MAP-fed tail-drop buffer.
Number-type abstraction for the templated API port.
The MAP/G/1/K queue with tail drop: Markovian arrivals, an arbitrary service law F,...
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
Matrix< T > D1
Definition map_moment.h:55
Matrix< T > D0
Definition map_moment.h:54
Return value of qsys_mapg1k_perflow, mirroring the MATLAB result struct.
std::vector< T > p0
empty-buffer probability of the n-th model
std::vector< T > lambda
per-flow arrival rate
T lossAggregate
sum_n L_n lambda_n / lambda
std::vector< T > pK
full-buffer probability of the n-th model
std::vector< T > lossRatio
per-flow loss ratio
T rho
offered load lambdaAggregate * S
std::vector< T > throughput
per-flow throughput
Return value of qsys_mapg1k, mirroring the MATLAB result struct.
T pK
P(buffer full).
T p0
P(buffer empty).
Service-time descriptor, the C++ form of the MATLAB svc struct.