LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pfqn_lekt.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_LEKT_H
6
#define LINE_API_PFQN_PFQN_LEKT_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* The common corrected asymptotic expansion (LE-KT), computed on the cheaper side.
12
*
13
* Templated port of matlab/src/api/pfqn/pfqn_lekt.m. The corrected logistic
14
* expansion (pfqn_ble) and the corrected Knessl-Tier expansion (pfqn_bkt) are
15
* ONE estimator, evaluated in M-1 and in R dimensions. With a think time their
16
* stationary points are one point in dual coordinates,
17
*
18
* xi_r = N_r / (Z_r + v u'L_r) (the class throughputs of the LE fixed point)
19
* v u_k = 1 / (1 - U_k) (the M/M/1 factor of the KT saddle)
20
*
21
* and Sylvester's identity det(I_R + C'C) = det(I_M + CC') exchanges the R x R
22
* Hessian determinant for the M x M one, after which every 2 pi cancels on both
23
* sides; the two agree to the accuracy of the saddle-point solvers. Without a
24
* think time the LE branch integrates the radius exactly as Gamma(N+M) while KT
25
* Laplaces it, so they differ by the constant (1 - log(2 pi)/2) - r(N+M), r the
26
* Stirling remainder of a Gamma direction; the common estimator is defined as
27
* the KT value, and the LE side here carries M (1 - log(2 pi)/2) - r(N+M) in
28
* place of pfqn_ble's (M-1)(1 - log(2 pi)/2). See _kb/03-api-layer.md.
29
*
30
* ROUTE. The KT side is an R-dimensional convex solve and an R x R
31
* determinant, the LE side an M-dimensional fixed point and an (M-1) x (M-1)
32
* one, so the KT side is taken when R <= M, and whenever a class self-loops
33
* (one nonzero demand and no think time), which pfqn_kt extracts exactly.
34
*
35
* ARITHMETIC. Inherited from both sides: gated on has_transcendental.
36
*/
37
38
#include <cmath>
39
#include <cstddef>
40
#include <string>
41
#include <vector>
42
43
#include "
line/api/pfqn/pfqn_asympt_common.h
"
44
#include "
line/api/pfqn/pfqn_bkt.h
"
45
#include "
line/api/pfqn/pfqn_ble.h
"
46
#include "
line/lang/lang_types.h
"
47
#include "
line/num/number.h
"
48
#include "
line/util/matrix.h
"
49
50
namespace
line
{
51
namespace
pfqn
{
52
53
/** Return value of pfqn_lekt, mirroring [Gn, lGn, route]. */
54
template
<
class
T>
55
struct
LektResult
{
56
T
G
;
57
T
lG
;
58
std::string
route
;
///< "kt" or "le"
59
};
60
61
/** "kt" when R <= M or a class self-loops, "le" otherwise. */
62
template
<
class
T>
63
std::string
pfqn_lekt_route
(
const
Matrix<T>
& L,
const
std::vector<T>& N,
const
std::vector<T>& Z) {
64
const
T zero =
num_traits<T>::from_int
(0);
65
const
std::size_t M = L.
rows
(), R = L.
cols
();
66
bool
selfloop =
false
;
67
if
(R > 1) {
68
for
(std::size_t r = 0; r < R && !selfloop; ++r) {
69
std::size_t nnz = 0;
70
for
(std::size_t i = 0; i < M; ++i)
71
if
(L(i, r) != zero) ++nnz;
72
const
T z = Z.empty() ? zero : Z[r];
73
if
(nnz == 1 && z == zero) selfloop =
true
;
74
}
75
}
76
return
(R <= M || selfloop) ?
"kt"
:
"le"
;
77
}
78
79
/**
80
* @brief The common corrected asymptotic expansion (LE-KT), computed on the
81
* cheaper side.
82
*
83
* @param L (M x R) demands, @param N (R) population, @param Z (R) think times
84
* (pass an empty vector or all zeros for the Z = 0 branch)
85
*/
86
template
<
class
T>
87
LektResult<T>
pfqn_lekt
(
const
Matrix<T>
& L,
const
std::vector<T>& N,
const
std::vector<T>& Z) {
88
static_assert
(
num_traits<T>::has_transcendental
,
89
"pfqn_lekt requires transcendental arithmetic (Laplace approximation of an integral)"
);
90
using
std::exp;
91
using
std::log;
92
const
T zero =
num_traits<T>::from_int
(0);
93
const
std::size_t M = L.
rows
(), R = L.
cols
();
94
std::vector<T> Zc = Z;
95
if
(Zc.empty()) Zc.assign(R, zero);
96
97
LektResult<T>
res;
98
res.
route
=
pfqn_lekt_route
(L, N, Zc);
99
if
(res.
route
==
"kt"
) {
100
BktResult<T>
k =
pfqn_bkt
(L, N, Zc);
101
res.
G
= k.
G
;
102
res.
lG
= k.
lG
;
103
return
res;
104
}
105
BleResult<T>
b =
pfqn_ble
(L, N, Zc);
106
res.
G
= b.
G
;
107
res.
lG
= b.
lG
;
108
109
T Ntot = zero, Lsum = zero, Zsum = zero;
110
for
(
const
T& x : N) Ntot += x;
111
for
(
const
T& x : Zc) Zsum += x;
112
for
(std::size_t i = 0; i < M; ++i)
113
for
(std::size_t r = 0; r < R; ++r) Lsum += L(i, r);
114
if
(M == 0 || N.empty() || Ntot == zero ||
num_traits<T>::to_double
(Lsum) < 1e-4) {
115
return
res;
// pfqn_ble's degenerate branch: the delay term is exact
116
}
117
const
bool
no_delay =
num_traits<T>::to_double
(Zsum) <
lang::GlobalConstants::Zero
;
118
if
(!no_delay)
return
res;
119
// the Z = 0 branch of pfqn_ble counts M-1 directions; the common estimator
120
// carries M kappa - r(N+M)
121
const
T half =
num_traits<T>::from_double
(0.5);
122
const
T twopi =
num_traits<T>::from_double
(6.283185307179586476925286766559);
123
const
T eta = T(Ntot +
num_traits<T>::from_int
(
static_cast<
long
>
(M)));
124
const
T kappa = T(
num_traits<T>::from_int
(1) - log(twopi) /
num_traits<T>::from_int
(2));
125
const
T r = T(detail::num_lgamma<T>(eta) - (eta - half) * log(eta) + eta - half * log(twopi));
126
res.
lG
+= kappa - r;
127
res.
G
= exp(res.
lG
);
128
return
res;
129
}
130
131
template
<
class
T>
132
LektResult<T>
pfqn_lekt
(
const
Matrix<T>
& L,
const
std::vector<T>& N) {
133
return
pfqn_lekt
(L, N, std::vector<T>());
134
}
135
136
}
// namespace pfqn
137
}
// namespace line
138
139
#endif
// LINE_API_PFQN_PFQN_LEKT_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_bkt
BktResult< T > pfqn_bkt(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Knessl-Tier expansion with the Stirling-remainder correction (BKT).
Definition
pfqn_bkt.h:78
line::pfqn::pfqn_lekt
LektResult< T > pfqn_lekt(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
The common corrected asymptotic expansion (LE-KT), computed on the cheaper side.
Definition
pfqn_lekt.h:87
line::pfqn::pfqn_lekt_route
std::string pfqn_lekt_route(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
"kt" when R <= M or a class self-loops, "le" otherwise.
Definition
pfqn_lekt.h:63
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:56
line::pfqn::BleResult
LeResult< T > BleResult
Return value of pfqn_ble, mirroring [Gn, lGn].
Definition
pfqn_ble.h:47
line::pfqn::BktResult
KtResult< T > BktResult
Return value of pfqn_bkt, mirroring [Gn, lGn] (X and Q are pfqn_kt's seeds).
Definition
pfqn_bkt.h:58
line
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_bkt.h
Knessl-Tier expansion with the Stirling-remainder correction (BKT).
pfqn_ble.h
Logistic expansion with the eps->0 bias correction (BLE).
line::lang::GlobalConstants::Zero
static constexpr double Zero
Definition
lang_types.h:670
line::num_traits
Definition
number.h:111
line::pfqn::KtResult::G
T G
Definition
pfqn_kt.h:57
line::pfqn::KtResult::lG
T lG
Definition
pfqn_kt.h:58
line::pfqn::LeResult::lG
T lG
Definition
pfqn_le.h:235
line::pfqn::LeResult::G
T G
Definition
pfqn_le.h:234
line::pfqn::LektResult
Return value of pfqn_lekt, mirroring [Gn, lGn, route].
Definition
pfqn_lekt.h:55
line::pfqn::LektResult::G
T G
Definition
pfqn_lekt.h:56
line::pfqn::LektResult::lG
T lG
Definition
pfqn_lekt.h:57
line::pfqn::LektResult::route
std::string route
"kt" or "le"
Definition
pfqn_lekt.h:58
include
line
api
pfqn
pfqn_lekt.h
Generated by
1.18.0