LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pfqn_mmsample2.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_PFQN_MMSAMPLE2_H
6
#define LINE_API_PFQN_MMSAMPLE2_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* Sampled McKenna-Mitra integral form of the normalizing constant of a
12
* repairman (single-queue plus delay) model.
13
*
14
* Templated port of matlab/src/api/pfqn/pfqn_mmsample2.m, cross-checked
15
* against jar/src/main/java/jline/api/pfqn/nc/Pfqn_mmsample2.java.
16
*
17
* For a single queue the McKenna-Mitra form collapses to the one-dimensional
18
* integral
19
*
20
* G(N) = 1/prod_r N_r! int_0^inf e^{-u} prod_r (Z_r + L_r u)^{N_r} du,
21
*
22
* whose log-integrand at the grid point u is
23
*
24
* f(u) = -u + sum_r N_r log(Z_r + L_r u).
25
*
26
* The reference lays a grid of ceil(samples/2) uniform points on [0,1) plus
27
* ceil(samples/2) points log-spaced over [1, 1e5], SORTS it, rescales the
28
* demands so that every coefficient is at least one, takes the panel widths
29
* du = [v(1), diff(v)] (the first panel covering [0, v(1)]) and reports the
30
* quadrature sum in the log domain,
31
*
32
* lG = log sum_i du_i exp(f(v_i)) - sum_r log N_r! + sum(N) log(scaleFactor).
33
*
34
* (An earlier reference took the maximum of the weighted log-integrand over an
35
* unsorted grid with the integrand (Z_r + L_r) u; MATLAB has since been
36
* corrected and this port follows the corrected estimator.)
37
*
38
* Only the FIRST row of L is read, matching the reference: this is a
39
* single-queue model and additional rows are ignored.
40
*
41
* Arithmetic: INEXACT BY CONSTRUCTION. The grid is random, the integrand is
42
* evaluated in the log domain, and the log-spaced block is generated by
43
* exponentiation.
44
*
45
* RNG contract: see pfqn_mc_common.h. Comparable to MATLAB only in
46
* distribution, never stream for stream; reproducible within this port only
47
* when the generator is passed in the same state.
48
*/
49
50
#include <algorithm>
51
#include <cmath>
52
#include <cstddef>
53
#include <limits>
54
#include <vector>
55
56
#include "
line/api/pfqn/pfqn_ca.h
"
57
#include "
line/api/pfqn/pfqn_mc_common.h
"
58
#include "
line/num/number.h
"
59
#include "
line/util/error.h
"
60
#include "
line/util/matrix.h
"
61
62
namespace
line
{
63
namespace
pfqn
{
64
65
/**
66
* @brief Sampled McKenna-Mitra integral form of the normalizing constant of a
67
* repairman (single-queue plus delay) model.
68
*
69
* @param L (M x R) demands; only row 0 is read, as in the reference
70
* @param N (R) population per class
71
* @param Z (R) think times
72
* @param samples grid size; half uniform on [0,1), half log-spaced on [1,1e5]
73
* @param rng explicit generator, advanced by the call
74
*/
75
template
<
class
T>
76
NcResult<T>
pfqn_mmsample2
(
const
Matrix<T>
& L,
const
std::vector<int>& N,
const
std::vector<T>& Z,
77
std::size_t samples,
McRng
&
rng
) {
78
static_assert
(
num_traits<T>::has_transcendental
,
79
"pfqn_mmsample2 requires transcendental arithmetic: it samples a random "
80
"quadrature grid and evaluates a log-domain integrand on it"
);
81
82
const
std::size_t R = N.size();
83
if
(L.
empty
())
throw
InputError
(
"pfqn_mmsample2: empty demand matrix"
);
84
if
(L.
cols
() != R)
throw
InputError
(
"pfqn_mmsample2: L and N disagree on the class count"
);
85
if
(Z.size() != R)
throw
InputError
(
"pfqn_mmsample2: Z has the wrong length"
);
86
for
(
int
n : N)
87
if
(n < 0)
throw
InputError
(
"pfqn_mmsample2: negative population"
);
88
if
(samples == 0)
throw
InputError
(
"pfqn_mmsample2: at least one grid point is required"
);
89
90
// ---- rescale so that every coefficient is at least one -----------------
91
T mn = L(0, 0);
92
for
(std::size_t i = 0; i < L.
rows
(); ++i)
93
for
(std::size_t r = 0; r < R; ++r)
94
if
(L(i, r) < mn) mn = L(i, r);
95
for
(std::size_t r = 0; r < R; ++r)
96
if
(Z[r] < mn) mn = Z[r];
97
const
T scale =
num_traits<T>::from_double
(1e-7) + mn;
98
if
(!(scale >
num_traits<T>::from_int
(0)))
99
throw
NumericError
(
ErrorKind
{
"Degenerate"
},
"pfqn_mmsample2: non-positive scale factor, demands must be positive"
);
100
101
// scaled coefficients Z_r/scale and L_r/scale (first row of L)
102
std::vector<double> Zs(R),
Ls
(R);
103
for
(std::size_t r = 0; r < R; ++r) {
104
Zs[r] =
num_traits<T>::to_double
(T(Z[r] / scale));
105
Ls
[r] =
num_traits<T>::to_double
(T(L(0, r) / scale));
106
}
107
long
Ntot = 0;
108
for
(
int
n : N) Ntot += n;
109
110
// ---- the grid: uniform block plus the log-spaced block, SORTED ---------
111
const
std::size_t nu =
static_cast<
std::size_t
>
(
112
std::ceil(0.5 *
static_cast<
double
>
(samples)));
113
const
std::size_t nl =
static_cast<
std::size_t
>
(
114
std::ceil(0.5 *
static_cast<
double
>
(samples)));
115
std::vector<double> v;
116
v.reserve(nu + nl);
117
for
(std::size_t i = 0; i < nu; ++i) v.push_back(
mc_uniform01
(
rng
));
118
for
(std::size_t i = 0; i < nl; ++i) {
119
const
double
t = nl == 1 ? 0.0 : 5.0 *
static_cast<
double
>
(i) /
static_cast<
double
>
(nl - 1);
120
v.push_back(std::pow(10.0, t));
121
}
122
std::sort(v.begin(), v.end());
123
124
// lterms_i = log(du_i) - v_i + sum_r N_r log(Z_r + L_r v_i), du = [v(1), diff(v)]
125
std::vector<double> lterms;
126
lterms.reserve(v.size());
127
double
lmax = -std::numeric_limits<double>::infinity();
128
for
(std::size_t i = 0; i < v.size(); ++i) {
129
const
double
du = i == 0 ? v[0] : v[i] - v[i - 1];
130
double
f = std::log(du) - v[i];
131
for
(std::size_t r = 0; r < R; ++r) {
132
if
(N[r] == 0)
continue
;
133
f +=
static_cast<
double
>
(N[r]) * std::log(Zs[r] +
Ls
[r] * v[i]);
134
}
135
lterms.push_back(f);
136
if
(f > lmax) lmax = f;
137
}
138
double
ssum = 0.0;
139
for
(
double
f : lterms)
140
if
(std::isfinite(f)) ssum += std::exp(f - lmax);
141
142
double
lG = lmax + std::log(ssum);
143
for
(std::size_t r = 0; r < R; ++r) lG -=
mc_log_factorial<T>
(N[r]);
144
lG +=
static_cast<
double
>
(Ntot) *
num_traits<T>::log_as_double
(scale);
145
return
{
mc_exp<T>
(lG), lG};
146
}
147
148
/** Reference call shape with an explicit grid size. */
149
template
<
class
T>
150
NcResult<T>
pfqn_mmsample2
(
const
Matrix<T>
& L,
const
std::vector<int>& N,
const
std::vector<T>& Z,
151
McRng
&
rng
) {
152
return
pfqn_mmsample2
(L, N, Z,
static_cast<
std::size_t
>
(100000),
rng
);
153
}
154
155
}
// namespace pfqn
156
}
// namespace line
157
158
#endif
// LINE_API_PFQN_MMSAMPLE2_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:105
line::Matrix
Definition
matrix.h:56
line::Matrix::cols
std::size_t cols() const
Definition
matrix.h:90
line::Matrix::rows
std::size_t rows() const
Definition
matrix.h:89
line::Matrix::empty
bool empty() const
Definition
matrix.h:92
line::NumericError::NumericError
NumericError(const std::string &what)
Definition
error.h:112
error.h
The exception types the port throws.
matrix.h
Dense matrix and non-owning view.
line::pfqn
Definition
cd_peak_scaling.h:43
line::pfqn::mc_log_factorial
double mc_log_factorial(long n)
log(n!) for a non-negative integer n, the factln / gammaln(1+n) of the references,...
Definition
pfqn_mc_common.h:143
line::pfqn::McRng
std::mt19937_64 McRng
The generator type every Monte Carlo entry point in this tree accepts.
Definition
pfqn_mc_common.h:62
line::pfqn::pfqn_mmsample2
NcResult< T > pfqn_mmsample2(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, std::size_t samples, McRng &rng)
Sampled McKenna-Mitra integral form of the normalizing constant of a repairman (single-queue plus del...
Definition
pfqn_mmsample2.h:76
line::pfqn::mc_uniform01
double mc_uniform01(McRng &g)
Uniform deviate on [0,1) with 53 significant bits, as a double.
Definition
pfqn_mc_common.h:69
line::pfqn::mc_exp
T mc_exp(double lv)
exp of a log-domain value, materialized in the working arithmetic.
Definition
pfqn_mc_common.h:132
line::pfqn::NcMethod::Ls
@ Ls
Definition
pfqn_nc.h:122
line::rng
Definition
rng_ssj.h:57
line
Conservation laws of a layered queueing network, enumerated from its structure.
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
pfqn_ca.h
Convolution algorithm for the exact normalizing constant of a closed product-form network (Buzen 1973...
pfqn_mc_common.h
Randomness scaffolding shared by the Monte Carlo normalizing-constant estimators (pfqn_mci,...
line::ErrorKind
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
Definition
error.h:37
line::num_traits
Definition
number.h:123
line::pfqn::NcResult
Return value of the normalizing-constant family, mirroring Ret.pfqnNc.
Definition
pfqn_ca.h:44
include
line
api
pfqn
pfqn_mmsample2.h
Generated by
1.18.0