LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
mtrace_joint.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_TRACE_MTRACE_JOINT_H
6#define LINE_API_TRACE_MTRACE_JOINT_H
7
8/**
9 * @file
10 * @ingroup api_trace
11 * Class-dependent joint moments of a marked trace,
12 *
13 * JM(a) = (1/N_a) sum_{j : A_{j+1} = a} T_j^{i1} T_{j+1}^{i2},
14 *
15 * the empirical estimate of E[(X_j)^{i1} (X_{j+1})^{i2}] conditioned on the
16 * middle event being of class a; the sum runs over the interior events, so
17 * the first and last event of the trace are excluded.
18 *
19 * Templated port of matlab/lib/m3a/m3a/mtrace/mtrace_joint.m, cross-checked
20 * against jar/src/main/java/jline/api/trace/Mtrace_joint.java (identical,
21 * including the index range and the normalization by the interior class
22 * count).
23 *
24 * Both references index classes by the RAW label 1..max(A) rather than by
25 * position in unique(A), so a label alphabet with gaps yields zero rows. That
26 * convention is preserved here: entry a-1 of the result refers to label a.
27 *
28 * ARITHMETIC: sums of products of integer powers, exact in Rational.
29 */
30
31#include <cstddef>
32#include <vector>
33
35#include "line/num/number.h"
36#include "line/util/error.h"
37
38namespace line {
39namespace trace {
40
41/** Return value of mtrace_joint. */
42template <class T>
44 std::vector<T> jm; ///< one moment per label 1..max(A)
45 std::vector<long> count; ///< interior events of each label; 0 = undefined
46};
47
48/**
49 * @brief Class-dependent joint moments of a marked trace, JM(a) = (1/N_a)
50 * sum_{j : A_{j+1} = a} T_j^{i1} T_{j+1}^{i2}, the empirical estimate
51 * of E[(X_j)^{i1} (X_{j+1})^{i2}] conditioned on the middle event
52 * being of class a; the sum runs over the interior events, so the
53 * first and last event of the trace are excluded.
54 *
55 * @param Tv inter-event times
56 * @param A class labels, positive
57 * @param i1 exponent of the first interval
58 * @param i2 exponent of the second interval
59 */
60template <class T>
61MtraceJointResult<T> mtrace_joint(const std::vector<T>& Tv, const std::vector<int>& A,
62 unsigned i1, unsigned i2) {
63 detail::require_marked(Tv, A, "mtrace_joint");
64 const std::size_t N = A.size();
65 if (N < 3) throw InputError("mtrace_joint: at least three events are required");
66 int maxlab = 0;
67 for (std::size_t k = 0; k < N; ++k) {
68 if (A[k] < 0) throw InputError("mtrace_joint: class labels must be nonnegative");
69 if (A[k] > maxlab) maxlab = A[k];
70 }
72 out.jm.assign(static_cast<std::size_t>(maxlab), num_traits<T>::from_int(0));
73 out.count.assign(static_cast<std::size_t>(maxlab), 0);
74
75 for (int a = 1; a <= maxlab; ++a) {
76 const std::size_t ai = static_cast<std::size_t>(a - 1);
77 for (std::size_t j = 1; j + 1 < N; ++j)
78 if (A[j] == a) out.count[ai] += 1;
79 T tmp = num_traits<T>::from_int(0);
80 for (std::size_t j = 0; j + 2 < N; ++j)
81 if (A[j + 1] == a) tmp += num_pow_int(Tv[j], i1) * num_pow_int(Tv[j + 1], i2);
82 if (out.count[ai] > 0) out.jm[ai] = tmp / num_traits<T>::from_int(out.count[ai]);
83 }
84 return out;
85}
86
87} // namespace trace
88} // namespace line
89
90#endif // LINE_API_TRACE_MTRACE_JOINT_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
MtraceJointResult< T > mtrace_joint(const std::vector< T > &Tv, const std::vector< int > &A, unsigned i1, unsigned i2)
Class-dependent joint moments of a marked trace, JM(a) = (1/N_a) sum_{j : A_{j+1} = a}...
T num_pow_int(const T &base, unsigned e)
Integer power, valid in any field (no transcendental requirement).
Definition number.h:192
Number-type abstraction for the templated API port.
Return value of mtrace_joint.
std::vector< long > count
interior events of each label; 0 = undefined
std::vector< T > jm
one moment per label 1..max(A)
Shared declarations for the empirical trace statistics domain.