LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
fj_tag_transform.h
Go to the documentation of this file.
1
// Copyright (c) 2012-2026, QORE Lab, Imperial College London
2
// All rights reserved.
3
#ifndef LINE_SOLVERS_TR_FJ_TAG_TRANSFORM_H
4
#define LINE_SOLVERS_TR_FJ_TAG_TRANSFORM_H
5
6
/**
7
* @file
8
* @ingroup line_solvers
9
* Fork-join TAG AUGMENTATION: the fold-back half of the transform/lift pair
10
* that CTMC and SSA share.
11
*
12
* `qn::fj_tag` is the OTHER fork-join route. Where `mmt` and `ht` drive an
13
* outer fixed point for MVA, NC and Fluid (`solvers/mva/fj_driver.h`), the tag
14
* augmentation is EXACT and single pass: it rewrites the struct so each sibling
15
* branch carries its own auxiliary class, the engine runs unchanged on that
16
* struct, and the auxiliary columns are folded back at the end.
17
*
18
* This is deliberately NOT built on the `fj_driver.h` shape. That driver owns a
19
* loop and takes the inner solve as a template parameter because MMT re-solves
20
* a transformed model repeatedly. `fj_tag` substitutes the struct and then the
21
* caller's own engine runs on it to completion: there is no callback seam and
22
* no second pass, so the reusable unit is the fold-back, not a driver.
23
*
24
* THE ONE C++-SPECIFIC POINT. CTMC and SSA carry DIFFERENT result containers
25
* (`ctmc::CtmcAvg<T>` over `Matrix<T>`, `ssa::SsaSolution` over
26
* `Matrix<double>`), which is why this is templated on the container rather
27
* than taking one. It is the same obstacle python meets, where SolverMVA keeps
28
* a dict and SolverNC a dataclass.
29
*
30
* Mirrors MATLAB `matlab/src/solvers/TR/solver_tr_fjtag_analyzer.m`, python
31
* `line_solver/solvers/fjtag_transform.py` and the JAR
32
* `jline.solvers.tr.FJTagTransform`.
33
*/
34
35
#include <cstddef>
36
#include <type_traits>
37
#include <vector>
38
39
#include "
line/lang/qn/network_struct.h
"
40
#include "
line/num/number.h
"
41
#include "
line/solvers/mva/solver_mva_runner.h
"
42
#include "
line/util/matrix.h
"
43
44
namespace
line
{
45
namespace
tr
{
46
47
/**
48
* Whether the model needs the tag augmentation at all.
49
*
50
* A Fork or a Join sends the model down the `qn::fj_tag` route; neither means
51
* it stays on the ordinary one. Four analyzers carried their own copy of this
52
* loop (CTMC steady-state and transient, SSA serial, the chain tables), which
53
* is the C++ share of the bookkeeping that MATLAB, the JAR and python absorbed
54
* into an `expand` phase.
55
*
56
* There is deliberately NO `expand` here to match those three. `qn::fj_tag`
57
* ALREADY returns the context they had to build by hand: `FjTagged` carries the
58
* augmented struct, the sync list, `fjclassmap` and `korig` together, so
59
* wrapping it would add a layer without removing a duplication.
60
*/
61
template
<
class
T>
62
bool
has_fork_join
(
const
qn::NetworkStruct<T>
&
sn
) {
63
if
(
sn
.has_fork())
return
true
;
64
for
(std::size_t i = 0; i <
sn
.nodes.size(); ++i)
65
if
(
sn
.nodes[i].nodetype ==
lang::NodeType::Join
)
return
true
;
66
return
false
;
67
}
68
69
/**
70
* Reduce the augmented metrics onto the original classes.
71
*
72
* A sibling class is a PART of the class it was forked from, so its queue
73
* length, utilization and throughput are exact aggregates and simply add.
74
* Response time is NOT additive and is recomputed by Little's law afterwards.
75
* The SYSTEM metrics are truncated rather than summed: `XN` is the departure
76
* rate at the parent class's reference station, which no sibling visits, and
77
* adding a branch's throughput to it would count each forked task once per
78
* branch.
79
*
80
* @tparam T the struct's numeric type
81
* @tparam Avg the caller's result container, with QN, UN, TN, RN, CN, XN
82
*/
83
template
<
class
T,
class
Avg>
84
void
fj_foldback
(
const
qn::NetworkStruct<T>
&
sn
, Avg& a,
85
const
std::vector<std::size_t>& fjclassmap, std::size_t korig) {
86
typedef
typename
std::remove_cv<
87
typename
std::remove_reference<
decltype
(a.QN(0, 0))>::type>::type S;
88
const
S zero =
num_traits<S>::from_int
(0);
89
const
std::size_t M = a.QN.rows();
90
for
(std::size_t x = 0; x < fjclassmap.size(); ++x) {
91
const
std::size_t r = fjclassmap[x];
92
if
(r == 0)
continue
;
93
for
(std::size_t i = 0; i < M; ++i) {
94
a.QN(i, r - 1) += a.QN(i, x);
95
a.UN(i, r - 1) += a.UN(i, x);
96
a.TN(i, r - 1) += a.TN(i, x);
97
}
98
}
99
Matrix<S>
Q(M, korig, zero), U(M, korig, zero), TT(M, korig, zero), Rr(M, korig, zero);
100
for
(std::size_t i = 0; i < M; ++i)
101
for
(std::size_t k = 0; k < korig; ++k) {
102
Q(i, k) = a.QN(i, k);
103
U(i, k) = a.UN(i, k);
104
TT(i, k) = a.TN(i, k);
105
Rr(i, k) =
num_traits<S>::to_double
(TT(i, k)) > 0 ? S(Q(i, k) / TT(i, k)) : zero;
106
}
107
a.QN = Q;
108
a.UN = U;
109
a.TN = TT;
110
a.RN = Rr;
111
// A Join's response time is QLen over the SIBLING arrival rate, not over
112
// its own firing rate: a Join sees one arrival per sibling for every job it
113
// releases. Applied here, on the FOLDED table, so both engines and every
114
// in-process caller read the same convention.
115
mva::sn_apply_join_respt
(
sn
, a.QN,
mva::sn_get_arvr_from_tput
(
sn
, a.TN), a.RN);
116
a.CN.resize(korig);
117
a.XN.resize(korig);
118
}
119
120
}
// namespace tr
121
}
// namespace line
122
123
#endif
// LINE_SOLVERS_TR_FJ_TAG_TRANSFORM_H
line::Matrix
Definition
matrix.h:56
line::qn::NetworkStruct
A network plus its refreshed NetworkStruct.
Definition
network_struct.h:838
matrix.h
Dense matrix and non-owning view.
line::lang::NodeType::Join
@ Join
Definition
lang_types.h:336
line::mva::sn_apply_join_respt
void sn_apply_join_respt(const qn::NetworkStruct< T > &L, const Matrix< T > &QN, const Matrix< T > &AN, Matrix< T > &RN)
Port of sn_get_arvr_from_tput: the arrival rate each station sees, from the throughputs and the class...
Definition
solver_mva_runner.h:467
line::mva::sn_get_arvr_from_tput
Matrix< T > sn_get_arvr_from_tput(const qn::NetworkStruct< T > &L, const Matrix< T > &TN)
Definition
solver_mva_runner.h:480
line::sn
Definition
sn_gd_balance.h:42
line::tr
Definition
fj_tag_transform.h:45
line::tr::fj_foldback
void fj_foldback(const qn::NetworkStruct< T > &sn, Avg &a, const std::vector< std::size_t > &fjclassmap, std::size_t korig)
Reduce the augmented metrics onto the original classes.
Definition
fj_tag_transform.h:84
line::tr::has_fork_join
bool has_fork_join(const qn::NetworkStruct< T > &sn)
Whether the model needs the tag augmentation at all.
Definition
fj_tag_transform.h:62
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.
solver_mva_runner.h
The SolverMVA class surface: @@SolverMVA/runAnalyzer.m and the gates around it.
line::num_traits
Definition
number.h:111
include
line
solvers
tr
fj_tag_transform.h
Generated by
1.18.0