LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
fj_rmax_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_RMAX_ERLANG_H
6
#define LINE_API_FJ_RMAX_ERLANG_H
7
8
/**
9
* @file
10
* @ingroup api_fj
11
* Expected maximum of K M/E_k/1 branch response times.
12
*
13
* Templated port of matlab/src/api/fj/fj_rmax_erlang.m.
14
*
15
* The branch mean response time comes from Pollaczek-Khinchine with the
16
* Erlang-k SCV 1/k,
17
*
18
* R = (k/mu) [1 + rho (1 + 1/k) / (2 (1 - rho))], rho = lambda k / mu
19
*
20
* At K = 2 the maximum has the closed form (Thomasian 2014, Eq. 34)
21
*
22
* R_2^max = 2 R - sum_{m,n < k} C(m+n,m) mu_R^{m+n} / (2 mu_R)^{m+n+1}
23
*
24
* with mu_R = k / R the rate that matches the response-time mean. For any
25
* other K the MATLAB file moment-matches the response time to an Erlang and
26
* integrates 1 - F(t)^K numerically.
27
*
28
* MIXED ARITHMETIC. The K = 2 branch is rational and exact in any field; the
29
* general-K branch needs exp and a quadrature and throws UnsupportedError at
30
* exact arithmetic.
31
*
32
* REFERENCE DEFECT: FJ_rmax.fj_rmax_erlang in
33
* jar/src/main/java/jline/api/fj/FJ_rmax.java drops the mu_R^{m+n} numerator
34
* from the K = 2 correction, computing C(m+n,m)/(2 mu_R)^{m+n+1} instead. The
35
* two agree only at mu_R = 1. MATLAB is ground truth and is what this port
36
* follows. Note also that the MATLAB correction simplifies to
37
* sum C(m+n,m) / (2^{m+n+1} mu_R), which is how it is evaluated here.
38
*/
39
40
#include "
line/api/fj/fj_types.h
"
41
#include "
line/api/fj/fj_xmax_erlang.h
"
42
#include "
line/num/number.h
"
43
#include "
line/util/error.h
"
44
45
namespace
line
{
46
namespace
fj
{
47
48
/**
49
* @brief Expected maximum of K M/E_k/1 branch response times.
50
*
51
* @param K number of branches, K >= 1
52
* @param k Erlang stages of the branch service time, k >= 1
53
* @param lambda arrival rate
54
* @param mu per-stage service rate (branch mean service is k/mu)
55
* @return expected maximum of the K branch response times
56
*/
57
template
<
class
T>
58
T
fj_rmax_erlang
(
unsigned
K,
unsigned
k,
const
T& lambda,
const
T& mu) {
59
detail::require_positive_K(K,
"fj_rmax_erlang"
);
60
if
(k < 1)
throw
InputError
(
"fj_rmax_erlang: the stage count k must be a positive integer"
);
61
const
T one =
num_traits<T>::from_int
(1), two =
num_traits<T>::from_int
(2);
62
const
T kt =
num_traits<T>::from_int
(
static_cast<
long
>
(k));
63
64
const
T mean_service = kt / mu;
65
const
T rho = lambda * mean_service;
66
if
(rho >= one)
throw
NumericError
(
"fj_rmax_erlang: unstable system, rho >= 1"
);
67
68
const
T cv2 = one / kt;
69
const
T R_single = mean_service * (one + rho * (one + cv2) / (two * (one - rho)));
70
71
if
(K == 2) {
72
const
T mu_resp = kt / R_single;
73
T correction =
num_traits<T>::from_int
(0);
74
for
(
unsigned
m = 0; m < k; ++m)
75
for
(
unsigned
n = 0; n < k; ++n)
76
correction += detail::fj_binom<T>(m + n, m) *
num_pow_int
(mu_resp, m + n) /
77
num_pow_int
(T(two * mu_resp), m + n + 1);
78
return
two * R_single - correction;
79
}
80
81
if
constexpr
(
num_traits<T>::has_transcendental
) {
82
// MATLAB's cv2_response: (1/k + rho)/(1 + rho), floored at 1/20.
83
const
T cv2r_raw = (cv2 + rho) / (one + rho);
84
const
T floor20 =
num_traits<T>::from_rational
(1, 20);
85
const
T cv2r = cv2r_raw > floor20 ? cv2r_raw : floor20;
86
const
double
inv =
num_traits<T>::to_double
(T(one / cv2r));
87
unsigned
k_resp =
static_cast<
unsigned
>
(std::ceil(inv));
88
if
(k_resp < 1) k_resp = 1;
89
const
T mu_resp =
num_traits<T>::from_int
(
static_cast<
long
>
(k_resp)) / R_single;
90
const
T upper = R_single *
num_traits<T>::from_int
(20);
91
return
detail::simpson<T>(
92
[&](
const
T& t) {
return
T(one -
num_pow_int
(detail::erlang_cdf(t, k_resp, mu_resp), K)); },
93
num_traits<T>::from_int
(0), upper);
94
}
else
{
95
throw
UnsupportedError
(
96
"fj_rmax_erlang: only K = 2 has a closed form; any other branch count needs a "
97
"quadrature of the fitted Erlang response-time CDF and therefore transcendental "
98
"arithmetic"
);
99
}
100
}
101
102
}
// namespace fj
103
}
// namespace line
104
105
#endif
// LINE_API_FJ_RMAX_ERLANG_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
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.
fj_xmax_erlang.h
Expected maximum of K i.i.d.
line::fj
Definition
fj_amva.h:34
line::fj::fj_rmax_erlang
T fj_rmax_erlang(unsigned K, unsigned k, const T &lambda, const T &mu)
Expected maximum of K M/E_k/1 branch response times.
Definition
fj_rmax_erlang.h:58
line
Definition
aoi_dist2ph.h:52
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_rmax_erlang.h
Generated by
1.18.0