LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
npfqn_traffic_split_rr.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_SPLIT_RR_H
6
#define LINE_API_NPFQN_TRAFFIC_SPLIT_RR_H
7
8
/**
9
* @file
10
* @ingroup api_npfqn
11
* Deterministic (round-robin) split degrees of every station-class departure
12
* stream.
13
*
14
* Templated port of matlab/src/api/npfqn/npfqn_traffic_split_rr.m,
15
* cross-checked against
16
* jar/src/main/java/jline/api/npfqn/Npfqn_traffic_split_rr.java and
17
* python/line_solver/api/npfqn/split_rr.py (identical).
18
*
19
* kRR(i,r) = k > 1 says the class-r departures of station i are dispatched
20
* one-in-k by a round-robin node, so a downstream flow carrying a fraction p of
21
* them is the k-fold convolution thinned at q = k p and has SCV 1 + p (d2 - k),
22
* against the Markovian 1 + p (d2 - 1). kRR(i,r) = 1 is an ordinary
23
* probabilistic split, which is what every entry stays at on a model with no
24
* round-robin dispatcher; the QNA/MNA equations then reduce exactly to the
25
* Bernoulli-thinning form they had before this factor existed.
26
*
27
* Only two topologies admit the deterministic rule: the station dispatches
28
* round-robin itself, or it feeds WITH PROBABILITY ONE a non-station node that
29
* does and whose pointer no other flow advances. A router shared by two
30
* upstream streams interleaves them, so neither sees a clean one-in-k split and
31
* both fall back to k = 1.
32
*
33
* THE DEGREE IS READ OFF `rtnodes`, NOT off `connmatrix` and not off an
34
* `outlinks` list. The reference prefers `sn.nodeparam{ind}{r}.outlinks`, the
35
* per-class destination list of the dispatcher, and falls back to the row of
36
* `sn.connmatrix`. This port's NetworkStruct carries neither field: `rtnodes`
37
* is the same graph once refresh_routing has expanded the strategies (the same
38
* substitution downstream_stations documents in network_struct.h). Counting the
39
* DISTINCT destination NODES of row (ind,r) reproduces the per-class `outlinks`
40
* semantics, which is the branch the reference takes whenever a dispatcher was
41
* actually built, and differs from the connmatrix fallback only on a link the
42
* model declares and then routes no mass over.
43
*
44
* ARITHMETIC: field, and integral in fact. The result is a matrix of counts;
45
* only comparisons against zero and against 1 - FineTol are taken, so this is
46
* exact at T = Rational.
47
*/
48
49
#include <cstddef>
50
#include <vector>
51
52
#include "
line/lang/lang_types.h
"
53
#include "
line/lang/qn/network_struct.h
"
54
#include "
line/num/number.h
"
55
#include "
line/util/matrix.h
"
56
57
namespace
line
{
58
namespace
npfqn
{
59
60
namespace
detail {
61
62
/** The routing strategy of (1-based node `ind`, 1-based class `r`). */
63
template
<
class
T>
64
qn::RoutingStrategy
routing_of(
const
qn::NetworkStruct<T>& sn, std::size_t ind, std::size_t r) {
65
const
std::vector<qn::RoutingStrategy>& rs = sn.nodes[ind - 1].routing;
66
return
rs.size() >= r ? rs[r - 1] : qn::RoutingStrategy::PROB;
67
}
68
69
/** Number of destinations the round-robin pointer of (`ind`, `r`) cycles through. */
70
template
<
class
T>
71
std::size_t rr_degree(
const
qn::NetworkStruct<T>& sn, std::size_t ind, std::size_t r) {
72
const
T zero = num_traits<T>::from_int(0);
73
const
std::size_t K = sn.nclasses, I = sn.nodes.size();
74
std::size_t k = 0;
75
for
(std::size_t j = 1; j <= I; ++j) {
76
bool
linked =
false
;
77
for
(std::size_t s = 1; s <= K && !linked; ++s)
78
if
(sn.rtnodes((ind - 1) * K + (r - 1), (j - 1) * K + (s - 1)) > zero) linked =
true
;
79
if
(linked) ++k;
80
}
81
return
k < 1 ? 1 : k;
82
}
83
84
}
// namespace detail
85
86
/**
87
* Port of `npfqn_traffic_split_rr.m`.
88
*
89
* @param sn the model, after refresh(): `rtnodes` carries the expanded routing
90
* @return an (nstations x nclasses) matrix of split degrees, 1 where the split
91
* is Markovian
92
*/
93
template
<
class
T>
94
Matrix<T>
npfqn_traffic_split_rr
(
const
qn::NetworkStruct<T>
&
sn
) {
95
const
T zero =
num_traits<T>::from_int
(0);
96
const
T one =
num_traits<T>::from_int
(1);
97
const
std::size_t M =
sn
.nstations, K =
sn
.nclasses, I =
sn
.nodes.size();
98
Matrix<T>
kRR(M, K, one);
99
100
bool
any_rr =
false
;
101
for
(
const
qn::NodeDef
& nd :
sn
.nodes)
102
for
(
qn::RoutingStrategy
rs : nd.
routing
)
103
if
(rs == qn::RoutingStrategy::RROBIN) any_rr =
true
;
104
if
(!any_rr)
return
kRR;
105
if
(
sn
.rtnodes.rows() < I * K)
return
kRR;
106
107
const
T sure = T(one -
num_traits<T>::from_double
(
lang::GlobalConstants::FineTol
));
108
for
(std::size_t ist = 1; ist <= M; ++ist) {
109
const
std::size_t ind =
sn
.node_of_station(ist);
110
if
(ind == 0)
continue
;
111
for
(std::size_t r = 1; r <= K; ++r) {
112
if
(detail::routing_of(
sn
, ind, r) == qn::RoutingStrategy::RROBIN) {
113
kRR(ist - 1, r - 1) =
114
num_traits<T>::from_int
(
static_cast<
long
>
(detail::rr_degree(
sn
, ind, r)));
115
continue
;
116
}
117
// a sure transition into a node that dispatches round-robin
118
const
std::size_t row = (ind - 1) * K + (r - 1);
119
std::size_t dest = 0, ndest = 0;
120
for
(std::size_t col = 0; col <
sn
.rtnodes.cols(); ++col)
121
if
(
sn
.rtnodes(row, col) > zero) {
122
dest = col;
123
++ndest;
124
}
125
if
(ndest != 1)
continue
;
126
const
std::size_t jnd = dest / K + 1, s = dest % K + 1;
127
if
(
sn
.nodes[jnd - 1].station != 0)
continue
;
128
if
(detail::routing_of(
sn
, jnd, s) != qn::RoutingStrategy::RROBIN)
continue
;
129
if
(
sn
.rtnodes(row, dest) < sure)
continue
;
130
// the round-robin pointer must be advanced by this stream alone
131
std::size_t nfeed = 0;
132
for
(std::size_t a = 0; a <
sn
.rtnodes.rows(); ++a)
133
if
(
sn
.rtnodes(a, dest) > zero) ++nfeed;
134
if
(nfeed != 1)
continue
;
135
kRR(ist - 1, r - 1) =
136
num_traits<T>::from_int
(
static_cast<
long
>
(detail::rr_degree(
sn
, jnd, s)));
137
}
138
}
139
return
kRR;
140
}
141
142
}
// namespace npfqn
143
}
// namespace line
144
145
#endif
// LINE_API_NPFQN_TRAFFIC_SPLIT_RR_H
line::Matrix
Definition
matrix.h:56
line::qn::NetworkStruct
A network plus its refreshed NetworkStruct.
Definition
network_struct.h:838
lang_types.h
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
matrix.h
Dense matrix and non-owning view.
line::lang::RoutingStrategy
RoutingStrategy
Routing strategies, with the values of MATLAB RoutingStrategy.
Definition
lang_types.h:389
line::npfqn
Definition
npfqn_bnd_bgt.h:76
line::npfqn::npfqn_traffic_split_rr
Matrix< T > npfqn_traffic_split_rr(const qn::NetworkStruct< T > &sn)
Port of npfqn_traffic_split_rr.m.
Definition
npfqn_traffic_split_rr.h:94
line::sn
Definition
sn_gd_balance.h:42
line
Definition
aoi_dist2ph.h:52
network_struct.h
A queueing network and its refreshed NetworkStruct.
number.h
Number-type abstraction for the templated API port.
line::lang::GlobalConstants::FineTol
static constexpr double FineTol
Definition
lang_types.h:668
line::num_traits
Definition
number.h:111
line::qn::NodeDef
A node of the network.
Definition
network_struct.h:174
line::qn::NodeDef::routing
std::vector< RoutingStrategy > routing
sn.routing, per class.
Definition
network_struct.h:188
include
line
api
npfqn
npfqn_traffic_split_rr.h
Generated by
1.18.0