LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
m3pp2m_fitc.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_M3PP2M_FITC_H
6#define LINE_API_MAM_M3PP2M_FITC_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * Marked MMPP(2) with m classes, fitted to counting-process characteristics
12 * (matlab/lib/m3a/m3a/m3pp/m3pp2m_fitc.m).
13 *
14 * The underlying MMPP(2) comes from mmpp2_fitc; the per-class split is then
15 * closed form. For each of the first m-1 classes the pair (q1i, q2i) of
16 * per-phase marking probabilities follows from the class rate a_i and dvt3(i),
17 * the difference between the variance of class i and that of all other classes
18 * combined at resolution t3. The last class absorbs the remainder,
19 * Dm = diag(1 - sum_i q1i, 1 - sum_i q2i) .* D1.
20 *
21 * The reference expressions contain sinh(u) exp(-u) with u = (r1 + r2) t / 2
22 * nine times each; that product is (1 - exp(-(r1 + r2) t))/2 exactly, and is
23 * evaluated in that form here -- algebraically identical, and free of the
24 * cancellation that sinh times a decaying exponential suffers at large t.
25 *
26 * Not ported: m3pp2m_fitc_approx and m3pp2m_fitc_approx_ag, which wrap this
27 * split in a quadratic program (quadprog) over the per-class variances, and
28 * mmpp2_fitc_approx, whose MMPP(2) stage is an optimproblem/solve call rather
29 * than a closed form.
30 *
31 * Gated on transcendental arithmetic: through mmpp2_fitc, and through the
32 * exponential in SH.
33 */
34
35#include <vector>
36
41#include "line/num/number.h"
42#include "line/util/error.h"
43#include "line/util/matrix.h"
44
45namespace line {
46namespace mam {
47
48/** Result of m3pp2m_fitc. */
49template <class T>
52 bool degenerate; ///< the underlying MMPP(2) degenerated to a Poisson process
53};
54
55/**
56 * Fit an M3PP(2, m). ai holds the per-class arrival rates (summing to a),
57 * dvt3 the per-class variance differences at resolution t3.
58 */
59template <class T>
60M3pp2mFitcResult<T> m3pp2m_fitc(const T& a, const T& bt1, const T& bt2, const T& binf,
61 const T& m3t2, const T& t1, const T& t2, const std::vector<T>& ai,
62 const std::vector<T>& dvt3, const T& t3) {
64 "m3pp2m_fitc requires transcendental arithmetic");
65 using fitdetail::num_exp;
66 using fitdetail::pw;
67
68 const T zero = num_traits<T>::from_int(0);
69 const T one = num_traits<T>::from_int(1);
70 const T two = num_traits<T>::from_int(2);
71
72 const std::size_t m = ai.size();
73 if (m == 0) throw InputError("m3pp2m_fitc: no classes");
74 if (dvt3.size() + 1 < m) throw InputError("m3pp2m_fitc: dvt3 shorter than the class count");
75 T asum = zero;
76 for (std::size_t i = 0; i < m; ++i) asum += ai[i];
77 if (num_abs(T(a - asum)) > num_traits<T>::from_double(1e-8))
78 throw InputError("m3pp2m_fitc: inconsistent per-class arrival rates");
79
80 const Mmpp2FitcResult<T> base = mmpp2_fitc(a, bt1, bt2, binf, m3t2, t1, t2);
81
83 res.degenerate = base.degenerate;
84 res.mmap.D0 = base.map.D0;
85 res.mmap.D1 = base.map.D1;
86
87 if (base.degenerate) {
88 // Marked Poisson process: the per-class matrices are the class rates.
89 for (std::size_t i = 0; i < m; ++i) {
90 Matrix<T> Dc(1, 1, ai[i]);
91 res.mmap.Dc.push_back(Dc);
92 }
93 return res;
94 }
95
96 const T l1 = base.map.D1(0, 0);
97 const T l2 = base.map.D1(1, 1);
98 const T r1 = base.map.D0(0, 1);
99 const T r2 = base.map.D0(1, 0);
100 const T t = t3;
101 // sinh(u) exp(-u) with u = (r1 + r2) t / 2
102 const T SH = (one - num_exp(T(-(r1 + r2) * t))) / two;
103
104 std::vector<T> q1(m, zero), q2(m, zero);
105 for (std::size_t i = 0; i + 1 < m; ++i) {
106 const T a_1 = ai[i];
107 const T dv_1 = dvt3[i];
108 q1[i] = -(dv_1*pw(r1,4) + dv_1*pw(r2,4) - 2*a_1*pw(r1,4)*t - 2*a_1*pw(r2,4)*t + 4*dv_1*r1*pw(r2,3) +
109 4*dv_1*pw(r1,3)*r2 + l1*pw(r2,4)*t + l2*pw(r1,4)*t + 6*dv_1*pw(r1,2)*pw(r2,2) + 4*a_1*l1*pw(r2,3)*
110 t - 4*a_1*l2*pw(r2,3)*t - 8*a_1*r1*pw(r2,3)*t - 8*a_1*pw(r1,3)*r2*t + 3*l1*r1*pw(r2,3)*t + l1*
111 pw(r1,3)*r2*t + l2*r1*pw(r2,3)*t + 3*l2*pw(r1,3)*r2*t - 12*a_1*pw(r1,2)*pw(r2,2)*t + 3*l1*pw(r1,2)*
112 pw(r2,2)*t + 2*pw(l1,2)*r1*pw(r2,2)*t + 2*pw(l1,2)*pw(r1,2)*r2*t + 3*l2*pw(r1,2)*pw(r2,2)*t +
113 2*pw(l2,2)*r1*pw(r2,2)*t + 2*pw(l2,2)*pw(r1,2)*r2*t - 8*a_1*l1*pw(r2,2)*SH + 8*a_1*l2*pw(r2,2)*
114 SH - 4*pw(l1,2)*r1*r2*SH - 4*pw(l2,2)*r1*r2*SH + 8*a_1*l1*r1*pw(r2,2)*t + 4*a_1*l1*pw(r1,2)*
115 r2*t - 8*a_1*l2*r1*pw(r2,2)*t - 4*a_1*l2*pw(r1,2)*r2*t - 4*l1*l2*r1*pw(r2,2)*t - 4*l1*l2*pw(r1,2)*
116 r2*t - 8*a_1*l1*r1*r2*SH + 8*a_1*l2*r1*r2*SH + 8*l1*l2*r1*r2*SH)/(4*l1*r2*(r1 + r2)*(2*l1*SH -
117 2*l2*SH - l1*r1*t - l1*r2*t + l2*r1*t + l2*r2*t));
118 q2[i] = (dv_1*pw(r1,4) + dv_1*pw(r2,4) - 2*a_1*pw(r1,4)*t - 2*a_1*pw(r2,4)*t + 4*dv_1*r1*pw(r2,3) +
119 4*dv_1*pw(r1,3)*r2 + l1*pw(r2,4)*t + l2*pw(r1,4)*t + 6*dv_1*pw(r1,2)*pw(r2,2) - 4*a_1*l1*pw(r1,3)*
120 t + 4*a_1*l2*pw(r1,3)*t - 8*a_1*r1*pw(r2,3)*t - 8*a_1*pw(r1,3)*r2*t + 3*l1*r1*pw(r2,3)*t + l1*
121 pw(r1,3)*r2*t + l2*r1*pw(r2,3)*t + 3*l2*pw(r1,3)*r2*t - 12*a_1*pw(r1,2)*pw(r2,2)*t + 3*l1*pw(r1,2)*
122 pw(r2,2)*t + 2*pw(l1,2)*r1*pw(r2,2)*t + 2*pw(l1,2)*pw(r1,2)*r2*t + 3*l2*pw(r1,2)*pw(r2,2)*t +
123 2*pw(l2,2)*r1*pw(r2,2)*t + 2*pw(l2,2)*pw(r1,2)*r2*t + 8*a_1*l1*pw(r1,2)*SH - 8*a_1*l2*pw(r1,2)*
124 SH - 4*pw(l1,2)*r1*r2*SH - 4*pw(l2,2)*r1*r2*SH - 4*a_1*l1*r1*pw(r2,2)*t - 8*a_1*l1*pw(r1,2)*
125 r2*t + 4*a_1*l2*r1*pw(r2,2)*t + 8*a_1*l2*pw(r1,2)*r2*t - 4*l1*l2*r1*pw(r2,2)*t - 4*l1*l2*pw(r1,2)*
126 r2*t + 8*a_1*l1*r1*r2*SH - 8*a_1*l2*r1*r2*SH + 8*l1*l2*r1*r2*SH)/(4*(r1 + r2)*(pw(l2,2)*pw(r1,2)*
127 t - 2*pw(l2,2)*r1*SH - l1*l2*pw(r1,2)*t + pw(l2,2)*r1*r2*t + 2*l1*l2*r1*SH - l1*l2*r1*r2*t));
128 }
129 T s1 = zero, s2 = zero;
130 for (std::size_t i = 0; i + 1 < m; ++i) {
131 s1 += q1[i];
132 s2 += q2[i];
133 }
134 q1[m - 1] = one - s1;
135 q2[m - 1] = one - s2;
136
137 for (std::size_t i = 0; i < m; ++i) {
138 Matrix<T> Dc(2, 2, zero);
139 Dc(0, 0) = q1[i] * base.map.D1(0, 0);
140 Dc(1, 1) = q2[i] * base.map.D1(1, 1);
141 res.mmap.Dc.push_back(Dc);
142 }
143 return res;
144}
145
146} // namespace mam
147} // namespace line
148
149#endif // LINE_API_MAM_M3PP2M_FITC_H
InputError(const std::string &what)
Definition error.h:39
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...
Dense matrix and non-owning view.
Marked MAP (MMAP) algebra: per-class rates, class probabilities, superposition, normalization and sca...
MMPP(2) matching counting-process characteristics (matlab/lib/kpctoolbox/mmpp/mmpp2_fitc....
Mmpp2FitcResult< T > mmpp2_fitc(const T &mu, const T &bt1, const T &bt2, const T &binf, const T &m3t2, const T &t1, const T &t2)
MMPP(2) from the arrival rate, the IDC at t1, t2 and infinity, and the third central moment of the co...
Definition mmpp2_fitc.h:102
M3pp2mFitcResult< T > m3pp2m_fitc(const T &a, const T &bt1, const T &bt2, const T &binf, const T &m3t2, const T &t1, const T &t2, const std::vector< T > &ai, const std::vector< T > &dvt3, const T &t3)
Fit an M3PP(2, m).
Definition m3pp2m_fitc.h:60
T num_abs(const T &v)
Definition number.h:172
Number-type abstraction for the templated API port.
Result of m3pp2m_fitc.
Definition m3pp2m_fitc.h:50
bool degenerate
the underlying MMPP(2) degenerated to a Poisson process
Definition m3pp2m_fitc.h:52
An MMAP: the underlying MAP plus the per-class arrival matrices.
Definition mmap_lambda.h:45
Result of mmpp2_fitc.
Definition mmpp2_fitc.h:91
bool degenerate
true when a Poisson process was returned instead
Definition mmpp2_fitc.h:93