LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
npfqn_traffic_merge_cs.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_NPFQN_TRAFFIC_MERGE_CS_H
6#define LINE_API_NPFQN_TRAFFIC_MERGE_CS_H
7
8/**
9 * @file
10 * @ingroup api_npfqn
11 * Merge of marked arrival flows with class switching.
12 *
13 * Templated port of matlab/src/api/npfqn/npfqn_traffic_merge_cs.m. See
14 * npfqn_traffic_merge.h for the shared conventions and for the reference
15 * defects of the plain merge.
16 *
17 * prob((i-1)R + r, s) is the probability that a class-r arrival from flow i
18 * switches to class s. Flow i is first re-marked with its own (R x R) block
19 * (mmap_mark.m), and the re-marked flows are then superposed class by class.
20 *
21 * RATE IDENTITY. Marking redistributes an arrival's class without touching
22 * (D0, D1), so lambda_s of the merged flow is sum_i sum_r lambda_{i,r} P_i(r,s)
23 * exactly, and when every P_i is stochastic the aggregate rate sum_s lambda_s
24 * equals the sum of the aggregate rates of the operands. Both are exact
25 * identities in the rational instantiation.
26 *
27 * REFERENCE DEFECTS in npfqn_traffic_merge_cs.m:
28 *
29 * 1. UNREACHABLE MERGE RULES. The function accepts config.merge but its
30 * switch has only the {'default','super'} case and no otherwise branch, so
31 * any other value (including the 'mixture' and 'interpos' that
32 * npfqn_traffic_merge accepts) silently leaves SMMAP undefined and MATLAB
33 * then raises "Output argument SMMAP not assigned". This port raises
34 * UnsupportedError naming the rule instead.
35 *
36 * 2. NO COMPRESSION AND NO NORMALIZATION. Unlike npfqn_traffic_merge, the
37 * class-switching variant never looks at config.compress and never calls
38 * mmap_normalize on the result; the normalization it does get comes from
39 * mmap_super itself. Reproduced as written: this port applies no
40 * compression here either.
41 *
42 * 3. R IS TAKEN FROM prob, NOT FROM THE FLOWS. size(prob, 2) sets the output
43 * class count and the (i-1)R + r indexing assumes size(prob, 1) == n R.
44 * A prob whose row count is not a multiple of the flow count silently
45 * mis-indexes in MATLAB; this port rejects it.
46 *
47 * ARITHMETIC. Marking and Kronecker sums only, so this is exact-capable and is
48 * instantiated at T = Rational.
49 */
50
51#include <cstddef>
52#include <vector>
53
57#include "line/num/number.h"
58#include "line/util/error.h"
59#include "line/util/matrix.h"
60
61namespace line {
62namespace npfqn {
63
64/**
65 * Merge flows that switch class on departure.
66 *
67 * @param flows n MMAPs, each carrying R marked classes
68 * @param prob (n R x R), prob((i-1)R + r, s) in MATLAB 1-based terms
69 * @param merge merge rule; only Default and Super are ported
70 * @return the merged MMAP with R classes
71 */
72template <class T>
73mam::Mmap<T> npfqn_traffic_merge_cs(const std::vector<mam::Mmap<T>>& flows, const Matrix<T>& prob,
74 Merge merge = Merge::Default) {
75 const std::size_t n = flows.size();
76 if (n == 0) throw InputError("npfqn_traffic_merge_cs: no flows to merge");
77 const std::size_t R = prob.cols();
78 if (R == 0 || prob.rows() != n * R)
79 throw InputError("npfqn_traffic_merge_cs: prob must be (n R) x R");
80
81 std::vector<mam::Mmap<T>> marked;
82 marked.reserve(n);
83 for (std::size_t i = 0; i < n; ++i) {
84 Matrix<T> P(R, R);
85 for (std::size_t r = 0; r < R; ++r)
86 for (std::size_t s = 0; s < R; ++s) P(r, s) = prob(i * R + r, s);
87 marked.push_back(mmap_mark_types(flows[i], P));
88 }
89
90 if (n == 1) return marked.front();
91
92 switch (merge) {
93 case Merge::Default:
94 case Merge::Super:
95 break;
96 default:
97 throw UnsupportedError("npfqn_traffic_merge_cs: only the 'default' and 'super' merge "
98 "rules are defined for the class-switching merge");
99 }
100
101 mam::Mmap<T> s = marked.front();
102 for (std::size_t j = 1; j < n; ++j) s = mmap_super_match(s, marked[j]);
103 return s;
104}
105
106} // namespace npfqn
107} // namespace line
108
109#endif // LINE_API_NPFQN_TRAFFIC_MERGE_CS_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
UnsupportedError(const std::string &what)
Definition error.h:51
The exception types the port throws.
Dense matrix and non-owning view.
Compression of a marked MAP into a smaller representation, and the two M3A primitives it is built fro...
Marked MAP (MMAP) algebra: per-class rates, class probabilities, superposition, normalization and sca...
Merge
Merge rule, MATLAB's config.merge.
@ Default
'default', identical to 'super'
mam::Mmap< T > mmap_super_match(const mam::Mmap< T > &a, const mam::Mmap< T > &b)
Superposition matching classes one to one (mmap_super.m, option 'match').
mam::Mmap< T > npfqn_traffic_merge_cs(const std::vector< mam::Mmap< T > > &flows, const Matrix< T > &prob, Merge merge=Merge::Default)
Merge flows that switch class on departure.
mam::Mmap< T > mmap_mark_types(const mam::Mmap< T > &m, const Matrix< T > &prob)
Re-mark an MMAP's K types into R classes (mmap_mark.m).
Superposition of several marked arrival flows into one.
Number-type abstraction for the templated API port.
An MMAP: the underlying MAP plus the per-class arrival matrices.
Definition mmap_lambda.h:45