5#ifndef LINE_API_INFER_INFER_SMP_H
6#define LINE_API_INFER_INFER_SMP_H
74 std::transform(s.begin(), s.end(), s.begin(),
75 [](
unsigned char c) { return static_cast<char>(std::tolower(c)); });
82 if (f ==
"exp")
return 1;
83 if (f ==
"weibull" || f ==
"gamma" || f ==
"lognormal")
return 2;
84 throw InputError(
"infer_smp_family: Unknown family '" + f +
85 "': use 'exp', 'weibull', 'gamma' or 'lognormal'.");
96 const std::vector<double>& t,
const std::vector<double>& eta,
97 std::vector<double>& logf, std::vector<double>& logS) {
99 const std::size_t n = t.size();
102 if (!(eta.empty() || eta.size() == 1 || eta.size() == n))
103 throw InputError(
"infer_smp_family: ETA must be a scalar or hold one value per instant");
104 const double log2pi = std::log(2.0 * 3.14159265358979323846);
105 for (std::size_t k = 0; k < n; ++k) {
106 const double tk = t[k];
107 double H0 = 0.0, logh0 = 0.0;
109 const double lam = std::exp(th[0]);
110 logh0 = std::log(lam);
112 }
else if (f ==
"weibull") {
113 const double kk = std::exp(th[0]), s = std::exp(th[1]);
114 H0 = std::pow(tk / s, kk);
115 logh0 = std::log(kk) - std::log(s) + (kk - 1.0) * (std::log(tk) - std::log(s));
116 }
else if (f ==
"gamma") {
117 const double a = std::exp(th[0]), b = std::exp(th[1]);
118 const double lf0 = (a - 1.0) * std::log(tk) - tk / b - std::lgamma(a) - a * std::log(b);
119 const double lS0 = std::log(std::max(pfqn::detail::gammainc(a, tk / b).q, 1e-300));
122 }
else if (f ==
"lognormal") {
123 const double mu = th[0], sg = std::exp(th[1]);
124 const double z = (std::log(tk) - mu) / sg;
125 const double lf0 = -std::log(tk) - std::log(sg) - 0.5 * log2pi - z * z / 2.0;
126 const double lS0 = std::log(std::max(0.5 * std::erfc(z / std::sqrt(2.0)), 1e-300));
132 const double e = eta.empty() ? 0.0 : (eta.size() == 1 ? eta[0] : eta[k]);
133 const double H = H0 * std::exp(e);
135 logf[k] = logh0 + e - H;
141 const std::vector<double>& th) {
143 if (f ==
"exp")
return std::vector<double>{std::exp(th[0])};
144 if (f ==
"weibull" || f ==
"gamma")
return std::vector<double>{std::exp(th[0]), std::exp(th[1])};
145 if (f ==
"lognormal")
return std::vector<double>{th[0], std::exp(th[1])};
147 return std::vector<double>();
155 const std::vector<double>& tev,
double texp) {
157 const double d =
static_cast<double>(tev.size());
158 if (f ==
"exp")
return std::vector<double>{std::log(d / texp)};
159 if (f ==
"weibull" || f ==
"gamma")
return std::vector<double>{0.0, std::log(texp / d)};
160 if (f ==
"lognormal") {
161 std::vector<double> lt(tev.size());
163 for (std::size_t k = 0; k < tev.size(); ++k) {
164 lt[k] = std::log(tev[k]);
169 if (tev.size() >= 2) {
172 for (
double v : lt) ss += (v - mean) * (v - mean);
173 const double sd = std::sqrt(ss / (d - 1.0));
174 if (sd > 0.0) sg = sd;
176 return std::vector<double>{mean, std::log(sg)};
179 return std::vector<double>();
188 const std::vector<double>& th,
double eta) {
195 throw InputError(
"infer_smp_family: A '" + f +
196 "' law scaled by a proportional-hazards factor is not a '" + f +
197 "' law, so it has no LINE distribution: build the environment at the "
198 "baseline (z = 0), or fit 'exp' or 'weibull'.");
222 std::vector<std::vector<std::vector<bool>>>
covmask;
238 std::vector<double>
se;
240 double prob = std::numeric_limits<double>::quiet_NaN();
258using Objective = std::function<double(
const std::vector<double>&)>;
261inline double nanmax(
const std::vector<double>& v) {
262 double m = std::numeric_limits<double>::quiet_NaN();
264 if (std::isnan(x))
continue;
265 if (std::isnan(m) || x > m) m = x;
271inline void nm_run(
const Objective& f,
const std::vector<double>& x0,
double tolx,
double tolf,
272 std::size_t maxit, std::vector<double>& xb,
double& fb) {
273 const std::size_t n = x0.size();
274 std::vector<std::vector<double>> v(n + 1, x0);
275 std::vector<double> fv(n + 1, 0.0);
277 for (std::size_t j = 0; j < n; ++j) {
278 std::vector<double> y = x0;
287 const auto sort_simplex = [&]() {
288 std::vector<std::size_t> ix(n + 1);
289 for (std::size_t k = 0; k <= n; ++k) ix[k] = k;
290 std::stable_sort(ix.begin(), ix.end(), [&](std::size_t a, std::size_t b) {
291 const double fa = fv[a], fb2 = fv[b];
292 if (std::isnan(fb2)) return !std::isnan(fa);
293 if (std::isnan(fa)) return false;
296 std::vector<std::vector<double>> v2(n + 1);
297 std::vector<double> f2(n + 1);
298 for (std::size_t k = 0; k <= n; ++k) {
308 std::vector<double> df(n), dx;
310 for (std::size_t j = 1; j <= n; ++j) {
311 df[j - 1] = std::fabs(fv[0] - fv[j]);
312 for (std::size_t a = 0; a < n; ++a) dx.push_back(std::fabs(v[j][a] - v[0][a]));
315 std::vector<double> xbar(n, 0.0);
316 for (std::size_t a = 0; a < n; ++a) {
318 for (std::size_t j = 0; j < n; ++j) s += v[j][a];
319 xbar[a] = s /
static_cast<double>(n);
321 std::vector<double>& vw = v[n];
322 std::vector<double> xr(n);
323 for (std::size_t a = 0; a < n; ++a) xr[a] = 2.0 * xbar[a] - vw[a];
324 const double fr = f(xr);
326 std::vector<double> xe(n);
327 for (std::size_t a = 0; a < n; ++a) xe[a] = 3.0 * xbar[a] - 2.0 * vw[a];
328 const double fe = f(xe);
336 }
else if (fr < fv[n - 1]) {
342 std::vector<double> xc(n);
343 for (std::size_t a = 0; a < n; ++a) xc[a] = 1.5 * xbar[a] - 0.5 * vw[a];
344 const double fc = f(xc);
352 std::vector<double> xcc(n);
353 for (std::size_t a = 0; a < n; ++a) xcc[a] = 0.5 * xbar[a] + 0.5 * vw[a];
354 const double fcc = f(xcc);
363 for (std::size_t j = 1; j <= n; ++j) {
364 for (std::size_t a = 0; a < n; ++a)
365 v[j][a] = v[0][a] + 0.5 * (v[j][a] - v[0][a]);
379 const std::size_t maxit =
opt.maxiter > 0 ?
opt.maxiter : 2000 * x0.size();
380 std::vector<double> x = x0;
382 for (
int restart = 0; restart < 4; ++restart) {
383 std::vector<double> xn;
386 const bool improved = fx - fn >
opt.tolf;
391 if (!improved)
break;
402 const std::size_t n = x.size();
403 std::vector<double> h(n);
404 for (std::size_t a = 0; a < n; ++a) h[a] = 1e-4 * std::max(1.0, std::fabs(x[a]));
406 const double f0 = f(x);
407 for (std::size_t a = 0; a < n; ++a) {
408 std::vector<double> xp = x, xm = x;
411 H(a, a) = (f(xp) - 2.0 * f0 + f(xm)) / (h[a] * h[a]);
412 for (std::size_t b = a + 1; b < n; ++b) {
413 std::vector<double> pp = xp, pm = xp, mp = xm, mm = xm;
418 H(a, b) = (f(pp) - f(pm) - f(mp) + f(mm)) / (4.0 * h[a] * h[b]);
422 const std::vector<double> nan(n, std::numeric_limits<double>::quiet_NaN());
423 for (std::size_t a = 0; a < n; ++a)
424 for (std::size_t b = 0; b < n; ++b)
425 if (!std::isfinite(H(a, b)))
return nan;
428 for (std::size_t j = 0; j < n; ++j) {
430 for (std::size_t k = 0; k < j; ++k) s -= R(k, j) * R(k, j);
431 if (!(s > 0.0))
return nan;
432 R(j, j) = std::sqrt(s);
433 for (std::size_t i = j + 1; i < n; ++i) {
435 for (std::size_t k = 0; k < j; ++k) t -= R(k, j) * R(k, i);
436 R(j, i) = t / R(j, j);
441 for (std::size_t c = 0; c < n; ++c)
442 for (std::size_t ii = n; ii-- > 0;) {
443 double s = (ii == c) ? 1.0 : 0.0;
444 for (std::size_t k = ii + 1; k < n; ++k) s -= R(ii, k) * Ri(k, c);
445 Ri(ii, c) = s / R(ii, ii);
447 std::vector<double> se(n, 0.0);
448 for (std::size_t a = 0; a < n; ++a) {
450 for (std::size_t c = 0; c < n; ++c) s += Ri(a, c) * Ri(a, c);
451 se[a] = std::sqrt(s);
458 const std::vector<std::size_t>& cov,
const double* beta) {
459 std::vector<double> eta(rows.size(), 0.0);
460 for (std::size_t r = 0; r < rows.size(); ++r) {
462 for (std::size_t c = 0; c < cov.size(); ++c) s += Z(rows[r], cov[c]) * beta[c];
471 const std::vector<std::size_t>& rows,
473 std::vector<double>& th, std::vector<double>& be,
474 std::vector<double>& se,
double& ll) {
475 const std::size_t q = cov.size();
477 std::vector<double> tev;
479 for (std::size_t k = 0; k < t.size(); ++k) {
481 if (ev[k]) tev.push_back(t[k]);
483 const Objective nll = [&](
const std::vector<double>& x) {
484 std::vector<double> eta;
485 if (q > 0) eta =
linpred(Z, rows, cov, x.data() + npar);
486 std::vector<double> lf, lS;
489 double sev = 0.0, scen = 0.0;
490 for (std::size_t k = 0; k < t.size(); ++k) {
496 double v = -(sev + scen);
497 if (!std::isfinite(v)) v = std::numeric_limits<double>::infinity();
500 std::vector<double> x;
502 x.push_back(std::log(
static_cast<double>(tev.size()) / tsum));
505 x0.resize(npar + q, 0.0);
508 th.assign(x.begin(), x.begin() + npar);
509 be.assign(x.begin() + npar, x.end());
515inline std::vector<double>
expand_beta(
const std::vector<double>& be,
516 const std::vector<std::size_t>& cov, std::size_t p) {
517 std::vector<double> b(p, 0.0);
518 for (std::size_t c = 0; c < cov.size(); ++c) b[cov[c]] = be[c];
527 const std::vector<std::vector<std::string>>& fam,
528 const std::vector<double>& t,
const std::vector<std::size_t>& to,
530 const std::vector<std::vector<std::vector<bool>>>& mask,
531 std::size_t p,
const SmpOptions&
opt, std::vector<SmpArc>& arcs,
532 double& ll, std::size_t& np) {
533 const std::size_t m = dests.size(), n = t.size();
534 std::vector<std::vector<std::size_t>> cov(m);
535 std::vector<std::size_t> npar(m, 0);
536 std::vector<std::string> famk(m);
537 for (std::size_t k = 0; k < m; ++k) {
538 for (std::size_t c = 0; c < p; ++c)
539 if (mask[i - 1][dests[k] - 1][c]) cov[k].push_back(c);
540 famk[k] = fam[i - 1][dests[k] - 1];
543 std::vector<char> cens(n, 0);
544 bool anycens =
false;
545 for (std::size_t r = 0; r < n; ++r)
550 std::vector<std::size_t> off(m, 0);
551 std::size_t pos = m - 1;
552 for (std::size_t k = 0; k < m; ++k) {
554 pos += npar[k] + cov[k].size();
557 std::vector<std::vector<std::size_t>> evidx(m);
558 for (std::size_t k = 0; k < m; ++k)
559 for (std::size_t r = 0; r < n; ++r)
560 if (to[r] == dests[k]) evidx[k].push_back(r);
562 const auto nll_dest = [&](std::size_t k,
const std::vector<double>& y) {
563 std::vector<double> tev(evidx[k].size()), eta;
564 std::vector<std::size_t> erows(evidx[k].size());
565 for (std::size_t q = 0; q < evidx[k].size(); ++q) {
566 tev[q] = t[evidx[k][q]];
567 erows[q] = rows[evidx[k][q]];
569 if (!cov[k].empty()) eta =
linpred(Z, erows, cov[k], y.data() + npar[k]);
570 std::vector<double> lf, lS;
574 for (
double v : lf) s += v;
576 if (!std::isfinite(v)) v = std::numeric_limits<double>::infinity();
579 const auto softmax = [&](
const std::vector<double>& x) {
580 std::vector<double> l(m, 0.0);
581 for (std::size_t k = 1; k < m; ++k) l[k] = x[k - 1];
582 const double mx = *std::max_element(l.begin(), l.end());
584 for (std::size_t k = 0; k < m; ++k) {
586 tot += std::exp(l[k]);
588 std::vector<double> pk(m);
589 for (std::size_t k = 0; k < m; ++k) pk[k] = std::exp(l[k]) / tot;
592 std::vector<std::size_t> crow;
593 for (std::size_t r = 0; r < n; ++r)
594 if (cens[r]) crow.push_back(r);
595 const Objective nll_state = [&](
const std::vector<double>& x) {
596 const std::vector<double> pk = softmax(x);
598 std::vector<double> Sc(crow.size(), 0.0);
599 for (std::size_t kk = 0; kk < m; ++kk) {
600 const std::vector<double> th(x.begin() + off[kk], x.begin() + off[kk] + npar[kk]);
601 std::vector<double> eta(n, 0.0);
602 if (!cov[kk].empty()) eta =
linpred(Z, rows, cov[kk], x.data() + off[kk] + npar[kk]);
603 std::vector<double> lf, lS;
606 const double lp = std::log(pk[kk]);
607 for (std::size_t r : evidx[kk]) s +=
lp + lf[r];
609 for (std::size_t q = 0; q < crow.size(); ++q) Sc[q] = Sc[q] + pk[kk] * std::exp(lS[crow[q]]);
612 for (
double c : Sc) s += std::log(std::max(c, 1e-300));
614 if (!std::isfinite(v)) v = std::numeric_limits<double>::infinity();
618 std::vector<double> x(pos, 0.0);
619 std::vector<std::size_t> cnt(m, 0);
620 for (std::size_t k = 0; k < m; ++k) {
621 cnt[k] = evidx[k].size();
622 std::vector<double> tev(cnt[k]);
624 for (std::size_t q = 0; q < cnt[k]; ++q) {
625 tev[q] = t[evidx[k][q]];
629 xk.resize(npar[k] + cov[k].size(), 0.0);
631 xk =
nelder_mead([&](
const std::vector<double>& y) {
return nll_dest(k, y); }, xk,
opt);
632 for (std::size_t q = 0; q < xk.size(); ++q) x[off[k] + q] = xk[q];
634 for (std::size_t k = 1; k < m; ++k)
635 x[k - 1] = std::log(
static_cast<double>(cnt[k]) /
static_cast<double>(cnt[0]));
639 const std::vector<double> Sfull =
hessian_se(nll_state, x);
640 const std::vector<double> pr = softmax(x);
641 for (std::size_t k = 0; k < m; ++k) {
642 const std::size_t b0 = off[k], b1 = off[k] + npar[k] + cov[k].size();
647 a.
theta.assign(x.begin() + off[k], x.begin() + off[k] + npar[k]);
649 a.
beta =
expand_beta(std::vector<double>(x.begin() + off[k] + npar[k], x.begin() + b1),
652 a.
se.assign(Sfull.begin() + b0, Sfull.begin() + b1);
654 a.
se =
hessian_se([&](
const std::vector<double>& y) {
return nll_dest(k, y); },
655 std::vector<double>(x.begin() + b0, x.begin() + b1));
671inline SmpFit infer_smp(
const std::vector<std::size_t>& from,
const std::vector<std::size_t>& to,
674 const std::size_t n = from.size();
675 if (to.size() != n || dur.size() != n || n == 0)
676 throw InputError(
"infer_smp: FROM, TO and DUR must be nonempty and of equal length.");
677 std::size_t smax = 0;
678 for (std::size_t k = 0; k < n; ++k) {
680 throw InputError(
"infer_smp: FROM must hold states 1..E and TO states 1..E, or 0 for "
681 "a censored sojourn.");
682 if (to[k] == from[k])
683 throw InputError(
"infer_smp: A sojourn cannot end in the state it started from.");
684 if (!std::isfinite(dur[k]) || !(dur[k] > 0.0))
685 throw InputError(
"infer_smp: Every sojourn duration must be finite and positive.");
686 smax = std::max(smax, std::max(from[k], to[k]));
688 const std::size_t E =
opt.nstates > 0 ?
opt.nstates : smax;
689 if (smax > E)
throw InputError(
"infer_smp: A state exceeds 'nstates'.");
693 throw InputError(
"infer_smp: The covariates must be a finite n x p matrix, one row per "
695 for (std::size_t r = 0; r < Z.
rows(); ++r)
696 for (std::size_t c = 0; c < Z.
cols(); ++c)
697 if (!std::isfinite(Z(r, c)))
698 throw InputError(
"infer_smp: The covariates must be a finite n x p matrix, one row "
700 const std::size_t p = Z.
cols();
701 std::vector<std::vector<std::vector<bool>>> mask =
opt.covmask;
703 mask.assign(E, std::vector<std::vector<bool>>(E, std::vector<bool>(p,
true)));
705 bool ok = mask.size() == E;
706 for (std::size_t i = 0; ok && i < E; ++i) {
707 ok = mask[i].size() == E;
708 for (std::size_t j = 0; ok && j < E; ++j) ok = mask[i][j].size() == p;
710 if (!ok)
throw InputError(
"infer_smp: The covariate mask must be E x E x p.");
713 std::vector<std::vector<std::string>> fam(E, std::vector<std::string>(E));
714 if (
opt.dist_table.empty()) {
715 for (std::size_t i = 0; i < E; ++i)
718 bool ok =
opt.dist_table.size() == E;
719 for (std::size_t i = 0; ok && i < E; ++i) ok =
opt.dist_table[i].size() == E;
721 throw InputError(
"infer_smp: The 'dist' option must be a family name or an E x E cell "
723 for (std::size_t i = 0; i < E; ++i)
724 for (std::size_t j = 0; j < E; ++j)
725 fam[i][j] =
opt.dist_table[i][j].empty() ? std::string(
"weibull")
728 for (std::size_t i = 0; i < E; ++i)
731 if (approach !=
"intensity" && approach !=
"sojourn")
732 throw InputError(
"infer_smp: The approach must be 'intensity' or 'sojourn'.");
739 std::size_t nparams = 0;
740 for (std::size_t i = 1; i <= E; ++i) {
741 std::vector<std::size_t> rows;
742 for (std::size_t k = 0; k < n; ++k)
743 if (from[k] == i) rows.push_back(k);
744 if (rows.empty())
continue;
745 std::vector<std::size_t> dests;
746 for (std::size_t r : rows)
747 if (to[r] > 0) dests.push_back(to[r]);
748 std::sort(dests.begin(), dests.end());
749 dests.erase(std::unique(dests.begin(), dests.end()), dests.end());
750 if (dests.empty())
continue;
751 std::vector<double> t(rows.size());
752 std::vector<std::size_t> tor(rows.size());
753 for (std::size_t q = 0; q < rows.size(); ++q) {
755 tor[q] = to[rows[q]];
757 if (approach ==
"intensity") {
758 for (std::size_t j : dests) {
759 std::vector<std::size_t> cov;
760 for (std::size_t c = 0; c < p; ++c)
761 if (mask[i - 1][j - 1][c]) cov.push_back(c);
762 std::vector<char> ev(rows.size(), 0);
764 for (std::size_t q = 0; q < rows.size(); ++q)
770 std::vector<double> be;
772 fit_intensity_arc(fam[i - 1][j - 1], t, ev, Z, rows, cov,
opt, a.
theta, be, a.
se,
776 a.
family = fam[i - 1][j - 1];
778 a.
beta = expand_beta(be, cov, p);
780 fit.
arcs.push_back(a);
782 nparams += a.
theta.size() + cov.size();
787 fit_sojourn_state(i, dests, fam, t, tor, Z, rows, mask, p,
opt, fit.
arcs, ll, np);
794 fit.
aic = 2.0 *
static_cast<double>(nparams) - 2.0 * loglik;
796 if (approach ==
"sojourn") {
799 for (std::size_t i = 1; i <= E; ++i) {
800 std::vector<lang::Distrib<double>> stage(E);
809 for (std::size_t j = 0; j < E; ++j) fit.
P(i - 1, j) = q.
P[j];
823 std::vector<double>
z;
836 const std::size_t E = fit.
nstates;
837 if (models.size() != E)
838 throw InputError(
"infer_smp_env: MODELS must be a cell of " + std::to_string(E) +
839 " networks, one per state.");
840 std::vector<std::string> names =
opt.names, types =
opt.types;
842 for (std::size_t e = 1; e <= E; ++e) names.push_back(
"S" + std::to_string(e));
843 if (types.empty()) types.assign(E,
"stage");
844 if (names.size() != E || types.size() != E)
845 throw InputError(
"infer_smp_env: 'names' and 'types' must have " + std::to_string(E) +
847 std::vector<double> z =
opt.z;
848 if (z.empty()) z.assign(fit.
ncov, 0.0);
849 if (z.size() != fit.
ncov)
850 throw InputError(
"infer_smp_env: 'z' must have " + std::to_string(fit.
ncov) +
851 " entries, one per covariate.");
853 for (std::size_t e = 0; e < E; ++e) envm.
set_stage(e, names[e], types[e], models[e]);
856 for (std::size_t c = 0; c < z.size(); ++c) eta += a.
beta[c] * z[c];
888 const std::vector<double>& zin = std::vector<double>()) {
889 std::vector<double> z = zin;
890 if (z.empty()) z.assign(fit.
ncov, 0.0);
891 if (z.size() != fit.
ncov)
892 throw InputError(
"infer_smp_hazard: 'z' must have " + std::to_string(fit.
ncov) +
893 " entries, one per covariate.");
894 bool ok = !t.empty();
895 for (std::size_t k = 0; ok && k < t.size(); ++k) {
896 if (!std::isfinite(t[k]) || !(t[k] > 0.0)) ok =
false;
897 if (k > 0 && !(t[k] - t[k - 1] > 0.0)) ok =
false;
899 if (!ok)
throw InputError(
"infer_smp_hazard: T must be ascending, finite and positive.");
900 const std::size_t E = fit.
nstates, nt = t.size();
901 std::vector<SmpHazard> hz(fit.
arcs.size());
902 std::vector<std::size_t> froms;
904 std::sort(froms.begin(), froms.end());
905 froms.erase(std::unique(froms.begin(), froms.end()), froms.end());
906 const auto eta_of = [&](
const SmpArc& a) {
908 for (std::size_t c = 0; c < z.size(); ++c) s += a.
beta[c] * z[c];
911 for (std::size_t i : froms) {
912 std::vector<std::size_t> idx;
913 for (std::size_t a = 0; a < fit.
arcs.size(); ++a)
914 if (fit.
arcs[a].from == i) idx.push_back(a);
915 const std::size_t m = idx.size();
916 std::vector<std::vector<double>> lf(m), lS(m);
917 for (std::size_t k = 0; k < m; ++k) {
923 std::vector<lang::Distrib<double>> stage(E);
924 for (std::size_t k = 0; k < m; ++k) {
930 std::vector<double> Si(nt, 0.0);
931 for (std::size_t j = 0; j < nt; ++j) {
933 for (std::size_t k = 0; k < m; ++k) s += lS[k][j];
936 for (std::size_t k = 0; k < m; ++k) {
945 for (std::size_t j = 0; j < nt; ++j) {
946 const double hh = std::exp(lf[k][j] - lS[k][j]);
947 const double cif = C.
C(a.
to - 1, j);
949 h.
sojourn[j] = hh * Si[j] / std::max(q.
P[a.
to - 1] - cif, 0.0);
955 std::vector<double> pk(m);
956 for (std::size_t k = 0; k < m; ++k) pk[k] = fit.
arcs[idx[k]].prob;
957 std::vector<double> Si(nt, 0.0);
958 for (std::size_t j = 0; j < nt; ++j)
959 for (std::size_t k = 0; k < m; ++k) Si[j] += std::exp(lS[k][j]) * pk[k];
960 const double tmax = t.back();
961 std::vector<double> g(1, 0.0);
962 const std::vector<double> ls =
964 for (
double v : ls) g.push_back(std::pow(10.0, v));
966 g.insert(g.end(), lin.begin(), lin.end());
967 g.insert(g.end(), t.begin(), t.end());
968 std::sort(g.begin(), g.end());
969 g.erase(std::unique(g.begin(), g.end()), g.end());
970 const std::size_t ng = g.size();
971 std::vector<double> gm(ng - 1);
972 for (std::size_t j = 0; j + 1 < ng; ++j) gm[j] = (g[j] + g[j + 1]) / 2.0;
973 std::vector<std::vector<double>> lfm(m), lSm(m);
974 for (std::size_t k = 0; k < m; ++k) {
979 std::vector<double> Sim(ng - 1, 0.0);
980 for (std::size_t j = 0; j + 1 < ng; ++j)
981 for (std::size_t k = 0; k < m; ++k) Sim[j] += std::exp(lSm[k][j]) * pk[k];
982 std::vector<std::size_t> at(nt);
983 for (std::size_t j = 0; j < nt; ++j)
984 at[j] =
static_cast<std::size_t
>(std::lower_bound(g.begin(), g.end(), t[j]) -
986 for (std::size_t k = 0; k < m; ++k) {
988 std::vector<double> cum(ng, 0.0);
989 for (std::size_t j = 0; j + 1 < ng; ++j)
990 cum[j + 1] = cum[j] + pk[k] * std::exp(lfm[k][j]) / Sim[j] * (g[j + 1] - g[j]);
994 h.intensity.resize(nt);
995 h.sojourn.resize(nt);
996 h.cumulative.resize(nt);
998 for (std::size_t j = 0; j < nt; ++j) {
999 h.intensity[j] = pk[k] * std::exp(lf[k][j]) / Si[j];
1000 h.sojourn[j] = std::exp(lf[k][j] - lS[k][j]);
1001 h.cumulative[j] = cum[at[j]];
1002 h.cif[j] = pk[k] * (1.0 - std::exp(lS[k][j]));
1016 std::vector<double>
A;
1029 const std::vector<std::size_t>& to,
1030 const std::vector<double>& dur,
1031 std::size_t nstates = 0) {
1032 const std::size_t n = from.size();
1033 if (to.size() != n || dur.size() != n || n == 0)
1034 throw InputError(
"infer_smp_nelson_aalen: FROM, TO and DUR must be nonempty and of equal "
1036 std::size_t smax = 0;
1037 for (std::size_t k = 0; k < n; ++k) {
1038 if (!std::isfinite(dur[k]) || !(dur[k] > 0.0) || from[k] < 1 || to[k] == from[k])
1039 throw InputError(
"infer_smp_nelson_aalen: Invalid sojourn data: see INFER_SMP for the "
1041 smax = std::max(smax, std::max(from[k], to[k]));
1043 const std::size_t E = nstates > 0 ? nstates : smax;
1044 std::vector<SmpNelsonAalen> na;
1045 for (std::size_t i = 1; i <= E; ++i) {
1046 std::vector<double> ti;
1047 std::vector<std::size_t> di;
1048 for (std::size_t k = 0; k < n; ++k)
1050 ti.push_back(dur[k]);
1051 di.push_back(to[k]);
1053 std::vector<std::size_t> dests;
1054 for (std::size_t d : di)
1055 if (d > 0) dests.push_back(d);
1056 std::sort(dests.begin(), dests.end());
1057 dests.erase(std::unique(dests.begin(), dests.end()), dests.end());
1058 for (std::size_t j : dests) {
1059 std::vector<double> tev;
1060 for (std::size_t q = 0; q < ti.size(); ++q)
1061 if (di[q] == j) tev.push_back(ti[q]);
1062 std::sort(tev.begin(), tev.end());
1063 tev.erase(std::unique(tev.begin(), tev.end()), tev.end());
1068 r.
A.resize(tev.size());
1069 r.
var.resize(tev.size());
1070 double a = 0.0, v = 0.0;
1071 for (std::size_t k = 0; k < tev.size(); ++k) {
1072 double d = 0.0, Y = 0.0;
1073 for (std::size_t q = 0; q < ti.size(); ++q) {
1074 if (ti[q] == tev[k] && di[q] == j) d += 1.0;
1075 if (ti[q] >= tev[k]) Y += 1.0;
1078 v = v + d / (Y * Y);
void add_kernel_transition(std::size_t e, std::size_t h, double prob, const lang::Distrib< T > &d, const ResetMarginal &reset=ResetMarginal())
addKernelTransition: a KERNEL arc of Q(e,h,t) = prob * F(t).
void set_stage(std::size_t e, const std::string &nm, const std::string &type, const qn::NetworkStruct< T > &model)
addStage: name the stage and give it its network.
void add_transition(std::size_t e, std::size_t h, const lang::Distrib< T > &d, const ResetMarginal &reset=ResetMarginal())
addTransition: enable e -> h with a distribution and a reset policy.
A network plus its refreshed NetworkStruct.
A random environment: a port of matlab/src/lang/Environment.m, restricted to what SolverENV reads out...
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense matrix and non-owning view.
void fit_sojourn_state(std::size_t i, const std::vector< std::size_t > &dests, const std::vector< std::vector< std::string > > &fam, const std::vector< double > &t, const std::vector< std::size_t > &to, const Matrix< double > &Z, const std::vector< std::size_t > &rows, const std::vector< std::vector< std::vector< bool > > > &mask, std::size_t p, const SmpOptions &opt, std::vector< SmpArc > &arcs, double &ll, std::size_t &np)
fitSojournState: state i of Approach I.
std::vector< double > expand_beta(const std::vector< double > &be, const std::vector< std::size_t > &cov, std::size_t p)
expandBeta: the effects of the selected covariates, zero elsewhere.
double nanmax(const std::vector< double > &v)
MATLAB's max over a vector: NaNs ignored, NaN when every entry is one.
std::function< double(const std::vector< double > &)> Objective
std::vector< double > nelder_mead(const Objective &f, const std::vector< double > &x0, const SmpOptions &opt)
nelderMead: restart nm_run from its own optimum, at most four runs.
std::vector< double > linpred(const Matrix< double > &Z, const std::vector< std::size_t > &rows, const std::vector< std::size_t > &cov, const double *beta)
Z(rows, cov) * beta, one value per row.
void fit_intensity_arc(const std::string &family, const std::vector< double > &t, const std::vector< char > &ev, const Matrix< double > &Z, const std::vector< std::size_t > &rows, const std::vector< std::size_t > &cov, const SmpOptions &opt, std::vector< double > &th, std::vector< double > &be, std::vector< double > &se, double &ll)
fitIntensityArc: one transition of Approach II, its events ev among the sojourns t.
void nm_run(const Objective &f, const std::vector< double > &x0, double tolx, double tolf, std::size_t maxit, std::vector< double > &xb, double &fb)
One run of the reference's Nelder-Mead (nmRun).
std::vector< double > hessian_se(const Objective &f, const std::vector< double > &x)
hessianSE: central-difference Hessian with steps 1e-4 max(1, |x|), its Cholesky factor H = R'R,...
std::string smp_family_name(const std::string &f)
Lower-case copy of a family name.
std::size_t infer_smp_family_npar(const std::string &family)
infer_smp_family(F, 'npar'): the number of parameters, validating the name.
std::vector< SmpHazard > infer_smp_hazard(const SmpFit &fit, const std::vector< double > &t, const std::vector< double > &zin=std::vector< double >())
infer_smp_hazard(fit, t, 'z', z): both hazard functions of every arc of a fit on the ascending instan...
std::vector< double > infer_smp_family_natural(const std::string &family, const std::vector< double > &th)
infer_smp_family(F, 'natural', THETA): rate | shape, scale | mu, sigma.
void infer_smp_family_logfs(const std::string &family, const std::vector< double > &th, const std::vector< double > &t, const std::vector< double > &eta, std::vector< double > &logf, std::vector< double > &logS)
infer_smp_family(F, 'logfs', THETA, T, ETA): log density and log survival at t under the proportional...
env::Environment< double > infer_smp_env(const SmpFit &fit, const std::vector< qn::NetworkStruct< double > > &models, const SmpEnvOptions &opt=SmpEnvOptions())
infer_smp_env(fit, models, ...): the Environment of a fit, models[e] the network of stage e.
lang::Distrib< double > infer_smp_family_dist(const std::string &family, const std::vector< double > &th, double eta)
infer_smp_family(F, 'dist', THETA, ETA): the LINE distribution of the law with hazard h0(t) exp(eta).
std::vector< double > infer_smp_family_theta0(const std::string &family, const std::vector< double > &tev, double texp)
infer_smp_family(F, 'theta0', TEV, TEXP): the starting point from the event times tev and the total e...
SmpFit infer_smp(const std::vector< std::size_t > &from, const std::vector< std::size_t > &to, const std::vector< double > &dur, const SmpOptions &opt=SmpOptions())
infer_smp(from, to, dur, ...): the fit, under opt.approach.
std::vector< SmpNelsonAalen > infer_smp_nelson_aalen(const std::vector< std::size_t > &from, const std::vector< std::size_t > &to, const std::vector< double > &dur, std::size_t nstates=0)
infer_smp_nelson_aalen(from, to, dur, 'nstates', E): the Nelson-Aalen estimate of the cumulative tran...
std::vector< double > linspace(double a, double b, std::size_t n)
linspace(a, b, n), with the last point exactly b.
SmpStageQuad smp_stage_quad(const std::vector< lang::Distrib< T > > &arcs, const std::vector< double > &probs)
SmpStageCif smp_stage_cif(const std::vector< lang::Distrib< T > > &arcs, const std::vector< double > &probs, const std::vector< double > &t)
CIF and holding-time CDF of a stage at the ascending instants t.
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
Closed networks with non-preemptive shortest-job-next (SJN/SJF) stations.
Cumulative incidence functions of one semi-Markov stage.
Embedded jump probabilities and mean holding time of a semi-Markov stage.
std::vector< double > beta
p covariate effects, zero where masked out
std::vector< double > theta
unconstrained parameters
std::vector< double > se
standard errors of [theta; beta]
std::vector< double > params
natural parameters
double prob
Approach I: p_ij; Approach II: the embedded probability at z = 0.
Options of infer_smp_env.
std::vector< std::string > types
default 'stage'
std::vector< std::string > names
default S1..SE
std::vector< double > z
covariate vector, default the baseline 0
Matrix< double > P
E x E embedded jump chain at z = 0.
std::vector< SmpArc > arcs
Both hazard functions of one transition, rows aligned with the instants asked for.
std::vector< double > sojourn
alpha_ij(t), the hazard of the conditional sojourn law
std::vector< double > cumulative
A~_ij(t) = int_0^t a~_ij(s) ds.
std::vector< double > intensity
a~_ij(t), the transition intensity
std::vector< double > cif
CIF_ij(t) = P(sojourn <= t, next state j).
One Nelson-Aalen estimate, on the distinct event times of its transition.
std::vector< double > time
the distinct event times of i -> j, ascending
std::vector< double > var
its Greenwood-type variance sum d/Y^2
std::vector< double > A
the estimate there (right-continuous step function)
Options of infer_smp, the reference's name/value pairs.
std::vector< std::vector< std::string > > dist_table
Per transition, dist_table[i][j] for i -> j (0-based states), when not empty; it must then be E x E,...
std::string dist
The family of every transition: 'weibull' (default), 'exp', 'gamma' or 'lognormal'.
std::vector< std::vector< std::vector< bool > > > covmask
covmask[i][j][c]: whether covariate c enters transition i -> j (0-based states); empty means all,...
Matrix< double > covariates
n x p covariates Z, one row per sojourn; an empty matrix means none.
std::size_t maxiter
Nelder-Mead iteration cap per run; 0 means 2000 per parameter.
std::string approach
'intensity' (Approach II, default) or 'sojourn' (Approach I).
std::size_t nstates
E; 0 means max(from, to).
static Distrib exp_rate(const T &r)
static Distrib weibull(const T &scale, const T &shape)
static Distrib gamma_dist(const T &shape, const T &scale)
Gamma(shape, scale), Weibull(scale, shape) and Lognormal(mu, sigma).
static Distrib lognormal(const T &logmean, const T &logsigma)
What smp_stage_cif returns: C(h, j) = CIF_h(t_j) and Fhold[j].
What smp_stage_quad returns.
std::vector< double > P
the embedded jump probabilities, one per arc