LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
mamap2m_coefficients.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_MAMAP2M_COEFFICIENTS_H
6#define LINE_API_MAM_MAMAP2M_COEFFICIENTS_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * The marking coefficients of a canonical AMAP(2), for the sigma fitters.
12 *
13 * Templated port of matlab/lib/m3a/m3a/mamap2m/mamap2m_can1_coefficients.m and
14 * mamap2m_can2_coefficients.m, cross-checked against
15 * jar/src/main/java/jline/api/mam/Mamap2m_coefficients.java.
16 *
17 * `mamap22_fit_fs_multiclass` and `mamap22_fit_bs_multiclass` match the class
18 * TRANSITION probabilities (sigma) alongside a forward or backward moment, and
19 * the relation between the marking and those characteristics is not the simple
20 * affine one the F+B fitter uses. These two tables carry it: G (or E) holds the
21 * per-flow contributions to the class probability, the sigma and the moment; U
22 * (or V) the quadratic terms; and Y (or Z) three determinants of G that decide
23 * whether the system is solvable.
24 *
25 * REFERENCE TYPO, corrected here and already corrected in the JAR. MATLAB's
26 * `mamap2m_can1_coefficients.m` assigns `G(10)` TWICE in consecutive lines:
27 *
28 * G(10) = (r1*r2^2)/(r1*r2 - r2 + 1); % this is G(9)
29 * G(10) = h1 - (h1*r1)/(r2*(r1 - 1) + 1);
30 *
31 * so the first value is discarded and G(9) is left at zero. The JAR writes them
32 * to indices 9 and 10 respectively, which is the only reading under which the
33 * table has no hole, and that is what is done here. Y does not read G(9), so the
34 * three determinants are unaffected; a consumer that reads the ninth
35 * coefficient gets zero from MATLAB and the intended value here.
36 *
37 * ARITHMETIC: field. Rational expressions only, so this instantiates exactly.
38 */
39
40#include <cstddef>
41#include <vector>
42
43#include "line/num/number.h"
44#include "line/util/error.h"
45
46namespace line {
47namespace mam {
48
49/** The three coefficient tables of one canonical form. */
50template <class T>
52 std::vector<T> G; ///< 15 entries for form 1, 14 for form 2 (there called E)
53 std::vector<T> U; ///< 12 entries (V for form 2)
54 std::vector<T> Y; ///< 3 determinants (Z for form 2)
55};
56
57/**
58 * First canonical form, a positive autocorrelation decay.
59 *
60 * Indices are 1-based in the reference; the vectors here are 0-based, so
61 * G[0] is the reference's G(1).
62 */
63template <class T>
64Mamap2mCoefficients<T> mamap2m_can1_coefficients(const T& h1, const T& h2, const T& r1,
65 const T& r2) {
66 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
67 const T two = num_traits<T>::from_int(2), three = num_traits<T>::from_int(3);
69 c.G.assign(15, zero);
70 c.U.assign(12, zero);
71 c.Y.assign(3, zero);
72
73 const T A = T(r2 * (r1 - one) + one); // the reference's r2*(r1-1)+1
74 const T B = T(r1 * r2 - r2 + one); // and r1*r2 - r2 + 1
75 if (A == zero || B == zero)
76 throw NumericError(
77 "mamap2m_can1_coefficients: the canonical denominators vanish at this (r1, r2); the "
78 "marking coefficients are undefined there");
79
80 c.G[0] = T(one - r1 / A);
81 c.G[1] = T(-(r1 * (r2 - one)) / B);
82 c.G[2] = T((r1 * r2) / B);
83 c.G[3] = T((r1 * (r1 - one)) / A - r1 + one);
84 c.G[4] = T(-(r1 * (r1 - one) * (r2 - one) * (r2 - two)) / B);
85 c.G[5] = T((r1 * r2 * (r1 - one) * (r2 - one)) / B);
86 c.G[6] = T((r1 * r1 * (r2 - one) * (r2 - one)) / A);
87 c.G[7] = T(-(r1 * r2 * (r1 + one) * (r2 - one)) / B);
88 // The reference writes this into G(10) and immediately overwrites it; see
89 // the header note. It belongs at G(9).
90 c.G[8] = T((r1 * r2 * r2) / B);
91 c.G[9] = T(h1 - (h1 * r1) / A);
92 c.G[10] = T(-(r1 * (r2 - one) * (h1 + h2 - h1 * r2)) / B);
93 c.G[11] = T((r1 * r2 * (h1 + h2 - h1 * r2)) / B);
94 c.G[12] = T(((h1 + h2 * r1) * (r1 - one) * (r2 - one)) / B);
95 c.G[13] = T(-(r1 * (h1 + h2 * r1) * (r2 - one)) / B);
96 c.G[14] = T((h2 * r1 * r2) / B);
97
98 const T t1 = T(h1 - h2 + h2 * r1);
99 c.U[0] = T(B * B);
100 c.U[1] = T(-B * (two * h1 - h1 * r1 - two * h1 * r2 + three * h2 * r1 - h2 * r1 * r1 +
101 h2 * r1 * r1 * r2 + h1 * r1 * r2 - h2 * r1 * r2));
102 c.U[2] = T(r1 * (r2 - one) * t1 * t1);
103 c.U[3] = T(B * (h2 * h2 * r1 - h1 * h1 * r2 + h1 * h1 + h1 * h2 * r1 - h1 * h2 * r1 * r2));
104 c.U[4] = T(-r1 * (r2 - one) * B * t1);
105 c.U[5] = T(r1 * (r2 - one) * (h1 - h1 * r2 + h2 * r1) * t1);
106 const T t2 = T(h2 - h1 * r2);
107 c.U[6] = T(B * B);
108 c.U[7] = T(-B * (two * h1 - two * h1 * r2 + h2 * r1 - h1 * r1 * r2 * r2 + h1 * r1 * r2 +
109 h2 * r1 * r2));
110 c.U[8] = T(r1 * t2 * t2 * (r2 - one));
111 c.U[9] = T(B * (h2 * h2 * r1 - h1 * h1 * r2 + h1 * h1 + h1 * h2 * r1 - h1 * h2 * r1 * r2));
112 c.U[10] = T(-r1 * t2 * (r2 - one) * B);
113 c.U[11] = T(r1 * t2 * (r2 - one) * (h1 - h1 * r2 + h2 * r1));
114
115 // Y(1) is the 3x3 determinant of the (G1,G2,G3 | G10,G11,G12 | G13,G14,G15)
116 // block, and Y(2), Y(3) two of its 2x2 minors.
117 c.Y[0] = T(c.G[0] * c.G[10] * c.G[14] - c.G[0] * c.G[11] * c.G[13] -
118 c.G[1] * c.G[9] * c.G[14] + c.G[1] * c.G[11] * c.G[12] +
119 c.G[2] * c.G[9] * c.G[13] - c.G[2] * c.G[10] * c.G[12]);
120 c.Y[1] = T(c.G[2] * c.G[12] - c.G[0] * c.G[14]);
121 c.Y[2] = T(c.G[9] * c.G[2] - c.G[11] * c.G[0]);
122 return c;
123}
124
125/** Second canonical form, a negative autocorrelation decay (E, V, Z). */
126template <class T>
127Mamap2mCoefficients<T> mamap2m_can2_coefficients(const T& h1, const T& h2, const T& r1,
128 const T& r2) {
129 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
130 const T two = num_traits<T>::from_int(2), three = num_traits<T>::from_int(3);
132 c.G.assign(14, zero);
133 c.U.assign(12, zero);
134 c.Y.assign(3, zero);
135
136 const T A = T(r2 * (r1 - one) - r1 + two);
137 const T B = T(r1 * (r2 - one) - r2 + two);
138 const T C = T(r1 + r2 - r1 * r2 - two);
139 if (A == zero || B == zero || C == zero)
140 throw NumericError(
141 "mamap2m_can2_coefficients: the canonical denominators vanish at this (r1, r2); the "
142 "marking coefficients are undefined there");
143
144 c.G[0] = T(one - one / A);
145 c.G[1] = T(-(r2 - one) / B);
146 c.G[2] = T(r2 / B);
147 c.G[3] = T((r2 - two) / B - r2 + two);
148 c.G[4] = T(r2 - r2 / B);
149 c.G[5] = T(-(r1 * (r2 - one) * (r2 - one)) / C);
150 c.G[6] = T(-r2 - (r2 * (two * r2 - three)) / B);
151 c.G[7] = T(r2 * r2 / A);
152 c.G[8] = T(h1 - h1 / A);
153 c.G[9] = T(h1 * (r2 - one) - ((r2 - one) * (two * h1 + h2 - h1 * r2)) / B);
154 c.G[10] = T((r2 * (two * h1 + h2 - h1 * r2)) / B - h1 * r2);
155 c.G[11] = T(h2 - h2 / A);
156 c.G[12] = T(((h1 + h2 * r1) * (r2 - one)) / C);
157 c.G[13] = T((h2 * r2) / B);
158
159 const T t1 = T(h1 - h2 + h2 * r1);
160 const T t2 = T(h1 - h2 - h1 * r1 + h1 * r1 * r2);
161 c.U[0] = T(-C * C);
162 c.U[1] = T(-C * (two * h1 + two * h2 - h1 * r2 - h2 * r2 + h2 * r1 * r2));
163 c.U[2] = T(h2 * (two * h1 - h1 * r2 + h2 * r1) * C);
164 c.U[3] = T((r2 - one) * t1 * t1);
165 c.U[4] = T(t1 * (two * r2 - r1 * r2 + r1 * r2 * r2 - r2 * r2));
166 c.U[5] = T(-(h1 * r2 + h2 * r2 - h1 * r2 * r2) * t1);
167 c.U[6] = T(-C * C);
168 c.U[7] = T(-C * (two * h1 + two * h2 - h1 * r2 - h2 * r2 + h1 * r1 * r2 * r2 - h1 * r1 * r2));
169 c.U[8] = T(h1 * C * (two * h2 + h1 * r1 - h2 * r2 + h1 * r1 * r2 * r2 - two * h1 * r1 * r2));
170 c.U[9] = T((r2 - one) * t2 * t2);
171 c.U[10] = T(-r2 * t2 * C);
172 c.U[11] = T(-r2 * (h1 + h2 - h1 * r2) * t2);
173
174 c.Y[0] = T(c.G[9] * c.G[11] * c.G[2] - c.G[9] * c.G[13] * c.G[0] -
175 c.G[10] * c.G[11] * c.G[1] + c.G[10] * c.G[12] * c.G[0] -
176 c.G[12] * c.G[2] * c.G[8] + c.G[13] * c.G[1] * c.G[8]);
177 c.Y[1] = T(c.G[11] * c.G[1] - c.G[12] * c.G[0]);
178 c.Y[2] = T(c.G[9] * c.G[0] - c.G[1] * c.G[8]);
179 return c;
180}
181
182} // namespace mam
183} // namespace line
184
185#endif // LINE_API_MAM_MAMAP2M_COEFFICIENTS_H
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
Mamap2mCoefficients< T > mamap2m_can1_coefficients(const T &h1, const T &h2, const T &r1, const T &r2)
First canonical form, a positive autocorrelation decay.
Mamap2mCoefficients< T > mamap2m_can2_coefficients(const T &h1, const T &h2, const T &r1, const T &r2)
Second canonical form, a negative autocorrelation decay (E, V, Z).
Number-type abstraction for the templated API port.
The three coefficient tables of one canonical form.
std::vector< T > G
15 entries for form 1, 14 for form 2 (there called E)
std::vector< T > Y
3 determinants (Z for form 2)
std::vector< T > U
12 entries (V for form 2)