5#ifndef LINE_API_MC_CTMC_UNIFORMIZATION_H
6#define LINE_API_MC_CTMC_UNIFORMIZATION_H
61T uniformization_rate(
const Matrix<T>& Q) {
62 const std::size_t n = Q.
rows();
64 for (std::size_t i = 0; i < n; ++i) {
66 if (a > qmax) qmax = a;
73 const std::size_t n = Q.
rows();
75 for (std::size_t i = 0; i < n; ++i)
76 for (std::size_t j = 0; j < n; ++j)
83std::vector<T> vecmat(
const std::vector<T>& v,
const Matrix<T>& P) {
84 const std::size_t n = P.rows();
85 std::vector<T> r(P.cols(), num_traits<T>::from_int(0));
86 for (std::size_t i = 0; i < n; ++i) {
87 if (v[i] == num_traits<T>::from_int(0))
continue;
88 for (std::size_t j = 0; j < P.cols(); ++j) r[j] += v[i] * P(i, j);
95std::size_t poisson_truncation(
double qt,
double tol,
long maxiter) {
97 maxiter =
static_cast<long>(std::max(100.0, std::ceil(qt + 10.0 * std::sqrt(qt) + 20.0)));
98 double s = 1.0, r = 1.0;
100 const double e = std::exp(-qt);
101 for (
long iter = 0, k = 0; iter < maxiter; ++iter) {
103 r = r * qt /
static_cast<double>(k);
105 kmax =
static_cast<std::size_t
>(k);
106 if ((1.0 - e * s) <= tol)
break;
125 double tol = 1e-12,
long maxiter = -1) {
127 "ctmc_uniformization requires transcendental arithmetic: the Poisson weights "
128 "involve exp(-q t), which is not a rational function of the rates");
129 const std::size_t n = Q.
rows();
130 if (Q.
cols() != n)
throw InputError(
"ctmc_uniformization: generator is not square");
131 if (pi0.size() != n)
throw InputError(
"ctmc_uniformization: pi0 has the wrong length");
133 const T q = detail::uniformization_rate(Q);
139 const double MAXQT = 500.0;
140 if (qt_full > MAXQT) {
141 const long nSeg =
static_cast<long>(std::ceil(qt_full / MAXQT));
144 for (
long s = 0; s < nSeg; ++s) {
152 const Matrix<T> P = detail::uniformized_matrix(Q, q);
158 std::vector<T> pi(n);
159 for (std::size_t i = 0; i < n; ++i) pi[i] = pi0[i] * ri;
160 std::vector<T> Pk = pi0;
161 for (std::size_t j = 1; j <= kmax; ++j) {
162 Pk = detail::vecmat(Pk, P);
164 for (std::size_t i = 0; i < n; ++i) pi[i] += ri * Pk[i];
176 double tol = 1e-12,
long maxiter = -1) {
178 "ctmc_timeaverage requires transcendental arithmetic (Poisson weights)");
179 const std::size_t n = Q.
rows();
180 if (Q.
cols() != n)
throw InputError(
"ctmc_timeaverage: generator is not square");
181 if (pi0.size() != n)
throw InputError(
"ctmc_timeaverage: pi0 has the wrong length");
184 const T q = detail::uniformization_rate(Q);
185 if (q == zero)
return {pi0, pi0, 0};
188 const double MAXQT = 500.0;
189 if (qt_full > MAXQT) {
190 const long nSeg =
static_cast<long>(std::ceil(qt_full / MAXQT));
192 std::vector<T> cur = pi0, integral(n, zero);
193 std::size_t kmax = 0;
194 for (
long s = 0; s < nSeg; ++s) {
196 for (std::size_t i = 0; i < n; ++i) integral[i] += tSeg * seg.
piTimeAvg[i];
200 for (std::size_t i = 0; i < n; ++i) integral[i] /= t;
201 return {integral, cur, kmax};
204 const Matrix<T> P = detail::uniformized_matrix(Q, q);
211 std::vector<T> Pk = pi0;
212 std::vector<T> piExit(n), piIntSum(n);
215 if (tail < zero) tail = zero;
216 for (std::size_t i = 0; i < n; ++i) {
217 piExit[i] = w * Pk[i];
218 piIntSum[i] = tail * Pk[i];
220 for (std::size_t j = 1; j <= kmax; ++j) {
221 Pk = detail::vecmat(Pk, P);
225 if (tail < zero) tail = zero;
226 for (std::size_t i = 0; i < n; ++i) {
227 piExit[i] += w * Pk[i];
228 piIntSum[i] += tail * Pk[i];
231 std::vector<T> avg(n);
232 for (std::size_t i = 0; i < n; ++i) avg[i] = piIntSum[i] / qt;
233 return {avg, piExit, kmax};
The exception types the port throws.
Dense matrix and non-owning view.
UniformizationResult< T > ctmc_uniformization(const std::vector< T > &pi0, const Matrix< T > &Q, const T &t, double tol=1e-12, long maxiter=-1)
Transient distribution of a CTMC by uniformization (Jensen's method), and the time-averaged distribut...
TimeAverageResult< T > ctmc_timeaverage(const std::vector< T > &pi0, const Matrix< T > &Q, const T &t, double tol=1e-12, long maxiter=-1)
Time-averaged distribution (1/t) int_0^t pi(u) du, plus pi(t) itself.
Number-type abstraction for the templated API port.
std::vector< T > piTimeAvg
time-averaged distribution over [0, t]
std::vector< T > piExit
distribution at time t