5#ifndef LINE_API_MAM_DTIME_H
6#define LINE_API_MAM_DTIME_H
67using DBatch = std::vector<Matrix<T>>;
75 for (std::size_t i = 0; i < A.
rows(); ++i)
76 for (std::size_t j = 0; j < A.
cols(); ++j) {
78 for (std::size_t k = 0; k < B.
rows(); ++k)
79 for (std::size_t l = 0; l < B.
cols(); ++l)
80 C(i * B.
rows() + k, j * B.
cols() + l) = a * B(k, l);
95 for (std::size_t i = 0; i < A.
rows(); ++i)
96 for (std::size_t j = 0; j < A.
cols(); ++j) C(i, j) = C(i, j) + B(i, j);
103 for (std::size_t i = 0; i < A.
rows(); ++i)
104 for (std::size_t j = 0; j < A.
cols(); ++j) C(i, j) = C(i, j) - B(i, j);
111 for (std::size_t i = 0; i < A.
rows(); ++i)
112 for (std::size_t k = 0; k < A.
cols(); ++k) {
113 const T& a = A(i, k);
114 for (std::size_t j = 0; j < B.
cols(); ++j) C(i, j) = C(i, j) + a * B(k, j);
122 std::size_t n = M.
rows();
124 for (std::size_t i = 0; i < n; ++i)
125 for (std::size_t j = 0; j < n; ++j) Mt(i, j) = M(j, i);
127 for (std::size_t r = 0; r < N.
rows(); ++r) {
128 std::vector<T> rhs(n);
129 for (std::size_t j = 0; j < n; ++j) rhs[j] = N(r, j);
130 std::vector<T> sol =
solve(Mt, rhs);
131 for (std::size_t j = 0; j < n; ++j) X(r, j) = sol[j];
139 std::size_t n = M.
rows();
141 for (std::size_t c = 0; c < N.
cols(); ++c) {
142 std::vector<T> rhs(n);
143 for (std::size_t i = 0; i < n; ++i) rhs[i] = N(i, c);
144 std::vector<T> sol =
solve(M, rhs);
145 for (std::size_t i = 0; i < n; ++i) X(i, c) = sol[i];
163 const double tol = 1e-8;
166 T p = one / mean_slots;
168 throw InputError(
"dph_from_dist: Geometric mean is outside the support {1,2,...}");
171 d.
alpha.assign(1, one);
178 long k =
static_cast<long>(m + 0.5);
179 if (std::abs(m -
static_cast<double>(k)) > tol * std::max(1.0, m) || k < 1)
180 throw InputError(
"dph_from_dist: Det is not a positive integral number of slots");
181 std::size_t n =
static_cast<std::size_t
>(k);
183 d.
alpha.assign(n, zero);
186 for (std::size_t i = 0; i + 1 < n; ++i) d.
A(i, i + 1) = one;
193 double width = std::sqrt(std::max(0.0, 12 * v + 1)) - 1;
194 long lo =
static_cast<long>(m - width / 2 + 0.5);
195 long hi =
static_cast<long>(m + width / 2 + 0.5);
196 if (lo < 1 || hi < lo)
197 throw InputError(
"dph_from_dist: DiscreteUniform is outside the support {1,2,...}");
198 std::size_t n =
static_cast<std::size_t
>(hi);
200 d.
alpha.assign(n, zero);
203 for (
long j = 1; j < hi; ++j) {
206 d.
A(
static_cast<std::size_t
>(j - 1),
static_cast<std::size_t
>(j)) = one - h;
212 "dph_from_dist: the process type has no exact discrete phase-type representation. "
213 "The discrete-time path accepts Geometric, Det on the slot lattice, DiscreteUniform "
221 std::size_t m = d.
A.rows();
225 for (std::size_t i = 0; i < m; ++i) {
227 for (std::size_t j = 0; j < m; ++j) rowsum = rowsum + d.
A(i, j);
229 for (std::size_t j = 0; j < m; ++j) out.
D1(i, j) = a * d.
alpha[j];
237 std::size_t m = d.
D0.rows();
238 if (m == 1)
return true;
240 std::size_t pivot = 0;
241 for (std::size_t i = 0; i < m; ++i) {
242 for (std::size_t j = 0; j < m; ++j) row_mass[i] = row_mass[i] + d.
D1(i, j);
247 for (std::size_t i = 0; i < m; ++i)
248 for (std::size_t j = 0; j < m; ++j) {
249 T expected = row_mass[i] * d.
D1(pivot, j) / row_mass[pivot];
259 throw InputError(
"dmap_to_dph: the D-MAP does not renew at events, so it has no DPH form");
260 std::size_t m = d.
D0.rows();
262 std::size_t pivot = 0;
263 for (std::size_t i = 0; i < m; ++i) {
264 for (std::size_t j = 0; j < m; ++j) row_mass[i] = row_mass[i] + d.
D1(i, j);
271 for (std::size_t j = 0; j < m; ++j) out.
alpha[j] = d.
D1(pivot, j) / row_mass[pivot];
281 std::size_t m = A[0].rows();
283 for (std::size_t k = 0; k < A.size(); ++k) P = detail::dt_add(P, A[k]);
286 for (std::size_t k = 1; k < A.size(); ++k)
287 for (std::size_t i = 0; i < m; ++i)
288 for (std::size_t j = 0; j < m; ++j)
304 std::size_t p = A.size() - 1, q = B.size() - 1;
306 E.reserve(p + q + 1);
307 for (std::size_t k = 0; k <= p + q; ++k) {
308 Matrix<T> Ek(A[0].rows() * B[0].rows(), A[0].cols() * B[0].cols(),
310 std::size_t lo = k > q ? k - q : 0;
311 for (std::size_t i = lo; i <= (k < p ? k : p); ++i)
312 Ek = detail::dt_add(Ek, detail::dt_kron(A[i], B[k - i]));
325 if (pd < 0 || pd > 1)
throw InputError(
"dmap_thin: the routing probability must lie in [0,1]");
327 std::size_t n = A.size() - 1;
330 for (std::size_t k = 0; k <= n; ++k) {
332 for (std::size_t j = k; j <= n; ++j) {
334 for (std::size_t i = 0; i < k; ++i)
337 for (std::size_t i = 0; i < k; ++i) w = w * p;
338 for (std::size_t i = 0; i < j - k; ++i) w = w * (one - p);
340 for (std::size_t r = 0; r < Bk.rows(); ++r)
341 for (std::size_t c = 0; c < Bk.cols(); ++c)
342 Bk(r, c) = Bk(r, c) + w * A[j](r, c);
347 while (B.size() > 2) {
349 for (std::size_t r = 0; r < B.back().rows(); ++r)
350 for (std::size_t c = 0; c < B.back().cols(); ++c)
352 if (worst >= 1e-14)
break;
365inline void dph2_moments(
double b,
double p1,
double p2,
double* m1,
double* m2,
double* m3) {
366 const double A1 = 1 / p1, A2 = 1 / p2;
367 const double S1 = (2 - p1) / (p1 * p1), S2 = (2 - p2) / (p2 * p2);
368 const double C1 = (p1 * p1 - 6 * p1 + 6) / (p1 * p1 * p1);
369 const double C2 = (p2 * p2 - 6 * p2 + 6) / (p2 * p2 * p2);
371 *m2 = b * (S1 + 2 * A1 * A2) + S2;
372 *m3 = b * (C1 + 3 * S1 * A2 + 3 * A1 * S2) + C2;
380inline bool dph2_from_3moments(
double m1,
double m2,
double m3,
double* b_out,
double* p1_out,
382 const double starts[4][2] = {{0.5, 0.5}, {0.9, 1 / std::max(1.0, m1)}, {0.2, 0.8}, {0.99, 0.3}};
383 for (
int s = 0; s < 4; ++s) {
384 double p1 = starts[s][0], p2 = starts[s][1];
385 for (
int it = 0; it < 200; ++it) {
386 const double b = (m1 - 1 / p2) * p1;
388 dph2_moments(b, p1, p2, &f1, &f2, &f3);
389 const double r2 = f2 - m2, r3 = f3 - m3;
390 if (std::abs(r2) <= 1e-11 * std::max(1.0, std::abs(m2)) &&
391 std::abs(r3) <= 1e-11 * std::max(1.0, std::abs(m3))) {
392 if (b < -1e-9 || b > 1 + 1e-9 || p1 <= 0 || p1 > 1 || p2 <= 0 || p2 > 1)
break;
393 *b_out = std::min(1.0, std::max(0.0, b));
398 const double h = 1e-7;
399 double a2, a3, c2, c3, d2, d3, dummy;
400 dph2_moments((m1 - 1 / p2) * (p1 + h), p1 + h, p2, &dummy, &a2, &a3);
401 dph2_moments((m1 - 1 / (p2 + h)) * p1, p1, p2 + h, &dummy, &c2, &c3);
402 const double j11 = (a2 - f2) / h, j12 = (c2 - f2) / h;
403 const double j21 = (a3 - f3) / h, j22 = (c3 - f3) / h;
404 const double det = j11 * j22 - j12 * j21;
405 if (std::abs(det) < 1e-18)
break;
406 double dp1 = -(j22 * r2 - j12 * r3) / det;
407 double dp2 = -(-j21 * r2 + j11 * r3) / det;
410 while (step > 1e-6 && (p1 + step * dp1 <= 1e-9 || p1 + step * dp1 > 1 ||
411 p2 + step * dp2 <= 1e-9 || p2 + step * dp2 > 1))
413 if (step <= 1e-6)
break;
422inline std::vector<double> butools_factorial_moms(
const std::vector<double>& m) {
423 const std::size_t n = m.size();
424 std::vector<double> fm(n, 0.0);
425 for (std::size_t i = 1; i <= n; ++i) {
427 std::vector<double> c(1, 1.0);
428 for (std::size_t j = 0; j < i; ++j) {
429 std::vector<double> nc(c.size() + 1, 0.0);
430 for (std::size_t q = 0; q < c.size(); ++q) {
432 nc[q] -=
static_cast<double>(j) * c[q];
437 for (std::size_t q = 1; q <= i; ++q) acc += c[q] * m[q - 1];
444inline std::vector<double> butools_reduced_moms(
const std::vector<double>& m) {
445 std::vector<double> rm = m;
447 for (std::size_t i = 0; i < m.size(); ++i) {
448 f /=
static_cast<double>(i + 1);
459inline void butools_me_from_moments(
const std::vector<double>& moms, std::vector<double>& alpha_out,
460 std::vector<std::vector<double>>& A_out) {
462 const std::vector<double> rmom = butools_reduced_moms(moms);
464 std::size_t m = rmom.size();
465 std::vector<double> rm;
467 rm.assign(rmom.begin(), rmom.begin() +
static_cast<std::ptrdiff_t
>(m - 1));
473 rm.insert(rm.begin(), 1.0);
474 const std::size_t L = 2 * m;
475 std::vector<double> f(L, 0.0), y(L, 0.0);
478 auto shift = [L](
const std::vector<double>& v) {
479 std::vector<double> o(L, 0.0);
480 for (std::size_t i = 1; i < L; ++i) o[i] = v[i - 1];
486 std::vector<double> d(L + 1, 0.0), beta(L + 1, 0.0);
487 std::vector<std::vector<double>> alpha(L + 1, std::vector<double>(L + 1, 0.0));
488 for (std::size_t i = 0; i < L; ++i) {
490 for (std::size_t j = 0; j < L && j < rm.size(); ++j) ro += rm[j] * f[j];
494 const std::vector<double> yold = y;
495 if (n > 0 && ro != 0.0) {
496 if (k > 0) beta[k] = ro / pow(rm[1], d[k] +
static_cast<double>(n) - 1.0);
498 d[k] =
static_cast<double>(n);
503 const long j = nold +
static_cast<long>(d[k]) + 1;
504 if (j >= 1 &&
static_cast<std::size_t
>(j) <= L)
505 alpha[k][
static_cast<std::size_t
>(j)] = ro / pow(rm[1],
static_cast<double>(j - 1));
507 const std::vector<double> sf = shift(f);
508 for (std::size_t j = 0; j < L; ++j) f[j] = sf[j] - ro * yold[j];
511 for (std::size_t i = 1; i <= k; ++i) dsum += d[i];
512 if (
static_cast<std::size_t
>(dsum) != m || dsum != std::floor(dsum))
513 throw NumericError(ErrorKind{
"Infeasible"},
"MEFromMoments: Insufficient matrix order!");
514 std::vector<std::vector<double>> K(m, std::vector<double>(m, 0.0));
516 for (std::size_t i = 0; i + 1 < m; ++i) K[i][i + 1] = rm[1];
518 for (std::size_t i = 2; i <= m; ++i) {
519 if (ind <
static_cast<double>(m)) {
520 const double inc = d[i];
522 if (ind <=
static_cast<double>(m)) {
523 const std::size_t row =
static_cast<std::size_t
>(ind) - 1;
524 const long col =
static_cast<long>(ind - inc - d[i - 1] + 1.0) - 1;
525 if (col >= 0 &&
static_cast<std::size_t
>(col) < m) K[row][
static_cast<std::size_t
>(col)] = beta[i - 1];
526 for (std::size_t j = 1; j <= static_cast<std::size_t>(inc); ++j) {
527 const long c2 =
static_cast<long>(ind) -
static_cast<long>(j);
528 if (c2 >= 0 &&
static_cast<std::size_t
>(c2) < m)
529 K[row][
static_cast<std::size_t
>(c2)] = alpha[i][j];
535 const std::size_t N = m;
536 Matrix<double> Tm(N, N, 0.0), U(N, N, 0.0), Km(N, N, 0.0);
537 for (std::size_t i = 0; i < N; ++i)
538 for (std::size_t j = 0; j < N; ++j) {
539 if (j <= i) Tm(i, j) = 1.0;
540 if (j >= i) U(i, j) = 1.0 /
static_cast<double>(N - i);
544 const Matrix<double> TiU =
matmul(Ti, U);
545 alpha_out.assign(N, 0.0);
546 for (std::size_t j = 0; j < N; ++j) alpha_out[j] = TiU(0, j);
548 for (std::size_t i = 0; i < N; ++i)
549 for (std::size_t j = 0; j < N; ++j) M(i, j) = -M(i, j);
550 const Matrix<double> A =
inverse(M);
551 A_out.assign(N, std::vector<double>(N, 0.0));
552 for (std::size_t i = 0; i < N; ++i)
553 for (std::size_t j = 0; j < N; ++j) A_out[i][j] = A(i, j);
562inline bool dph2_from_3moments_butools(
double m1,
double m2,
double m3,
double alpha_out[2],
563 double A_out[2][2]) {
566 std::vector<double> moms{m1, m2, m3};
567 std::vector<double> rfmoms = butools_reduced_moms(butools_factorial_moms(moms));
568 rfmoms.insert(rfmoms.begin(), 1.0);
569 std::vector<double> vlist(3, 0.0), tmp(4, 0.0);
572 for (std::size_t i = 1; i <= 3; ++i) {
573 tmp[i] = (i % 2 == 0 ? 1.0 : -1.0) * rfmoms[i];
574 kf *=
static_cast<double>(i);
576 for (std::size_t j = 0; j <= i; ++j) acc += tmp[j];
577 vlist[i - 1] = kf * acc;
579 std::vector<double> beta;
580 std::vector<std::vector<double>> Cv;
582 butools_me_from_moments(vlist, beta, Cv);
583 }
catch (
const Error&) {
586 if (beta.size() != 2)
return false;
587 Matrix<double> C(2, 2, 0.0);
588 for (std::size_t i = 0; i < 2; ++i)
589 for (std::size_t j = 0; j < 2; ++j) C(i, j) = Cv[i][j];
590 Matrix<double> iC, B;
593 Matrix<double> iCpI = iC;
597 }
catch (
const Error&) {
600 for (std::size_t i = 0; i < 2; ++i) {
601 if (!std::isfinite(beta[i]))
return false;
602 for (std::size_t j = 0; j < 2; ++j)
603 if (!std::isfinite(B(i, j)))
return false;
606 const double prec = 1e-14;
607 const double bsum = beta[0] + beta[1];
608 if (bsum < -prec || bsum > 1.0 + prec)
return false;
609 const double tr = B(0, 0) + B(1, 1), det = B(0, 0) * B(1, 1) - B(0, 1) * B(1, 0);
610 const double disc = tr * tr / 4.0 - det;
611 if (disc < 0.0)
return false;
612 double l1 = tr / 2.0 + sqrt(disc), l2 = tr / 2.0 - sqrt(disc);
614 if (std::abs(l1) < std::abs(l2) || (std::abs(l1) == std::abs(l2) && l1 < l2)) std::swap(l1, l2);
615 if (l1 > 1.0 + prec)
return false;
616 const double p1 = beta[0] * (1.0 - B(0, 0) - B(0, 1)) + beta[1] * (1.0 - B(1, 0) - B(1, 1));
617 double b0, b1, B00, B01, B10, B11;
618 if (l1 > 0.0 && l2 > 0.0 && l1 != l2) {
619 const double d1 = (1.0 - l1) * (1.0 - p1 - l2) / (l1 - l2);
620 const double d2 = p1 - d1;
621 b0 = d1 * (l1 - l2) / ((1.0 - l1) * (1.0 - l2));
622 b1 = (d1 + d2) / (1.0 - l2);
623 B00 = l1; B01 = 1.0 - l1; B10 = 0.0; B11 = l2;
624 }
else if (l1 > 0.0 && l1 == l2) {
625 const double d2 = p1;
626 const double d1 = (1.0 - l1) * (1.0 - d2 - l1) / l1;
627 b0 = d1 * l1 / ((1.0 - l1) * (1.0 - l1));
628 b1 = d2 / (1.0 - l1);
629 B00 = l1; B01 = 1.0 - l1; B10 = 0.0; B11 = l1;
630 }
else if (l1 > 0.0) {
631 const double d1 = (1.0 - l1) * (1.0 - p1 - l2) / (l1 - l2);
632 const double d2 = p1 - d1;
633 b0 = (d1 * l1 + d2 * l2) / ((1.0 - l1) * (1.0 - l2));
634 b1 = (d1 + d2) * (1.0 - l1 - l2) / ((1.0 - l1) * (1.0 - l2));
635 B00 = l1 + l2; B01 = 1.0 - l1 - l2; B10 = l1 * l2 / (l1 + l2 - 1.0); B11 = 0.0;
639 if (!std::isfinite(b0) || !std::isfinite(b1) || !std::isfinite(B00) || !std::isfinite(B01) ||
640 !std::isfinite(B10) || !std::isfinite(B11))
644 A_out[0][0] = B00; A_out[0][1] = B01; A_out[1][0] = B10; A_out[1][1] = B11;
668 if (d.
D0.rows() <= max_order)
return d;
670 std::vector<T> moms =
dmap_moment(d, std::vector<unsigned>{1u, 2u, 3u});
675 double al[2] = {0.0, 0.0}, Am[2][2] = {{0.0, 0.0}, {0.0, 0.0}};
676 if (detail::dph2_from_3moments_butools(m1, m2, m3, al, Am)) {
682 for (std::size_t i = 0; i < 2; ++i)
687 }
catch (
const Error&) {
713 if (A[0].rows() <= max_order)
return A;
714 const std::size_t nb = A.size() - 1, m = A[0].rows();
717 for (std::size_t k = 1; k < A.size(); ++k) Ptot = detail::dt_add(Ptot, A[k]);
722 for (std::size_t k = 0; k < nb; ++k) {
723 for (std::size_t i = 0; i < m; ++i)
724 for (std::size_t j = 0; j < m; ++j) qraw[k] = qraw[k] + pi_phase[i] * A[k + 1](i, j);
725 mass = mass + qraw[k];
728 throw InputError(
"dmap_compress_batch: the batch stream carries no events");
732 marked.
D1 = detail::dt_sub(Ptot, A[0]);
736 out.push_back(markedC.
D0);
737 for (std::size_t k = 0; k < nb; ++k) {
739 const T w = qraw[k] / mass;
740 for (std::size_t i = 0; i < blk.
rows(); ++i)
741 for (std::size_t j = 0; j < blk.
cols(); ++j) blk(i, j) = blk(i, j) * w;
755 int max_iter = 200) {
756 std::size_t m = A1.
rows();
758 Matrix<T> inv_local = detail::dt_left_solve(detail::dt_sub(I, A1), I);
759 Matrix<T> B0 = detail::dt_mul(inv_local, A0);
760 Matrix<T> B2 = detail::dt_mul(inv_local, A2);
764 for (
int it = 0; it < max_iter; ++it) {
765 Matrix<T> A1n = detail::dt_add(detail::dt_mul(B0, B2), detail::dt_mul(B2, B0));
768 Matrix<T> inv_n = detail::dt_left_solve(detail::dt_sub(I, A1n), I);
769 B0 = detail::dt_mul(inv_n, A0n);
770 B2 = detail::dt_mul(inv_n, A2n);
771 G = detail::dt_add(G, detail::dt_mul(PI, B0));
772 PI = detail::dt_mul(PI, B2);
775 for (std::size_t i = 0; i < m; ++i) {
777 for (std::size_t j = 0; j < m; ++j) rowsum = rowsum + G(i, j);
778 residual = std::max(residual,
781 if (residual < 1e-14)
break;
798 double tol = 1e-14) {
799 std::size_t m = A[0].rows();
801 for (
int it = 0; it < max_iter; ++it) {
804 for (std::size_t k = 1; k < A.size(); ++k) {
805 Gnew = detail::dt_add(Gnew, detail::dt_mul(A[k], Gpow));
806 if (k + 1 < A.size()) Gpow = detail::dt_mul(Gpow, G);
809 for (std::size_t i = 0; i < m; ++i)
810 for (std::size_t j = 0; j < m; ++j)
813 if (delta < tol)
break;
832 std::size_t max_num_comp = 1000) {
835 std::size_t m = A[0].rows();
836 std::size_t dega = A.size() - 1;
837 std::size_t degb = B.size() - 1;
842 std::vector<Matrix<T>> hatA = A;
844 std::vector<T> beta(m, zero);
845 for (std::size_t i = 0; i < m; ++i)
846 for (std::size_t j = 0; j < m; ++j) beta[i] = beta[i] + sumA(i, j);
847 for (std::size_t i = dega; i-- > 1;) {
848 sumA = detail::dt_add(sumA, A[i]);
849 hatA[i] = detail::dt_add(A[i], detail::dt_mul(hatA[i + 1], G));
850 for (std::size_t r = 0; r < m; ++r)
851 for (std::size_t c = 0; c < m; ++c) beta[r] = beta[r] + sumA(r, c);
853 sumA = detail::dt_add(sumA, A[0]);
857 for (std::size_t i = 0; i < m; ++i) drift = drift + theta[i] * beta[i];
859 throw InputError(
"mg1_dt_pi: the chain characterized by A is not positive recurrent");
861 Matrix<T> invBarA1 = detail::dt_left_solve(detail::dt_sub(I, hatA[1]), I);
865 std::vector<Matrix<T>> hatB = B;
867 std::vector<T> Bbeta(m, zero);
868 for (std::size_t i = degb; i-- > 1;) {
869 for (std::size_t r = 0; r < m; ++r)
870 for (std::size_t c = 0; c < m; ++c) Bbeta[r] = Bbeta[r] + sumBB0(r, c);
871 sumBB0 = detail::dt_add(sumBB0, B[i]);
872 hatB[i] = detail::dt_add(B[i], detail::dt_mul(hatB[i + 1], G));
875 Matrix<T> Kmat = detail::dt_add(B[0], detail::dt_mul(hatB[1], G));
881 for (std::size_t r = 0; r < m; ++r)
882 for (std::size_t c = 0; c < m; ++c) W(r, c) = W(r, c) - (one - beta[r]) * g[c];
883 Matrix<T> invW = detail::dt_left_solve(W, I);
884 std::vector<T> temp(m, zero);
885 for (std::size_t r = 0; r < m; ++r)
886 for (std::size_t c = 0; c < m; ++c) temp[r] = temp[r] + invW(r, c);
888 const T inv_slack = one / (one - drift);
889 std::vector<T> psi1(m, zero), psi2(m, one);
890 Matrix<T> M1 = detail::dt_sub(detail::dt_sub(I, A[0]), hatA[1]);
891 Matrix<T> M2 = detail::dt_sub(sumBB0, hatB[1]);
892 for (std::size_t r = 0; r < m; ++r) {
893 T acc1 = zero, acc2 = zero, a0row = zero;
894 for (std::size_t c = 0; c < m; ++c) {
895 acc1 = acc1 + M1(r, c) * temp[c];
896 acc2 = acc2 + M2(r, c) * temp[c];
897 a0row = a0row + A[0](r, c);
899 psi1[r] = acc1 + inv_slack * a0row;
900 psi2[r] = one + acc2 + inv_slack * Bbeta[r];
903 std::vector<T> tmp(m, zero), tilde(m, zero);
904 for (std::size_t r = 0; r < m; ++r)
905 for (std::size_t c = 0; c < m; ++c) tmp[r] = tmp[r] + invBarA1(r, c) * psi1[c];
906 for (std::size_t r = 0; r < m; ++r) {
908 for (std::size_t c = 0; c < m; ++c) acc = acc + hatB[1](r, c) * tmp[c];
909 tilde[r] = psi2[r] + acc;
912 for (std::size_t r = 0; r < m; ++r) denom = denom + kappa[r] * tilde[r];
914 std::vector<std::vector<T>> pi;
915 std::vector<T> pi0(m, zero);
916 for (std::size_t r = 0; r < m; ++r) pi0[r] = kappa[r] / denom;
920 for (std::size_t r = 0; r < m; ++r) sumpi += num_traits<T>::to_double(pi0[r]);
921 std::size_t numit = 1;
922 while (sumpi < 1 - 1e-10 && numit < max_num_comp) {
923 std::vector<T> pin(m, zero);
925 for (std::size_t r = 0; r < m; ++r)
926 for (std::size_t c = 0; c < m; ++c)
927 pin[c] = pin[c] + pi0[r] * hatB[numit](r, c);
928 for (std::size_t j = 1; j <= std::min(numit - 1, dega - 1); ++j)
929 for (std::size_t r = 0; r < m; ++r)
930 for (std::size_t c = 0; c < m; ++c)
931 pin[c] = pin[c] + pi[numit - j][r] * hatA[j + 1](r, c);
932 std::vector<T> row(m, zero);
933 for (std::size_t r = 0; r < m; ++r)
934 for (std::size_t c = 0; c < m; ++c) row[c] = row[c] + pin[r] * invBarA1(r, c);
936 for (std::size_t r = 0; r < m; ++r) sumpi += num_traits<T>::to_double(row[r]);
941 out.reserve(pi.size() * m);
942 for (std::size_t i = 0; i < pi.size(); ++i)
943 for (std::size_t r = 0; r < m; ++r) out.push_back(pi[i][r]);
957 std::size_t max_num_comp = 1000) {
959 std::size_t ma = arv.
D0.rows(), ms = svc.
D0.rows(), mtot = ma * ms;
963 for (std::size_t i = 0; i < ma; ++i)
964 for (std::size_t j = 0; j < ma; ++j) avga = avga + pi_a[i] * arv.
D1(i, j);
967 for (std::size_t i = 0; i < ms; ++i)
968 for (std::size_t j = 0; j < ms; ++j) avgs = avgs + pi_s[i] * svc.
D1(i, j);
970 throw InputError(
"q_dt_map_map_1: the load of the system exceeds one");
974 Matrix<T> A0 = detail::dt_add(detail::dt_kron(arv.
D0, svc.
D0),
975 detail::dt_kron(arv.
D1, svc.
D1));
983 Matrix<T> denom = detail::dt_sub(detail::dt_sub(I, A0), detail::dt_mul(A1, G));
984 Matrix<T> R = detail::dt_right_divide(A1, denom);
988 Matrix<T> lower = detail::dt_add(A0, detail::dt_mul(R, Am1));
990 for (std::size_t i = 0; i < mtot; ++i)
991 for (std::size_t j = 0; j < mtot; ++j) {
992 joint(i, j) = B0(i, j);
993 joint(mtot + i, j) = Am1(i, j);
994 joint(i, mtot + j) = B1(i, j);
995 joint(mtot + i, mtot + j) = lower(i, j);
999 Matrix<T> temp = detail::dt_left_solve(detail::dt_sub(I, R), I);
1000 std::vector<T> pi0(pi01.begin(), pi01.begin() + mtot);
1001 std::vector<T> pi1(pi01.begin() + mtot, pi01.end());
1003 for (std::size_t i = 0; i < mtot; ++i) norm = norm + pi0[i];
1004 for (std::size_t i = 0; i < mtot; ++i)
1005 for (std::size_t j = 0; j < mtot; ++j) norm = norm + pi1[i] * temp(i, j);
1006 for (std::size_t i = 0; i < mtot; ++i) {
1007 pi0[i] = pi0[i] / norm;
1008 pi1[i] = pi1[i] / norm;
1013 for (std::size_t i = 0; i < mtot; ++i) mass0 = mass0 + pi0[i];
1014 ql.push_back(mass0);
1015 std::vector<T> cur = pi1;
1017 for (std::size_t it = 0; it < max_num_comp; ++it) {
1019 for (std::size_t i = 0; i < mtot; ++i) mass = mass + cur[i];
1022 if (acc > 1 - 1e-10)
break;
1024 for (std::size_t j = 0; j < mtot; ++j)
1025 for (std::size_t i = 0; i < mtot; ++i) nxt[j] = nxt[j] + cur[i] * R(i, j);
1030 for (std::size_t i = 0; i < ql.size(); ++i) total = total + ql[i];
1031 for (std::size_t i = 0; i < ql.size(); ++i) ql[i] = ql[i] / total;
1038 std::size_t max_num_comp = 1000) {
1068 std::size_t max_num_comp = 1000,
bool want_departure =
false) {
1070 std::size_t ms = svc.
D0.rows(), ma = arv[0].rows(), K = arv.size() - 1;
1071 std::size_t m = ma * ms;
1076 svc_batch.push_back(svc.
D0);
1077 svc_batch.push_back(svc.
D1);
1080 throw InputError(
"mg1_dt_queue: the discrete-time load of the station is not below one");
1084 std::vector<Matrix<T>> Ablocks, Bblocks;
1085 Ablocks.push_back(detail::dt_kron(arv[0], svc.
D1));
1086 for (std::size_t k = 0; k <= K; ++k) {
1088 if (k + 1 <= K) blk = detail::dt_add(blk, detail::dt_kron(arv[k + 1], svc.
D1));
1089 Ablocks.push_back(blk);
1091 for (std::size_t k = 0; k <= K; ++k) Bblocks.push_back(detail::dt_kron(arv[k], Ims));
1093 std::vector<T> pi =
mg1_dt_pi(Bblocks, Ablocks, max_num_comp);
1096 std::size_t nlev = pi.size() / m;
1098 for (std::size_t i = 0; i < nlev; ++i)
1099 for (std::size_t j = 0; j < m; ++j) out.
ql[i] = out.
ql[i] + pi[i * m + j];
1101 for (std::size_t i = 0; i < nlev; ++i) total = total + out.
ql[i];
1102 for (std::size_t i = 0; i < nlev; ++i) out.
ql[i] = out.
ql[i] / total;
1105 for (std::size_t i = 0; i < nlev; ++i)
1107 out.
UN = one - out.
ql[0];
1110 if (want_departure) {
1112 std::size_t L = nlev - 1;
1113 for (std::size_t i = 0; i < nlev; ++i) {
1115 if (cum > 1 - 1e-10) {
1121 std::size_t nstates = (L + 1) * m;
1126 for (std::size_t i = 0; i <= L; ++i)
1127 for (std::size_t k = 0; k <= K; ++k) {
1129 std::size_t tgt = std::min(L, k);
1130 Matrix<T> blk = detail::dt_kron(arv[k], Ims);
1131 for (std::size_t r = 0; r < m; ++r)
1132 for (std::size_t c = 0; c < m; ++c)
1133 D0(i * m + r, tgt * m + c) = D0(i * m + r, tgt * m + c) + blk(r, c);
1135 std::size_t tno = std::min(L, i + k);
1137 for (std::size_t r = 0; r < m; ++r)
1138 for (std::size_t c = 0; c < m; ++c)
1139 D0(i * m + r, tno * m + c) = D0(i * m + r, tno * m + c) + no(r, c);
1140 std::size_t tdep = std::min(L, i - 1 + k);
1142 for (std::size_t r = 0; r < m; ++r)
1143 for (std::size_t c = 0; c < m; ++c)
1144 D1(i * m + r, tdep * m + c) = D1(i * m + r, tdep * m + c) + dp(r, c);
Base error for the multiprecision C++ port.
NumericError(const std::string &what)
Discrete-time Markovian arrival processes (D-MAPs).
Equilibrium distribution of a discrete-time Markov chain, and stochastic complementation.
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
LU factorization with partial pivoting, templated on the number type.
Dense matrix and non-owning view.
ProcessType
Distribution kinds, with the values of MATLAB ProcessType.
DBatch< T > dmap_compress_batch(const DBatch< T > &A, std::size_t max_order)
Order reduction of a BATCH stream.
Matrix< T > mg1_dt_g(const std::vector< Matrix< T > > &A, int max_iter=5000, double tol=1e-14)
G matrix of an M/G/1-type chain by functional iteration on G = sum_k A_k G^k, the blocks being stocha...
Dmap< T > dmap_compress(const Dmap< T > &d, std::size_t max_order)
Reduces the order of a D-MAP by matching interevent moments.
bool dmap_isfeasible(const Dmap< T > &d)
True when D0 and D1 are nonnegative and D0 + D1 is stochastic.
std::vector< T > q_dt_map_map_1(const Dmap< T > &arv, const Dmap< T > &svc, std::size_t max_num_comp=1000)
Queue length distribution of a discrete-time D-MAP/D-MAP/1/FCFS queue, the queue-length half of Q_DT_...
std::vector< Matrix< T > > DBatch
A discrete batch arrival stream, entry k carrying the slots with k events.
T dmap_lambda_batch(const DBatch< T > &A)
Mean number of EVENTS per slot, pi sum_k k A_k e.
std::vector< T > q_dt_ph_ph_1(const Dph< T > &arv, const Dph< T > &svc, std::size_t max_num_comp=1000)
Queue length of a discrete-time DPH/DPH/1/FCFS queue, via the D-MAP route.
Matrix< T > qbd_dt_g(const Matrix< T > &A0, const Matrix< T > &A1, const Matrix< T > &A2, int max_iter=200)
G matrix of a discrete-time QBD by logarithmic reduction (Latouche and Ramaswami).
DtQueueResult< T > mg1_dt_queue(const DBatch< T > &arv, const Dmap< T > &svc, std::size_t max_num_comp=1000, bool want_departure=false)
Discrete-time single-server queue with batch D-MAP arrivals, DBMAP/D-MAP/1.
Dph< T > dph_from_dist(lang::ProcessType type, const T &mean_slots, const T &scv)
Exact discrete phase-type representation of a lattice-valued law.
Dmap< T > dph_to_dmap(const Dph< T > &d)
Renewal D-MAP (A, a alpha) of a discrete phase-type law.
std::vector< T > dmap_moment(const Dmap< T > &d, const std::vector< unsigned > &orders)
Raw moments of the interarrival time in slots, for orders 1, 2 and 3 only.
Dph< T > dmap_to_dph(const Dmap< T > &d)
Discrete phase-type law underlying a renewal D-MAP.
DBatch< T > dmap_super(const DBatch< T > &A, const DBatch< T > &B)
Superposition, E_k = sum_{i+j=k} kron(A_i, B_j).
bool dmap_is_renewal(const Dmap< T > &d)
True when D1 has rank one, i.e.
std::vector< T > mg1_dt_pi(const std::vector< Matrix< T > > &B, const std::vector< Matrix< T > > &A, std::size_t max_num_comp=1000)
Stationary vector of an M/G/1-type chain by the stable Ramaswami formula.
DBatch< T > dmap_thin(const DBatch< T > &A, const T &p)
Bernoulli thinning, B_k = sum_{n>=k} C(n,k) p^k (1-p)^(n-k) A_n.
std::vector< T > dtmc_solve(const Matrix< T > &P)
Stationary distribution of a stochastic matrix P.
Conservation laws of a layered queueing network, enumerated from its structure.
Matrix< T > inverse(const Matrix< T > &A)
Inverse by LU with one factorization and n back substitutions.
Matrix< T > matmul(const Matrix< T > &A, const Matrix< T > &B)
Matrix product A B.
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.
static constexpr double Zero
A discrete-time MAP: substochastic D0 (no arrival) and D1 (one arrival).
A discrete phase-type law: initial row vector alpha and transient A.
std::size_t order() const
Outcome of a slotted station solve.