LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
qsys_lindley_moment.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_QSYS_LINDLEY_MOMENT_H
6
#define LINE_API_QSYS_QSYS_LINDLEY_MOMENT_H
7
8
/**
9
* @file
10
* @ingroup api_qsys
11
* One conditional Lindley moment for exponential primitives.
12
*
13
* Templated port of matlab/src/api/qsys/qsys_lindley_moment.m. No JAR
14
* counterpart. Returns E[max(Wn + S - A, 0)^m] with A ~ Exp(lambda),
15
* S ~ Exp(mu) and m >= 1, evaluated at every entry of Wn.
16
*
17
* This is the algorithm shared by qsys_mm1_lindley, which calls it once per
18
* moment order, and qsys_hh1_lindley, which mixes it over the arrival and
19
* service phases. The density of S - A is the asymmetric Laplace density
20
* lambda mu/(lambda+mu) times e^{-mu x} on x > 0 and e^{lambda x} on x < 0,
21
* which splits the expectation into
22
*
23
* S = sum_{k=0}^{m} C(m,k) w^k (m-k)! / mu^(m-k+1)
24
* T = (-1)^m m! ( sum_{k=0}^{m} (-lambda w)^k/k! - e^{-lambda w} ) / lambda^(m+1)
25
*
26
* with the value lambda mu/(lambda+mu) (S + T). The T term is the upper
27
* incomplete gamma Gamma(m+1, -lambda w), which for integer m+1 has the finite
28
* form m! e^{-x} sum_k x^k/k! valid at the negative argument needed here.
29
* Substituting it cancels the growing exponential, so no incomplete gamma
30
* routine is needed and nothing overflows at large w.
31
*
32
* ARITHMETIC: exp() is the only transcendental step, and it appears once per
33
* evaluation point rather than inside the sum, so the exact instantiation is
34
* refused rather than silently rounded. Everything else is a finite sum of
35
* rational terms and is exact whenever the arithmetic is.
36
*/
37
38
#include <cstddef>
39
#include <vector>
40
41
#include "
line/api/qsys/qsys_types.h
"
42
#include "
line/num/number.h
"
43
#include "
line/util/error.h
"
44
45
namespace
line
{
46
namespace
qsys
{
47
48
/**
49
* @brief One conditional Lindley moment for exponential primitives.
50
*
51
* @param lambda arrival rate, positive
52
* @param mu service rate, positive
53
* @param Wn current waiting times, nonnegative
54
* @param m moment order, at least 1
55
* @return E[max(Wn + S - A, 0)^m] evaluated at every entry of Wn
56
*/
57
template
<
class
T>
58
std::vector<T>
qsys_lindley_moment
(
const
T& lambda,
const
T& mu,
const
std::vector<T>& Wn,
59
unsigned
m) {
60
static_assert
(
num_traits<T>::has_transcendental
,
61
"qsys_lindley_moment requires transcendental arithmetic: the incomplete "
62
"gamma term carries an exp(-lambda w) that no finite field evaluates"
);
63
const
T zero =
num_traits<T>::from_int
(0);
64
if
(lambda <= zero)
throw
InputError
(
"qsys_lindley_moment: lambda must be positive"
);
65
if
(mu <= zero)
throw
InputError
(
"qsys_lindley_moment: mu must be positive"
);
66
if
(m < 1)
throw
InputError
(
"qsys_lindley_moment: the moment order must be at least 1"
);
67
68
// C(m,k) built by the multiplicative recurrence so it stays exact in T
69
std::vector<T> binom(m + 1,
num_traits<T>::from_int
(1));
70
for
(
unsigned
k = 1; k <= m; ++k)
71
binom[k] = binom[k - 1] *
num_traits<T>::from_int
(
static_cast<
long
>
(m - k + 1)) /
72
num_traits<T>::from_int
(
static_cast<
long
>
(k));
73
74
std::vector<T> out;
75
out.reserve(Wn.size());
76
const
T pref = lambda * mu / (lambda + mu);
77
const
T sign = (m % 2 == 0) ?
num_traits<T>::from_int
(1) :
num_traits<T>::from_int
(-1);
78
const
T mfact =
num_factorial<T>
(m);
79
for
(std::size_t i = 0; i < Wn.size(); ++i) {
80
const
T& w = Wn[i];
81
if
(w < zero)
throw
InputError
(
"qsys_lindley_moment: Wn must be nonnegative"
);
82
T sTerm = zero;
83
for
(
unsigned
k = 0; k <= m; ++k)
84
sTerm += binom[k] *
num_pow_int
(w, k) *
num_factorial<T>
(m - k) /
85
num_pow_int
(mu, m - k + 1);
86
const
T x = -lambda * w;
87
T inner = zero;
88
for
(
unsigned
k = 0; k <= m; ++k) inner +=
num_pow_int
(x, k) /
num_factorial<T>
(k);
89
const
T tTerm = sign * mfact * (inner - detail::num_exp(x)) /
num_pow_int
(lambda, m + 1);
90
out.push_back(pref * (sTerm + tTerm));
91
}
92
return
out;
93
}
94
95
/** Scalar overload of the same expression. */
96
template
<
class
T>
97
T
qsys_lindley_moment
(
const
T& lambda,
const
T& mu,
const
T& Wn,
unsigned
m) {
98
return
qsys_lindley_moment
(lambda, mu, std::vector<T>(1, Wn), m)[0];
99
}
100
101
}
// namespace qsys
102
}
// namespace line
103
104
#endif
// LINE_API_QSYS_QSYS_LINDLEY_MOMENT_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_lindley_moment
std::vector< T > qsys_lindley_moment(const T &lambda, const T &mu, const std::vector< T > &Wn, unsigned m)
One conditional Lindley moment for exponential primitives.
Definition
qsys_lindley_moment.h:58
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.
qsys_types.h
Shared return type and arithmetic helpers for the templated qsys port.
line::num_traits
Definition
number.h:111
include
line
api
qsys
qsys_lindley_moment.h
Generated by
1.18.0