LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
map_max.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_MAX_H
6#define LINE_API_MAM_MAP_MAX_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * Maximum of two independent MAPs, and its marked k-stage generalization.
12 *
13 * Templated port of matlab/lib/kpctoolbox/map/map_max.m and
14 * matlab/lib/m3a/m3a/mmap/mmap_max.m. These are the synchronization primitives
15 * behind a fork-join: the joined interval is the maximum of the two branch
16 * intervals, not their sum, so the phase space carries a RACE followed by the
17 * residual of whichever branch is still running.
18 *
19 * map_max therefore has order na*nb + na + nb: the product block while both
20 * branches are alive, then one absorbing-residual block per branch. Reading the
21 * order as na*nb, as for a superposition, drops exactly the residual phases
22 * that make the maximum different from the minimum.
23 *
24 * mmap_max keeps k rounds of the race, so its order is na*nb*(1+2k), with the
25 * marks of both branches carried through unchanged.
26 */
27
28#include <cstddef>
29#include <vector>
30
33#include "line/num/number.h"
34#include "line/util/error.h"
35#include "line/util/linalg.h"
36#include "line/util/matrix.h"
37
38namespace line {
39namespace mam {
40
41namespace detail {
42
43/** Copies src into the (br, bc) block of dst, blocks being rb x cb. */
44template <class T>
45void set_block(Matrix<T>& dst, std::size_t br, std::size_t bc, const Matrix<T>& src) {
46 for (std::size_t i = 0; i < src.rows(); ++i)
47 for (std::size_t j = 0; j < src.cols(); ++j) dst(br + i, bc + j) = src(i, j);
48}
49
50} // namespace detail
51
52/** MAP of the maximum of two independent MAPs. */
53template <class T>
54Map<T> map_max(const Map<T>& A, const Map<T>& B) {
55 const std::size_t na = A.D0.rows(), nb = B.D0.rows();
56 const T zero = num_traits<T>::from_int(0);
57 std::vector<T> a(na, zero), b(nb, zero);
58 for (std::size_t i = 0; i < na; ++i)
59 for (std::size_t j = 0; j < na; ++j) a[i] -= A.D0(i, j);
60 for (std::size_t i = 0; i < nb; ++i)
61 for (std::size_t j = 0; j < nb; ++j) b[i] -= B.D0(i, j);
62 const std::size_t nab = na * nb, N = nab + nb + na;
63 Matrix<T> M0(N, N, zero);
64 const Matrix<T> S = krons(A.D0, B.D0);
65 detail::set_block(M0, 0, 0, S);
66 // kron(a, I_nb) sits to the right of the product block, then kron(I_na, b)
67 for (std::size_t i = 0; i < na; ++i)
68 for (std::size_t j = 0; j < nb; ++j) M0(i * nb + j, nab + j) = a[i];
69 for (std::size_t i = 0; i < na; ++i)
70 for (std::size_t j = 0; j < nb; ++j) M0(i * nb + j, nab + nb + i) = b[j];
71 detail::set_block(M0, nab, nab, B.D0);
72 detail::set_block(M0, nab + nb, nab + nb, A.D0);
73 const std::vector<T> pa = map_pie(A), pb = map_pie(B);
74 std::vector<T> pie(N, zero);
75 for (std::size_t i = 0; i < na; ++i)
76 for (std::size_t j = 0; j < nb; ++j) pie[i * nb + j] = pa[i] * pb[j];
77 std::vector<T> d(N, zero);
78 for (std::size_t j = 0; j < nb; ++j) d[nab + j] = b[j];
79 for (std::size_t i = 0; i < na; ++i) d[nab + nb + i] = a[i];
80 Matrix<T> M1(N, N, zero);
81 for (std::size_t i = 0; i < N; ++i)
82 for (std::size_t j = 0; j < N; ++j) M1(i, j) = d[i] * pie[j];
83 return Map<T>{M0, M1};
84}
85
86/** MMAP of the maximum over k synchronization rounds of two independent MMAPs. */
87template <class T>
88Mmap<T> mmap_max(const Mmap<T>& a, const Mmap<T>& b, unsigned k) {
89 if (k == 0) throw InputError("mmap_max: k must be positive");
90 if (a.classes() != b.classes())
91 throw InputError("mmap_max: the two MMAPs must carry the same number of classes");
92 const std::size_t na = a.order(), nb = b.order(), n = na * nb;
93 const std::size_t nblk = 1 + 2 * static_cast<std::size_t>(k);
94 const std::size_t N = n * nblk;
95 const T zero = num_traits<T>::from_int(0);
96 const Matrix<T> Ia = eye<T>(na), Ib = eye<T>(nb);
97 const Matrix<T> A0B0 = krons(a.D0, b.D0);
98 const Matrix<T> A1IB = kron(a.D1, Ib);
99 const Matrix<T> IAB1 = kron(Ia, b.D1);
100 const Matrix<T> IAB0 = kron(Ia, b.D0);
101 const Matrix<T> A0IB = kron(a.D0, Ib);
102 Matrix<T> M0(N, N, zero);
103 detail::set_block(M0, 0, 0, A0B0);
104 detail::set_block(M0, 0, n, A1IB);
105 detail::set_block(M0, 0, 2 * n, IAB1);
106 for (std::size_t bi = 1; bi + 2 <= nblk - 1; ++bi)
107 detail::set_block(M0, bi * n, bi * n, A0B0);
108 detail::set_block(M0, (nblk - 2) * n, (nblk - 2) * n, IAB0);
109 detail::set_block(M0, (nblk - 1) * n, (nblk - 1) * n, A0IB);
110 for (unsigned i = 2; i <= k; ++i) {
111 const std::size_t r = (1 + 2 * (i - 2)) * n, c = (3 + 2 * (i - 2)) * n;
112 detail::set_block(M0, r, c, A1IB);
113 detail::set_block(M0, r + n, c + n, IAB1);
114 }
115 Mmap<T> out;
116 out.D0 = M0;
117 out.D1 = Matrix<T>(N, N, zero);
118 detail::set_block(out.D1, n, 0, IAB1);
119 detail::set_block(out.D1, 2 * n, 0, A1IB);
120 for (unsigned i = 2; i <= k; ++i) {
121 const std::size_t r = (1 + 2 * (i - 1)) * n, c = (1 + 2 * (i - 2)) * n;
122 detail::set_block(out.D1, r, c, IAB1);
123 detail::set_block(out.D1, r + n, c + n, A1IB);
124 }
125 for (std::size_t cls = 0; cls < a.classes(); ++cls) {
126 Matrix<T> Mc(N, N, zero);
127 const Matrix<T> IABc = kron(Ia, b.Dc[cls]);
128 const Matrix<T> AcIB = kron(a.Dc[cls], Ib);
129 detail::set_block(Mc, n, 0, IABc);
130 detail::set_block(Mc, 2 * n, 0, AcIB);
131 for (unsigned i = 2; i <= k; ++i) {
132 const std::size_t r = (1 + 2 * (i - 1)) * n, c = (1 + 2 * (i - 2)) * n;
133 detail::set_block(Mc, r, c, IABc);
134 detail::set_block(Mc, r + n, c + n, AcIB);
135 }
136 out.Dc.push_back(Mc);
137 }
138 return out;
139}
140
141} // namespace mam
142} // namespace line
143
144#endif
InputError(const std::string &what)
Definition error.h:39
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.
Marked MAP (MMAP) algebra: per-class rates, class probabilities, superposition, normalization and sca...
Mmap< T > mmap_max(const Mmap< T > &a, const Mmap< T > &b, unsigned k)
MMAP of the maximum over k synchronization rounds of two independent MMAPs.
Definition map_max.h:88
Matrix< T > krons(const Matrix< T > &A, const Matrix< T > &B)
Kronecker sum, MATLAB's krons: kron(A, I_nb) + kron(I_na, B).
Definition mmap_lambda.h:71
Matrix< T > kron(const Matrix< T > &A, const Matrix< T > &B)
Kronecker product.
Definition mmap_lambda.h:57
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
Definition map_moment.h:89
Map< T > map_max(const Map< T > &A, const Map< T > &B)
MAP of the maximum of two independent MAPs.
Definition map_max.h:54
Matrix< T > eye(std::size_t n)
Identity of order n.
Definition linalg.h:28
Number-type abstraction for the templated API port.
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
Matrix< T > D0
Definition map_moment.h:54
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
Matrix< T > D1
Definition mmap_lambda.h:47
std::vector< Matrix< T > > Dc
per-class matrices, sum_c Dc = D1
Definition mmap_lambda.h:48
std::size_t order() const
Definition mmap_lambda.h:50