LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_mmapg1k.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_MMAPG1K_H
6#define LINE_API_QSYS_QSYS_MMAPG1K_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * Exact per-class throughput and loss ratio of an MMAP[K]/G/1/K tail-drop
12 * queue. Port of matlab/src/api/qsys/qsys_mmapg1k.m.
13 *
14 * Two classes of equal arrival rate but different interarrival variability or
15 * autocorrelation receive different loss ratios. An aggregate-only finite
16 * buffer analysis cannot express that: it returns one blocking probability p
17 * and sets T_k = lambda_k (1 - p), making the loss ratio identical across
18 * classes BY CONSTRUCTION. What breaks the tie here is the phase resolution of
19 * the full-buffer probability. A class-k arrival leaves phase i at rate
20 * (D1c_k e)_i, so
21 *
22 * lambda_k = pi D1c_k e, L_k = (pKvec D1c_k e)/lambda_k,
23 * T_k = lambda_k (1 - L_k),
24 *
25 * with pi the stationary phase law of the aggregate MAP and pKvec the joint law
26 * of (level = K, phase) that qsys_mapg1k returns. No independence between
27 * classes is assumed and no PASTA argument is used.
28 *
29 * This is exact whenever the joint MMAP is available, which it is inside a
30 * solver that propagates MMAPs between stations. Use qsys_mapg1k_perflow for
31 * the setting where the flows are given as separate MAPs and the joint process
32 * would cost prod_n M_n phases.
33 *
34 * The model assumes a single server and a service law that is iid and
35 * independent of class: per-class service would make the departure rate depend
36 * on which class holds the server, which this state space does not represent.
37 *
38 * ARITHMETIC. Inherits the transcendental gate from qsys_mapg1k; the per-class
39 * layer on top is finite exact linear algebra.
40 *
41 * Reference: Chydzinski, A. Per-Flow Throughput of a FIFO Buffer. Applied
42 * System Innovation 2026, 9, 112.
43 */
44
45#include <cstddef>
46#include <vector>
47
50#include "line/num/number.h"
51#include "line/util/error.h"
52#include "line/util/linalg.h"
53#include "line/util/matrix.h"
54
55namespace line {
56namespace qsys {
57
58/** Return value of qsys_mmapg1k, mirroring the MATLAB result struct. */
59template <class T>
61 std::vector<T> throughput; ///< per-class throughput
62 std::vector<T> lossRatio; ///< per-class loss ratio, in [0,1]
63 std::vector<T> lambda; ///< per-class arrival rate
66 T lossAggregate; ///< aggregate loss ratio of the whole stream
67 T p0;
68 T pK;
69 std::vector<T> pKvec;
70 std::vector<T> plevel;
74 T rho;
75};
76
77/**
78 * MMAP[K]/G/1/K with tail drop.
79 *
80 * @param D0 hidden transition matrix of the arrival MMAP (M x M)
81 * @param D1c per-class arrival matrices; D0 + sum_k D1c[k] must be an
82 * irreducible generator
83 * @param svc service law, shared by all classes
84 * @param K buffer size in packets
85 * @param tol convergence tolerance
86 * @param nmaxCap cap on the level truncation
87 */
88template <class T>
89MmapG1kResult<T> qsys_mmapg1k(const Matrix<T>& D0, const std::vector<Matrix<T>>& D1c,
90 const ServiceLaw<T>& svc, std::size_t K, const T& tol,
91 std::size_t nmaxCap) {
93 "qsys_mmapg1k requires transcendental arithmetic");
94 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
95 if (D1c.empty()) throw InputError("qsys_mmapg1k: at least one class is required");
96 const std::size_t M = D0.rows();
97 if (D0.cols() != M) throw InputError("qsys_mmapg1k: D0 must be square");
98 const std::size_t R = D1c.size();
99 mam::Map<T> agg;
100 agg.D0 = D0;
101 agg.D1 = Matrix<T>(M, M, zero);
102 for (std::size_t k = 0; k < R; ++k) {
103 if (D1c[k].rows() != M || D1c[k].cols() != M)
104 throw InputError("qsys_mmapg1k: every per-class D1 must match the order of D0");
105 for (std::size_t i = 0; i < M; ++i)
106 for (std::size_t j = 0; j < M; ++j) agg.D1(i, j) += D1c[k](i, j);
107 }
108
109 const MapG1kResult<T> r = qsys_mapg1k(agg, svc, K, tol, nmaxCap);
110 const std::vector<T> e = ones<T>(M);
111 const std::vector<T> pit = mam::map_prob(agg);
112
114 out.throughput.assign(R, zero);
115 out.lossRatio.assign(R, zero);
116 out.lambda.assign(R, zero);
117 out.lambdaAggregate = zero;
118 out.throughputAggregate = zero;
119 for (std::size_t k = 0; k < R; ++k) {
120 const std::vector<T> col = mulvec(D1c[k], e);
121 T lam = zero, blocked = zero;
122 for (std::size_t i = 0; i < M; ++i) {
123 lam += pit[i] * col[i];
124 blocked += r.pKvec[i] * col[i];
125 }
126 out.lambda[k] = lam;
127 out.lossRatio[k] = (lam > zero) ? T(blocked / lam) : zero;
128 out.throughput[k] = lam * (one - out.lossRatio[k]);
129 out.lambdaAggregate += lam;
130 out.throughputAggregate += out.throughput[k];
131 }
133 out.p0 = r.p0;
134 out.pK = r.pK;
135 out.pKvec = r.pKvec;
136 out.plevel = r.plevel;
139 out.utilization = r.utilization;
140 out.rho = r.rho;
141 return out;
142}
143
144/** qsys_mmapg1k with the qsys_mapg1k defaults tol = 1e-12, nmax = 200000. */
145template <class T>
146MmapG1kResult<T> qsys_mmapg1k(const Matrix<T>& D0, const std::vector<Matrix<T>>& D1c,
147 const ServiceLaw<T>& svc, std::size_t K) {
148 return qsys_mmapg1k(D0, D1c, svc, K, T(num_traits<T>::from_double(1e-12)),
149 static_cast<std::size_t>(200000));
150}
151
152} // namespace qsys
153} // namespace line
154
155#endif // LINE_API_QSYS_QSYS_MMAPG1K_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.
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.
std::vector< T > map_prob(const Map< T > &m)
Stationary distribution of the phase process, pi (D0 + D1) = 0.
Definition map_moment.h:73
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.
MmapG1kResult< T > qsys_mmapg1k(const Matrix< T > &D0, const std::vector< Matrix< T > > &D1c, const ServiceLaw< T > &svc, std::size_t K, const T &tol, std::size_t nmaxCap)
MMAP[K]/G/1/K with tail drop.
std::vector< T > mulvec(const Matrix< T > &A, const std::vector< T > &v)
Matrix times column vector, A v.
Definition linalg.h:62
std::vector< T > ones(std::size_t n)
Column vector of ones, the ubiquitous e in MAP algebra.
Definition linalg.h:104
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, mirroring the MATLAB result struct.
std::vector< T > plevel
P(level = l), l = 0..K.
T rho
offered load lambda S
std::vector< T > pKvec
P(level = K, phase j), summing to pK.
T pK
P(buffer full).
T p0
P(buffer empty).
T lossProbability
1 - throughput/lambda
T meanQueueLength
E[number in system].
Return value of qsys_mmapg1k, mirroring the MATLAB result struct.
std::vector< T > lossRatio
per-class loss ratio, in [0,1]
std::vector< T > pKvec
std::vector< T > lambda
per-class arrival rate
std::vector< T > plevel
T lossAggregate
aggregate loss ratio of the whole stream
std::vector< T > throughput
per-class throughput
Service-time descriptor, the C++ form of the MATLAB svc struct.