LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
fj_xmax_erlang.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_FJ_XMAX_ERLANG_H
6
#define LINE_API_FJ_XMAX_ERLANG_H
7
8
/**
9
* @file
10
* @ingroup api_fj
11
* Expected maximum of K i.i.d. Erlang-k service times.
12
*
13
* Templated port of matlab/src/api/fj/fj_xmax_erlang.m, cross-checked against
14
* FJ_xmax.fj_xmax_erlang in jar/src/main/java/jline/api/fj/FJ_xmax.java
15
* (identical formulas; the JAR replaces MATLAB's adaptive `integral` with a
16
* 10001-point composite Simpson rule, which this port also does).
17
*
18
* MIXED ARITHMETIC. At k = 2 the MATLAB file uses the closed form
19
*
20
* X_K^max = (1/mu) sum_{n=1..K} C(K,n) (-1)^{n-1} sum_{m=1..n} C(n,m) m! / (2 n^{m+1})
21
*
22
* which is rational and therefore exact in any field, cancellation included:
23
* the alternating outer sum is exactly the kind that double cannot carry past
24
* about K = 25. For any other k the mean is a quadrature of 1 - F(t)^K against
25
* the Erlang CDF and needs exp, so it is only available when T carries
26
* transcendental functions; asking for it at exact arithmetic throws
27
* UnsupportedError rather than silently substituting something else.
28
*/
29
30
#include "
line/api/fj/fj_types.h
"
31
#include "
line/num/number.h
"
32
#include "
line/util/error.h
"
33
34
namespace
line
{
35
namespace
fj
{
36
37
namespace
detail {
38
39
/** Erlang-k CDF, 1 - exp(-mu t) sum_{j<k} (mu t)^j / j!. */
40
template
<
class
T>
41
T erlang_cdf(
const
T& t,
unsigned
k,
const
T& mu) {
42
static_assert
(num_traits<T>::has_transcendental,
43
"erlang_cdf requires transcendental arithmetic"
);
44
const
T zero = num_traits<T>::from_int(0);
45
if
(t <= zero)
return
zero;
46
const
T x = mu * t;
47
T S = zero;
48
for
(
unsigned
j = 0; j < k; ++j) S +=
num_pow_int
(x, j) /
num_factorial<T>
(j);
49
return
num_traits<T>::from_int(1) - num_exp(T(-x)) * S;
50
}
51
52
/** Erlang-k survival function, exp(-mu x) sum_{j<k} (mu x)^j / j!. */
53
template
<
class
T>
54
T erlang_survival(
const
T& x,
unsigned
k,
const
T& mu) {
55
static_assert
(num_traits<T>::has_transcendental,
56
"erlang_survival requires transcendental arithmetic"
);
57
const
T zero = num_traits<T>::from_int(0);
58
if
(x <= zero)
return
num_traits<T>::from_int(1);
59
const
T y = mu * x;
60
T S = zero;
61
for
(
unsigned
j = 0; j < k; ++j) S +=
num_pow_int
(y, j) /
num_factorial<T>
(j);
62
return
num_exp(T(-y)) * S;
63
}
64
65
/** Quadrature branch of fj_xmax_erlang, for k != 2. */
66
template
<
class
T>
67
T fj_xmax_erlang_quad(
unsigned
K,
unsigned
k,
const
T& mu) {
68
const
T kk = num_traits<T>::from_int(
static_cast<
long
>
(k));
69
const
T upper = kk / mu * num_traits<T>::from_int(10) + num_traits<T>::from_int(10) * num_sqrt(kk) / mu;
70
const
T one = num_traits<T>::from_int(1);
71
return
simpson<T>([&](
const
T& t) {
return
T(one -
num_pow_int
(erlang_cdf(t, k, mu), K)); },
72
num_traits<T>::from_int(0), upper);
73
}
74
75
}
// namespace detail
76
77
/**
78
* @brief Expected maximum of K i.i.d. Erlang-k service times.
79
*
80
* @param K number of branches, K >= 1
81
* @param k Erlang stages, k >= 1
82
* @param mu per-stage rate, > 0 (branch mean is k/mu)
83
* @return expected maximum of K Erlang-k samples
84
*/
85
template
<
class
T>
86
T
fj_xmax_erlang
(
unsigned
K,
unsigned
k,
const
T& mu) {
87
detail::require_positive_K(K,
"fj_xmax_erlang"
);
88
if
(k < 1)
throw
InputError
(
"fj_xmax_erlang: the stage count k must be a positive integer"
);
89
if
(mu <=
num_traits<T>::from_int
(0))
throw
InputError
(
"fj_xmax_erlang: the rate mu must be positive"
);
90
91
if
(k == 2) {
92
T outer =
num_traits<T>::from_int
(0);
93
const
T two =
num_traits<T>::from_int
(2);
94
for
(
unsigned
n = 1; n <= K; ++n) {
95
const
T nn =
num_traits<T>::from_int
(
static_cast<
long
>
(n));
96
T inner =
num_traits<T>::from_int
(0);
97
for
(
unsigned
m = 1; m <= n; ++m)
98
inner += detail::fj_binom<T>(n, m) *
num_factorial<T>
(m) / (two *
num_pow_int
(nn, m + 1));
99
const
T term = detail::fj_binom<T>(K, n) * inner;
100
if
((n - 1) % 2 == 0) outer += term;
101
else
outer -= term;
102
}
103
return
outer / mu;
104
}
105
106
if
constexpr
(
num_traits<T>::has_transcendental
) {
107
return
detail::fj_xmax_erlang_quad<T>(K, k, mu);
108
}
else
{
109
throw
UnsupportedError
(
110
"fj_xmax_erlang: only k = 2 has a closed form; any other stage count needs a "
111
"quadrature of the Erlang CDF and therefore transcendental arithmetic"
);
112
}
113
}
114
115
}
// namespace fj
116
}
// namespace line
117
118
#endif
// LINE_API_FJ_XMAX_ERLANG_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
line::UnsupportedError::UnsupportedError
UnsupportedError(const std::string &what)
Definition
error.h:51
error.h
The exception types the port throws.
fj_types.h
Shared return types and arithmetic helpers for the templated fork-join port.
line::fj
Definition
fj_amva.h:34
line::fj::fj_xmax_erlang
T fj_xmax_erlang(unsigned K, unsigned k, const T &mu)
Expected maximum of K i.i.d.
Definition
fj_xmax_erlang.h:86
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.
line::num_traits
Definition
number.h:111
include
line
api
fj
fj_xmax_erlang.h
Generated by
1.18.0