LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_mapph1.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_MAPPH1_H
6#define LINE_API_QSYS_QSYS_MAPPH1_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * The MAP/PH/1 FCFS queue.
12 *
13 * ALGORITHM, AND HOW IT DIFFERS FROM THE MATLAB REFERENCE.
14 * matlab/src/api/qsys/qsys_mapph1.m computes these quantities by calling
15 * BUTools' MMAPPH1FCFS, which is not transcribed here. This port computes the
16 * SAME quantities from the port's own
17 * QBD machinery: a PH service (sigma, S) is the renewal MAP
18 *
19 * D0 = S, D1 = (-S e) sigma,
20 *
21 * so MAP/PH/1 is literally a MAP/MAP/1 queue with a renewal service process,
22 * and the problem is handed to qsys_mapmap1 (see qsys_mapmap1.h for the QBD
23 * construction). Different algorithm, same quantity. Because the service MAP
24 * built this way IS a renewal process, none of the caveats about discarded
25 * service correlation in qsys_mapmap1.h apply to this function: the reference
26 * and the port model the identical stochastic system here.
27 *
28 * MEASURED AGREEMENT (MATLAB R2025a, T = double). Metric order is
29 * meanQueueLength / meanWaitingTime / meanSojournTime / utilization.
30 * - M/M/1 collapse, qsys_mapph1(D0 = [-2], D1 = [2], sigma = [1], S = [-3]):
31 * MATLAB 1.999999999999999 / 0.6666666666666656 / 0.9999999999999989 /
32 * 0.6666666666666666; the port returns the textbook 2 / 0.666666666666668 /
33 * 1 / 0.666666666666667. Relative differences 5e-16, 1.8e-15, 1.1e-15,
34 * 1e-16.
35 * - Correlated MMPP2 arrival D0 = [-2.5 0.2; 0.1 -0.7], D1 = diag(2.3, 0.6)
36 * (lambda = 7/6) with Erlang-2 service sigma = [1 0], S = [-6 6; 0 -6]:
37 * MATLAB 0.8364637529649164 / 0.3836355977794533 / 0.7169689311127866 /
38 * 0.3888888888888888; port 0.836463752964917 / 0.383635597779453 /
39 * 0.716968931112786 / 0.388888888888889. Relative differences below 1e-15
40 * on every metric.
41 * - Erlang-2 arrival D0 = [-4 4; 0 -4], D1 = [0 0; 4 0] (lambda = 2) with
42 * hyperexponential service sigma = [0.6 0.4], S = diag(-8, -1.6): MATLAB
43 * 2.133647429543165 / 0.7418237147715814 / 1.066823714771581 / 0.65; port
44 * 2.13364742954318 / 0.741823714771588 / 1.06682371477159 / 0.65. Relative
45 * differences below 1e-15 on every metric.
46 *
47 * The port therefore reproduces the BUTools reference to machine precision on
48 * this family. It deliberately does NOT reproduce LINE's own MATLAB
49 * qbd_mapmap1 on the equivalent MAP pair, which returns 0.8364637492083693 and
50 * 2.133647423495968 for the second and third cases: those are 4.5e-9 and
51 * 2.8e-9 BELOW the values above because MATLAB's qbd_mapmap1 sums the level
52 * distribution until the accumulated mass reaches 1 - 1e-10 and discards the
53 * remaining tail times its level index, while this port sums the whole
54 * geometric tail in closed form (see qbd_mapmap1.h).
55 *
56 * ARITHMETIC. Gated on num_traits<T>::has_transcendental, inherited from
57 * qsys_mapmap1 and ultimately from the cyclic reduction that produces R; see
58 * qbd_r.h. The PH-to-MAP conversion itself is exact matrix algebra.
59 */
60
61#include <cstddef>
62#include <vector>
63
66#include "line/num/number.h"
67#include "line/util/error.h"
68#include "line/util/matrix.h"
69
70namespace line {
71namespace qsys {
72
73namespace detail {
74
75/**
76 * The renewal MAP of a PH distribution: D0 = S, D1 = (-S e) beta. Exact matrix
77 * algebra, so un-gated.
78 */
79template <class T>
80mam::Map<T> ph_to_map(const std::vector<T>& beta, const Matrix<T>& S) {
81 const std::size_t m = S.rows();
82 if (S.cols() != m || beta.size() != m)
83 throw InputError("ph_to_map: beta and S dimensions are inconsistent");
84 mam::Map<T> out;
85 out.D0 = S;
86 out.D1 = Matrix<T>(m, m, num_traits<T>::from_int(0));
87 for (std::size_t i = 0; i < m; ++i) {
88 T exit = num_traits<T>::from_int(0);
89 for (std::size_t j = 0; j < m; ++j) exit -= S(i, j);
90 for (std::size_t j = 0; j < m; ++j) out.D1(i, j) = exit * beta[j];
91 }
92 return out;
93}
94
95} // namespace detail
96
97/**
98 * MAP/PH/1 by the exact QBD solution of the equivalent MAP/MAP/1 queue.
99 *
100 * @param arrival arrival MAP (D0, D1)
101 * @param sigma PH service entry vector, length m
102 * @param S PH service sub-generator, m x m
103 * @param dist_size how many entries of queueLengthDist to materialize
104 */
105template <class T>
106MapMap1Result<T> qsys_mapph1(const mam::Map<T>& arrival, const std::vector<T>& sigma,
107 const Matrix<T>& S, std::size_t dist_size) {
109 "qsys_mapph1 requires transcendental arithmetic");
110 return qsys_mapmap1(arrival, detail::ph_to_map(sigma, S), dist_size);
111}
112
113/** qsys_mapph1 with 100 materialized levels, the reference's numQLProbs. */
114template <class T>
115MapMap1Result<T> qsys_mapph1(const mam::Map<T>& arrival, const std::vector<T>& sigma,
116 const Matrix<T>& S) {
117 return qsys_mapph1(arrival, sigma, S, static_cast<std::size_t>(100));
118}
119
120} // namespace qsys
121} // namespace line
122
123#endif // LINE_API_QSYS_QSYS_MAPPH1_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.
MapMap1Result< T > qsys_mapph1(const mam::Map< T > &arrival, const std::vector< T > &sigma, const Matrix< T > &S, std::size_t dist_size)
MAP/PH/1 by the exact QBD solution of the equivalent MAP/MAP/1 queue.
MapMap1Result< T > qsys_mapmap1(const mam::Map< T > &arrival, const mam::Map< T > &service, std::size_t dist_size)
MAP/MAP/1 by the exact QBD solution.
Number-type abstraction for the templated API port.
The MAP/MAP/1 FCFS queue: mean number in system, waiting time, sojourn time, utilization and the queu...
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
Return value of the MAP/MAP/1 family (qsys_mapmap1, qsys_mapph1, qsys_phph1), carrying the same quant...