LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
trace_idi.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_IDI_H
6#define LINE_API_TRACE_TRACE_IDI_H
7
8/**
9 * @file
10 * @ingroup api_trace
11 * Index of dispersion for intervals,
12 *
13 * IDI(k) = k * var(S_t + ... + S_{t+k-1}) / mean(S_t + ... + S_{t+k-1})^2,
14 *
15 * the standard burstiness descriptor of Sriram and Whitt (JSAC 6, 1986).
16 *
17 * Templated port of matlab/lib/kpctoolbox/trace/trace_idi.m, cross-checked
18 * against `jar/src/main/java/jline/api/trace/Trace_var.java#trace_idi`.
19 *
20 * REFERENCE DEFECT (both codebases, identical): the vector of aggregated
21 * samples is allocated with length(S)-k entries but the loop fills only
22 * length(S)-k-1 of them, so a spurious ZERO sample is always included in the
23 * variance and the mean. The bias is O(1/(n-k)) and vanishes for long traces,
24 * but it is real and it is reproduced here deliberately: removing it would
25 * silently change every IDI/IDC value LINE reports. The `drop_trailing_zero`
26 * flag computes the intended statistic instead.
27 *
28 * DIVERGENCE, MATLAB vs JAR: MATLAB's var uses the n-1 denominator, the JAR's
29 * trace_var uses n; MATLAB is the reference. The 'aggregate-mix' branch of
30 * trace_idi.m is not ported -- it partitions the trace by a per-sample
31 * aggregation-count vector that no caller in LINE supplies, and its MATLAB
32 * implementation overwrites Sk on every outer iteration, so what it returns
33 * is the statistic of the last partition only.
34 *
35 * ARITHMETIC: sums, a variance and a division, exact in Rational.
36 */
37
38#include <cstddef>
39#include <vector>
40
44#include "line/num/number.h"
45#include "line/util/error.h"
46
47namespace line {
48namespace trace {
49
50/** Return value of trace_idi, mirroring [IDIk, support]. */
51template <class T>
53 std::vector<T> idi; ///< one value per requested k
54 std::vector<long> support; ///< the number of points each value rests on
55};
56
57/**
58 * @brief Index of dispersion for intervals, IDI(k) = k * var(S_t + ... +
59 * S_{t+k-1}) / mean(S_t + ... + S_{t+k-1})^2, the standard burstiness
60 * descriptor of Sriram and Whitt (JSAC 6, 1986).
61 *
62 * @param k_set aggregation levels
63 * @param aggregate_n 0 for raw samples; n > 0 when S is already the
64 * sum of n inter-arrivals, which uses k/n windows
65 * (MATLAB's 'aggregate' option)
66 * @param drop_trailing_zero true removes the spurious zero sample described
67 * above; false (default) reproduces the references
68 * @param S the interarrival-time trace
69 */
70template <class T>
71TraceIdiResult<T> trace_idi(const std::vector<T>& S, const std::vector<long>& k_set,
72 long aggregate_n = 0, bool drop_trailing_zero = false) {
73 detail::require_nonempty(S, "trace_idi");
74 const long n = static_cast<long>(S.size());
76 for (std::size_t a = 0; a < k_set.size(); ++a) {
77 const long k = k_set[a];
78 if (k <= 0) throw InputError("trace_idi: the aggregation level must be positive");
79 long keff = k;
80 long support = n - k - 1;
81 if (aggregate_n > 0) {
82 keff = k / aggregate_n;
83 if (keff <= 0) throw InputError("trace_idi: the aggregation level is below n");
84 support = n / keff;
85 }
86 const long len = n - keff; // allocated length in both references
87 const long filled = n - keff - 1;
88 if (filled < 1) throw InputError("trace_idi: the aggregation level exceeds the trace length");
89 const long used = drop_trailing_zero ? filled : len;
90 if (used < 2) throw InputError("trace_idi: too few aggregated samples for a variance");
91
92 std::vector<T> Sk(static_cast<std::size_t>(used), num_traits<T>::from_int(0));
93 for (long t = 0; t < filled; ++t) {
95 for (long j = t; j < t + keff; ++j) s += S[static_cast<std::size_t>(j)];
96 Sk[static_cast<std::size_t>(t)] = s;
97 }
98 const T mu = trace_mean(Sk);
99 if (mu == num_traits<T>::from_int(0))
100 throw NumericError("trace_idi: the aggregated samples have zero mean");
101 out.idi.push_back(num_traits<T>::from_int(k) * trace_var(Sk) / (mu * mu));
102 out.support.push_back(support);
103 }
104 return out;
105}
106
107} // namespace trace
108} // namespace line
109
110#endif // LINE_API_TRACE_TRACE_IDI_H
InputError(const std::string &what)
Definition error.h:39
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
T trace_mean(const std::vector< T > &S)
(1/n) sum_i S(i).
Definition trace_mean.h:31
T trace_var(const std::vector< T > &S, bool unbiased=true)
Sample variance of a trace.
Definition trace_var.h:45
TraceIdiResult< T > trace_idi(const std::vector< T > &S, const std::vector< long > &k_set, long aggregate_n=0, bool drop_trailing_zero=false)
Index of dispersion for intervals, IDI(k) = k * var(S_t + ... + S_{t+k-1}) / mean(S_t + ....
Definition trace_idi.h:71
Number-type abstraction for the templated API port.
Return value of trace_idi, mirroring [IDIk, support].
Definition trace_idi.h:52
std::vector< T > idi
one value per requested k
Definition trace_idi.h:53
std::vector< long > support
the number of points each value rests on
Definition trace_idi.h:54
Sample mean of a trace.
Shared declarations for the empirical trace statistics domain.
Sample variance of a trace.