LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
map_count_moment.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_MAM_MAP_COUNT_MOMENT_H
6#define LINE_API_MAM_MAP_COUNT_MOMENT_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * Power moments of the counts of a MAP in a window of length t.
12 *
13 * Templated port of matlab/lib/kpctoolbox/map/map_count_moment.m. The moment
14 * generating function of the number of arrivals N(t) is
15 *
16 * M(z) = theta exp(D0 t + e^z D1 t) e, E[N(t)^k] = d^k M / dz^k |_{z=0},
17 *
18 * with theta the stationary phase vector.
19 *
20 * DIVERGENCE, deliberately: MATLAB evaluates those derivatives by NUMERICAL
21 * differentiation (derivest, Richardson extrapolation) for orders up to 4 and
22 * by symbolic differentiation beyond, so its accuracy degrades quickly with
23 * the order and it needs the Symbolic Toolbox for order 5 and above. This port
24 * takes the derivatives analytically, at the cost of one larger exponential.
25 * Write the exponent as a polynomial in z,
26 *
27 * B(z) = Q t + sum_{j>=1} (D1 t / j!) z^j, Q = D0 + D1,
28 *
29 * truncated at z^K. Polynomials in z modulo z^(K+1) are represented faithfully
30 * by block upper-triangular Toeplitz matrices, G[i][i+j] = B_j, and that
31 * representation is a ring homomorphism, so exp(G) is the representation of
32 * exp(B(z)) mod z^(K+1): its (0,j) block is exactly the z^j Taylor
33 * coefficient, i.e. the j-th derivative divided by j!. Hence
34 *
35 * E[N(t)^k] = k! theta [exp(G)]_{0,k} e,
36 *
37 * accurate to the tolerance of the exponential at every order, with no step
38 * size to choose and no symbolic algebra. The cost is one exponential of an
39 * (K+1)n square matrix.
40 *
41 * ARITHMETIC: transcendental (one matrix exponential).
42 *
43 * The JAR has no counterpart of this function.
44 */
45
46#include <cstddef>
47#include <vector>
48
51#include "line/num/number.h"
52#include "line/util/error.h"
53#include "line/util/expm.h"
54#include "line/util/linalg.h"
55#include "line/util/matrix.h"
56
57namespace line {
58namespace mam {
59
60/**
61 * @brief Power moments of the counts of a MAP in a window of length t.
62 *
63 * @param m the MAP (D0, D1)
64 * @param t window length
65 * @param orders orders of the moments to compute (0 returns 1)
66 * @return E[N(t)^k] for each requested order, in the order of orders
67 */
68template <class T>
69std::vector<T> map_count_moment(const Map<T>& m, const T& t, const std::vector<unsigned>& orders) {
71 "map_count_moment requires transcendental arithmetic");
72 if (t < num_traits<T>::from_int(0)) throw InputError("map_count_moment: negative window length");
73 unsigned K = 0;
74 for (std::size_t i = 0; i < orders.size(); ++i)
75 if (orders[i] > K) K = orders[i];
76
77 const std::size_t n = m.order();
78 const std::vector<T> theta = map_prob(m);
79 const Matrix<T> Q = map_infgen(m);
80
81 // Block Toeplitz representation of B(z) = Qt + sum_j (D1 t / j!) z^j.
82 const std::size_t N = (K + 1) * n;
84 for (std::size_t bi = 0; bi <= K; ++bi) {
85 for (std::size_t bj = bi; bj <= K; ++bj) {
86 const std::size_t j = bj - bi;
87 const T fac = j == 0 ? num_traits<T>::from_int(1)
88 : num_traits<T>::from_int(1) / num_factorial<T>(static_cast<unsigned>(j));
89 for (std::size_t r = 0; r < n; ++r)
90 for (std::size_t c = 0; c < n; ++c) {
91 const T coeff = j == 0 ? T(Q(r, c)) : T(m.D1(r, c) * fac);
92 G(bi * n + r, bj * n + c) = coeff * t;
93 }
94 }
95 }
96 const Matrix<T> E = expm(G);
97
98 std::vector<T> out;
99 out.reserve(orders.size());
100 for (std::size_t i = 0; i < orders.size(); ++i) {
101 const unsigned k = orders[i];
103 for (std::size_t r = 0; r < n; ++r)
104 for (std::size_t c = 0; c < n; ++c) s += theta[r] * E(r, k * n + c);
105 out.push_back(num_factorial<T>(k) * s);
106 }
107 return out;
108}
109
110
111/**
112 * Per-class counting moments of a marked MAP, `mmap_count_moment`.
113 *
114 * Port of jar/src/main/java/jline/api/mam/Mmap_count_moment.java. Class c's own
115 * counting process is the MAP whose arrivals are c's alone and whose hidden
116 * transitions absorb every other class,
117 *
118 * D0' = D0 + sum_{j != c} D1_j, D1' = D1_c,
119 *
120 * so the per-class moments are `map_count_moment` on that marginal. That
121 * marginalization is exact -- an arrival of another class IS a hidden phase
122 * transition as far as class c's counter is concerned -- and it is why the
123 * per-class counts are NOT independent: they share the phase process.
124 *
125 * @param m the marked MAP
126 * @param t window length
127 * @param orders moment orders
128 * @return (orders x classes) matrix of counting moments
129 */
130template <class T>
131Matrix<T> mmap_count_moment(const Mmap<T>& m, const T& t, const std::vector<unsigned>& orders) {
132 const std::size_t K = m.classes();
133 if (K == 0) throw InputError("mmap_count_moment: the MMAP has no classes");
134 Matrix<T> out(orders.size(), K, num_traits<T>::from_int(0));
135 for (std::size_t c = 0; c < K; ++c) {
136 Map<T> marg;
137 marg.D0 = m.D0;
138 for (std::size_t j = 0; j < K; ++j) {
139 if (j == c) continue;
140 for (std::size_t a = 0; a < marg.D0.rows(); ++a)
141 for (std::size_t b = 0; b < marg.D0.cols(); ++b) marg.D0(a, b) += m.Dc[j](a, b);
142 }
143 marg.D1 = m.Dc[c];
144 const std::vector<T> mm = map_count_moment(marg, t, orders);
145 for (std::size_t i = 0; i < orders.size(); ++i) out(i, c) = mm[i];
146 }
147 return out;
148}
149
150} // namespace mam
151} // namespace line
152
153#endif // LINE_API_MAM_MAP_COUNT_MOMENT_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Matrix exponential by scaling and squaring with a diagonal Pade approximant.
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.
Marked MAP (MMAP) algebra: per-class rates, class probabilities, superposition, normalization and sca...
Matrix< T > map_infgen(const Map< T > &m)
Generator of the underlying phase process, D0 + D1.
Definition map_moment.h:62
Matrix< T > mmap_count_moment(const Mmap< T > &m, const T &t, const std::vector< unsigned > &orders)
Per-class counting moments of a marked MAP, mmap_count_moment.
std::vector< T > map_prob(const Map< T > &m)
Stationary distribution of the phase process, pi (D0 + D1) = 0.
Definition map_moment.h:73
std::vector< T > map_count_moment(const Map< T > &m, const T &t, const std::vector< unsigned > &orders)
Power moments of the counts of a MAP in a window of length t.
T num_factorial(unsigned n)
Factorial as a value of T.
Definition number.h:184
Matrix< T > expm(const Matrix< T > &A)
Matrix exponential exp(A).
Definition expm.h:141
Number-type abstraction for the templated API port.
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
std::size_t order() const
Definition map_moment.h:57
An MMAP: the underlying MAP plus the per-class arrival matrices.
Definition mmap_lambda.h:45
std::size_t classes() const
Definition mmap_lambda.h:51
Matrix< T > D0
Definition mmap_lambda.h:46
std::vector< Matrix< T > > Dc
per-class matrices, sum_c Dc = D1
Definition mmap_lambda.h:48