LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pfqn_xia.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_XIA_H
6
#define LINE_API_PFQN_XIA_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* Xia's asymptotic approximation of the normalizing constant of a
12
* load-dependent (multiserver) closed network.
13
*
14
* Templated port of jar/src/main/java/jline/api/pfqn/ld/Pfqn_xia.java. MATLAB
15
* has no counterpart.
16
*
17
* The demands are first rescaled so that the largest per-server utilization
18
* rho_i = L_i / s_i is one. The stations that attain it are the BOTTLENECK SET
19
* B; they saturate and contribute the M/M/s saturated term, while every other
20
* station contributes its finite-capacity Erlang-like partial sum
21
*
22
* F(u, k) = sum_{j < k} u^j / j! + (u^k / k!) / (1 - u/k),
23
*
24
* the closed form of the geometric tail beyond the k-th server. The result is
25
*
26
* log G ~ -log((B-1)!) - N log(c) + sum_{b in B} [ s_b log L_b - log(s_b!) ]
27
* + sum_{k not in B} log F(L_k, s_k),
28
*
29
* c being the rescaling factor. Note the leading behaviour in N enters ONLY
30
* through -N log c: this is the large-population limit, so the approximation
31
* does not resolve the O(1) corrections that a finite population carries.
32
*
33
* A NON-BOTTLENECK STATION WITH u > k GIVES A NEGATIVE F, whose logarithm is
34
* NaN and poisons the whole constant. The reference guards only against an
35
* INFINITE F (u == k exactly), not a negative one, so it propagates the NaN;
36
* that is reproduced rather than patched, because suppressing the term would
37
* quietly return a plausible number for a model the expansion does not cover.
38
* The condition cannot arise when every station has one server, but it can once
39
* s varies. Note that at Real precision Boost raises on log of a negative where
40
* double returns NaN, so the same input surfaces as an exception rather than a
41
* NaN; both are refusals and neither is a silent wrong number.
42
*
43
* Arithmetic: TRANSCENDENTAL. Logs and factorials throughout.
44
*/
45
46
#include <cmath>
47
#include <cstddef>
48
#include <vector>
49
50
#include "
line/api/pfqn/pfqn_asympt_common.h
"
51
#include "
line/num/number.h
"
52
#include "
line/util/error.h
"
53
#include "
line/util/matrix.h
"
54
55
namespace
line
{
56
namespace
pfqn
{
57
58
namespace
detail {
59
60
/** F(u,k) = sum_{j<k} u^j/j! + (u^k/k!)/(1 - u/k). */
61
template
<
class
T>
62
T pfqn_xia_F(
const
T& u,
const
T& k) {
63
const
T one = num_traits<T>::from_int(1);
64
const
long
kk =
static_cast<
long
>
(num_traits<T>::to_double(k));
65
T ret = num_traits<T>::from_int(0);
66
T upow = one;
67
T fact = one;
68
for
(
long
j = 0; j < kk; ++j) {
69
ret += T(upow / fact);
70
upow *= u;
71
fact *= num_traits<T>::from_int(j + 1);
72
}
73
// the tail term: u^k / k! / (1 - u/k)
74
const
T denom = T(one - T(u / k));
75
return
T(ret + T(T(upow / fact) / denom));
76
}
77
78
}
// namespace detail
79
80
/**
81
* @brief Xia's asymptotic approximation of the normalizing constant of a
82
* load-dependent (multiserver) closed network.
83
*
84
* @param L (M) service demands
85
* @param N population
86
* @param s (M) server counts
87
* @return log of the approximate normalizing constant
88
*/
89
template
<
class
T>
90
T
pfqn_xia
(
const
std::vector<T>& L,
int
N,
const
std::vector<T>& s) {
91
static_assert
(
num_traits<T>::has_transcendental
,
92
"pfqn_xia is an asymptotic expansion in logs and needs transcendental "
93
"arithmetic"
);
94
using
std::log;
95
const
std::size_t M = L.size();
96
if
(M == 0)
throw
InputError
(
"pfqn_xia requires at least one station"
);
97
if
(s.size() != M)
throw
InputError
(
"pfqn_xia: L and s disagree on the station count"
);
98
const
T zero =
num_traits<T>::from_int
(0);
99
for
(std::size_t i = 0; i < M; ++i) {
100
if
(L[i] <= zero)
throw
InputError
(
"pfqn_xia requires positive demands"
);
101
if
(s[i] <= zero)
throw
InputError
(
"pfqn_xia requires positive server counts"
);
102
}
103
104
std::vector<T> rho(M);
105
for
(std::size_t i = 0; i < M; ++i) rho[i] = T(L[i] / s[i]);
106
T rmax = rho[0];
107
for
(std::size_t i = 1; i < M; ++i)
108
if
(rho[i] > rmax) rmax = rho[i];
109
const
T scalefactor = T(
num_traits<T>::from_int
(1) / rmax);
110
std::vector<T>
Ls
(M), rs(M);
111
for
(std::size_t i = 0; i < M; ++i) {
112
Ls
[i] = T(L[i] * scalefactor);
113
rs[i] = T(rho[i] * scalefactor);
114
}
115
T rsmax = rs[0];
116
for
(std::size_t i = 1; i < M; ++i)
117
if
(rs[i] > rsmax) rsmax = rs[i];
118
119
std::vector<std::size_t> bnk, nbnk;
120
for
(std::size_t i = 0; i < M; ++i) {
121
if
(rs[i] == rsmax)
122
bnk.push_back(i);
123
else
124
nbnk.push_back(i);
125
}
126
const
std::size_t B = bnk.size();
127
128
T logGasy = T(-detail::num_factln<T>(
num_traits<T>::from_int
(
static_cast<
long
>
(B) - 1)) -
129
num_traits<T>::from_int
(N) * log(scalefactor));
130
for
(std::size_t b = 0; b < B; ++b) {
131
const
std::size_t i = bnk[b];
132
logGasy += s[i] * log(
Ls
[i]) - detail::num_factln<T>(s[i]);
133
}
134
for
(std::size_t k = 0; k < nbnk.size(); ++k) {
135
const
std::size_t i = nbnk[k];
136
const
T f = detail::pfqn_xia_F(
Ls
[i], s[i]);
137
const
double
fd =
num_traits<T>::to_double
(f);
138
if
(std::isfinite(fd)) logGasy += log(f);
139
}
140
return
logGasy;
141
}
142
143
}
// namespace pfqn
144
}
// namespace line
145
146
#endif
// LINE_API_PFQN_XIA_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
error.h
The exception types the port throws.
matrix.h
Dense matrix and non-owning view.
line::pfqn
Definition
cd_peak_scaling.h:43
line::pfqn::pfqn_xia
T pfqn_xia(const std::vector< T > &L, int N, const std::vector< T > &s)
Xia's asymptotic approximation of the normalizing constant of a load-dependent (multiserver) closed n...
Definition
pfqn_xia.h:90
line::pfqn::NcMethod::Ls
@ Ls
Definition
pfqn_nc.h:122
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,...
line::num_traits
Definition
number.h:111
include
line
api
pfqn
pfqn_xia.h
Generated by
1.18.0