LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
m3pp2m_fitc_trace.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_TRACE_H
6#define LINE_API_MAM_M3PP2M_FITC_TRACE_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * M3PP(2, m) fitted to the counting process of a multi-class TRACE
12 * (matlab/lib/m3a/m3a/m3pp/m3pp2m_fitc_trace.m), and the analogous
13 * MMPP(2) entry point for a given MAP
14 * (matlab/lib/kpctoolbox/mmpp/mmpp2_fitc_theoretical.m).
15 *
16 * The trace is reduced to counting windows with mtrace_iat2counts at two
17 * resolutions, and the aggregate characteristics (rate, IDC at t1 and at tinf,
18 * third central moment at t2) plus the per-class ones are read off those
19 * windows; the four methods then differ only in WHICH per-class statistic they
20 * feed to the corresponding fitter:
21 * - exact_delta -> m3pp2m_fitc, per-class variance DIFFERENCE
22 * - approx_delta -> m3pp2m_fitc_approx, same, least squares
23 * - approx_cov -> m3pp22_fitc_approx_cov, pairwise covariance, 2 classes only
24 * - approx_ag -> m3pp2m_fitc_approx_ag, variance plus covariance
25 *
26 * Two conventions of the reference are load-bearing and are kept verbatim.
27 * First, bt2 is set EQUAL to bt1 rather than measured at t2: the reference
28 * counts at t1 and reuses the window (mNt2 = mNt1), so the second time scale
29 * enters only through t2 = t1 + mean(T) in the fitter's own algebra. Second,
30 * t3 = tinf and not t1; the reference carries a comment recording that change,
31 * and it is what sets how far out the per-class characteristics are matched.
32 *
33 * MATLAB's `var` normalizes by n - 1 and its `cov` likewise; both are used here
34 * with the same denominator, since the fitted characteristics are compared
35 * against the reference's.
36 *
37 * Gated on transcendental arithmetic, through the fitters.
38 */
39
40#include <cstddef>
41#include <string>
42#include <vector>
43
52#include "line/num/number.h"
53#include "line/util/error.h"
54#include "line/util/matrix.h"
55
56namespace line {
57namespace mam {
58
59/** Result of m3pp2m_fitc_trace. */
60template <class T>
62 Mmap<T> mmap; ///< the fitted M3PP(2, m)
63 std::string method; ///< the method actually run
64 T a; ///< the aggregate rate read off the trace
65 T bt1; ///< IDC at t1
66 T binf; ///< IDC at tinf
67 T m3t2; ///< third central moment of counts at t2
68};
69
70namespace fitdetail {
71
72/** Sample variance, MATLAB `var`, of the row sums of a count matrix. */
73template <class T>
74T rowsum_var(const Matrix<long>& C) {
75 const std::size_t n = C.rows();
76 if (n < 2) throw InputError("m3pp2m_fitc_trace: fewer than two counting windows");
77 std::vector<T> s(n, num_traits<T>::from_int(0));
78 for (std::size_t i = 0; i < n; ++i) {
79 long acc = 0;
80 for (std::size_t j = 0; j < C.cols(); ++j) acc += C(i, j);
81 s[i] = num_traits<T>::from_int(acc);
82 }
84 for (std::size_t i = 0; i < n; ++i) mu += s[i];
85 mu /= num_traits<T>::from_int(static_cast<long>(n));
86 T acc = num_traits<T>::from_int(0);
87 for (std::size_t i = 0; i < n; ++i) acc += (s[i] - mu) * (s[i] - mu);
88 return acc / num_traits<T>::from_int(static_cast<long>(n - 1));
89}
90
91/** Sample raw moment of order `power` of the row sums of a count matrix. */
92template <class T>
93T rowsum_moment(const Matrix<long>& C, unsigned power) {
94 const std::size_t n = C.rows();
95 T acc = num_traits<T>::from_int(0);
96 for (std::size_t i = 0; i < n; ++i) {
97 long s = 0;
98 for (std::size_t j = 0; j < C.cols(); ++j) s += C(i, j);
100 for (unsigned k = 0; k < power; ++k) p *= num_traits<T>::from_int(s);
101 acc += p;
102 }
103 return acc / num_traits<T>::from_int(static_cast<long>(n));
104}
105
106/** Sample variance of "column c" and of "everything but column c". */
107template <class T>
108void split_var(const Matrix<long>& C, std::size_t c, T& vc, T& vrest) {
109 const std::size_t n = C.rows();
110 if (n < 2) throw InputError("m3pp2m_fitc_trace: fewer than two counting windows");
111 std::vector<T> x(n), y(n);
112 for (std::size_t i = 0; i < n; ++i) {
113 long tot = 0;
114 for (std::size_t j = 0; j < C.cols(); ++j) tot += C(i, j);
115 x[i] = num_traits<T>::from_int(C(i, c));
116 y[i] = num_traits<T>::from_int(tot - C(i, c));
117 }
118 T mx = num_traits<T>::from_int(0), my = num_traits<T>::from_int(0);
119 for (std::size_t i = 0; i < n; ++i) {
120 mx += x[i];
121 my += y[i];
122 }
123 const T nn = num_traits<T>::from_int(static_cast<long>(n));
124 mx /= nn;
125 my /= nn;
126 T ax = num_traits<T>::from_int(0), ay = num_traits<T>::from_int(0);
127 for (std::size_t i = 0; i < n; ++i) {
128 ax += (x[i] - mx) * (x[i] - mx);
129 ay += (y[i] - my) * (y[i] - my);
130 }
131 const T nm1 = num_traits<T>::from_int(static_cast<long>(n - 1));
132 vc = ax / nm1;
133 vrest = ay / nm1;
134}
135
136/** Sample covariance between "column c" and "everything but column c". */
137template <class T>
138T split_cov(const Matrix<long>& C, std::size_t c) {
139 const std::size_t n = C.rows();
140 if (n < 2) throw InputError("m3pp2m_fitc_trace: fewer than two counting windows");
141 std::vector<T> x(n), y(n);
142 for (std::size_t i = 0; i < n; ++i) {
143 long tot = 0;
144 for (std::size_t j = 0; j < C.cols(); ++j) tot += C(i, j);
145 x[i] = num_traits<T>::from_int(C(i, c));
146 y[i] = num_traits<T>::from_int(tot - C(i, c));
147 }
148 T mx = num_traits<T>::from_int(0), my = num_traits<T>::from_int(0);
149 for (std::size_t i = 0; i < n; ++i) {
150 mx += x[i];
151 my += y[i];
152 }
153 const T nn = num_traits<T>::from_int(static_cast<long>(n));
154 mx /= nn;
155 my /= nn;
156 T acc = num_traits<T>::from_int(0);
157 for (std::size_t i = 0; i < n; ++i) acc += (x[i] - mx) * (y[i] - my);
158 return acc / num_traits<T>::from_int(static_cast<long>(n - 1));
159}
160
161} // namespace fitdetail
162
163/**
164 * Fit a multi-class trace with an M3PP(2, m) on its counting process.
165 *
166 * @param Tv inter-arrival times
167 * @param A class labels
168 * @param method 'exact_delta', 'approx_delta', 'approx_cov' or 'approx_ag'
169 * @param t1 finite time scale
170 * @param tinf near-infinite time scale
171 */
172template <class T>
173M3pp2mFitcTraceResult<T> m3pp2m_fitc_trace(const std::vector<T>& Tv, const std::vector<int>& A,
174 const std::string& method, const T& t1, const T& tinf) {
176 "m3pp2m_fitc_trace requires transcendental arithmetic");
177 if (Tv.empty()) throw InputError("m3pp2m_fitc_trace: empty trace");
178 if (A.size() != Tv.size())
179 throw InputError("m3pp2m_fitc_trace: labels and inter-arrival times disagree");
180
183 const std::size_t m = N1.labels.size();
184 if (method == "approx_cov" && m > 2)
185 throw InputError("m3pp2m_fitc_trace: approximate covariance fitting only supports two "
186 "classes");
187
188 T sumT = num_traits<T>::from_int(0);
189 for (std::size_t i = 0; i < Tv.size(); ++i) sumT += Tv[i];
190 const T mean = sumT / num_traits<T>::from_int(static_cast<long>(Tv.size()));
191 const T a = num_traits<T>::from_int(1) / mean;
192 const T t2 = t1 + mean;
193 const T t3 = tinf; // the reference sets the third scale to tinf, not t1
194
195 std::vector<T> ai(m);
196 for (std::size_t i = 0; i < m; ++i) {
197 long cnt = 0;
198 for (std::size_t k = 0; k < A.size(); ++k)
199 if (A[k] == N1.labels[i]) ++cnt;
200 ai[i] = a * num_traits<T>::from_int(cnt) /
201 num_traits<T>::from_int(static_cast<long>(A.size()));
202 }
203
204 const T bt1 = fitdetail::rowsum_var<T>(N1.counts) / (a * t1);
205 const T bt2 = bt1; // the reference reuses the t1 window for the second scale
206 const T binf = fitdetail::rowsum_var<T>(Ninf.counts) / (a * tinf);
207 const T m3t2 = fitdetail::m3_from_raw(fitdetail::rowsum_moment<T>(N1.counts, 1),
208 fitdetail::rowsum_moment<T>(N1.counts, 2),
209 fitdetail::rowsum_moment<T>(N1.counts, 3));
210
212 out.method = method;
213 out.a = a;
214 out.bt1 = bt1;
215 out.binf = binf;
216 out.m3t2 = m3t2;
217
218 if (method == "exact_delta" || method == "approx_delta") {
219 std::vector<T> dvt3(m);
220 for (std::size_t i = 0; i < m; ++i) {
222 fitdetail::split_var<T>(N1.counts, i, vc, vr);
223 dvt3[i] = vc - vr;
224 }
225 if (method == "exact_delta")
226 out.mmap = m3pp2m_fitc(a, bt1, bt2, binf, m3t2, t1, t2, ai, dvt3, t3).mmap;
227 else
228 out.mmap = m3pp2m_fitc_approx(a, bt1, bt2, binf, m3t2, t1, t2, ai, dvt3, t3).mmap;
229 return out;
230 }
231 if (method == "approx_cov") {
232 const T V = fitdetail::rowsum_var<T>(N1.counts);
234 T dummy = num_traits<T>::from_int(0);
235 fitdetail::split_var<T>(N1.counts, 0, v0, dummy);
236 fitdetail::split_var<T>(N1.counts, 1, v1, dummy);
237 const T s = (V - v0 - v1) / num_traits<T>::from_int(2);
238 out.mmap = m3pp22_fitc_approx_cov(a, bt1, bt2, binf, m3t2, t1, t2, ai, s, t3).mmap;
239 return out;
240 }
241 if (method == "approx_ag") {
242 std::vector<T> gt3(m);
243 for (std::size_t i = 0; i < m; ++i) {
245 fitdetail::split_var<T>(N1.counts, i, vc, vr);
246 gt3[i] = vc + fitdetail::split_cov<T>(N1.counts, i);
247 }
248 out.mmap = m3pp2m_fitc_approx_ag(a, bt1, bt2, binf, m3t2, t1, t2, ai, gt3, t3).mmap;
249 return out;
250 }
251 throw InputError("m3pp2m_fitc_trace: unknown method '" + method + "'");
252}
253
254/** m3pp2m_fitc_trace with the reference's default time scales. */
255template <class T>
256M3pp2mFitcTraceResult<T> m3pp2m_fitc_trace(const std::vector<T>& Tv, const std::vector<int>& A,
257 const std::string& method) {
258 if (Tv.empty()) throw InputError("m3pp2m_fitc_trace: empty trace");
259 T sumT = num_traits<T>::from_int(0);
260 for (std::size_t i = 0; i < Tv.size(); ++i) sumT += Tv[i];
261 const T mean = sumT / num_traits<T>::from_int(static_cast<long>(Tv.size()));
262 const T t1 = num_traits<T>::from_int(10) * mean;
263 const T span = (sumT - Tv[0]) / num_traits<T>::from_int(100);
264 const T ten_t = num_traits<T>::from_int(10) * t1;
265 return m3pp2m_fitc_trace(Tv, A, method, t1, ten_t > span ? ten_t : span);
266}
267
268/**
269 * MMPP(2) fitted to the counting characteristics of a GIVEN MAP
270 * (matlab/lib/kpctoolbox/mmpp/mmpp2_fitc_theoretical.m). The characteristics
271 * are the rate at t1, the IDC at t1, t2 and tinf, and the third central moment
272 * of counts at t2, all evaluated exactly on the input MAP.
273 */
274template <class T>
275Mmpp2FitcResult<T> mmpp2_fitc_theoretical(const Map<T>& mp, const T& t1, const T& t2,
276 const T& tinf) {
278 "mmpp2_fitc_theoretical requires transcendental arithmetic");
279 std::vector<T> ts;
280 ts.push_back(t1);
281 ts.push_back(t2);
282 ts.push_back(tinf);
283 const std::vector<T> mu = map_count_mean(mp, ts);
284 const std::vector<T> vr = map_count_var(mp, ts);
285
286 const T a = mu[0] / t1;
287 const T bt1 = vr[0] / (a * t1);
288 const T bt2 = vr[1] / (a * t2);
289 const T binf = vr[2] / (a * tinf);
290
291 std::vector<unsigned> orders;
292 orders.push_back(1);
293 orders.push_back(2);
294 orders.push_back(3);
295 const std::vector<T> mt2 = map_count_moment(mp, t2, orders);
296 const T m3t2 = fitdetail::m3_from_raw(mt2[0], mt2[1], mt2[2]);
297
298 return mmpp2_fitc(a, bt1, bt2, binf, m3t2, t1, t2);
299}
300
301/** mmpp2_fitc_theoretical with the reference's default time scales 1, 10, 1e8. */
302template <class T>
307
308} // namespace mam
309} // namespace line
310
311#endif // LINE_API_MAM_M3PP2M_FITC_TRACE_H
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
The exception types the port throws.
M3PP(2, 2) fitted to the count COVARIANCE between its two classes (matlab/lib/m3a/m3a/m3pp/m3pp22_fit...
Marked MMPP(2) with m classes, fitted to counting-process characteristics (matlab/lib/m3a/m3a/m3pp/m3...
M3PP(2, m) fitted to counting-process characteristics with an optimized per-class split (matlab/lib/m...
M3PP obtained by SUPERPOSING one second-order process per class (matlab/lib/m3a/m3a/m3pp/m3pp_superpo...
Mean of the counting process of a MAP at resolution t.
Power moments of the counts of a MAP in a window of length t.
Variance of the counting process of a MAP at resolution t.
Dense matrix and non-owning view.
Per-class counting processes of a marked trace: for each arrival, how many events of each class fall ...
M3pp2mFitcApproxResult< T > m3pp2m_fitc_approx_ag(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 > &gt3, const T &t3, const std::vector< Bound< T > > &bounds, const AugLagOptions< T > &opt)
m3pp2m_fitc_approx_ag: fit the underlying MMPP(2) by optimization, then apply the 'ag' per-class spli...
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
std::vector< T > map_count_var(const Map< T > &m, const std::vector< T > &t)
Variance of the counting process of a MAP at resolution t.
Mmpp2FitcResult< T > mmpp2_fitc_theoretical(const Map< T > &mp, const T &t1, const T &t2, const T &tinf)
MMPP(2) fitted to the counting characteristics of a GIVEN MAP (matlab/lib/kpctoolbox/mmpp/mmpp2_fitc_...
std::vector< T > map_count_mean(const Map< T > &m, const std::vector< T > &t)
Mean of the counting process of a MAP at resolution t.
M3pp22FitcCovResult< T > m3pp22_fitc_approx_cov(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 T &st3, const T &t3, const AugLagOptions< T > &opt)
Fit the underlying MMPP(2) by optimization, then apply the covariance split.
M3pp2mFitcApproxResult< T > m3pp2m_fitc_approx(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, const std::vector< Bound< T > > &bounds, const AugLagOptions< T > &opt)
m3pp2m_fitc_approx: fit the underlying MMPP(2) by optimization, then split the classes on their varia...
M3pp2mFitcTraceResult< T > m3pp2m_fitc_trace(const std::vector< T > &Tv, const std::vector< int > &A, const std::string &method, const T &t1, const T &tinf)
Fit a multi-class trace with an M3PP(2, m) on its counting process.
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.
MtraceCountsResult< T > mtrace_iat2counts(const std::vector< T > &Tv, const std::vector< int > &A, const T &scale)
Per-class counting processes of a marked trace: for each arrival, how many events of each class fall ...
Number-type abstraction for the templated API port.
Result of m3pp2m_fitc_trace.
std::string method
the method actually run
Mmap< T > mmap
the fitted M3PP(2, m)
T m3t2
third central moment of counts at t2
T a
the aggregate rate read off the trace
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
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
Return value of mtrace_iat2counts.
Matrix< long > counts
(rows x C), column c for labels[c]
std::vector< int > labels
the distinct labels, increasing