5#ifndef LINE_API_MC_CTMC_TAKAHASHI_H
6#define LINE_API_MC_CTMC_TAKAHASHI_H
84 std::size_t numSteps,
double massTol = 1e-14) {
86 "ctmc_takahashi requires transcendental arithmetic: it is seeded by "
87 "ctmc_courtois, whose epsMAX is an eigenvalue modulus, and its large-system "
88 "block solve is GMRES, which stops on a residual tolerance");
89 const std::size_t n = Q.
rows();
90 if (Q.
cols() != n)
throw InputError(
"ctmc_takahashi: generator is not square");
93 const std::size_t nMacro = MS.size();
96 const detail::CourtoisCore<T> c = detail::courtois_core(Q, MS, detail::courtois_default_rate(Q, MS));
99 std::vector<std::size_t> off(nMacro + 1, 0);
100 for (std::size_t i = 0; i < nMacro; ++i) off[i + 1] = off[i] + MS[i].size();
101 std::vector<T> pperm(n, zero);
102 for (std::size_t i = 0; i < nMacro; ++i)
103 for (std::size_t a = off[i]; a < off[i + 1]; ++a) pperm[a] = pMacro[i] * c.pmicro[a];
106 r.
pcourt = detail::unpermute_states(pperm, c.v);
113 if (qmax == zero)
throw InputError(
"ctmc_takahashi: the generator has no transitions");
117 for (std::size_t step = 0; step < numSteps; ++step) {
122 std::vector<T> S(nMacro, zero);
123 for (std::size_t I = 0; I < nMacro; ++I)
124 for (std::size_t i : MS[I]) S[I] += pn_1[i];
125 for (std::size_t I = 0; I < nMacro; ++I) {
126 if (!(S[I] > tol))
continue;
127 for (std::size_t J = 0; J < nMacro; ++J) {
128 if (I == J)
continue;
130 for (std::size_t i : MS[I])
131 for (std::size_t j : MS[J]) acc += P(i, j) * pn_1[i] / S[I];
135 for (std::size_t I = 0; I < nMacro; ++I) {
137 for (std::size_t J = 0; J < nMacro; ++J)
138 if (J != I) rs += G(I, J);
145 for (std::size_t I = 0; I < nMacro; ++I) {
146 if (!(S[I] > tol))
continue;
147 for (std::size_t j = 0; j < n; ++j) {
149 for (std::size_t i : MS[I]) acc += P(i, j) * pn_1[i];
150 GI(I, j) = acc / S[I];
155 for (std::size_t I = 0; I < nMacro; ++I) {
156 const std::size_t sz = MS[I].size();
158 std::vector<T> b(sz, zero);
159 for (std::size_t i = 0; i < sz; ++i) {
160 for (std::size_t j = 0; j < sz; ++j)
161 A(i, j) = (i == j ? one : zero) - P(MS[I][j], MS[I][i]);
162 for (std::size_t K = 0; K < nMacro; ++K)
163 if (K != I) b[i] += gamma[K] * GI(K, MS[I][i]);
173 if (bs.
flag == 0) xI = bs.
x;
176 if (xI.empty()) xI =
solve(A, b);
177 for (std::size_t i = 0; i < sz; ++i) pn[MS[I][i]] = xI[i];
181 for (
const T& x : pn) tot += x;
182 if (tot == zero)
throw NumericError(
"ctmc_takahashi: the disaggregation step returned a null vector");
183 for (T& x : pn) x /= tot;
NumericError(const std::string &what)
Preconditioned stabilized biconjugate gradients, for the linear systems a generator produces.
Courtois decomposition of a nearly completely decomposable (NCD) CTMC.
Koury-McAllister-Stewart aggregation-disaggregation for a nearly completely decomposable CTMC.
Uniformization (randomization) of a CTMC: the embedded DTMC P = I + Q/q.
Equilibrium distribution of a discrete-time Markov chain, and stochastic complementation.
The exception types the port throws.
LU factorization with partial pivoting, templated on the number type.
Dense matrix and non-owning view.
BicgstabResult< T > ctmc_bicgstab(const Matrix< T > &A, const std::vector< T > &b, double tol=1e-12, long maxit=0, const std::vector< T > &x0=std::vector< T >())
Preconditioned stabilized biconjugate gradients, for the linear systems a generator produces.
constexpr std::size_t GMRES_MIN_STATES
Order above which the direct sparse factorization is abandoned in favour of the Krylov path.
T ctmc_maxabs(const Matrix< T > &Q)
Largest magnitude of any entry of Q; equals max_i |q_ii| for a generator.
TakahashiResult< T > ctmc_takahashi(const Matrix< T > &Q, const std::vector< std::vector< std::size_t > > &MS, std::size_t numSteps, double massTol=1e-14)
Takahashi's aggregation-disaggregation for a nearly completely decomposable CTMC.
std::vector< T > dtmc_solve(const Matrix< T > &P)
Stationary distribution of a stochastic matrix P.
RandomizationResult< T > ctmc_randomization(const Matrix< T > &Q, const T &q)
Uniformization (randomization) of a CTMC: the embedded DTMC P = I + Q/q.
GmresResult< T > ctmc_gmres(const Matrix< T > &A, const std::vector< T > &b, double tol=1e-12, long restart=0, long maxit=0, const std::vector< T > &x0=std::vector< T >())
Restarted GMRES with an ILUT preconditioner, for the linear systems a generator produces.
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.
std::vector< T > x
solution
int flag
0 converged, 1 iteration limit, 3 stagnation, 4 breakdown
int flag
0 converged, 1 iteration limit, 3 stagnation/divergence
std::vector< T > x
solution
T eps
NCD index, as ctmc_courtois defines it.
T epsMAX
maximum admissible NCD index
Matrix< T > Qperm
Q reordered by macro-state.
std::vector< T > p
estimate after numSteps sweeps
std::vector< T > pcourt
the Courtois starting point
std::vector< T > p_1
the previous iterate