76 double reachTol = 1e-15,
77 double zeroColTol = 1e-12) {
78 const std::size_t N = Qin.
rows();
79 if (Qin.
cols() != N)
throw InputError(
"ctmc_solve_reducible_blkdecomp: generator is not square");
80 if (!pin.empty() && pin.size() != N)
81 throw InputError(
"ctmc_solve_reducible_blkdecomp: initial vector has the wrong length");
92 for (std::size_t i = 0; i < N; ++i) {
94 for (std::size_t j = 0; j < N; ++j)
95 if (i != j && !(
num_abs(T(Adj(i, j))) > arctol)) Adj(i, j) = zero;
98 const std::size_t numSCC = s.
numSCC();
107 for (std::size_t j = 0; j < N; ++j) r.
pis(0, j) = r.
pi[j];
112 std::vector<std::size_t> transStates, recStates, transSccIds, recSccIds;
113 for (std::size_t c = 0; c < numSCC; ++c) {
115 recSccIds.push_back(c);
116 recStates.insert(recStates.end(), s.
members[c].begin(), s.
members[c].end());
118 transSccIds.push_back(c);
119 transStates.insert(transStates.end(), s.
members[c].begin(), s.
members[c].end());
122 std::sort(transStates.begin(), transStates.end());
123 std::sort(recStates.begin(), recStates.end());
124 const std::size_t nt = transStates.size(), nr = recStates.size();
127 "ctmc_solve_reducible_blkdecomp: no recurrent class, the chain admits no limiting "
132 std::vector<std::size_t> lupiv;
134 bool lu_ready =
false;
136 for (std::size_t a = 0; a < nt; ++a) {
137 for (std::size_t b = 0; b < nt; ++b) Q_ttT(b, a) = Q(transStates[a], transStates[b]);
138 for (std::size_t b = 0; b < nr; ++b) Q_ta(a, b) = Q(transStates[a], recStates[b]);
144 std::vector<std::size_t> recPos(N,
static_cast<std::size_t
>(-1));
145 for (std::size_t k = 0; k < nr; ++k) recPos[recStates[k]] = k;
148 std::vector<std::vector<T>> pirec(numSCC);
155 auto transient_sojourn = [&](
const std::vector<T>& rhs) {
156 std::vector<T> sojourn;
164 if (bb.
flag == 0) sojourn = bb.
x;
168 if (sojourn.empty()) {
181 auto absorb_limiting = [&](
const std::vector<T>& p0) {
182 std::vector<T> piv(N, zero);
183 std::vector<T> hit(nr, zero);
186 std::vector<T> rhs(nt);
187 for (std::size_t a = 0; a < nt; ++a) {
188 rhs[a] = -p0[transStates[a]];
189 if (rhs[a] != zero) anyT =
true;
193 const std::vector<T> sojourn = transient_sojourn(rhs);
194 for (std::size_t b = 0; b < nr; ++b) {
196 for (std::size_t a = 0; a < nt; ++a) acc += sojourn[a] * Q_ta(a, b);
201 for (std::size_t k = 0; k < nr; ++k) hit[k] += p0[recStates[k]];
203 for (std::size_t cr : recSccIds) {
204 const std::vector<std::size_t>& idx = s.
members[cr];
206 for (std::size_t a : idx) reach += hit[recPos[a]];
207 if (reach < rtol)
continue;
208 if (idx.size() == 1) {
211 if (pirec[cr].empty()) pirec[cr] =
ctmc_solve(detail::submatrix(Q, idx));
212 const std::vector<T>& pi_c = pirec[cr];
213 for (std::size_t k = 0; k < idx.size(); ++k) piv[idx[k]] = pi_c[k] * reach;
221 for (std::size_t c = 0; c < numSCC; ++c) {
222 std::vector<T> p0(N, zero);
224 for (std::size_t a : s.
members[c]) p0[a] = w;
225 for (std::size_t j = 0; j < N; ++j) r.
pi0(c, j) = p0[j];
226 const std::vector<T> piv = absorb_limiting(p0);
227 for (std::size_t j = 0; j < N; ++j) r.
pis(c, j) = piv[j];
230 r.
pi.assign(N, zero);
234 std::vector<T> pinl(numSCC, one);
236 for (std::size_t j = 0; j < N; ++j) {
238 for (std::size_t i = 0; i < N; ++i) cs +=
num_abs(T(Q(i, j)));
239 if (cs < ztol) pinl[s.
scc[j] - 1] = zero;
242 for (
const T& v : pinl) tot += v;
244 for (T& v : pinl) v /= tot;
246 for (std::size_t c = 0; c < numSCC; ++c)
249 for (std::size_t c = 0; c < numSCC; ++c) {
250 if (!(pinl[c] > zero))
continue;
251 for (std::size_t j = 0; j < N; ++j) r.
pi[j] += r.
pis(c, j) * pinl[c];
253 if (transSccIds.size() == 1)
254 for (std::size_t j = 0; j < N; ++j) r.
pi[j] = r.
pis(transSccIds[0], j);
260 std::vector<T> p0 = pin;
262 for (
const T& v : p0) tot0 += v;
264 for (T& v : p0) v /= tot0;
265 r.
pi = absorb_limiting(p0);
269 for (
const T& v : r.
pi) tot += v;
271 for (T& v : r.
pi) v /= tot;
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.
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.