LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
qsys_maxima_twomoment.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_QSYS_MAXIMA_TWOMOMENT_H
6
#define LINE_API_QSYS_MAXIMA_TWOMOMENT_H
7
8
/**
9
* @file
10
* @ingroup api_qsys
11
* Two-moment approximation for the maximum of n iid non-negative variables.
12
*
13
* Templated port of matlab/src/api/qsys/qsys_maxima_twomoment.m, cross-checked
14
* against jar/src/main/java/jline/api/qsys/Qsys_maxima_twomoment.java.
15
*
16
* THE SHAPE OF THE ANSWER. For a law with an exponential-like tail the maximum
17
* of n samples grows like c~^2 (log n + ...): doubling n ADDS a constant, it
18
* does not scale the answer. The two moments buy the SLOPE and an offset:
19
*
20
* x_n(q) = c~^2 [log(n eta) - log log(1/q)] (1.9)
21
* E[M_n] = c~^2 [log(n eta) + gamma]
22
* cs2 >= 1: c~^2 = cs2, eta = (cs2+1)/(2 cs2^2) (1.11)-(1.12)
23
* cs2 < 1: c~^2 = sqrt(cs2), eta = exp((1-sqrt(cs2))/sqrt(cs2))
24
*
25
* WHEN NOT TO USE IT: n must pass n* ~ cs2/q (4.22), because with a highly
26
* variable law only about n p of the samples can contend for the maximum.
27
* Measured against exact maxima the closed form is within a few percent for
28
* n >= 100 at cs2 = 4 and 16, and useless at n = 10 for cs2 = 16 -- exactly what
29
* n* predicts.
30
*
31
* AND WHEN TWO MOMENTS ARE NOT ENOUGH: below cs2 = 1 the maximum is genuinely
32
* family-dependent. An Erlang and a shifted exponential with the same two
33
* moments have maxima differing by tens of percent, diverging as n grows,
34
* because their tails decay at different rates.
35
*
36
* ARITHMETIC. Logarithms throughout: transcendental only.
37
*
38
* Reference: C. Crow, D. Goldberg, W. Whitt (2007). Two-moment approximations
39
* for maxima. Operations Research 55(3), 532-548.
40
*/
41
42
#include <cmath>
43
#include <cstddef>
44
#include <string>
45
46
#include "
line/num/number.h
"
47
#include "
line/util/error.h
"
48
49
namespace
line
{
50
namespace
qsys
{
51
52
/** Two-moment description of a maximum. */
53
template
<
class
T>
54
struct
MaximaResult
{
55
T
value
;
///< the closed-form mean or quantile
56
T
slope
;
///< mean * c~^2, the coefficient of log n
57
T
eta
;
///< the offset inside the logarithm
58
T
threshold
;
///< n*, below which the form should not be used
59
bool
reliable
;
///< whether n >= n*
60
std::string
family
;
///< the representative law used
61
T
exactFittedValue
;
///< the maximum computed exactly from that representative
62
bool
hasFitted
=
false
;
63
};
64
65
/**
66
* @brief Two-moment approximation for the maximum of n iid non-negative
67
* variables.
68
*
69
* @param n the number of samples
70
* @param mean the mean of the underlying law
71
* @param cs2 its squared coefficient of variation
72
* @param q a quantile level in (0,1); non-positive returns the mean
73
* @param exactFitted also compute the maximum exactly from the fitted law
74
*/
75
template
<
class
T>
76
MaximaResult<T>
qsys_maxima_twomoment
(std::size_t n,
const
T& mean,
const
T& cs2,
77
const
T& q =
num_traits<T>::from_int
(0),
78
bool
exactFitted =
true
) {
79
static_assert
(
num_traits<T>::has_transcendental
,
"qsys_maxima_twomoment needs logarithms"
);
80
using
std::exp;
81
using
std::log;
82
using
std::pow;
83
using
std::sqrt;
84
const
T zero =
num_traits<T>::from_int
(0);
85
const
T one =
num_traits<T>::from_int
(1);
86
const
T two =
num_traits<T>::from_int
(2);
87
if
(n < 1)
throw
InputError
(
"qsys_maxima_twomoment: at least one sample is required"
);
88
if
(mean <= zero)
throw
InputError
(
"qsys_maxima_twomoment: the mean must be positive"
);
89
if
(cs2 <= zero)
throw
InputError
(
"qsys_maxima_twomoment: the SCV must be positive"
);
90
if
(q < zero || q >= one)
91
throw
InputError
(
"qsys_maxima_twomoment: the quantile level must lie in [0,1)"
);
92
93
const
T EULER =
num_traits<T>::from_double
(0.5772156649015329);
94
MaximaResult<T>
r;
95
T ct, eta;
96
if
(cs2 >= one) {
97
ct = cs2;
98
eta = (cs2 + one) / (two * cs2 * cs2);
99
r.
family
=
"H2"
;
100
}
else
{
101
ct = sqrt(cs2);
102
eta = exp((one - sqrt(cs2)) / sqrt(cs2));
103
r.
family
=
"shifted exponential"
;
104
}
105
const
T nT =
num_traits<T>::from_int
(
static_cast<
long
>
(n));
106
const
bool
wantMean = (q <= zero);
107
const
T inner = wantMean ? T(log(nT * eta) + EULER) : T(log(nT * eta) - log(log(one / q)));
108
r.
value
= mean * ct * inner;
109
r.
slope
= mean * ct;
110
r.
eta
= eta;
111
r.
threshold
= cs2 / (wantMean ?
num_traits<T>::from_rational
(1, 2) : q);
// eq. (4.22)
112
r.
reliable
= nT >= r.
threshold
;
113
114
if
(exactFitted) {
115
// Fit the representative law and compute the maximum exactly from F^n.
116
T d = zero, m = mean, p1 = zero, l1 = zero, l2 = zero, hi;
117
if
(cs2 >= one) {
118
p1 = (one + sqrt((cs2 - one) / (cs2 + one))) / two;
119
l1 = two * p1 / mean;
120
l2 = two * (one - p1) / mean;
121
hi =
num_traits<T>::from_int
(40) * mean * (cs2 > one ? cs2 : one);
122
}
else
{
123
d = mean * (one - sqrt(cs2));
124
m = mean * sqrt(cs2);
125
hi = d +
num_traits<T>::from_int
(40) * m;
126
}
127
auto
ccdf = [&](
const
T& t) {
128
if
(cs2 >= one)
return
T(p1 * exp(-l1 * t) + (one - p1) * exp(-l2 * t));
129
return
t <= d ? one : T(exp(-(t - d) / m));
130
};
131
const
std::size_t gn = 200000;
132
const
T h = hi /
num_traits<T>::from_int
(
static_cast<
long
>
(gn));
133
r.
hasFitted
=
true
;
134
if
(wantMean) {
135
T acc = zero;
136
for
(std::size_t i = 0; i <= gn; ++i) {
137
const
T t =
num_traits<T>::from_int
(
static_cast<
long
>
(i)) * h;
138
const
T v = one - pow(one - ccdf(t),
num_traits<T>::from_int
(
static_cast<
long
>
(n)));
139
acc += (i == 0 || i == gn) ? T(v / two) : v;
140
}
141
r.
exactFittedValue
= acc * h;
142
}
else
{
143
r.
exactFittedValue
= hi;
144
for
(std::size_t i = 0; i <= gn; ++i) {
145
const
T t =
num_traits<T>::from_int
(
static_cast<
long
>
(i)) * h;
146
if
(pow(one - ccdf(t),
num_traits<T>::from_int
(
static_cast<
long
>
(n))) >= q) {
147
r.
exactFittedValue
= t;
148
break
;
149
}
150
}
151
}
152
}
153
return
r;
154
}
155
156
}
// namespace qsys
157
}
// namespace line
158
159
#endif
// LINE_API_QSYS_MAXIMA_TWOMOMENT_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
error.h
The exception types the port throws.
line::qsys
Definition
qsys_bmapm1.h:58
line::qsys::qsys_maxima_twomoment
MaximaResult< T > qsys_maxima_twomoment(std::size_t n, const T &mean, const T &cs2, const T &q=num_traits< T >::from_int(0), bool exactFitted=true)
Two-moment approximation for the maximum of n iid non-negative variables.
Definition
qsys_maxima_twomoment.h:76
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
line::num_traits
Definition
number.h:111
line::qsys::MaximaResult
Two-moment description of a maximum.
Definition
qsys_maxima_twomoment.h:54
line::qsys::MaximaResult::slope
T slope
mean * c~^2, the coefficient of log n
Definition
qsys_maxima_twomoment.h:56
line::qsys::MaximaResult::value
T value
the closed-form mean or quantile
Definition
qsys_maxima_twomoment.h:55
line::qsys::MaximaResult::eta
T eta
the offset inside the logarithm
Definition
qsys_maxima_twomoment.h:57
line::qsys::MaximaResult::reliable
bool reliable
whether n >= n*
Definition
qsys_maxima_twomoment.h:59
line::qsys::MaximaResult::threshold
T threshold
n*, below which the form should not be used
Definition
qsys_maxima_twomoment.h:58
line::qsys::MaximaResult::hasFitted
bool hasFitted
Definition
qsys_maxima_twomoment.h:62
line::qsys::MaximaResult::family
std::string family
the representative law used
Definition
qsys_maxima_twomoment.h:60
line::qsys::MaximaResult::exactFittedValue
T exactFittedValue
the maximum computed exactly from that representative
Definition
qsys_maxima_twomoment.h:61
include
line
api
qsys
qsys_maxima_twomoment.h
Generated by
1.18.0