5#ifndef LINE_API_SIM_RUNLENGTH_H
6#define LINE_API_SIM_RUNLENGTH_H
82 if (lambda <= zero || mu <= zero)
83 throw InputError(
"sim_asymvar_mm1: the arrival and service rates must be positive");
84 const T rho = lambda / mu;
85 if (rho >= one)
throw InputError(
"sim_asymvar_mm1: the queue must be stable, rho < 1");
87 r.
mean = rho / (one - rho);
88 r.
variance = rho / ((one - rho) * (one - rho));
89 const T d = (one - rho) * (one - rho) * (one - rho) * (one - rho);
106 const std::vector<T>& pi = std::vector<T>()) {
109 const std::size_t n = A.
rows();
110 if (A.
cols() != n)
throw InputError(
"sim_asymvar_ctmc: the generator must be square");
111 if (f.size() != n)
throw InputError(
"sim_asymvar_ctmc: one reward per state is required");
112 for (std::size_t i = 0; i < n; ++i) {
114 for (std::size_t j = 0; j < n; ++j) row += A(i, j);
116 throw InputError(
"sim_asymvar_ctmc: the generator rows must sum to zero");
118 std::vector<T> p = pi;
122 std::vector<T> b(n, zero);
123 for (std::size_t j = 0; j + 1 < n; ++j)
124 for (std::size_t i = 0; i < n; ++i) M(j, i) = A(i, j);
125 for (std::size_t i = 0; i < n; ++i) M(n - 1, i) = one;
130 for (std::size_t i = 0; i < n; ++i) mean += p[i] * f[i];
132 for (std::size_t i = 0; i < n; ++i) g[i] = f[i] - mean;
140 std::size_t drop = 0;
141 for (std::size_t i = 1; i < n; ++i)
142 if (p[i] > p[drop]) drop = i;
144 std::vector<T> b2(n, zero);
146 for (std::size_t i = 0; i < n; ++i) {
147 if (i == drop)
continue;
148 for (std::size_t j = 0; j < n; ++j) M2(r0, j) = A(i, j);
152 for (std::size_t j = 0; j < n; ++j) M2(n - 1, j) = p[j];
153 const std::vector<T> d =
solve(M2, b2);
158 for (std::size_t i = 0; i < n; ++i) {
190 throw InputError(
"sim_runlength: a relative precision is meaningless for a zero mean");
191 if (asymVar < zero)
throw InputError(
"sim_runlength: the asymptotic variance cannot be negative");
192 if (relPrecision <= zero)
throw InputError(
"sim_runlength: the relative precision must be positive");
193 if (confidence <= zero || confidence >= one)
194 throw InputError(
"sim_runlength: the confidence must lie in (0,1)");
197 const T target = one - confidence;
198 for (
int i = 0; i < 200; ++i) {
199 const T mid = (lo + hi) / two;
200 if (erfc(mid / sqrt(two)) > target) {
207 r.
z = (lo + hi) / two;
208 r.
requiredRunLength = (r.
z / relPrecision) * (r.
z / relPrecision) * asymVar / (mean * mean);
211 if (runLength > zero) {
213 r.
halfWidth = r.
z * sqrt(asymVar / runLength);
250 const T& samplesUsed,
254 "sim_runlength_plan needs erfc for the quantile");
256 if (samplesUsed <= zero)
257 throw InputError(
"sim_runlength_plan: the number of samples already used must be positive");
271 for (std::size_t i = 0; i < means.
rows(); ++i)
272 for (std::size_t r = 0; r < means.
cols(); ++r) {
273 if (i >= ciHalfWidth.
rows() || r >= ciHalfWidth.
cols())
continue;
276 if (!std::isfinite(h) || h <= 0.0 || !std::isfinite(m) || m <= 0.0)
continue;
277 const T av = T(ciHalfWidth(i, r) / z * (ciHalfWidth(i, r) / z) * samplesUsed);
280 sim_runlength<T>(means(i, r), av, relPrecision, confidence).requiredRunLength;
The exception types the port throws.
LU factorization with partial pivoting, templated on the number type.
Dense matrix and non-owning view.
RunLengthPlan< T > sim_runlength_plan(const Matrix< T > &means, const Matrix< T > &ciHalfWidth, const T &samplesUsed, const T &relPrecision=num_traits< T >::from_rational(1, 20), const T &confidence=num_traits< T >::from_rational(19, 20))
How long a simulation run should have been, from the one it already did.
AsymVarResult< T > sim_asymvar_ctmc(const Matrix< T > &A, const std::vector< T > &f, const std::vector< T > &pi=std::vector< T >())
Asymptotic variance of a reward on a CTMC: 2 sum_x pi(x)g(x)d(x) with g = f - E_pi[f] and A d = -g,...
AsymVarResult< T > sim_asymvar_mm1(const T &lambda, const T &mu)
Asymptotic variance of the M/M/1 number-in-system process.
RunLengthResult< T > sim_runlength(const T &mean, const T &asymVar, const T &relPrecision=num_traits< T >::from_rational(1, 20), const T &confidence=num_traits< T >::from_rational(19, 20), const T &runLength=num_traits< T >::from_int(0))
Run length for a steady-state estimate of a given relative precision.
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.
Number-type abstraction for the templated API port.
Second-order description of a steady-state estimator.
T asymptoticVariance
sigma^2, what the run length depends on
std::vector< T > deviation
the deviation vector, for the CTMC form
T relaxationTime
sigma^2/Var, the correlation time scale
T variance
Var of the process itself.
T mean
the steady-state mean
The plan of sim_runlength_plan: what the run should have been.
Matrix< T > asymptoticVariance
sigma^2 per (station, class), NaN where unplannable
Matrix< T > requiredSamples
the run length that reaches relPrecision
T relPrecision
the precision planned for
T confidence
the level the half-widths were computed at
T samplesUsed
the run length they came from
Outcome of the run-length plan.
bool hasRun
whether a run length was supplied
T halfWidth
the half-width a supplied run buys
T z
the two-sided normal quantile used
T achievedRelPrecision
that half-width over the mean