LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
amap2_fitall_gamma.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_AMAP2_FITALL_GAMMA_H
6#define LINE_API_MAM_AMAP2_FITALL_GAMMA_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * All AMAP(2) representations matching three moments and the autocorrelation
12 * decay rate (matlab/lib/m3a/m3a/amap2/amap2_fitall_gamma.m).
13 *
14 * The two phase means h1, h2 come from the same quadratic as aph2_fitall. For
15 * GAMMA >= 0 the first canonical form leaves a further quadratic in the
16 * branching probability r2, with discriminant
17 * z = M1^2 G^2 + (2 M1 h1 + 2 M1 h2 - 4 h1 h2 - 2 M1^2) G
18 * + M1^2 - 2 M1 h1 - 2 M1 h2 + h1^2 + 2 h1 h2 + h2^2,
19 * so up to four AMAP(2)s can match the same characteristics; for GAMMA < 0 the
20 * second canonical form determines r1 and r2 uniquely per (h1, h2). Solutions
21 * whose probabilities fall outside [0, 1] beyond r12tol are discarded, the
22 * others are clamped into [0, 1].
23 *
24 * Unlike aph2_fitall this returns an empty vector when the characteristics are
25 * infeasible: no approximate fitting is performed, exactly as in the reference.
26 *
27 * Gated on transcendental arithmetic: the two moment discriminants and the
28 * SCV <= 1 lower bound of the third moment are square roots.
29 */
30
31#include <vector>
32
36#include "line/num/number.h"
37#include "line/util/error.h"
38
39namespace line {
40namespace mam {
41
42/**
43 * Every AMAP(2) matching (M1, M2, M3, GAMMA). degentol screens the degenerate
44 * discriminants (MATLAB 1e-8); r12tol is the slack allowed on the branching
45 * probabilities before a solution is rejected (MATLAB 1e-6).
46 */
47template <class T>
48std::vector<Map<T>> amap2_fitall_gamma(const T& M1, const T& M2, const T& M3, const T& GAMMA,
49 const T& degentol, const T& r12tol) {
51 "amap2_fitall_gamma requires transcendental arithmetic");
52 using fitdetail::num_sqrt;
53 using fitdetail::pw;
54
55 const T zero = num_traits<T>::from_int(0);
56 const T one = num_traits<T>::from_int(1);
57 const T two = num_traits<T>::from_int(2);
58 const T three = num_traits<T>::from_int(3);
59 const T four = num_traits<T>::from_int(4);
60
61 std::vector<Map<T>> out;
62 if (M1 <= zero) throw InputError("amap2_fitall_gamma: non-positive first moment");
63
64 const T SCV = (M2 - M1 * M1) / (M1 * M1);
65 bool degenerate = false;
66 if (SCV <= one) {
67 const T d = one - SCV;
68 const T M3lb = three * pw(M1, 3) * (three * SCV - one + num_sqrt(two) * d * num_sqrt(d));
69 if (num_abs(T(M3 - M3lb)) < degentol) degenerate = true;
70 }
71
72 T tmp0 = zero;
73 if (!degenerate) {
74 tmp0 = M3 * M3 / num_traits<T>::from_int(9) +
75 ((num_traits<T>::from_int(8) * pw(M1, 3)) / three - two * M2 * M1) * M3 -
76 three * M1 * M1 * M2 * M2 + two * pw(M2, 3);
77 if (tmp0 < zero) return out;
78 }
79
80 const T tmp1 = three * num_sqrt(tmp0);
81 const T tmp2 = M3 - three * M1 * M2;
82 const T tmp3 = num_traits<T>::from_int(6) * M2 - num_traits<T>::from_int(12) * M1 * M1;
83 if (tmp3 == zero) throw NumericError("amap2_fitall_gamma: degenerate moment set (M2 = 2 M1^2)");
84
85 const std::size_t n = (tmp0 == zero) ? 1u : 2u;
86 std::vector<T> h1v(n, zero), h2v(n, zero);
87 if (n == 1) {
88 h2v[0] = tmp2 / tmp3;
89 h1v[0] = h2v[0];
90 } else {
91 h2v[0] = (tmp2 + tmp1) / tmp3;
92 h2v[1] = (tmp2 - tmp1) / tmp3;
93 h1v[1] = h2v[0];
94 h1v[0] = h2v[1];
95 }
96 for (std::size_t j = 0; j < n; ++j)
97 if (h2v[j] <= zero) return out;
98
99 const T lo = -r12tol;
100 const T hi = one + r12tol;
101
102 for (std::size_t j = 0; j < n; ++j) {
103 const T h1 = h1v[j];
104 const T h2 = h2v[j];
105 if (GAMMA >= zero) {
106 const T z = M1 * M1 * GAMMA * GAMMA +
107 (two * M1 * h1 + two * M1 * h2 - four * h1 * h2 - two * M1 * M1) * GAMMA +
108 M1 * M1 - two * M1 * h1 - two * M1 * h2 + h1 * h1 + two * h1 * h2 + h2 * h2;
109 std::vector<T> r2v;
110 if (num_abs(z) < degentol) {
111 if (h1 == zero) continue;
112 r2v.push_back(T((h1 - M1 + h2 + GAMMA * M1) / (two * h1)));
113 } else if (z > zero) {
114 if (h1 == zero) continue;
115 const T s = num_sqrt(z);
116 r2v.push_back(T((h1 - M1 + h2 - s + GAMMA * M1) / (two * h1)));
117 r2v.push_back(T((h1 - M1 + h2 + s + GAMMA * M1) / (two * h1)));
118 }
119 for (std::size_t i = 0; i < r2v.size(); ++i) {
120 T r2 = r2v[i];
121 const T den = h2 - M1 * r2;
122 if (den == zero) continue;
123 T r1 = (M1 - h1 - M1 * r2 + h1 * r2) / den;
124 if (!(r1 >= lo && r1 <= hi && r2 >= lo && r2 <= hi)) continue;
125 if (r1 > one) r1 = one;
126 if (r1 < zero) r1 = zero;
127 if (r2 > one) r2 = one;
128 if (r2 < zero) r2 = zero;
129 out.push_back(amap2_assemble(h1, h2, r1, r2, 1));
130 }
131 } else {
132 if (h1 == zero) continue;
133 T r2 = (h1 - M1 + h2 + GAMMA * M1) / h1;
134 if (r2 == one) continue;
135 T r1 = (r2 + (h1 + h2 - h1 * r2) / M1 - two) / (r2 - one);
136 if (!(r1 >= lo && r1 <= hi && r2 >= lo && r2 <= hi)) continue;
137 if (r1 > one) r1 = one;
138 if (r1 < zero) r1 = zero;
139 if (r2 > one) r2 = one;
140 if (r2 < zero) r2 = zero;
141 out.push_back(amap2_assemble(h1, h2, r1, r2, 2));
142 }
143 }
144 return out;
145}
146
147/** amap2_fitall_gamma with the MATLAB defaults degentol = 1e-8, r12tol = 1e-6. */
148template <class T>
149std::vector<Map<T>> amap2_fitall_gamma(const T& M1, const T& M2, const T& M3, const T& GAMMA) {
150 return amap2_fitall_gamma(M1, M2, M3, GAMMA, T(num_traits<T>::from_double(1e-8)),
152}
153
154} // namespace mam
155} // namespace line
156
157#endif // LINE_API_MAM_AMAP2_FITALL_GAMMA_H
Assemble an AMAP(2) in one of the two canonical forms (matlab/lib/m3a/m3a/amap2/amap2_assemble....
InputError(const std::string &what)
Definition error.h:39
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
Scalar helpers shared by the MAP/PH moment-matching headers.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Map< T > amap2_assemble(const T &l1, const T &l2, const T &p1, const T &p2, int form)
AMAP(2) in canonical form 1 (gamma >= 0) or 2 (gamma < 0).
std::vector< Map< T > > amap2_fitall_gamma(const T &M1, const T &M2, const T &M3, const T &GAMMA, const T &degentol, const T &r12tol)
Every AMAP(2) matching (M1, M2, M3, GAMMA).
T num_abs(const T &v)
Definition number.h:172
Number-type abstraction for the templated API port.