LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pfqn_ble.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_BLE_H
6
#define LINE_API_PFQN_PFQN_BLE_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* Logistic expansion with the eps->0 bias correction (BLE).
12
*
13
* Templated port of matlab/src/api/pfqn/pfqn_ble.m. Cas17 Theorem 4.1 holds for
14
* eps >= eps_N > 0; the K(1+eps*N) self-looping populations are what make the
15
* integrand concentrate. Evaluated at eps->0, as pfqn_le does, the curvature at
16
* the saddle tends to 1 rather than growing with N, so Laplace's method has no
17
* asymptotic regime there and carries an O(1) relative bias per Laplaced
18
* direction. With kappa = r(1) = 1 - log(2 pi)/2 and r(a) the Stirling remainder
19
* r(a) = gammaln(a) - ((a - 1/2) log a - a + log(2 pi)/2),
20
* the two branch constants are (as in MATLAB pfqn_ble.m):
21
* Z = 0 : M*kappa - r(M), the M-1 simplex directions plus the Jacobian, the
22
* radial integral being exact as Gamma(N+M);
23
* Z > 0 : M*kappa, the radial direction is Laplaced in t = log(v) and
24
* contributes exactly +r(M), cancelling the -r(M).
25
* The published expansion is NOT in error; see _kb/03-api-layer.md.
26
*
27
* ARITHMETIC. Inherited from pfqn_le: the correction is a logarithm, so the
28
* routine is gated on num_traits<T>::has_transcendental for the same reason.
29
*
30
* DEGENERATE BRANCH. When there is no queueing station to expand around, pfqn_le
31
* returns the exact delay term and there is no Laplace step to correct, so
32
* pfqn_ble returns it unchanged; this is the MATLAB branching.
33
*/
34
35
#include <cmath>
36
#include <cstddef>
37
#include <vector>
38
39
#include "
line/api/pfqn/pfqn_asympt_common.h
"
40
#include "
line/api/pfqn/pfqn_le.h
"
41
#include "
line/lang/lang_types.h
"
42
#include "
line/num/number.h
"
43
#include "
line/util/matrix.h
"
44
45
namespace
line
{
46
namespace
pfqn
{
47
48
/** Return value of pfqn_ble, mirroring [Gn, lGn]. */
49
template
<
class
T>
50
using
BleResult
=
LeResult<T>
;
51
52
/**
53
* Logistic expansion estimate of the normalizing constant, bias-corrected.
54
*
55
* @param L (M x R) demands, @param N (R) population, @param Z (R) think times
56
* (pass an empty vector or all zeros for the Z = 0 branch)
57
*/
58
template
<
class
T>
59
BleResult<T>
pfqn_ble
(
const
Matrix<T>
& L,
const
std::vector<T>& N,
const
std::vector<T>& Z) {
60
static_assert
(
num_traits<T>::has_transcendental
,
61
"pfqn_ble requires transcendental arithmetic (Laplace approximation of an integral)"
);
62
using
std::exp;
63
using
std::log;
64
const
std::size_t M = L.
rows
(), R = L.
cols
();
65
const
T zero =
num_traits<T>::from_int
(0);
66
67
BleResult<T>
res =
pfqn_le
(L, N, Z);
68
69
T Ntot = zero, Lsum = zero, Zsum = zero;
70
for
(
const
T& x : N) Ntot += x;
71
for
(
const
T& x : Z) Zsum += x;
72
for
(std::size_t i = 0; i < M; ++i)
73
for
(std::size_t r = 0; r < R; ++r) Lsum += L(i, r);
74
if
(M == 0 || N.empty() || Ntot == zero ||
num_traits<T>::to_double
(Lsum) < 1e-4) {
75
return
res;
76
}
77
78
// Same predicate pfqn_le branches on, so the constant always matches the branch.
79
const
bool
no_delay =
80
Z.empty() ||
num_traits<T>::to_double
(Zsum) <
lang::GlobalConstants::Zero
;
81
const
T one =
num_traits<T>::from_int
(1);
82
const
T twopi =
num_traits<T>::from_double
(6.283185307179586476925286766559);
83
const
T kappa = T(one - log(twopi) /
num_traits<T>::from_int
(2));
84
const
T Mt =
num_traits<T>::from_int
(
static_cast<
long
>
(M));
85
// MATLAB: Z=0 adds M*kappa - stirlingrem(M); Z>0 adds M*kappa.
86
res.
lG
+= Mt * kappa;
87
if
(no_delay) {
88
// stirlingrem(a) = gammaln(a) - ((a-0.5)*log(a) - a + 0.5*log(2*pi))
89
const
T half =
num_traits<T>::from_rational
(1, 2);
90
const
T rem = T(detail::num_lgamma<T>(Mt) - T(T(Mt - half) * log(Mt) - Mt + half * log(twopi)));
91
res.
lG
-= rem;
92
}
93
res.
G
= exp(res.
lG
);
94
return
res;
95
}
96
97
template
<
class
T>
98
BleResult<T>
pfqn_ble
(
const
Matrix<T>
& L,
const
std::vector<T>& N) {
99
return
pfqn_ble
(L, N, std::vector<T>());
100
}
101
102
}
// namespace pfqn
103
}
// namespace line
104
105
#endif
// LINE_API_PFQN_PFQN_BLE_H
line::Matrix
Definition
matrix.h:56
line::Matrix::cols
std::size_t cols() const
Definition
matrix.h:90
line::Matrix::rows
std::size_t rows() const
Definition
matrix.h:89
lang_types.h
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
matrix.h
Dense matrix and non-owning view.
line::pfqn
Definition
cd_peak_scaling.h:43
line::pfqn::pfqn_ble
BleResult< T > pfqn_ble(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Logistic expansion estimate of the normalizing constant, bias-corrected.
Definition
pfqn_ble.h:59
line::pfqn::BleResult
LeResult< T > BleResult
Return value of pfqn_ble, mirroring [Gn, lGn].
Definition
pfqn_ble.h:50
line::pfqn::pfqn_le
LeResult< T > pfqn_le(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Logistic expansion estimate of the normalizing constant.
Definition
pfqn_le.h:245
line
Conservation laws of a layered queueing network, enumerated from its structure.
Definition
aoi_dist2ph.h:52
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,...
pfqn_le.h
Logistic expansion (LE) asymptotic approximation of the normalizing constant of a closed product-form...
line::lang::GlobalConstants::Zero
static constexpr double Zero
Definition
lang_types.h:767
line::num_traits
Definition
number.h:123
line::pfqn::LeResult
Return value of pfqn_le, mirroring [Gn, lGn].
Definition
pfqn_le.h:233
line::pfqn::LeResult::lG
T lG
Definition
pfqn_le.h:235
line::pfqn::LeResult::G
T G
Definition
pfqn_le.h:234
include
line
api
pfqn
pfqn_ble.h
Generated by
1.18.0