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^{-v} prod_r ((Z_r + L_r) v)^{N_r} dv,
21
*
22
* whose log-integrand at the grid point v is
23
*
24
* f(v) = -v + sum(N) log v + sum_r N_r log(Z_r + L_r).
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], rescaling the demands so
28
* that every coefficient is at least one, and reports
29
*
30
* lG = max_i (du_i + f(v_i)) - sum_r log N_r! + sum(N) log(scaleFactor).
31
*
32
* DEFECT IN THE REFERENCE, reproduced here rather than repaired. The estimator
33
* takes the MAXIMUM of the weighted log-integrand instead of summing the
34
* quadrature contributions log sum_i du_i exp(f(v_i)). Two consequences:
35
*
36
* - the width of the integrand is discarded, so the estimate is short by the
37
* Laplace factor sqrt(2 pi sum(N)): with the exact value being
38
* log((sum N)!) + sum_r N_r log(Z_r+L_r) - sum_r log N_r!, the returned
39
* value is Stirling's leading term without the sqrt(2 pi n) correction, a
40
* systematic relative shortfall of about 1/sqrt(2 pi sum(N)) in the log and
41
* a factor sqrt(2 pi sum(N)) in G itself;
42
* - the grid v is NOT sorted (uniform points first, then an increasing
43
* log-spaced block), so du = [0, diff(v)] alternates in sign and is not a
44
* quadrature weight at all; it merely perturbs the argmax.
45
*
46
* Because of this the routine does not converge to the exact constant as the
47
* sample count grows, and its test in this tree asserts the reference's own
48
* behaviour and the size of the shortfall, not agreement with pfqn_ca.
49
*
50
* Only the FIRST row of L is read, matching the reference: this is a
51
* single-queue model and additional rows are ignored.
52
*
53
* Arithmetic: INEXACT BY CONSTRUCTION. The grid is random, the integrand is
54
* evaluated in the log domain, and the log-spaced block is generated by
55
* exponentiation.
56
*
57
* RNG contract: see pfqn_mc_common.h. Comparable to MATLAB only in
58
* distribution, never stream for stream; reproducible within this port only
59
* when the generator is passed in the same state.
60
*/
61
62
#include <cmath>
63
#include <cstddef>
64
#include <limits>
65
#include <vector>
66
67
#include "
line/api/pfqn/pfqn_ca.h
"
68
#include "
line/api/pfqn/pfqn_mc_common.h
"
69
#include "
line/num/number.h
"
70
#include "
line/util/error.h
"
71
#include "
line/util/matrix.h
"
72
73
namespace
line
{
74
namespace
pfqn
{
75
76
/**
77
* @brief Sampled McKenna-Mitra integral form of the normalizing constant of a
78
* repairman (single-queue plus delay) model.
79
*
80
* @param L (M x R) demands; only row 0 is read, as in the reference
81
* @param N (R) population per class
82
* @param Z (R) think times
83
* @param samples grid size; half uniform on [0,1), half log-spaced on [1,1e5]
84
* @param rng explicit generator, advanced by the call
85
*/
86
template
<
class
T>
87
NcResult<T>
pfqn_mmsample2
(
const
Matrix<T>
& L,
const
std::vector<int>& N,
const
std::vector<T>& Z,
88
std::size_t samples,
McRng
&
rng
) {
89
static_assert
(
num_traits<T>::has_transcendental
,
90
"pfqn_mmsample2 requires transcendental arithmetic: it samples a random "
91
"quadrature grid and evaluates a log-domain integrand on it"
);
92
93
const
std::size_t R = N.size();
94
if
(L.
empty
())
throw
InputError
(
"pfqn_mmsample2: empty demand matrix"
);
95
if
(L.
cols
() != R)
throw
InputError
(
"pfqn_mmsample2: L and N disagree on the class count"
);
96
if
(Z.size() != R)
throw
InputError
(
"pfqn_mmsample2: Z has the wrong length"
);
97
for
(
int
n : N)
98
if
(n < 0)
throw
InputError
(
"pfqn_mmsample2: negative population"
);
99
if
(samples == 0)
throw
InputError
(
"pfqn_mmsample2: at least one grid point is required"
);
100
101
// ---- rescale so that every coefficient is at least one -----------------
102
T mn = L(0, 0);
103
for
(std::size_t i = 0; i < L.
rows
(); ++i)
104
for
(std::size_t r = 0; r < R; ++r)
105
if
(L(i, r) < mn) mn = L(i, r);
106
for
(std::size_t r = 0; r < R; ++r)
107
if
(Z[r] < mn) mn = Z[r];
108
const
T scale =
num_traits<T>::from_double
(1e-7) + mn;
109
if
(!(scale >
num_traits<T>::from_int
(0)))
110
throw
NumericError
(
"pfqn_mmsample2: non-positive scale factor, demands must be positive"
);
111
112
// sum_r N_r log((Z_r + L_r)/scale), the v-independent part of f
113
double
lcoef = 0.0;
114
for
(std::size_t r = 0; r < R; ++r) {
115
if
(N[r] == 0)
continue
;
116
const
T coef = (Z[r] + L(0, r)) / scale;
117
lcoef += N[r] *
num_traits<T>::log_as_double
(coef);
118
}
119
long
Ntot = 0;
120
for
(
int
n : N) Ntot += n;
121
122
// ---- the grid: uniform block, then the log-spaced block ----------------
123
const
std::size_t nu =
static_cast<
std::size_t
>
(
124
std::ceil(0.5 *
static_cast<
double
>
(samples)));
125
const
std::size_t nl =
static_cast<
std::size_t
>
(
126
std::ceil(0.5 *
static_cast<
double
>
(samples)));
127
std::vector<double> v;
128
v.reserve(nu + nl);
129
for
(std::size_t i = 0; i < nu; ++i) v.push_back(
mc_uniform01
(
rng
));
130
for
(std::size_t i = 0; i < nl; ++i) {
131
const
double
t = nl == 1 ? 0.0 : 5.0 *
static_cast<
double
>
(i) /
static_cast<
double
>
(nl - 1);
132
v.push_back(std::pow(10.0, t));
133
}
134
135
double
best = -std::numeric_limits<double>::infinity();
136
for
(std::size_t i = 0; i < v.size(); ++i) {
137
// du = [0, diff(v)]: the reference's (sign-indefinite) weight term.
138
const
double
du = i == 0 ? 0.0 : v[i] - v[i - 1];
139
if
(v[i] <= 0.0)
continue
;
// log(0) would be -inf and never wins the max
140
const
double
f = du - v[i] +
static_cast<
double
>
(Ntot) * std::log(v[i]) + lcoef;
141
if
(f > best) best = f;
142
}
143
144
double
lG = best;
145
for
(std::size_t r = 0; r < R; ++r) lG -=
mc_log_factorial<T>
(N[r]);
146
lG +=
static_cast<
double
>
(Ntot) *
num_traits<T>::log_as_double
(scale);
147
return
{
mc_exp<T>
(lG), lG};
148
}
149
150
/** Reference call shape with an explicit grid size. */
151
template
<
class
T>
152
NcResult<T>
pfqn_mmsample2
(
const
Matrix<T>
& L,
const
std::vector<int>& N,
const
std::vector<T>& Z,
153
McRng
&
rng
) {
154
return
pfqn_mmsample2
(L, N, Z,
static_cast<
std::size_t
>
(100000),
rng
);
155
}
156
157
}
// namespace pfqn
158
}
// namespace line
159
160
#endif
// LINE_API_PFQN_MMSAMPLE2_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
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:45
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:87
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::rng
Definition
rng_ssj.h:56
line
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::num_traits
Definition
number.h:111
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