LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
mtrace_merge.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_MERGE_H
6#define LINE_API_TRACE_MTRACE_MERGE_H
7
8/**
9 * @file
10 * @ingroup api_trace
11 * Superposes two single-class traces into one marked trace, labelling the
12 * events of the first stream 1 and those of the second 2.
13 *
14 * Templated port of matlab/lib/m3a/m3a/mtrace/mtrace_merge.m, cross-checked
15 * against jar/src/main/java/jline/api/trace/Mtrace_merge.java (identical; the
16 * JAR carries an explicit comment that the single shared time origin
17 * `sort([0; cumsum(t1); cumsum(t2)])` matters, since merging the two
18 * cumulative-sum vectors with separate origins injects a spurious zero-length
19 * interval).
20 *
21 * Ties are broken in favour of the first stream, which is MATLAB's stable
22 * sort and is reproduced with std::stable_sort.
23 *
24 * ARITHMETIC: a merge and pairwise differences, exact in Rational.
25 */
26
27#include <algorithm>
28#include <cstddef>
29#include <vector>
30
32#include "line/num/number.h"
33#include "line/util/error.h"
34
35namespace line {
36namespace trace {
37
38/** Return value of mtrace_merge, mirroring [T, L]. */
39template <class T>
41 std::vector<T> times; ///< inter-arrival times of the merged process
42 std::vector<int> labels; ///< 1 for the first stream, 2 for the second
43};
44
45/**
46 * @brief Superposes two single-class traces into one marked trace, labelling
47 * the events of the first stream 1 and those of the second 2.
48 *
49 * @param t1 inter-arrival times of the first trace
50 * @param t2 inter-arrival times of the second trace
51 */
52template <class T>
53MtraceMergeResult<T> mtrace_merge(const std::vector<T>& t1, const std::vector<T>& t2) {
54 if (t1.empty() && t2.empty()) throw InputError("mtrace_merge: both traces are empty");
55 struct Event {
56 T time;
57 int label;
58 };
59 std::vector<Event> ev;
60 ev.reserve(t1.size() + t2.size() + 1);
61 Event origin;
62 origin.time = num_traits<T>::from_int(0);
63 origin.label = 0;
64 ev.push_back(origin);
65 T acc = num_traits<T>::from_int(0);
66 for (std::size_t i = 0; i < t1.size(); ++i) {
67 acc += t1[i];
68 Event e;
69 e.time = acc;
70 e.label = 1;
71 ev.push_back(e);
72 }
74 for (std::size_t i = 0; i < t2.size(); ++i) {
75 acc += t2[i];
76 Event e;
77 e.time = acc;
78 e.label = 2;
79 ev.push_back(e);
80 }
81 std::stable_sort(ev.begin(), ev.end(),
82 [](const Event& a, const Event& b) { return a.time < b.time; });
83
85 out.times.reserve(ev.size() - 1);
86 out.labels.reserve(ev.size() - 1);
87 for (std::size_t k = 1; k < ev.size(); ++k) {
88 out.times.push_back(ev[k].time - ev[k - 1].time);
89 out.labels.push_back(ev[k].label);
90 }
91 return out;
92}
93
94} // namespace trace
95} // namespace line
96
97#endif // LINE_API_TRACE_MTRACE_MERGE_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
MtraceMergeResult< T > mtrace_merge(const std::vector< T > &t1, const std::vector< T > &t2)
Superposes two single-class traces into one marked trace, labelling the events of the first stream 1 ...
Number-type abstraction for the templated API port.
Return value of mtrace_merge, mirroring [T, L].
std::vector< int > labels
1 for the first stream, 2 for the second
std::vector< T > times
inter-arrival times of the merged process
Shared declarations for the empirical trace statistics domain.