LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pfqn_pbh.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_PBH_H
6
#define LINE_API_PFQN_PFQN_PBH_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* Performance Bound Hierarchy (Eager and Sevcik 1983, ACM TOCS 1(2):99-115)
12
* for single-class closed product-form networks, and the two iterative
13
* families that are defined in terms of it.
14
*
15
* Templated port of matlab/src/api/pfqn/pfqn_pbh.m, pfqn_pbk.m and
16
* pfqn_bjbk.m. `level` MVA steps from an ABA-initialized residence give nested
17
* optimistic and pessimistic bounds that converge to exact MVA as level -> N.
18
*
19
* MATLAB REDUNDANCY, reproduced rather than hidden: pfqn_pbk.m and
20
* pfqn_bjbk.m are both one-line forwarders to pfqn_pbh with the same
21
* arguments, so PB(k) and BJB(k) return identical numbers for every input.
22
* The two names are kept because the surrounding solver code refers to both,
23
* and collapsing them here would hide the fact in the port.
24
*
25
* ARITHMETIC. The recursion is a finite sequence of field operations -- no
26
* root, no logarithm anywhere -- so these bounds are EXACT in rational
27
* arithmetic and are deliberately left ungated. That is worth having: a bound
28
* violated only by rounding cannot be told apart from a real violation.
29
*/
30
31
#include <algorithm>
32
#include <cstddef>
33
#include <vector>
34
35
#include "
line/num/number.h
"
36
#include "
line/util/error.h
"
37
38
namespace
line
{
39
namespace
pfqn
{
40
41
/** Return value of pfqn_pbh, mirroring [Xlo, Xhi, Qlo, Qhi]. */
42
template
<
class
T>
43
struct
PbhBounds
{
44
T
Xlo
;
45
T
Xhi
;
46
std::vector<T>
Qlo
;
47
std::vector<T>
Qhi
;
48
};
49
50
namespace
detail {
51
52
/** Per-station residence vector of the level-`level` bound, one side. */
53
template
<
class
T>
54
std::vector<T> pbh_residence(
const
std::vector<T>& L,
int
N,
const
T& Z,
int
level,
bool
optimistic) {
55
const
std::size_t K = L.size();
56
const
T zero =
num_traits<T>::from_int
(0), one =
num_traits<T>::from_int
(1);
57
std::size_t b = 0;
58
for
(std::size_t i = 1; i < K; ++i)
59
if
(L[i] > L[b]) b = i;
60
const
int
lv = std::min(level, N);
61
const
int
n0 = N - lv;
62
T Lsum = zero;
63
for
(
const
T& x : L) Lsum += x;
64
65
std::vector<T> Rk(K, zero);
66
if
(optimistic) {
67
T asym = T(
num_traits<T>::from_int
(n0) * L[b] - Z);
68
if
(asym < Lsum) asym = Lsum;
69
const
T v = T(asym /
num_traits<T>::from_int
(
static_cast<
long
>
(K)));
70
Rk.assign(K, v);
71
}
else
{
72
Rk.assign(K, zero);
73
Rk[b] =
num_traits<T>::from_int
(n0);
74
}
75
if
(n0 == 0) Rk.assign(K, zero);
76
77
for
(
int
n = n0 + 1; n <= N; ++n) {
78
T Rtot = zero;
79
for
(
const
T& x : Rk) Rtot += x;
80
if
(n == 1 || T(Z + Rtot) == zero) {
81
Rk = L;
82
}
else
{
83
const
T f = T(
num_traits<T>::from_int
(n - 1) / T(Z + Rtot));
84
for
(std::size_t i = 0; i < K; ++i) Rk[i] = T(L[i] * T(one + f * Rk[i]));
85
}
86
}
87
return
Rk;
88
}
89
90
}
// namespace detail
91
92
/**
93
* @brief Performance Bound Hierarchy (Eager and Sevcik 1983, ACM TOCS
94
* 1(2):99-115) for single-class closed product-form networks, and the
95
* two iterative families that are defined in terms of it.
96
*
97
* @param L (M) per-station demands
98
* @param N population
99
* @param Z think time
100
* @param level hierarchy level >= 0, clamped to N
101
*/
102
template
<
class
T>
103
PbhBounds<T>
pfqn_pbh
(
const
std::vector<T>& L,
int
N,
const
T& Z,
int
level) {
104
const
std::size_t K = L.size();
105
if
(K == 0)
throw
InputError
(
"pfqn_pbh: empty demand vector"
);
106
if
(N < 0)
throw
InputError
(
"pfqn_pbh: negative population"
);
107
if
(level < 0)
throw
InputError
(
"pfqn_pbh: negative hierarchy level"
);
108
const
T zero =
num_traits<T>::from_int
(0);
109
T Lmax = L[0], Lsum = zero;
110
for
(
const
T& x : L) {
111
Lsum += x;
112
if
(x > Lmax) Lmax = x;
113
}
114
115
const
std::vector<T> Ro = detail::pbh_residence(L, N, Z, level,
true
);
116
const
std::vector<T> Rp = detail::pbh_residence(L, N, Z, level,
false
);
117
118
T Rosum = zero, Rpsum = zero;
119
for
(
const
T& x : Ro) Rosum += x;
120
for
(
const
T& x : Rp) Rpsum += x;
121
122
// Joint with the asymptotic residence lower bound R(N) >= max(N Lmax - Z, sum L).
123
T RoC = Rosum;
124
T asym = T(
num_traits<T>::from_int
(N) * Lmax - Z);
125
if
(asym < Lsum) asym = Lsum;
126
if
(RoC < asym) RoC = asym;
127
128
PbhBounds<T>
r;
129
if
(Lmax == zero)
throw
NumericError
(
"pfqn_pbh: all demands are zero"
);
130
r.
Xhi
= T(
num_traits<T>::from_int
(1) / Lmax);
131
const
T alt = T(
num_traits<T>::from_int
(N) / T(Z + RoC));
132
if
(alt < r.
Xhi
) r.
Xhi
= alt;
133
r.
Xlo
= T(
num_traits<T>::from_int
(N) / T(Z + Rpsum));
134
135
r.
Qlo
.resize(K);
136
r.
Qhi
.resize(K);
137
for
(std::size_t i = 0; i < K; ++i) {
138
r.
Qlo
[i] = T(r.
Xlo
* Ro[i]);
139
r.
Qhi
[i] = T(r.
Xhi
* Rp[i]);
140
}
141
return
r;
142
}
143
144
template
<
class
T>
145
PbhBounds<T>
pfqn_pbh
(
const
std::vector<T>& L,
int
N,
const
T& Z) {
146
return
pfqn_pbh
(L, N, Z, 1);
147
}
148
149
/** PB(k), the iterative Eager-Sevcik proportional bound. Forwards to pfqn_pbh. */
150
template
<
class
T>
151
PbhBounds<T>
pfqn_pbk
(
const
std::vector<T>& L,
int
N,
const
T& Z,
int
k) {
152
return
pfqn_pbh
(L, N, Z, k);
153
}
154
155
template
<
class
T>
156
PbhBounds<T>
pfqn_pbk
(
const
std::vector<T>& L,
int
N,
const
T& Z) {
157
return
pfqn_pbh
(L, N, Z, 1);
158
}
159
160
/** BJB(k), the iterative Balanced Job Bound. Forwards to pfqn_pbh. */
161
template
<
class
T>
162
PbhBounds<T>
pfqn_bjbk
(
const
std::vector<T>& L,
int
N,
const
T& Z,
int
k) {
163
return
pfqn_pbh
(L, N, Z, k);
164
}
165
166
template
<
class
T>
167
PbhBounds<T>
pfqn_bjbk
(
const
std::vector<T>& L,
int
N,
const
T& Z) {
168
return
pfqn_pbh
(L, N, Z, 1);
169
}
170
171
}
// namespace pfqn
172
}
// namespace line
173
174
#endif
// LINE_API_PFQN_PFQN_PBH_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
error.h
The exception types the port throws.
line::pfqn
Definition
cd_peak_scaling.h:43
line::pfqn::pfqn_pbk
PbhBounds< T > pfqn_pbk(const std::vector< T > &L, int N, const T &Z, int k)
PB(k), the iterative Eager-Sevcik proportional bound.
Definition
pfqn_pbh.h:151
line::pfqn::pfqn_bjbk
PbhBounds< T > pfqn_bjbk(const std::vector< T > &L, int N, const T &Z, int k)
BJB(k), the iterative Balanced Job Bound.
Definition
pfqn_pbh.h:162
line::pfqn::pfqn_pbh
PbhBounds< T > pfqn_pbh(const std::vector< T > &L, int N, const T &Z, int level)
Performance Bound Hierarchy (Eager and Sevcik 1983, ACM TOCS 1(2):99-115) for single-class closed pro...
Definition
pfqn_pbh.h:103
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
line::num_traits
Definition
number.h:111
line::pfqn::PbhBounds
Return value of pfqn_pbh, mirroring [Xlo, Xhi, Qlo, Qhi].
Definition
pfqn_pbh.h:43
line::pfqn::PbhBounds::Qlo
std::vector< T > Qlo
Definition
pfqn_pbh.h:46
line::pfqn::PbhBounds::Xlo
T Xlo
Definition
pfqn_pbh.h:44
line::pfqn::PbhBounds::Qhi
std::vector< T > Qhi
Definition
pfqn_pbh.h:47
line::pfqn::PbhBounds::Xhi
T Xhi
Definition
pfqn_pbh.h:45
include
line
api
pfqn
pfqn_pbh.h
Generated by
1.18.0