5#ifndef LINE_API_MAM_MAP_SAMPLE_H
6#define LINE_API_MAM_MAP_SAMPLE_H
66 for (std::size_t i = 0; i < P.size(); ++i) {
67 if (P[i] < zero)
throw InputError(
"randp: all probabilities should be 0 or larger");
70 if (P.empty() || !(total > zero))
throw InputError(
"randp: all zero probabilities");
73 for (std::size_t i = 0; i < P.size(); ++i) {
83 std::vector<std::size_t>
last;
99 const std::vector<T>& pie0 = std::vector<T>(),
102 "map_sample draws exponential deviates");
103 const std::size_t K = m.
order();
104 if (K == 0 || m.
D1.rows() != K)
throw InputError(
"map_sample: D0 and D1 disagree");
110 trace->first.assign(n, 0);
111 trace->last.assign(n, 0);
117 for (std::size_t i = 0; i < n; ++i)
122 const std::vector<T> start = pie0.empty() ?
map_pie(m) : pie0;
123 if (start.size() != K)
throw InputError(
"map_sample: the initial law has the wrong length");
124 std::size_t cur =
randp(start,
rng);
128 std::vector<std::vector<T>> jump(K, std::vector<T>(2 * K, zero));
129 std::vector<T> hold(K, zero);
130 for (std::size_t i = 0; i < K; ++i) {
131 const T rate = -m.
D0(i, i);
133 throw InputError(
"map_sample: a phase has no exit rate");
135 for (std::size_t j = 0; j < K; ++j) {
136 if (i != j) jump[i][j] = T(m.
D0(i, j) / rate);
137 jump[i][K + j] = T(m.
D1(i, j) / rate);
141 for (std::size_t s = 0; s < n; ++s) {
147 const std::size_t d =
randp(jump[cur],
rng);
160namespace sampledetail {
165 const std::size_t n = A.
rows();
167 for (std::size_t i = 0; i < n; ++i) {
169 for (std::size_t j = 0; j < n; ++j)
171 nrm = std::max(nrm, r);
178 const T h = T(t / num_traits<T>::from_double(std::pow(2.0, s)));
179 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
180 Matrix<T> R(n, n, zero), term(n, n, zero);
181 for (std::size_t i = 0; i < n; ++i) {
185 for (
int k = 1; k <= 40; ++k) {
186 Matrix<T> nx(n, n, zero);
187 for (std::size_t i = 0; i < n; ++i)
188 for (std::size_t j = 0; j < n; ++j) {
190 for (std::size_t q = 0; q < n; ++q) v += term(i, q) * A(q, j) * h;
191 nx(i, j) = T(v / num_traits<T>::from_int(k));
194 for (std::size_t i = 0; i < n; ++i)
195 for (std::size_t j = 0; j < n; ++j) R(i, j) += term(i, j);
197 for (
int k = 0; k < s; ++k) {
198 Matrix<T> sq(n, n, zero);
199 for (std::size_t i = 0; i < n; ++i)
200 for (std::size_t j = 0; j < n; ++j) {
202 for (std::size_t q = 0; q < n; ++q) v += R(i, q) * R(q, j);
212T survival(
const Matrix<T>& D0,
const std::vector<T>& a,
const T& x) {
218 const Matrix<T> E = sampledetail::expm(D0, x);
219 T s = num_traits<T>::from_int(0);
220 for (std::size_t i = 0; i < a.size(); ++i)
221 for (std::size_t j = 0; j < a.size(); ++j) s += a[i] * E(i, j);
250 const std::vector<T>& a0 = std::vector<T>(),
251 std::vector<T>* a_out = 0) {
253 "rap_sample inverts a matrix-exponential survival function");
254 const std::size_t K = m.
order();
255 if (K == 0 || m.
D1.rows() != K)
throw InputError(
"rap_sample: D0 and D1 disagree");
258 std::vector<T> a = a0.empty() ?
map_pie(m) : a0;
259 if (a.size() != K)
throw InputError(
"rap_sample: the initial law has the wrong length");
261 if (!(mean > 0.0))
throw InputError(
"rap_sample: the process has no positive mean");
265 for (std::size_t s = 0; s < n; ++s) {
268 double lo = 0.0, hi = mean;
269 for (
int k = 0; k < 200; ++k) {
276 for (
int k = 0; k < 200; ++k) {
277 const double mid = 0.5 * (lo + hi);
284 if (hi - lo < 1e-14 * (1.0 + hi))
break;
291 std::vector<T> b(K, zero), c(K, zero);
292 for (std::size_t j = 0; j < K; ++j)
293 for (std::size_t i = 0; i < K; ++i) b[j] += a[i] * E(i, j);
295 for (std::size_t j = 0; j < K; ++j) {
296 for (std::size_t i = 0; i < K; ++i) c[j] += b[i] * m.
D1(i, j);
300 throw NumericError(
"rap_sample: the entry law lost all its mass");
301 for (std::size_t j = 0; j < K; ++j) a[j] = T(c[j] / tot);
304 if (a_out != 0) *a_out = a;
NumericError(const std::string &what)
The exception types the port throws.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
std::size_t randp(const std::vector< T > &P, pfqn::McRng &rng)
Draw an index from a discrete law, m3a's randp.
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
std::vector< T > rap_sample(const Map< T > &m, std::size_t n, pfqn::McRng &rng, const std::vector< T > &a0=std::vector< T >(), std::vector< T > *a_out=0)
Sample a RAP or a matrix exponential by inverse transform.
std::vector< T > map_sample(const Map< T > &m, std::size_t n, pfqn::McRng &rng, const std::vector< T > &pie0=std::vector< T >(), SampleTrace *trace=0)
Sample the inter-arrival times of a MAP, a RAP or a matrix exponential.
std::mt19937_64 McRng
The generator type every Monte Carlo entry point in this tree accepts.
double mc_uniform01(McRng &g)
Uniform deviate on [0,1) with 53 significant bits, as a double.
Matrix< T > expm(const Matrix< T > &A)
Matrix exponential exp(A).
Number-type abstraction for the templated API port.
Randomness scaffolding shared by the Monte Carlo normalizing-constant estimators (pfqn_mci,...
A MAP as the pair of matrices (D0, D1).
std::size_t order() const
The state a sampled inter-arrival began and ended in.
std::vector< std::size_t > first
phase at the start of each interval, 0-based
std::vector< std::size_t > last
phase entered on each arrival, 0-based