LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
trace_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_TRACE_JOINT_H
6#define LINE_API_TRACE_TRACE_JOINT_H
7
8/**
9 * @file
10 * @ingroup api_trace
11 * Joint moments of a trace, E[X_i^{k_1} X_{i+l_2}^{k_2} ...].
12 *
13 * Templated port of matlab/lib/kpctoolbox/trace/trace_joint.m, cross-checked
14 * against `jar/src/main/java/jline/api/trace/Trace_var.java#trace_joint`.
15 *
16 * The lag argument is a vector of INCREMENTS: MATLAB forms
17 * `lag = sort(cumsum(lag))` and then shifts it so that its first entry is 0,
18 * so trace_bicov's [1,i,j] means the triple (X_t, X_{t+i}, X_{t+i+j}).
19 *
20 * REFERENCE DEFECT (JAR): Trace_var.trace_joint sorts the lag vector but
21 * never takes the cumulative sum, and then indexes it with
22 * `adjustedLag[min(j, adjustedLag.length-1)]`, which also silently reuses the
23 * last lag when order is longer than lag. It therefore computes a different
24 * joint moment from MATLAB for every lag vector that is not already
25 * cumulative -- including the [1,i,j] grid that Trace_var.trace_bicov feeds
26 * it, so the JAR bicovariance is wrong wherever i or j differs from 1.
27 * MATLAB is the reference and is what this port implements; a lag and order
28 * of different lengths is rejected instead of being padded.
29 *
30 * ARITHMETIC: products of integer powers of the samples and one division,
31 * exact in Rational.
32 */
33
34#include <algorithm>
35#include <cstddef>
36#include <vector>
37
39#include "line/num/number.h"
40#include "line/util/error.h"
41
42namespace line {
43namespace trace {
44
45/**
46 * @brief Joint moments of a trace, E[X_i^{k_1} X_{i+l_2}^{k_2} ...].
47 *
48 * @param S the trace
49 * @param lag lag increments; cumulated and shifted to start at 0
50 * @param order the exponent of each factor, same length as lag
51 */
52template <class T>
53T trace_joint(const std::vector<T>& S, const std::vector<int>& lag,
54 const std::vector<unsigned>& order) {
55 detail::require_nonempty(S, "trace_joint");
56 if (lag.size() != order.size())
57 throw InputError("trace_joint: lag and order must have the same length");
58 if (lag.empty()) throw InputError("trace_joint: an empty lag vector");
59
60 std::vector<long> L(lag.size());
61 long acc = 0;
62 for (std::size_t i = 0; i < lag.size(); ++i) {
63 acc += lag[i];
64 L[i] = acc;
65 }
66 std::sort(L.begin(), L.end());
67 const long base = L[0];
68 for (std::size_t i = 0; i < L.size(); ++i) L[i] -= base;
69 const long maxlag = L.back();
70 if (maxlag < 0) throw InputError("trace_joint: the cumulated lags are not increasing");
71
72 const long n = static_cast<long>(S.size());
73 const long len = n - maxlag;
74 if (len <= 0) throw InputError("trace_joint: the lag span exceeds the trace length");
75
77 for (long t = 0; t < len; ++t) {
78 T prod = num_traits<T>::from_int(1);
79 for (std::size_t i = 0; i < L.size(); ++i)
80 prod *= num_pow_int(S[static_cast<std::size_t>(t + L[i])], order[i]);
81 sum += prod;
82 }
83 return sum / num_traits<T>::from_int(len);
84}
85
86} // namespace trace
87} // namespace line
88
89#endif // LINE_API_TRACE_TRACE_JOINT_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
T trace_joint(const std::vector< T > &S, const std::vector< int > &lag, const std::vector< unsigned > &order)
Joint moments of a trace, E[X_i^{k_1} X_{i+l_2}^{k_2} ...].
Definition trace_joint.h:53
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.
Shared declarations for the empirical trace statistics domain.