5#ifndef LINE_API_MC_DTMC_SOLVE_REDUCIBLE_H
6#define LINE_API_MC_DTMC_SOLVE_REDUCIBLE_H
62 std::vector<std::size_t>
scc;
77 const std::size_t m = Pl.
rows();
81 std::vector<std::size_t>
tr, rec;
82 for (std::size_t i = 0; i < m; ++i) (isrec[i] ? rec :
tr).push_back(i);
85 for (std::size_t i : rec) PI(i, i) = one;
86 if (
tr.empty())
return PI;
89 "dtmc_solve_reducible: the chain has no recurrent component, so no limiting "
90 "distribution exists");
94 for (std::size_t a = 0; a <
tr.size(); ++a)
95 for (std::size_t b = 0; b <
tr.size(); ++b)
96 A(a, b) = (a == b ? one : zero) - Pl(
tr[a],
tr[b]);
98 const std::vector<std::size_t> piv =
lu_factor(LU);
99 for (std::size_t c = 0; c < rec.size(); ++c) {
100 std::vector<T> rhs(
tr.size());
101 for (std::size_t a = 0; a <
tr.size(); ++a) rhs[a] = Pl(
tr[a], rec[c]);
103 for (std::size_t a = 0; a <
tr.size(); ++a) PI(
tr[a], rec[c]) = rhs[a];
121 double zeroColTol = 1e-12) {
122 const std::size_t N = P.
rows();
123 if (P.
cols() != N)
throw InputError(
"dtmc_solve_reducible: transition matrix is not square");
124 if (!pin.empty() && pin.size() != N)
125 throw InputError(
"dtmc_solve_reducible: initial vector has the wrong length");
130 const std::size_t numSCC = s.
numSCC();
139 for (std::size_t j = 0; j < N; ++j) r.
pis(0, j) = r.
pi[j];
149 for (std::size_t i = 0; i < numSCC; ++i)
150 for (std::size_t j = 0; j < numSCC; ++j) {
151 if (i == j)
continue;
153 for (std::size_t a : s.
members[i])
154 for (std::size_t b : s.
members[j]) acc += P(a, b);
158 for (std::size_t i = 0; i < numSCC; ++i)
160 for (std::size_t j = 0; j < numSCC; ++j) Pl(i, j) = zero;
166 std::vector<T> pinl(numSCC, zero);
169 for (std::size_t i = 0; i < numSCC; ++i) pinl[i] = one;
170 for (std::size_t j = 0; j < N; ++j) {
172 for (std::size_t i = 0; i < N; ++i) cs += P(i, j);
173 if (cs < tol) pinl[s.
scc[j] - 1] = zero;
176 for (
const T& v : pinl) tot += v;
179 for (std::size_t i = 0; i < numSCC; ++i)
182 for (T& v : pinl) v /= tot;
185 for (std::size_t i = 0; i < numSCC; ++i) {
187 for (std::size_t a : s.
members[i]) acc += pin[a];
200 std::vector<std::vector<T>> within(numSCC);
201 for (std::size_t j = 0; j < numSCC; ++j)
207 r.
pi.assign(N, zero);
208 for (std::size_t i = 0; i < numSCC; ++i) {
210 for (std::size_t j = 0; j < numSCC; ++j) r.
pil(i, j) = PI(i, j);
211 for (std::size_t j = 0; j < numSCC; ++j) {
212 if (r.
pil(i, j) == zero)
continue;
213 for (std::size_t k = 0; k < s.
members[j].size(); ++k)
218 if (!(pinl[i] > zero))
continue;
219 for (std::size_t k = 0; k < N; ++k) r.
pi[k] += r.
pis(i, k) * pinl[i];
224 std::size_t nTrans = 0, transIdx = 0;
225 for (std::size_t i = 0; i < numSCC; ++i)
230 if (nTrans == 1 && pin.empty())
231 for (std::size_t k = 0; k < N; ++k) r.
pi[k] = r.
pis(transIdx, k);
NumericError(const std::string &what)
Normalize a non-negative matrix into a stochastic transition matrix.
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.
ReducibleResult< T > dtmc_solve_reducible(const Matrix< T > &P, const std::vector< T > &pin, double zeroColTol=1e-12)
Limiting distribution of a discrete-time Markov chain whose transition matrix may be reducible.
Matrix< T > dtmc_makestochastic(const Matrix< T > &Pin)
Normalize a non-negative matrix into a stochastic transition matrix.
SccResult stronglyconncomp(const Matrix< T > &A)
Strongly connected components of a directed graph, and which of them are recurrent (closed under the ...
std::vector< T > dtmc_solve(const Matrix< T > &P)
Stationary distribution of a stochastic matrix P.
void lu_solve(const Matrix< T > &LU, const std::vector< std::size_t > &piv, std::vector< T > &b)
Solve LUx = Pb in place on b, using the factors from lu_factor.
std::vector< std::size_t > lu_factor(Matrix< T > &A)
In-place LU of A (n x n).
Number-type abstraction for the templated API port.
Strongly connected components of a directed graph, and which of them are recurrent (closed under the ...
Matrix< T > pil
numSCC x numSCC, limiting vector of the lumped chain
Matrix< T > pis
numSCC x N, limiting vector per starting component
std::vector< T > pi
limiting distribution, length N
Matrix< T > pi0
numSCC x numSCC, the lumped starting vectors (empty if irreducible)
std::vector< bool > isrec
recurrence flag per component
Matrix< T > Pl
lumped chain
std::vector< std::size_t > scc
component index of each state, 1-based
std::size_t numSCC() const
std::vector< bool > recurrent
recurrent[c-1] is true when component c has no edge leaving it.
std::vector< std::size_t > scc
Component index of each state, 1-based as in MATLAB (0 is never used).
std::vector< std::vector< std::size_t > > members
Member states of each component, ascending.