178 std::size_t maxLevelParam,
unsigned maxIter,
const T& tol,
181 "qsys_bmapm1 runs tolerance-terminated iterations (G, and the level truncation)");
186 "qsys_bmapm1: the BMAP must be given as {D0,D1,...,DK} with at least D0 and D1");
187 const std::size_t V = D[0].rows();
188 for (std::size_t k = 0; k < D.size(); ++k) {
189 if (D[k].rows() != V || D[k].cols() != V)
190 throw InputError(
"qsys_bmapm1: BMAP matrix D{" + std::to_string(k) +
191 "} is not conformable");
193 for (std::size_t i = 0; i < V; ++i)
194 for (std::size_t j = 0; j < V; ++j)
196 throw InputError(
"qsys_bmapm1: BMAP arrival matrix D{" +
197 std::to_string(k) +
"} must be non-negative");
201 for (std::size_t i = 0; i < V; ++i)
202 for (std::size_t j = 0; j < V; ++j) Dsum(i, j) += Dk(i, j);
203 for (std::size_t i = 0; i < V; ++i) {
205 for (std::size_t j = 0; j < V; ++j) s += Dsum(i, j);
208 "qsys_bmapm1: BMAP matrices are inconsistent, sum_k D_k must have zero row sums");
211 throw InputError(
"qsys_bmapm1: the service rate mu must be a finite positive scalar");
213 const std::size_t K = D.
size() - 1;
218 for (std::size_t k = 1; k <= K; ++k)
219 for (std::size_t i = 0; i < V; ++i)
220 for (std::size_t j = 0; j < V; ++j)
225 for (
const T& v : t) r.
lambda += v;
229 T outflow = T(-D[0](0, 0));
230 for (std::size_t i = 1; i < V; ++i)
231 if (T(-D[0](i, i)) > outflow) outflow = T(-D[0](i, i));
232 const T qmin = T(outflow + mu);
237 "qsys_bmapm1: the uniformization constant does not dominate the total outflow rate; "
238 "the randomized chain would have negative entries");
243 for (std::size_t i = 0; i < V; ++i) {
244 r.
A0(i, i) = T(mu / r.
q);
245 for (std::size_t j = 0; j < V; ++j) {
246 r.
A1(i, j) = T(D[0](i, j) / r.
q);
247 r.
B0(i, j) = T(D[0](i, j) / r.
q);
249 r.
A1(i, i) = T(r.
A1(i, i) - mu / r.
q + one);
250 r.
B0(i, i) = T(r.
B0(i, i) + one);
253 for (std::size_t k = 1; k <= K; ++k) {
255 for (std::size_t i = 0; i < V; ++i)
256 for (std::size_t j = 0; j < V; ++j) r.
Bk[k - 1](i, j) = T(D[k](i, j) / r.
q);
259 for (std::size_t i = 0; i < V; ++i)
260 for (std::size_t j = 0; j < V; ++j) {
261 r.
A(i, j) = r.
A0(i, j) + r.
A1(i, j);
262 for (std::size_t k = 0; k < K; ++k) r.
A(i, j) += r.
Bk[k](i, j);
269 for (
unsigned it = 0; it < maxIter; ++it) {
272 for (std::size_t i = 0; i < V; ++i)
273 for (std::size_t j = 0; j < V; ++j) Gnew(i, j) += r.
A0(i, j);
274 for (std::size_t k = 0; k < K; ++k) {
277 for (std::size_t i = 0; i < V; ++i)
278 for (std::size_t j = 0; j < V; ++j) Gnew(i, j) += add(i, j);
281 for (std::size_t i = 0; i < V; ++i)
282 for (std::size_t j = 0; j < V; ++j)
293 for (std::size_t k = 0; k < K; ++k)
294 for (std::size_t i = 0; i < V; ++i)
295 for (std::size_t j = 0; j < V; ++j)
300 const std::vector<T> up =
vecmul(r.
alpha, upDrift);
302 for (std::size_t i = 0; i < V; ++i) r.
drift += up[i] - dn[i];
306 std::size_t levelMax;
307 if (maxLevelParam > 0) {
308 levelMax = maxLevelParam;
309 r.
levelProb = bmapm1_detail::solve_levels(D, mu, V, K, levelMax);
313 const double slack = std::max(1.0 - std::min(rd, 0.999),
314 std::numeric_limits<double>::epsilon());
315 levelMax = std::max<std::size_t>(50,
static_cast<std::size_t
>(std::ceil(20.0 / slack)));
317 r.
levelProb = bmapm1_detail::solve_levels(D, mu, V, K, levelMax);
319 if (r.
truncError <= tailTol || (2 * levelMax + 1) * V > 200000)
break;
324 std::vector<double> levelMass(r.
levelProb.rows(), 0.0);
325 for (std::size_t n = 0; n < r.
levelProb.rows(); ++n)
326 for (std::size_t i = 0; i < V; ++i)
335 std::size_t usable1 = 0;
336 for (std::size_t n = 0; n < levelMass.size(); ++n)
337 if (levelMass[n] > 1e-12) usable1 = n + 1;
339 r.
decayRate = std::numeric_limits<double>::quiet_NaN();
341 const std::size_t ref0 = std::max<std::size_t>(2, usable1 / 2) - 1;
342 r.
decayRate = (ref0 + 1 < levelMass.size() && levelMass[ref0] > 0.0)
343 ? levelMass[ref0 + 1] / levelMass[ref0]
344 : std::numeric_limits<double>::quiet_NaN();
348 for (std::size_t n = 0; n < levelMass.size(); ++n)