LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
map_bernstein.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_MAM_MAP_BERNSTEIN_H
6
#define LINE_API_MAM_MAP_BERNSTEIN_H
7
8
/**
9
* @file
10
* @ingroup api_mam
11
* Acyclic phase-type approximation of an arbitrary density by Bernstein
12
* exponentials.
13
*
14
* Templated port of matlab/lib/kpctoolbox/map/map_bernstein.m and
15
* jar/src/main/java/jline/api/mam/Aph_bernstein.java, after
16
* Horvath and Vicario, "Construction of Phase Type Distributions by Bernstein
17
* Exponentials", EPEW 2023, 201-215.
18
*
19
* The construction evaluates the target density at the n Bernstein nodes
20
* x_i = -log(i/n) and uses the values as the entry law of the Erlang cascade
21
* T = diag(-1..-n) + superdiag(1..n-1),
22
* whose i-th phase has an Erlang(i,i) residual time. The result is a renewal
23
* process, D1 = -T 1 alpha, so the fit is a PH and not a general MAP; the caller
24
* rescales it to the target mean with map_scale, since the construction pins the
25
* time unit at one.
26
*
27
* WHICH REFERENCE. The MATLAB and JAR versions differ and MATLAB is the ground
28
* truth here: it skips a node where the density is not finite and positive,
29
* renormalizes alpha (which the bare 1/(i c) weights only satisfy up to the
30
* skipped nodes), and falls back to an Erlang-n of unit mean when the
31
* normalization constant is not usable at all. The JAR divides by c
32
* unconditionally, so a density that underflows at some node -- a Pareto below
33
* its scale, a Uniform outside its support, any bounded law -- gives it a NaN
34
* generator instead of a fit. That path is exactly the one `sn_nonmarkov_toph`
35
* takes for Uniform and Pareto service.
36
*
37
* ARITHMETIC: transcendental, since the nodes are logarithms of i/n.
38
*/
39
40
#include <cmath>
41
#include <cstddef>
42
#include <functional>
43
44
#include "
line/api/mam/map_moment.h
"
45
#include "
line/api/mam/map_transform.h
"
46
#include "
line/num/number.h
"
47
#include "
line/util/error.h
"
48
#include "
line/util/matrix.h
"
49
50
namespace
line
{
51
namespace
mam
{
52
53
/**
54
* @brief Acyclic phase-type approximation of an arbitrary density by
55
* Bernstein exponentials.
56
*
57
* @param f the density to approximate, evaluated at positive abscissae
58
* @param order number of phases, the reference default being 20
59
* @return the fitted renewal MAP, of unit time scale; rescale with map_scale
60
*/
61
template
<
class
T>
62
Map<T>
map_bernstein
(
const
std::function<
double
(
double
)>& f,
unsigned
order = 20) {
63
static_assert
(
num_traits<T>::has_transcendental
,
64
"map_bernstein evaluates the density at logarithmic nodes"
);
65
if
(order == 0)
throw
InputError
(
"map_bernstein: the order must be positive"
);
66
const
std::size_t n = order;
67
const
T zero =
num_traits<T>::from_int
(0);
68
69
std::vector<double> fv(n, 0.0);
70
double
c = 0.0;
71
for
(std::size_t i = 1; i <= n; ++i) {
72
const
double
xi = -std::log(
static_cast<
double
>
(i) /
static_cast<
double
>
(n));
73
const
double
fi = f(xi);
74
if
(std::isfinite(fi) && fi > 0.0) {
75
fv[i - 1] = fi;
76
c += fi /
static_cast<
double
>
(i);
77
}
78
}
79
// No usable mass at any node: the reference returns a unit-mean Erlang-n and
80
// leaves the rescaling to the caller, rather than emitting a NaN generator.
81
if
(!(c > 0.0) || !std::isfinite(c))
82
return
map_erlang
(
num_traits<T>::from_int
(1),
static_cast<
unsigned
>
(n));
83
84
std::vector<double> alpha(n, 0.0);
85
double
asum = 0.0;
86
for
(std::size_t i = 1; i <= n; ++i) {
87
if
(fv[i - 1] > 0.0) {
88
alpha[i - 1] = fv[i - 1] / (
static_cast<
double
>
(i) * c);
89
asum += alpha[i - 1];
90
}
91
}
92
if
(asum > 0.0) {
93
for
(std::size_t i = 0; i < n; ++i) alpha[i] /= asum;
94
}
else
{
95
alpha[0] = 1.0;
// degenerate: start in the first phase
96
}
97
98
Map<T>
m;
99
m.
D0
=
Matrix<T>
(n, n, zero);
100
m.
D1
=
Matrix<T>
(n, n, zero);
101
for
(std::size_t i = 0; i < n; ++i) {
102
m.
D0
(i, i) =
num_traits<T>::from_int
(-
static_cast<
int
>
(i + 1));
103
if
(i + 1 < n) m.
D0
(i, i + 1) =
num_traits<T>::from_int
(
static_cast<
int
>
(i + 1));
104
}
105
// D1 = -T P with P = 1 alpha: every phase restarts from the entry law.
106
for
(std::size_t i = 0; i < n; ++i) {
107
T rowsum = zero;
108
for
(std::size_t j = 0; j < n; ++j) rowsum += m.
D0
(i, j);
109
for
(std::size_t j = 0; j < n; ++j)
110
m.
D1
(i, j) = T(-rowsum *
num_traits<T>::from_double
(alpha[j]));
111
}
112
return
m;
113
}
114
115
/**
116
* The reference's (D0, D1) spelling of the same fit, kept because the JAR
117
* exposes it under this name (Aph_bernstein) and callers ported from it expect
118
* the pair rather than a Map.
119
*/
120
template
<
class
T>
121
Map<T>
aph_bernstein
(
const
std::function<
double
(
double
)>& f,
unsigned
order = 20) {
122
return
map_bernstein<T>
(f, order);
123
}
124
125
}
// namespace mam
126
}
// namespace line
127
128
#endif
// LINE_API_MAM_MAP_BERNSTEIN_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
line::Matrix::Matrix
Matrix()
Definition
matrix.h:58
error.h
The exception types the port throws.
map_moment.h
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
map_transform.h
MAP constructors and structural transformations.
matrix.h
Dense matrix and non-owning view.
line::mam
Definition
amap2_adjust_gamma.h:78
line::mam::map_bernstein
Map< T > map_bernstein(const std::function< double(double)> &f, unsigned order=20)
Acyclic phase-type approximation of an arbitrary density by Bernstein exponentials.
Definition
map_bernstein.h:62
line::mam::map_erlang
Map< T > map_erlang(const T &mean, unsigned k)
Erlang-k renewal MAP with the given mean (map_erlang.m).
Definition
map_transform.h:125
line::mam::aph_bernstein
Map< T > aph_bernstein(const std::function< double(double)> &f, unsigned order=20)
The reference's (D0, D1) spelling of the same fit, kept because the JAR exposes it under this name (A...
Definition
map_bernstein.h:121
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
line::mam::Map
A MAP as the pair of matrices (D0, D1).
Definition
map_moment.h:53
line::mam::Map::D1
Matrix< T > D1
Definition
map_moment.h:55
line::mam::Map::D0
Matrix< T > D0
Definition
map_moment.h:54
line::num_traits
Definition
number.h:111
include
line
api
mam
map_bernstein.h
Generated by
1.18.0