101 std::size_t numSteps) {
103 "ctmc_kms requires transcendental arithmetic: it is seeded by ctmc_courtois, "
104 "whose epsMAX is an eigenvalue modulus, and its large-system block solve is "
105 "GMRES, which stops on a residual tolerance");
106 const std::size_t n = Q.
rows();
107 if (Q.
cols() != n)
throw InputError(
"ctmc_kms: generator is not square");
110 const std::size_t nMacro = MS.size();
112 const detail::CourtoisCore<T> c = detail::courtois_core(Q, MS, detail::courtois_default_rate(Q, MS));
113 const std::vector<T> pMacro =
dtmc_solve(c.G);
116 std::vector<std::size_t> off(nMacro + 1, 0);
117 for (std::size_t i = 0; i < nMacro; ++i) off[i + 1] = off[i] + MS[i].size();
119 std::vector<T> pn(n, zero);
120 for (std::size_t i = 0; i < nMacro; ++i)
121 for (std::size_t a = off[i]; a < off[i + 1]; ++a) pn[a] = pMacro[i] * c.pmicro[a];
124 r.
pcourt = detail::unpermute_states(pn, c.v);
129 std::vector<T> pn_1 = pn;
130 for (std::size_t step = 0; step < numSteps; ++step) {
134 std::vector<T> pcond = pn_1;
135 for (std::size_t I = 0; I < nMacro; ++I) {
137 for (std::size_t a = off[I]; a < off[I + 1]; ++a) s += pn_1[a];
139 for (std::size_t a = off[I]; a < off[I + 1]; ++a) pcond[a] /= s;
143 for (std::size_t I = 0; I < nMacro; ++I)
144 for (std::size_t J = 0; J < nMacro; ++J) {
146 for (std::size_t b = off[J]; b < off[J + 1]; ++b) {
148 for (std::size_t a = off[I]; a < off[I + 1]; ++a) s += c.P(b, a);
154 for (std::size_t i = 0; i < nMacro; ++i)
155 for (std::size_t j = 0; j < nMacro; ++j) Gt(i, j) = G(j, i);
159 std::vector<T> zn(n, zero);
160 for (std::size_t I = 0; I < nMacro; ++I)
161 for (std::size_t a = off[I]; a < off[I + 1]; ++a) zn[a] = w[I] * pcond[a];
164 std::vector<T> rhs(n, zero);
165 for (std::size_t I = 0; I < nMacro; ++I)
166 for (std::size_t J = 0; J < nMacro; ++J)
167 for (std::size_t a = off[I]; a < off[I + 1]; ++a)
168 for (std::size_t b = off[J]; b < off[J + 1]; ++b) {
170 rhs[b] += zn[a] * c.P(a, b);
172 M(a, b) = (a == b ? one : zero) - c.P(a, b);
174 M(a, b) = -c.P(a, b);
178 pn = detail::aggregation_block_solve(M, rhs);
180 for (
const T& x : pn) tot += x;
181 if (tot == zero)
throw NumericError(
"ctmc_kms: the disaggregation sweep returned a null vector");
182 for (T& x : pn) x /= tot;
185 r.
p = detail::unpermute_states(pn, c.v);
186 r.
p_1 = detail::unpermute_states(pn_1, c.v);
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.
KmsResult< T > ctmc_kms(const Matrix< T > &Q, const std::vector< std::vector< std::size_t > > &MS, std::size_t numSteps)
Koury-McAllister-Stewart aggregation-disaggregation for a nearly completely decomposable CTMC.
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.