LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pfqn_ldbcmp.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_PFQN_PFQN_LDBCMP_H
6
#define LINE_API_PFQN_PFQN_LDBCMP_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* Anselmi-Cremonesi (2008) lower throughput bound for a closed single-class
12
* BCMP network with load-dependent stations.
13
*
14
* Templated port of matlab/src/api/pfqn/pfqn_ldbcmp.m. The bound (their eq. 15)
15
* uses the fact that a closed BCMP network is, as N -> inf, equivalent to the
16
* open network obtained by removing the bottleneck and injecting at rate
17
* 1/Dmax; Algorithm 1 refines it to a monotone fixed point
18
*
19
* X = (N - Qhat) / [ Dmax (b + N - Qhat) - b (Dmax X')^N Dmax ]
20
*
21
* where Qhat is the sum of the non-bottleneck open queue lengths, b the number
22
* of bottleneck stations, and c(i) the Heffes load-dependence coefficient.
23
*
24
* APPLICABILITY. The bound requires N >= Qhat and every non-bottleneck
25
* utilization below one. MATLAB returns NaN in both cases; the port reports it
26
* through a flag on the result instead, since a NaN throughput propagates
27
* silently while a flag has to be read.
28
*
29
* ARITHMETIC. The fixed point raises Dmax X to the integer power N, which is
30
* num_pow_int and stays in the field, and everything else is an addition or a
31
* division. The bound is therefore EXACT in rational arithmetic and is left
32
* ungated -- but note that the iteration is a contraction, not a closed form,
33
* so what is exact is each iterate, not the limit.
34
*/
35
36
#include <cstddef>
37
#include <limits>
38
#include <vector>
39
40
#include "
line/num/number.h
"
41
#include "
line/util/error.h
"
42
43
namespace
line
{
44
namespace
pfqn
{
45
46
/** Return value of pfqn_ldbcmp, mirroring [Xlo, Rhi, Qhat]. */
47
template
<
class
T>
48
struct
LdBcmpBound
{
49
T
Xlo
;
50
T
Rhi
;
51
T
Qhat
;
52
bool
applicable
;
///< false where MATLAB returns NaN (N < Qhat, or rho >= 1)
53
};
54
55
/**
56
* @brief Anselmi-Cremonesi (2008) lower throughput bound for a closed
57
* single-class BCMP network with load-dependent stations.
58
*
59
* @param L (M) limiting demands, @param N population, @param Z think time
60
* @param c (M) Heffes coefficients, empty for all fixed-rate stations
61
* @param tol relative fixed-point tolerance (MATLAB default 1e-10)
62
*/
63
template
<
class
T>
64
LdBcmpBound<T>
pfqn_ldbcmp
(
const
std::vector<T>& L,
const
T& N,
const
T& Z,
const
std::vector<T>& c,
65
const
T& tol) {
66
const
std::size_t M = L.size();
67
if
(M == 0)
throw
InputError
(
"pfqn_ldbcmp: empty demand vector"
);
68
if
(!c.empty() && c.size() != M)
throw
InputError
(
"pfqn_ldbcmp: c has the wrong length"
);
69
const
T zero =
num_traits<T>::from_int
(0), one =
num_traits<T>::from_int
(1);
70
71
T Dm = L[0];
72
for
(
const
T& x : L)
73
if
(x > Dm) Dm = x;
74
if
(Dm <= zero)
throw
InputError
(
"pfqn_ldbcmp: all demands are zero"
);
75
// MATLAB's bottleneck test is abs(D - Dm) <= 1e-12*Dm; the tolerance is a
76
// floating-point guard and is kept, so the two agree station for station.
77
const
T bt = T(
num_traits<T>::from_double
(1e-12) * Dm);
78
long
bmax = 0;
79
std::vector<bool> isbott(M,
false
);
80
for
(std::size_t i = 0; i < M; ++i) {
81
if
(
num_abs
(T(L[i] - Dm)) <= bt) {
82
isbott[i] =
true
;
83
++bmax;
84
}
85
}
86
87
LdBcmpBound<T>
r;
88
r.
applicable
=
true
;
89
const
T lambda = T(one / Dm);
90
T Qhat = zero;
91
for
(std::size_t i = 0; i < M; ++i) {
92
if
(isbott[i])
continue
;
93
const
T rho = T(lambda * L[i]);
94
if
(rho >= one) {
95
r.
applicable
=
false
;
96
r.
Xlo
= zero;
97
r.
Rhi
= zero;
98
r.
Qhat
= zero;
99
return
r;
100
}
101
const
T ci = c.empty() ? zero : c[i];
102
Qhat += T(T(ci + one) * rho / T(one - rho));
103
}
104
Qhat += lambda * Z;
105
r.
Qhat
= Qhat;
106
if
(T(N - Qhat) < zero) {
107
r.
applicable
=
false
;
108
r.
Xlo
= zero;
109
r.
Rhi
= zero;
110
return
r;
111
}
112
113
const
T a = T(N - Qhat);
114
// Dmax X' is raised to the integer power N, so N must be integral here,
115
// exactly as in MATLAB, where N indexes a closed population.
116
const
double
Nd =
num_traits<T>::to_double
(N);
117
if
(Nd < 0.0 || Nd != std::floor(Nd))
118
throw
InputError
(
"pfqn_ldbcmp: the population must be a non-negative integer"
);
119
const
unsigned
Nu =
static_cast<
unsigned
>
(Nd);
120
121
T Xprime = zero, Xlo = zero;
122
for
(
int
it = 0; it < 10000; ++it) {
123
const
T Xprev = Xlo;
124
const
T denom = T(Dm * T(
num_traits<T>::from_int
(bmax) + N - Qhat) -
125
num_traits<T>::from_int
(bmax) *
num_pow_int
(T(Dm * Xprime), Nu) * Dm);
126
if
(denom == zero)
throw
NumericError
(
"pfqn_ldbcmp: zero denominator in the fixed point"
);
127
Xlo = T(a / denom);
128
Xprime = Xlo;
129
if
(Xprev > zero && T(
num_abs
(T(Xprev - Xlo)) / Xprev) <= tol)
break
;
130
}
131
r.
Xlo
= Xlo;
132
if
(Xlo == zero) {
133
// Exactly at the regime boundary N == Qhat the numerator N - Qhat is
134
// zero, so the bound degenerates to X >= 0: still valid, and MATLAB
135
// returns it with Rhi = N/0 = Inf rather than erroring. An exact
136
// backend has no infinity to return there.
137
if
constexpr
(
num_traits<T>::has_transcendental
) {
138
r.
Rhi
=
num_traits<T>::from_double
(std::numeric_limits<double>::infinity());
139
return
r;
140
}
else
{
141
throw
UnsupportedError
(
142
"pfqn_ldbcmp: at N == Qhat the throughput bound degenerates to zero and the "
143
"response-time bound is infinite, which exact arithmetic cannot represent"
);
144
}
145
}
146
r.
Rhi
= T(N / Xlo);
147
return
r;
148
}
149
150
template
<
class
T>
151
LdBcmpBound<T>
pfqn_ldbcmp
(
const
std::vector<T>& L,
const
T& N,
const
T& Z) {
152
return
pfqn_ldbcmp
(L, N, Z, std::vector<T>(),
num_traits<T>::from_double
(1e-10));
153
}
154
155
}
// namespace pfqn
156
}
// namespace line
157
158
#endif
// LINE_API_PFQN_PFQN_LDBCMP_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
line::NumericError::NumericError
NumericError(const std::string &what)
Definition
error.h:45
line::UnsupportedError::UnsupportedError
UnsupportedError(const std::string &what)
Definition
error.h:51
error.h
The exception types the port throws.
line::pfqn
Definition
cd_peak_scaling.h:43
line::pfqn::pfqn_ldbcmp
LdBcmpBound< T > pfqn_ldbcmp(const std::vector< T > &L, const T &N, const T &Z, const std::vector< T > &c, const T &tol)
Anselmi-Cremonesi (2008) lower throughput bound for a closed single-class BCMP network with load-depe...
Definition
pfqn_ldbcmp.h:64
line
Definition
aoi_dist2ph.h:52
line::num_abs
T num_abs(const T &v)
Definition
number.h:172
line::num_pow_int
T num_pow_int(const T &base, unsigned e)
Integer power, valid in any field (no transcendental requirement).
Definition
number.h:192
number.h
Number-type abstraction for the templated API port.
line::num_traits
Definition
number.h:111
line::pfqn::LdBcmpBound
Return value of pfqn_ldbcmp, mirroring [Xlo, Rhi, Qhat].
Definition
pfqn_ldbcmp.h:48
line::pfqn::LdBcmpBound::applicable
bool applicable
false where MATLAB returns NaN (N < Qhat, or rho >= 1)
Definition
pfqn_ldbcmp.h:52
line::pfqn::LdBcmpBound::Qhat
T Qhat
Definition
pfqn_ldbcmp.h:51
line::pfqn::LdBcmpBound::Xlo
T Xlo
Definition
pfqn_ldbcmp.h:49
line::pfqn::LdBcmpBound::Rhi
T Rhi
Definition
pfqn_ldbcmp.h:50
include
line
api
pfqn
pfqn_ldbcmp.h
Generated by
1.18.0