LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
matlab_ilt.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_MATLAB_ILT_H
6
#define LINE_API_MAM_MATLAB_ILT_H
7
8
/**
9
* @file
10
* @ingroup api_mam
11
* Numerical inverse Laplace transform in the Abate-Whitt framework, the port of
12
* `matlab/lib/thirdparty/iltcme/matlab_ilt.m`.
13
*
14
* Every variant evaluates the same quadrature
15
*
16
* f(t) ~= (1/t) sum_k Re( eta_k F(beta_k / t) )
17
*
18
* and differs only in the (eta, beta) pair:
19
*
20
* - **cme** (the default, and the only one `solver_mam_transient_qbd` uses):
21
* concentrated matrix exponential weights read from the vendored ILT-CME
22
* table. The entry chosen is the steepest -- smallest cv2 -- whose n+1 does
23
* not exceed the evaluation budget, which is exactly the reference's scan.
24
* - **euler**: binomial (Euler) weights, no table.
25
* - **gaver**: Gaver-Stehfest weights, no table.
26
*
27
* WHY cme IS NOT INTERCHANGEABLE WITH THE OTHER TWO, since it is tempting to
28
* reach for a table-free variant: they are different quadratures with different
29
* error behaviour, so substituting one for another changes the answer. The
30
* reference defaults to cme; a port that quietly used euler would produce
31
* numbers that are not the reference's while reporting the same method. That is
32
* why the table is vendored rather than avoided.
33
*
34
* ARITHMETIC. Double only, and deliberately: the transform is evaluated at
35
* COMPLEX arguments, and the whole route is transcendental. The signature takes
36
* a `std::function` over `std::complex<double>` so a caller supplies its own
37
* transform.
38
*/
39
40
#include <algorithm>
41
#include <cmath>
42
#include <complex>
43
#include <cstddef>
44
#include <functional>
45
#include <vector>
46
47
#include "
line/api/mam/iltcme_table.h
"
48
#include "
line/util/error.h
"
49
50
namespace
line
{
51
namespace
mam
{
52
53
/** Which Abate-Whitt weights to use. */
54
enum class
IltMethod
{ Cme, Euler,
Gaver
};
55
56
/**
57
* Invert a Laplace transform at the requested time points.
58
*
59
* @param fun the transform F(s), evaluated at complex s
60
* @param times the points to invert at; each must be positive
61
* @param maxFnEvals evaluation budget per point, which selects the CME entry
62
* @param method the weight family; the reference's default is Cme
63
*/
64
inline
std::vector<double>
matlab_ilt
(
65
const
std::function<std::complex<double>(
const
std::complex<double>&)>& fun,
66
const
std::vector<double>& times, std::size_t maxFnEvals,
67
IltMethod
method =
IltMethod::Cme
) {
68
if
(times.empty())
return
{};
69
for
(
double
t : times)
70
if
(!(t > 0.0))
71
throw
InputError
(
"matlab_ilt: every evaluation time must be strictly positive"
);
72
73
std::vector<std::complex<double>> eta, beta;
74
75
if
(method ==
IltMethod::Cme
) {
76
// The reference's scan: start at entry 0 REGARDLESS of its cost, then
77
// take any entry that is steeper and affordable. Seeding with entry 0
78
// before testing the bound is why it is always reachable.
79
if
(
iltcme::kTableSize
== 0)
80
throw
InputError
(
"matlab_ilt: the vendored ILT-CME table is empty"
);
81
const
iltcme::CmeEntry
* best = &
iltcme::kTable
[0];
82
for
(std::size_t i = 1; i <
iltcme::kTableSize
; ++i) {
83
const
iltcme::CmeEntry
& e =
iltcme::kTable
[i];
84
if
(e.
cv2
< best->
cv2
&&
static_cast<
std::size_t
>
(e.
n
) + 1 <= maxFnEvals) best = &e;
85
}
86
const
double
mu1 = best->
mu1
;
87
eta.reserve(
static_cast<
std::size_t
>
(best->
n
) + 1);
88
beta.reserve(
static_cast<
std::size_t
>
(best->
n
) + 1);
89
eta.emplace_back(best->
c
* mu1, 0.0);
90
beta.emplace_back(mu1, 0.0);
91
for
(
int
k = 0; k < best->
n
; ++k) {
92
eta.emplace_back(best->
a
[k] * mu1, best->
b
[k] * mu1);
93
beta.emplace_back(mu1, mu1 *
static_cast<
double
>
(k + 1) * best->
omega
);
94
}
95
}
else
{
96
// The reference also carries table-free 'euler' and 'gaver' weights.
97
// Neither is ported: `solver_mam_transient_qbd` is the only caller and
98
// it takes the default, so those branches are unreachable here, and an
99
// unreachable branch is an untested one. They are NOT a substitute for
100
// cme in any case -- different quadratures with different error -- which
101
// is exactly why the cme table was vendored rather than avoided.
102
throw
UnsupportedError
(
103
"matlab_ilt: only the CME weights are ported; the reference's 'euler' and 'gaver' "
104
"variants are unreachable from this tree and are different quadratures, not "
105
"substitutes for cme"
);
106
}
107
108
std::vector<double> out(times.size(), 0.0);
109
for
(std::size_t i = 0; i < times.size(); ++i) {
110
const
double
t = times[i];
111
double
acc = 0.0;
112
for
(std::size_t k = 0; k < eta.size(); ++k)
113
acc += std::real(eta[k] * fun(beta[k] / t));
114
out[i] = acc / t;
115
}
116
return
out;
117
}
118
119
}
// namespace mam
120
}
// namespace line
121
122
#endif
// LINE_API_MAM_MATLAB_ILT_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.
iltcme_table.h
The vendored concentrated-matrix-exponential (CME) coefficient table that matlab_ilt reads from iltcm...
line::mam::iltcme::kTable
const CmeEntry kTable[]
The reachable entries, in table order.
Definition
iltcme_table.cpp:360
line::mam::iltcme::kTableSize
const std::size_t kTableSize
Definition
iltcme_table.cpp:534
line::mam
Definition
amap2_adjust_gamma.h:78
line::mam::IltMethod
IltMethod
Which Abate-Whitt weights to use.
Definition
matlab_ilt.h:54
line::mam::IltMethod::Cme
@ Cme
Definition
matlab_ilt.h:54
line::mam::IltMethod::Gaver
@ Gaver
Definition
matlab_ilt.h:54
line::mam::matlab_ilt
std::vector< double > matlab_ilt(const std::function< std::complex< double >(const std::complex< double > &)> &fun, const std::vector< double > ×, std::size_t maxFnEvals, IltMethod method=IltMethod::Cme)
Invert a Laplace transform at the requested time points.
Definition
matlab_ilt.h:64
line
Definition
aoi_dist2ph.h:52
line::mam::iltcme::CmeEntry
One CME entry, carrying only the fields matlab_ilt reads.
Definition
iltcme_table.h:37
line::mam::iltcme::CmeEntry::omega
double omega
angular frequency
Definition
iltcme_table.h:40
line::mam::iltcme::CmeEntry::a
const double * a
cosine coefficients, length n
Definition
iltcme_table.h:43
line::mam::iltcme::CmeEntry::n
int n
number of cosine/sine terms; the transform costs n+1 evaluations
Definition
iltcme_table.h:38
line::mam::iltcme::CmeEntry::mu1
double mu1
first moment scale
Definition
iltcme_table.h:41
line::mam::iltcme::CmeEntry::cv2
double cv2
squared coefficient of variation; smaller is steeper
Definition
iltcme_table.h:42
line::mam::iltcme::CmeEntry::c
double c
constant term
Definition
iltcme_table.h:39
line::mam::iltcme::CmeEntry::b
const double * b
sine coefficients, length n
Definition
iltcme_table.h:44
include
line
api
mam
matlab_ilt.h
Generated by
1.18.0