LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
sn_to_qrf_alpha.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_SN_SN_TO_QRF_ALPHA_H
6
#define LINE_API_SN_SN_TO_QRF_ALPHA_H
7
8
/**
9
* @file
10
* @ingroup api_sn
11
* The QRF load-dependent rate scaling alpha(i,n), derived from an sn.
12
*
13
* Port of matlab/src/api/sn/sn_to_qrf_alpha.m.
14
*
15
* The load-dependent QRF arms carry a scaling alpha(i,n) that multiplies EVERY
16
* rate out of station i while it holds n jobs, completions mu and background
17
* phase changes v alike -- see the q construction in `qrf_noblo_mmi_ld`. That
18
* is exactly the rate law of
19
*
20
* an infinite server alpha(i,n) = n
21
* a c-server station alpha(i,n) = min(n, c_i)
22
* limited load dependence alpha(i,n) = sn.lldscaling(i,n)
23
*
24
* so the three COMPOSE BY MULTIPLICATION and not one of them is an
25
* approximation: the relaxed chain is the model's own, and the QRF answer keeps
26
* whatever status it had on a single-server model.
27
*
28
* WHERE IT STOPS BEING THE MODEL'S OWN IS PHASE-TYPE SERVICE AT A STATION THAT
29
* SERVES SEVERAL JOBS AT ONCE. The QRF local state carries ONE phase per
30
* station, a faithful description of one job in service and of nothing else:
31
* min(n,c) jobs served in parallel each advance through a phase of their own,
32
* and no scaling of a single-phase process reproduces that joint motion. A
33
* multiserver or delay station must therefore be exponential -- scaling a PH
34
* server by min(n,c) would answer a DIFFERENT chain, so the relaxation would
35
* stop containing the model's stationary distribution and the number would
36
* bound nothing. Limited load dependence at a SINGLE server is exempt and
37
* admits PH freely: one job is in service whatever the rate.
38
*
39
* THE UTILIZATION NORMALIZER IS THE DECLARED PEAK, NOT max(alpha). LINE reports
40
* U = T*S/peak at every station whose rate scales with the population, one
41
* convention shared by multiserver, lld and class dependence. `peak` is
42
* therefore nservers(i) times the largest lld scaling the model can REACH, and
43
* not max(alpha(i,:)): at c = 3 with N = 2 the reachable alpha peaks at 2 while
44
* the station still has three servers, and normalizing by 2 would report a
45
* utilization the model never attains. Infinite at a delay, where LINE reports
46
* U = QN instead.
47
*/
48
49
#include <algorithm>
50
#include <cmath>
51
#include <cstddef>
52
#include <limits>
53
#include <sstream>
54
#include <string>
55
#include <vector>
56
57
#include "
line/lang/distribution.h
"
58
#include "
line/lang/qn/network_struct.h
"
59
#include "
line/num/number.h
"
60
61
namespace
line
{
62
namespace
sn
{
63
64
/** The scaling, the utilization normalizer, and why they may not exist. */
65
struct
QrfAlpha
{
66
std::vector<std::vector<double> >
alpha
;
///< (M x N) scaling at population n = 1..N
67
std::string
msg
;
///< empty on success
68
bool
ld
=
false
;
///< alpha is not identically 1
69
std::vector<double>
peak
;
///< (M) utilization normalizer; inf at a delay
70
};
71
72
/**
73
* `ld` stays TRUE through a refusal: the model IS load dependent, and the
74
* caller has to tell "no arm serves this" from "the arm you asked for does
75
* not". Clearing it would report the latter for both.
76
*/
77
template
<
class
T>
78
QrfAlpha
sn_to_qrf_alpha
(
const
qn::NetworkStruct<T>
& L) {
79
QrfAlpha
out;
80
const
std::size_t M = L.
nstations
;
81
out.
peak
.assign(M, 1.0);
82
83
double
Nd = 0.0;
84
const
std::vector<double> njobs = L.
njobs
();
85
for
(std::size_t r = 0; r < njobs.size(); ++r) Nd += njobs[r];
86
if
(!(Nd >= 1.0) || std::isinf(Nd)) {
87
out.
alpha
.assign(M, std::vector<double>(1, 1.0));
88
out.
msg
=
"the QRF bounds need a closed model with a finite population."
;
89
return
out;
90
}
91
const
std::size_t N =
static_cast<
std::size_t
>
(Nd + 0.5);
92
out.
alpha
.assign(M, std::vector<double>(N, 1.0));
93
94
for
(std::size_t i = 0; i < M; ++i) {
95
const
double
c = L.
stations
[i].nservers;
96
const
bool
is_delay = std::isinf(c) || L.
stations
[i].sched == qn::SchedStrategy::INF;
97
const
bool
serves_many = is_delay || c > 1.0;
98
const
std::size_t smax = L.
stations
[i].lldscaling.size();
99
// The phase count is read where the adapter reads it, from the service
100
// process: that {D0,D1} pair is what sizes the local state, so testing
101
// it keeps the refusal and the formulation on one quantity.
102
std::size_t ki = 1;
103
{
104
const
mam::Map<T>
m =
lang::dist_to_map
(L.
service
[i][0]);
105
if
(m.
D0
.rows() > 0) ki =
static_cast<
std::size_t
>
(m.
D0
.rows());
106
}
107
if
(serves_many && ki > 1) {
108
std::ostringstream os;
109
os <<
"station "
<< (i + 1) <<
" serves "
;
110
if
(is_delay)
111
os <<
"unboundedly many"
;
112
else
113
os <<
"up to "
<<
static_cast<
int
>
(c);
114
os <<
" jobs at once with "
<< ki
115
<<
"-phase service, and the QRF local state carries one phase per station, which "
116
"describes one job in service and no more. Give that station exponential "
117
"service, or use a single-server model."
;
118
out.
msg
= os.str();
119
out.
ld
=
true
;
120
return
out;
121
}
122
double
lldpeak = 1.0;
123
for
(std::size_t n = 1; n <= N; ++n) {
124
double
a = 1.0;
125
if
(is_delay)
126
a =
static_cast<
double
>
(n);
127
else
if
(c > 1.0)
128
a = std::min(
static_cast<
double
>
(n), c);
129
if
(smax > 0) {
130
const
double
s =
131
num_traits<T>::to_double
(L.
stations
[i].lldscaling[std::min(n, smax) - 1]);
132
lldpeak = std::max(lldpeak, s);
133
a *= s;
134
}
135
out.
alpha
[i][n - 1] = a;
136
if
(a != 1.0) out.
ld
=
true
;
137
}
138
out.
peak
[i] = is_delay ? std::numeric_limits<double>::infinity() : c * lldpeak;
139
}
140
return
out;
141
}
142
143
}
// namespace sn
144
}
// namespace line
145
146
#endif
// LINE_API_SN_SN_TO_QRF_ALPHA_H
line::qn::NetworkStruct
A network plus its refreshed NetworkStruct.
Definition
network_struct.h:838
line::qn::NetworkStruct::service
std::vector< std::vector< Distrib< T > > > service
service[i][r], 0-based station and class; a disabled entry marks a pair never visited.
Definition
network_struct.h:856
line::qn::NetworkStruct::stations
std::vector< Station< T > > stations
stations[k-1] is the k-th station
Definition
network_struct.h:851
line::qn::NetworkStruct::njobs
std::vector< double > njobs() const
sn.njobs: the population of each class, infinite for an open one.
Definition
network_struct.h:1315
line::qn::NetworkStruct::nstations
std::size_t nstations
Definition
network_struct.h:1074
distribution.h
What refreshProcessRepresentations and refreshLST compute FROM a distribution: the (D0,...
line::lang::dist_to_map
mam::Map< T > dist_to_map(const Distrib< T > &d)
Definition
distribution.h:149
line::sn
Definition
sn_gd_balance.h:42
line::sn::sn_to_qrf_alpha
QrfAlpha sn_to_qrf_alpha(const qn::NetworkStruct< T > &L)
ld stays TRUE through a refusal: the model IS load dependent, and the caller has to tell "no arm serv...
Definition
sn_to_qrf_alpha.h:78
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::mam::Map
A MAP as the pair of matrices (D0, D1).
Definition
map_moment.h:53
line::mam::Map::D0
Matrix< T > D0
Definition
map_moment.h:54
line::num_traits
Definition
number.h:111
line::sn::QrfAlpha
The scaling, the utilization normalizer, and why they may not exist.
Definition
sn_to_qrf_alpha.h:65
line::sn::QrfAlpha::ld
bool ld
alpha is not identically 1
Definition
sn_to_qrf_alpha.h:68
line::sn::QrfAlpha::msg
std::string msg
empty on success
Definition
sn_to_qrf_alpha.h:67
line::sn::QrfAlpha::peak
std::vector< double > peak
(M) utilization normalizer; inf at a delay
Definition
sn_to_qrf_alpha.h:69
line::sn::QrfAlpha::alpha
std::vector< std::vector< double > > alpha
(M x N) scaling at population n = 1..N
Definition
sn_to_qrf_alpha.h:66
include
line
api
sn
sn_to_qrf_alpha.h
Generated by
1.18.0