507 const std::size_t M = spec.
x0.rows(), R = spec.
x0.cols();
508 const std::size_t narcs = spec.
arcs.size(), P = spec.
alpha0.size();
509 const std::size_t MR = M * R;
510 const std::size_t K = spec.
obsTimes.size();
513 throw InputError(
"infer_variational: sched and nservers must have one entry per station");
517 "infer_variational: routeprob, arcparam and arcrate must have one entry per "
520 throw InputError(
"infer_variational: alpha0 and beta0 must have the same length");
521 if (spec.
obsData.rows() != K || (K > 0 && spec.
obsData.cols() != MR))
522 throw InputError(
"infer_variational: obsData must be K x M*R");
524 throw InputError(
"infer_variational: obsRange must have M*R entries");
525 for (std::size_t e = 0; e < narcs; ++e) {
526 if (spec.
arcs[e][0] == 0 && spec.
arcs[e][1] == 0)
527 throw InputError(
"infer_variational: a transition cannot be external at both ends");
530 "infer_variational: a transition without a parameter needs a positive known rate");
535 throw InputError(
"infer_variational: capacity must have M*R entries");
538 std::vector<std::size_t> src(narcs), dst(narcs), cls(narcs);
539 for (std::size_t e = 0; e < narcs; ++e) {
540 src[e] = spec.
arcs[e][0];
541 dst[e] = spec.
arcs[e][1];
542 cls[e] = spec.
arcs[e][2];
545 Matrix<T> sgnClass(narcs, MR, zero), sgnStat(narcs, M, zero);
546 for (std::size_t e = 0; e < narcs; ++e) {
548 sgnClass(e, (cls[e] - 1) * M + dst[e] - 1) += one;
549 sgnStat(e, dst[e] - 1) += one;
552 sgnClass(e, (cls[e] - 1) * M + src[e] - 1) -= one;
553 sgnStat(e, src[e] - 1) -= one;
557 std::vector<T> x0v(MR, zero), x0s(M, zero), capStat(M, zero);
558 for (std::size_t m = 0; m < M; ++m) {
559 for (std::size_t r = 0; r < R; ++r) {
560 x0v[r * M + m] = spec.
x0(m, r);
561 x0s[m] += spec.
x0(m, r);
562 capStat[m] += spec.
capacity[r * M + m];
567 std::vector<T> xbar(x0v), xbars(M, zero);
568 for (std::size_t k = 0; k < MR; ++k) {
571 for (std::size_t q = 0; q < K; ++q) {
572 if (!(spec.
obsData(q, k) == unobs)) {
579 for (std::size_t m = 0; m < M; ++m)
580 for (std::size_t r = 0; r < R; ++r) xbars[m] += xbar[r * M + m];
583 if (K == 0)
throw InputError(
"infer_variational: tmax is required without observations");
585 for (std::size_t k = 0; k < K; ++k)
589 if (!(
opt.tmax > 0))
throw InputError(
"infer_variational: tmax must be positive");
590 if (
opt.ngrid < 0 &&
opt.dt < 0)
opt.ngrid = 201;
591 if (
opt.ngrid < 0)
opt.ngrid =
static_cast<long>(std::llround(
opt.tmax /
opt.dt)) + 1;
592 opt.ngrid = std::max<long>(2,
opt.ngrid);
593 opt.dt =
opt.tmax /
static_cast<double>(
opt.ngrid - 1);
597 for (std::size_t e = 0; e < narcs; ++e) {
600 const std::size_t p = spec.
arcparam[e] - 1;
607 const std::size_t kc = (cls[e] - 1) * M + src[e] - 1;
610 spec.
sched[src[e] - 1],
611 spec.
capacity[kc], capStat[src[e] - 1]));
613 fmax = std::max(fmax, lam * u *
opt.tmax);
615 opt.ymax = std::max<long>(
616 20,
static_cast<long>(std::ceil(2 * fmax + 5 * std::sqrt(std::max(1.0, fmax)))));
618 opt.ymax = std::max<long>(2,
opt.ymax);
619 if (
opt.rate_max < 0)
620 opt.rate_max =
opt.rate_cap_factor *
static_cast<double>(
opt.ymax) /
opt.tmax;
622 const std::size_t G =
static_cast<std::size_t
>(
opt.ngrid);
623 const std::size_t ymax =
static_cast<std::size_t
>(
opt.ymax);
624 const std::size_t ny = ymax + 1;
625 const std::size_t S =
opt.nsamples;
631 std::vector<T> yvec(ny), tgrid(G);
632 for (std::size_t y = 0; y < ny; ++y) yvec[y] = num_traits<T>::from_int(
static_cast<int>(y));
633 for (std::size_t g = 0; g < G; ++g) tgrid[g] = num_traits<T>::from_int(
static_cast<int>(g)) * dt;
635 std::vector<std::size_t> obsIdx(K, 0);
636 for (std::size_t k = 0; k < K; ++k) {
638 obsIdx[k] =
static_cast<std::size_t
>(std::min<long>(std::max<long>(idx, 0),
639 static_cast<long>(G) - 1));
643 std::vector<T> arcServers(narcs, one);
644 for (std::size_t e = 0; e < narcs; ++e) {
646 arcSched[e] = spec.
sched[src[e] - 1];
647 arcServers[e] = spec.
nservers[src[e] - 1];
651 std::vector<T> alpha(spec.
alpha0), beta(spec.
beta0);
653 std::vector<Matrix<T>> Y, nu, slack, gexp, hexp;
656 slack.reserve(narcs);
661 auto rate_mean = [&](std::size_t e) {
662 const std::size_t p = spec.
arcparam[e];
664 return spec.
routeprob[e] * alpha[p - 1] / beta[p - 1];
666 auto rate_log_mean = [&](std::size_t e) {
667 const std::size_t p = spec.
arcparam[e];
669 return log(spec.
routeprob[e]) + detail::iv_digamma(alpha[p - 1]) - log(beta[p - 1]);
672 for (std::size_t e = 0; e < narcs; ++e) {
673 const T lam = rate_mean(e);
676 const std::size_t kc = (cls[e] - 1) * M + src[e] - 1;
677 u0 = detail::iv_ups(xbar[kc], xbars[src[e] - 1], arcServers[e], arcSched[e],
678 spec.
capacity[kc], capStat[src[e] - 1]);
681 if (nu0 < deltaT) nu0 = deltaT;
683 for (std::size_t g = 0; g < G; ++g)
684 for (std::size_t y = 0; y < ymax; ++y) nue(g, y) = nu0;
686 Y.push_back(detail::iv_forward(nue, dt,
opt));
697 auto rate_moments = [&](std::size_t e,
const std::vector<Matrix<T>>& Ys,
Matrix<T>& ge,
699 const T lam = rate_mean(e);
700 const T loglam = rate_log_mean(e);
701 const bool has_origin = src[e] > 0;
702 const std::size_t kclass = has_origin ? (cls[e] - 1) * M + src[e] - 1 : 0;
703 const T sgnOwnClass = has_origin ? sgnClass(e, kclass) : zero;
704 const T sgnOwnStat = has_origin ? sgnStat(e, src[e] - 1) : zero;
705 const T d0 = deltaT / lam;
706 for (std::size_t q = 0; q < K; ++q)
707 for (std::size_t y = 0; y < ny; ++y) obsw(q, y) = one;
708 std::vector<T> accg(ny), acch(ny);
710 for (std::size_t g = 0; g < G; ++g) {
713 for (std::size_t q = 0; q < K; ++q)
714 if (obsIdx[q] == g) hasObs =
true;
716 std::fill(accg.begin(), accg.end(), zero);
717 std::fill(acch.begin(), acch.end(), zero);
718 for (std::size_t s = 0; s < S; ++s) {
719 T a = zero, b = zero;
723 for (std::size_t f = 0; f < narcs; ++f) {
724 if (f == e)
continue;
725 a += sgnClass(f, kclass) * Ys[f](g, s);
726 b += sgnStat(f, src[e] - 1) * Ys[f](g, s);
730 for (std::size_t k = 0; k < MR; ++k) {
732 for (std::size_t f = 0; f < narcs; ++f)
733 if (f != e) acc += sgnClass(f, k) * Ys[f](g, s);
737 for (std::size_t y = 0; y < ny; ++y) {
740 u = detail::iv_ups(a + sgnOwnClass * yvec[y], b + sgnOwnStat * yvec[y],
741 arcServers[e], arcSched[e], spec.
capacity[kclass],
742 capStat[src[e] - 1]);
744 acch[y] += log(u + d0);
753 for (std::size_t y = 0; y < ny; ++y) {
754 ge(g, y) = deltaT + lam * (accg[y] / Sn);
755 he(g, y) = exp(loglam + acch[y] / Sn);
758 for (std::size_t q = 0; q < K; ++q) {
759 if (obsIdx[q] != g)
continue;
760 for (std::size_t y = 0; y < ny; ++y) {
762 for (std::size_t k = 0; k < MR; ++k) {
763 if (spec.
obsData(q, k) == unobs)
continue;
767 for (std::size_t s = 0; s < S; ++s) {
768 const T x = aStore(k, s) + sgnClass(e, k) * yvec[y];
772 }
else if (!(x < zero) && !(x > spec.
obsRange[k])) {
775 ak += log(floorT + p);
779 obsw(q, y) = exp(acc);
786 std::vector<T> bound;
787 Matrix<T> alphaTrace(P,
opt.iter_max, zero), betaTrace(P,
opt.iter_max, zero);
788 bool converged =
false;
789 std::size_t iter = 0;
790 std::vector<Matrix<T>> Ys(narcs,
Matrix<T>(G, S, zero));
791 Matrix<T> ge(G, ny, zero), he(G, ny, zero), obsw(std::max<std::size_t>(K, 1), ny, zero);
793 for (std::size_t it = 1; it <=
opt.iter_max; ++it) {
795 for (std::size_t e = 0; e < narcs; ++e) {
796 for (std::size_t f = 0; f < narcs; ++f) Ys[f] = detail::iv_sample(Y[f], S, f);
797 rate_moments(e, Ys, ge, he, obsw,
true);
798 const Matrix<T> r = detail::iv_backward(ge, he, slack[e], Y[e], obsIdx, obsw, dt,
opt);
803 Matrix<T> nue(G, ny, zero), sl(G, ny, zero);
804 for (std::size_t g = 0; g < G; ++g) {
805 for (std::size_t y = 0; y < ymax; ++y) {
807 if (r(g, y) > zero) val = he(g, y) * r(g, y + 1) / r(g, y);
808 if (!(val > zero)) val = zero;
809 if (val > rateMaxT) {
810 const T w = Y[e](g, y) > floorT ? Y[e](g, y) : floorT;
811 sl(g, y) = w * log(val / rateMaxT);
819 Y[e] = detail::iv_forward(nue, dt,
opt);
825 for (std::size_t f = 0; f < narcs; ++f) Ys[f] = detail::iv_sample(Y[f], S, f);
826 std::vector<T> firings(P, zero), exposure(P, zero);
827 std::vector<char> seen(P * MR, 0);
828 for (std::size_t e = 0; e < narcs; ++e) {
829 const std::size_t p = spec.
arcparam[e];
830 if (p == 0)
continue;
835 T m1 = zero, m0 = zero;
836 for (std::size_t y = 0; y < ny; ++y) {
837 m1 += Y[e](G - 1, y) * yvec[y];
838 m0 += Y[e](0, y) * yvec[y];
840 firings[p - 1] += m1 - m0;
841 const std::size_t kclass = (cls[e] - 1) * M + src[e] - 1;
842 if (!seen[(p - 1) * MR + kclass]) {
843 seen[(p - 1) * MR + kclass] = 1;
844 std::vector<T> ue(G, zero);
846 for (std::size_t g = 0; g < G; ++g) {
848 for (std::size_t s = 0; s < S; ++s) {
849 T a = x0v[kclass], b = x0s[src[e] - 1];
850 for (std::size_t f = 0; f < narcs; ++f) {
851 a += sgnClass(f, kclass) * Ys[f](g, s);
852 b += sgnStat(f, src[e] - 1) * Ys[f](g, s);
854 acc += detail::iv_ups(a, b, spec.
nservers[src[e] - 1],
856 capStat[src[e] - 1]);
860 exposure[p - 1] += detail::iv_trapz(ue, dt);
863 for (std::size_t p = 0; p < P; ++p) {
864 alpha[p] = spec.
alpha0[p] + firings[p];
865 beta[p] = spec.
beta0[p] + exposure[p];
866 alphaTrace(p, it - 1) = alpha[p];
867 betaTrace(p, it - 1) = beta[p];
873 for (std::size_t e = 0; e < narcs; ++e) {
874 rate_moments(e, Ys, ge, he, obsw,
false);
883 std::vector<T> acc(G, zero);
884 for (std::size_t e = 0; e < narcs; ++e) {
885 for (std::size_t g = 0; g < G; ++g) {
887 for (std::size_t y = 0; y < ny; ++y) {
888 const T n = nu[e](g, y);
889 T term = n - gexp[e](g, y);
891 const T hh = hexp[e](g, y) > floorT ? hexp[e](g, y) : floorT;
892 term -= n * log(n / hh);
894 s += Y[e](g, y) * term;
898 b += detail::iv_trapz(acc, dt);
901 for (std::size_t k = 0; k < K; ++k) {
902 const std::size_t g = obsIdx[k];
904 for (std::size_t s = 0; s < S; ++s) {
906 for (std::size_t j = 0; j < MR; ++j) {
907 if (spec.
obsData(k, j) == unobs)
continue;
909 for (std::size_t f = 0; f < narcs; ++f) x += sgnClass(f, j) * Ys[f](g, s);
913 }
else if (!(x < zero) && !(x > spec.
obsRange[j])) {
916 a += log(floorT + p);
922 for (std::size_t p = 0; p < P; ++p)
923 b -= detail::iv_kl_gamma(alpha[p], beta[p], spec.
alpha0[p], spec.
beta0[p]);
933 for (std::size_t p = 0; p < P; ++p) {
935 betaTrace(p, it - 2));
937 crit = std::max(crit, std::abs(cur - prev) / std::max(1e-12, prev));
939 if (crit <=
opt.tol) {
951 for (std::size_t p = 0; p < P; ++p) {
952 out.
rates[p] = alpha[p] / beta[p];
958 for (std::size_t p = 0; p < P; ++p) {
959 for (std::size_t i = 0; i < iter; ++i) {
971 for (std::size_t e = 0; e < narcs; ++e)
972 for (std::size_t g = 0; g < G; ++g)
973 if (Y[e](g, ny - 1) > tailmass) tailmass = Y[e](g, ny - 1);
977 for (std::size_t g = 0; g < G; ++g)
978 for (std::size_t k = 0; k < MR; ++k) out.
qlen(g, k) = x0v[k];
979 for (std::size_t e = 0; e < narcs; ++e) {
980 for (std::size_t g = 0; g < G; ++g) {
982 for (std::size_t y = 0; y < ny; ++y) my += Y[e](g, y) * yvec[y];
983 for (std::size_t k = 0; k < MR; ++k) out.
qlen(g, k) += my * sgnClass(e, k);