LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
sim_sts_quantile_areas.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_SIM_SIM_STS_QUANTILE_AREAS_H
6
#define LINE_API_SIM_SIM_STS_QUANTILE_AREAS_H
7
8
/**
9
* @file
10
* @ingroup api_sim
11
* Standardized time series areas of the batched quantile process.
12
*
13
* Port of matlab/src/api/sim/sim_sts_quantile_areas.m. The b*m observations are
14
* split into b nonoverlapping batches of size m; the function returns the
15
* signed standardized time series (STS) areas of the quantile-estimation
16
* process, the batched quantile estimators, and the three variance-parameter
17
* estimators the QUEST procedures build confidence intervals from.
18
*
19
* With yhat_p(j,m) the empirical p-quantile of batch j and yhat_p(j,k) that of
20
* its first k observations, the STS process of batch j is
21
* T_{j,m}(k/m) = (k/sqrt(m)) (yhat_p(j,m) - yhat_p(j,k)),
22
* its signed area is
23
* A_p(w;j,m) = m^{-1} sum_{k=1}^{m} w(k/m) T_{j,m}(k/m),
24
* and the three estimators of sigma_p^2 = lim n Var(ytilde_p(n)) are
25
* A_p(w;b,m) = b^{-1} sum_j A_p(w;j,m)^2 (STS area)
26
* N_p(b,m) = (b-1)^{-1} m sum_j (yhat_p(j,m)-ytilde_p(n))^2 (NBQ)
27
* V_p(w;b,m) = [b A_p(w;b,m) + (b-1) N_p(b,m)] / (2b-1) (combined)
28
* where ytilde_p(n) is the full-sample empirical p-quantile over all n = b*m
29
* observations. The first two have limiting chi-square laws on b and b-1
30
* degrees of freedom and are asymptotically independent, so the combined
31
* estimator carries 2b-1 degrees of freedom and is about sqrt(2) less variable
32
* than either component.
33
*
34
* WEIGHT FUNCTION. The requirement on w is that int_0^1 w(t)B(t)dt be standard
35
* normal for a standard Brownian bridge B; for a constant w = c that variance is
36
* c^2/12, so c = sqrt(12) is the normalizing choice and any other constant
37
* rescales every area and A_p by (c/sqrt(12))^2. Only constant weights are
38
* supported, as in the reference.
39
*
40
* COST. The prefix quantiles yhat_p(j,k) are exact order statistics, not a
41
* running approximation: a Fenwick tree over the within-batch ranks is advanced
42
* one observation at a time and searched by binary lifting, so the whole
43
* function is O(b m log m). MATLAB advances the b trees in lockstep to keep its
44
* k loop vectorized; here the batches are simply looped, which is the same
45
* arithmetic in a different order.
46
*
47
* A SINGLE BATCH carries no between-batch degrees of freedom, so N_p and V_p are
48
* NaN at b = 1 while areas and bqe stay valid; sim_firquest pools them across
49
* replications instead of reading them per replication.
50
*
51
* Reference: C. Alexopoulos, D. Goldsman, A. Lolos, K. D. Dingec, J. R. Wilson,
52
* "Steady-State Quantile Estimation Using Standardized Time Series", 2020/2023;
53
* A. Lolos et al., Proc. Winter Simulation Conference, 2023, theorems 1-3.
54
*/
55
56
#include <algorithm>
57
#include <cmath>
58
#include <cstddef>
59
#include <numeric>
60
#include <vector>
61
62
#include "
line/api/sim/sim_types.h
"
63
#include "
line/num/number.h
"
64
#include "
line/util/error.h
"
65
66
namespace
line
{
67
namespace
sim
{
68
69
/** Batched-quantile statistics of one sample path. */
70
template
<
class
T>
71
struct
StsQuantileStats
{
72
std::vector<T>
areas
;
///< b signed STS areas A_p(w;j,m)
73
std::vector<T>
bqe
;
///< b batched quantile estimators yhat_p(j,m)
74
T
quantile
;
///< Full-sample empirical p-quantile ytilde_p(n)
75
T
Ap
;
///< Batched STS area estimator A_p(w;b,m)
76
T
Np
;
///< NBQ variance-parameter estimator N_p(b,m), NaN at b = 1
77
T
Vp
;
///< Combined variance-parameter estimator, NaN at b = 1
78
std::size_t
b
= 0;
///< Batch count
79
std::size_t
m
= 0;
///< Batch size
80
std::size_t
n
= 0;
///< Number of observations used, b*m
81
};
82
83
namespace
detail {
84
85
/** Fenwick prefix-count tree over the ranks 1..m of one batch. */
86
class
RankTree {
87
public
:
88
explicit
RankTree(std::size_t m) : f_(m + 1, 0), m_(m) {
89
step_ = 1;
90
while
(step_ * 2 <= m) step_ *= 2;
91
}
92
93
void
add(std::size_t rank) {
94
for
(std::size_t i = rank; i <= m_; i += i & (~i + 1)) ++f_[i];
95
}
96
97
/**
98
* Zero-based index of the L-th smallest rank inserted so far, i.e. MATLAB's
99
* pos + 1 with pos the last position whose prefix count stays below L.
100
*/
101
std::size_t select(std::size_t L)
const
{
102
std::size_t pos = 0, rem = L;
103
for
(std::size_t step = step_; step > 0; step >>= 1) {
104
const
std::size_t cand = pos + step;
105
if
(cand <= m_ && f_[cand] < rem) {
106
rem -= f_[cand];
107
pos = cand;
108
}
109
}
110
return
pos;
111
}
112
113
private
:
114
std::vector<std::size_t> f_;
115
std::size_t m_;
116
std::size_t step_;
117
};
118
119
}
// namespace detail
120
121
/**
122
* @brief Standardized time series areas of the batched quantile process.
123
*
124
* @param Y exactly b*m finite observations, in sample-path order
125
* @param b batch count, positive
126
* @param m batch size, positive
127
* @param p quantile order in (0,1)
128
* @param weight constant STS weight function, sqrt(12) by default
129
*/
130
template
<
class
T>
131
StsQuantileStats<T>
sim_sts_quantile_areas
(
const
std::vector<T>& Y, std::size_t b, std::size_t m,
132
double
p,
double
weight = std::sqrt(12.0)) {
133
static_assert
(
num_traits<T>::has_transcendental
,
134
"sim_sts_quantile_areas: the areas carry the irrational normalizing weight "
135
"sqrt(12)/(m sqrt(m)), so exact arithmetic is refused"
);
136
if
(b < 1)
throw
InputError
(
"sim_sts_quantile_areas: the batch count b must be positive"
);
137
if
(m < 1)
throw
InputError
(
"sim_sts_quantile_areas: the batch size m must be positive"
);
138
if
(!(p > 0.0) || !(p < 1.0))
139
throw
InputError
(
"sim_sts_quantile_areas: p must be a real scalar in (0,1)"
);
140
if
(weight == 0.0)
141
throw
InputError
(
"sim_sts_quantile_areas: weight must be a nonzero real scalar"
);
142
143
const
std::size_t n = b * m;
144
if
(Y.size() != n)
145
throw
InputError
(
"sim_sts_quantile_areas: Y must hold exactly b*m observations"
);
146
for
(std::size_t i = 0; i < n; ++i)
147
if
(!detail::num_isfinite(Y[i]))
148
throw
InputError
(
"sim_sts_quantile_areas: the sample path must be finite"
);
149
150
StsQuantileStats<T>
st;
151
st.
b
= b;
152
st.
m
= m;
153
st.
n
= n;
154
st.
areas
.assign(b,
num_traits<T>::from_int
(0));
155
st.
bqe
.assign(b,
num_traits<T>::from_int
(0));
156
157
const
T wgt =
num_traits<T>::from_double
(weight);
158
const
T md =
num_traits<T>::from_int
(
static_cast<
long
>
(m));
159
const
T scale = T(wgt / T(md * detail::num_sqrt(md)));
160
const
std::size_t bqeIdx =
static_cast<
std::size_t
>
(
161
std::ceil(
static_cast<
double
>
(m) * p)) - 1;
162
163
std::vector<std::size_t> ord(m), rnk(m);
164
for
(std::size_t j = 0; j < b; ++j) {
165
const
T* col = &Y[j * m];
166
167
std::iota(ord.begin(), ord.end(),
static_cast<
std::size_t
>
(0));
168
// stable, so ties keep sample-path order exactly as MATLAB's sort does
169
std::stable_sort(ord.begin(), ord.end(),
170
[col](std::size_t a, std::size_t c) { return col[a] < col[c]; });
171
std::vector<T> sorted(m);
172
for
(std::size_t r = 0; r < m; ++r) {
173
sorted[r] = col[ord[r]];
174
rnk[ord[r]] = r + 1;
175
}
176
177
st.
bqe
[j] = sorted[bqeIdx];
178
179
detail::RankTree tree(m);
180
T acc =
num_traits<T>::from_int
(0);
181
for
(std::size_t k = 1; k <= m; ++k) {
182
tree.add(rnk[k - 1]);
183
const
std::size_t L =
184
static_cast<
std::size_t
>
(std::ceil(p *
static_cast<
double
>
(k)));
185
const
T qk = sorted[tree.select(L)];
186
acc += T(
num_traits<T>::from_int
(
static_cast<
long
>
(k)) * T(st.
bqe
[j] - qk));
187
}
188
st.
areas
[j] = T(scale * acc);
189
}
190
191
std::vector<T> all(Y);
192
std::sort(all.begin(), all.end());
193
st.
quantile
= all[
static_cast<
std::size_t
>
(std::ceil(
static_cast<
double
>
(n) * p)) - 1];
194
195
T sumSq =
num_traits<T>::from_int
(0);
196
for
(std::size_t j = 0; j < b; ++j) sumSq += T(st.
areas
[j] * st.
areas
[j]);
197
st.
Ap
= T(sumSq /
num_traits<T>::from_int
(
static_cast<
long
>
(b)));
198
199
if
(b >= 2) {
200
T sd =
num_traits<T>::from_int
(0);
201
for
(std::size_t j = 0; j < b; ++j) {
202
const
T d = T(st.
bqe
[j] - st.
quantile
);
203
sd += T(d * d);
204
}
205
st.
Np
= T(md * sd /
num_traits<T>::from_int
(
static_cast<
long
>
(b - 1)));
206
st.
Vp
= T((
num_traits<T>::from_int
(
static_cast<
long
>
(b)) * st.
Ap
+
207
num_traits<T>::from_int
(
static_cast<
long
>
(b - 1)) * st.
Np
) /
208
num_traits<T>::from_int
(
static_cast<
long
>
(2 * b - 1)));
209
}
else
{
210
st.
Np
= detail::num_nan<T>();
211
st.
Vp
= detail::num_nan<T>();
212
}
213
return
st;
214
}
215
216
}
// namespace sim
217
}
// namespace line
218
219
#endif
// LINE_API_SIM_SIM_STS_QUANTILE_AREAS_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
error.h
The exception types the port throws.
line::sim
Definition
sim_dist.h:44
line::sim::sim_sts_quantile_areas
StsQuantileStats< T > sim_sts_quantile_areas(const std::vector< T > &Y, std::size_t b, std::size_t m, double p, double weight=std::sqrt(12.0))
Standardized time series areas of the batched quantile process.
Definition
sim_sts_quantile_areas.h:131
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
sim_types.h
Shared arithmetic helpers for the templated simulation output-analysis port.
line::num_traits
Definition
number.h:111
line::sim::StsQuantileStats
Batched-quantile statistics of one sample path.
Definition
sim_sts_quantile_areas.h:71
line::sim::StsQuantileStats::n
std::size_t n
Number of observations used, b*m.
Definition
sim_sts_quantile_areas.h:80
line::sim::StsQuantileStats::b
std::size_t b
Batch count.
Definition
sim_sts_quantile_areas.h:78
line::sim::StsQuantileStats::Ap
T Ap
Batched STS area estimator A_p(w;b,m).
Definition
sim_sts_quantile_areas.h:75
line::sim::StsQuantileStats::areas
std::vector< T > areas
b signed STS areas A_p(w;j,m)
Definition
sim_sts_quantile_areas.h:72
line::sim::StsQuantileStats::Np
T Np
NBQ variance-parameter estimator N_p(b,m), NaN at b = 1.
Definition
sim_sts_quantile_areas.h:76
line::sim::StsQuantileStats::bqe
std::vector< T > bqe
b batched quantile estimators yhat_p(j,m)
Definition
sim_sts_quantile_areas.h:73
line::sim::StsQuantileStats::Vp
T Vp
Combined variance-parameter estimator, NaN at b = 1.
Definition
sim_sts_quantile_areas.h:77
line::sim::StsQuantileStats::quantile
T quantile
Full-sample empirical p-quantile ytilde_p(n).
Definition
sim_sts_quantile_areas.h:74
line::sim::StsQuantileStats::m
std::size_t m
Batch size.
Definition
sim_sts_quantile_areas.h:79
include
line
api
sim
sim_sts_quantile_areas.h
Generated by
1.18.0