LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pfqn_cbh.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_CBH_H
6
#define LINE_API_PFQN_PFQN_CBH_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* Convolutional Bound Hierarchy (Dowdy, Eager, Gordon and Saxton 1984) on the
12
* throughput of a single-class closed product-form network.
13
*
14
* Templated port of matlab/src/api/pfqn/pfqn_cbh.m. Column c = M - level of
15
* Buzen's g array is filled from a Balanced Job Bound estimate of the first c
16
* stations (e_0 = 1, e_i = e_{i-1}/B_i), the remaining `level` stations are
17
* convolved exactly, and the infinite-server delay is convolved exactly as
18
* well. The BJB upper fill yields the upper bound, the lower fill the lower
19
* bound, and both meet the exact solution at level = M.
20
*
21
* ARITHMETIC. Every step is an addition, a multiplication or a division of
22
* field elements -- the balanced fill uses the arithmetic mean and the maximum
23
* of the demands, not a root or a logarithm -- so the bound is EXACT in
24
* rational arithmetic and is deliberately left ungated. The only non-rational
25
* ingredient, Z^j/j!, is a rational for rational Z.
26
*/
27
28
#include <algorithm>
29
#include <cstddef>
30
#include <vector>
31
32
#include "
line/api/pfqn/pfqn_asympt_common.h
"
33
#include "
line/num/number.h
"
34
#include "
line/util/error.h
"
35
36
namespace
line
{
37
namespace
pfqn
{
38
39
/** Return value of pfqn_cbh, mirroring [Xlo, Xhi]. */
40
template
<
class
T>
41
struct
CbhBounds
{
42
T
Xlo
;
43
T
Xhi
;
44
};
45
46
namespace
detail {
47
48
/** One side of the hierarchy: BJB-filled column c, then exact convolution. */
49
template
<
class
T>
50
T cbh_hier(
const
std::vector<T>& L,
int
N,
const
T& Z, std::size_t c,
bool
upper) {
51
const
std::size_t M = L.size();
52
const
T zero =
num_traits<T>::from_int
(0), one =
num_traits<T>::from_int
(1);
53
T Rc = zero, Lbc = L[0];
54
for
(std::size_t i = 0; i < c; ++i) {
55
Rc += L[i];
56
if
(L[i] > Lbc) Lbc = L[i];
57
}
58
const
T Lac = T(Rc /
num_traits<T>::from_int
(
static_cast<
long
>
(c)));
59
60
std::vector<T> g(
static_cast<
std::size_t
>
(N) + 1, zero);
61
if
(c == 1) {
62
// The single-server column is already exact: g(n) = L_1^n.
63
for
(
int
n = 0; n <= N; ++n) g[static_cast<std::size_t>(n)] =
num_pow_int
(L[0],
static_cast<
unsigned
>
(n));
64
}
else
{
65
g[0] = one;
66
for
(
int
i = 1; i <= N; ++i) {
67
const
T iT =
num_traits<T>::from_int
(i);
68
const
T den = upper ? T(Rc + T(iT - one) * Lac) : T(Rc + T(iT - one) * Lbc);
69
const
T B = T(iT / den);
// BJB fill; upper fill -> upper bound
70
if
(B == zero)
throw
NumericError
(
"pfqn_cbh: zero balanced-job-bound fill"
);
71
g[
static_cast<
std::size_t
>
(i)] = T(g[
static_cast<
std::size_t
>
(i) - 1] / B);
72
}
73
}
74
for
(std::size_t m = c; m < M; ++m)
75
for
(
int
n = 1; n <= N; ++n)
76
g[
static_cast<
std::size_t
>
(n)] += L[m] * g[
static_cast<
std::size_t
>
(n) - 1];
77
78
if
(Z > zero) {
79
std::vector<T> gd(
static_cast<
std::size_t
>
(N) + 1, zero);
80
// Poisson weight Z^j/j!. In double the naive ratio overflows for j >~ 171
81
// and j runs to the POPULATION; an exact T cannot overflow and keeps it.
82
for
(
int
j = 0; j <= N; ++j) {
83
if
constexpr
(
num_traits<T>::has_transcendental
) {
84
using
std::exp;
85
using
std::log;
86
const
T jT =
num_traits<T>::from_int
(j);
87
gd[
static_cast<
std::size_t
>
(j)] = T(exp(jT * log(Z) - detail::num_factln<T>(jT)));
88
}
else
{
89
gd[
static_cast<
std::size_t
>
(j)] =
90
T(
num_pow_int
(Z,
static_cast<
unsigned
>
(j)) /
num_factorial<T>
(
static_cast<
unsigned
>
(j)));
91
}
92
}
93
std::vector<T> gfull(
static_cast<
std::size_t
>
(N) + 1, zero);
94
for
(
int
n = 0; n <= N; ++n) {
95
T acc = zero;
96
for
(
int
j = 0; j <= n; ++j)
97
acc += g[
static_cast<
std::size_t
>
(j)] * gd[
static_cast<
std::size_t
>
(n - j)];
98
gfull[
static_cast<
std::size_t
>
(n)] = acc;
99
}
100
g = gfull;
101
}
102
if
(g[
static_cast<
std::size_t
>
(N)] == zero)
throw
NumericError
(
"pfqn_cbh: zero normalizing constant"
);
103
return
T(g[
static_cast<
std::size_t
>
(N) - 1] / g[
static_cast<
std::size_t
>
(N)]);
104
}
105
106
}
// namespace detail
107
108
/**
109
* @brief Convolutional Bound Hierarchy (Dowdy, Eager, Gordon and Saxton 1984)
110
* on the throughput of a single-class closed product-form network.
111
*
112
* @param L (M) per-station demands
113
* @param N population
114
* @param Z think time
115
* @param level number of exactly convolved stations, clamped to [1, M]
116
*/
117
template
<
class
T>
118
CbhBounds<T>
pfqn_cbh
(
const
std::vector<T>& L,
int
N,
const
T& Z,
int
level) {
119
const
std::size_t M = L.size();
120
if
(M == 0)
throw
InputError
(
"pfqn_cbh: empty demand vector"
);
121
if
(N < 1)
throw
InputError
(
"pfqn_cbh: population must be at least one"
);
122
int
lv = std::max(1, std::min(level,
static_cast<
int
>
(M)));
123
const
std::size_t c =
static_cast<
std::size_t
>
(std::max(1,
static_cast<
int
>
(M) - lv));
124
CbhBounds<T>
r;
125
r.
Xlo
= detail::cbh_hier(L, N, Z, c,
false
);
126
r.
Xhi
= detail::cbh_hier(L, N, Z, c,
true
);
127
return
r;
128
}
129
130
template
<
class
T>
131
CbhBounds<T>
pfqn_cbh
(
const
std::vector<T>& L,
int
N,
const
T& Z) {
132
return
pfqn_cbh
(L, N, Z, 2);
133
}
134
135
}
// namespace pfqn
136
}
// namespace line
137
138
#endif
// LINE_API_PFQN_PFQN_CBH_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_cbh
CbhBounds< T > pfqn_cbh(const std::vector< T > &L, int N, const T &Z, int level)
Convolutional Bound Hierarchy (Dowdy, Eager, Gordon and Saxton 1984) on the throughput of a single-cl...
Definition
pfqn_cbh.h:118
line
Definition
aoi_dist2ph.h:52
line::num_factorial
T num_factorial(unsigned n)
Factorial as a value of T.
Definition
number.h:184
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.
pfqn_asympt_common.h
Shared scalar machinery for the integration / asymptotic members of the pfqn family (pfqn_le,...
line::num_traits
Definition
number.h:111
line::pfqn::CbhBounds
Return value of pfqn_cbh, mirroring [Xlo, Xhi].
Definition
pfqn_cbh.h:41
line::pfqn::CbhBounds::Xlo
T Xlo
Definition
pfqn_cbh.h:42
line::pfqn::CbhBounds::Xhi
T Xhi
Definition
pfqn_cbh.h:43
include
line
api
pfqn
pfqn_cbh.h
Generated by
1.18.0