2 % @brief Equilibrium distribution of the continuous-time Markov chain
4 % @author LINE Development Team
8 % @brief Equilibrium distribution of the continuous-time Markov chain
11 % Calculates the equilibrium distribution of a continuous-time Markov chain given its infinitesimal generator matrix.
16 % [p, Q, nConnComp, connComp] = ctmc_solve(Q, options)
21 % <tr><th>Name<th>Description
22 % <tr><td>Q<td>Infinitesimal generator matrix of the continuous-time Markov chain
23 % <tr><td>options<td>(Optional) Solver options (method: 'gpu' or default, force: boolean, verbose: 2 for debug)
28 % <tr><th>Name<th>Description
29 % <tr><td>p<td>Equilibrium distribution vector
30 % <tr><td>Q<td>Processed generator matrix (e.g., after removing spurious zeros)
31 % <tr><td>nConnComp<td>Number of connected components found (if reducible)
32 % <tr><td>connComp<td>Vector assigning each state to a connected component
37 % Q = [-0.5, 0.5; 0.2, -0.2];
41function [p, Q, nConnComp, connComp]=ctmc_solve(Q,options)
43if length(Q) > 6000 && (nargin==1 || ~options.force)
44 %
do not
switch to line_printf to force printout
45 fprintf(1,
'The order of Q is greater than 6000, i.e., %d elements. Press key to continue.\n',length(Q));
52 connComp = 1:length(Q);
56Q = ctmc_makeinfgen(Q); % so that spurious diagonal elements are set to 0
60 symvariables = symvar(Q); % find all symbolic variables
61 B = double(subs(Q+Q
',symvariables,ones(size(symvariables)))); % replace all symbolic variables with 1.0
65[nConnComp, connComp] = weaklyconncomp(B);
67 % reducible generator - solve each component recursively
68 line_warning(mfilename,'Reducible generator. No initial vector available, decomposing and solving each component recursively.\n');
76 Qc = Q(connComp==c,connComp==c);
77 Qc = ctmc_makeinfgen(Qc);
78 p(connComp==c) = ctmc_solve(Qc);
93Qnnz_1 = Qnnz; bnnz_1 = bnnz;
98 nnzel = find(sum(abs(Qnnz),1)~=0 & sum(abs(Qnnz),2)'~=0);
99 if length(nnzel) < n && ~isReducible
101 if (nargin > 1 && options.verbose == 2) % debug
102 line_warning(mfilename,'The infinitesimal generator
is reducible.\n');
105 Qnnz = Qnnz(nnzel, nnzel);
107 Qnnz = ctmc_makeinfgen(Qnnz);
108 if all(size(Qnnz_1(:)) == size(Qnnz(:))) && all(size(bnnz_1(:)) == size(bnnz(:)))
111 Qnnz_1 = Qnnz; bnnz_1 = bnnz; nnzel = 1:length(Qnnz);
130warning('off','MATLAB:singularMatrix');
132 p(nnzel)=Qnnz'\ bnnz;
134 % verify if this has become reducible
136 symvariables = symvar(Qnnz); % find all symbolic variables
137 B =
double(subs(Qnnz+Qnnz',symvariables,ones(size(symvariables)))); % replace all symbolic variables with 1.0
139 B = abs(Qnnz+Qnnz')>0;
141 [nConnComp, connComp] = weaklyconncomp(B);
143 % reducible generator - solve each component recursively
145 p(nnzel) = sym(zeros(1,n));
147 p(nnzel) = zeros(1,n);
151 Qc = Q(connComp==c,connComp==c);
152 Qc = ctmc_makeinfgen(Qc);
153 p(intersect(find(connComp==c),nnzel)) = ctmc_solve(Qc);
160 switch options.method
163 gQnnz = gpuArray(Qnnz');
164 gbnnz = gpuArray(bnnz);
165 pGPU = gQnnz \ gbnnz;
166 gathered_pGPU = gather(pGPU);
167 p(nnzel) = gathered_pGPU; % transfer from GPU to local env
169 warning('ctmc_solve: GPU either not available or execution failed. Switching to default method.');
170 p(nnzel) = Qnnz'\ bnnz;
173 p(nnzel)=Qnnz'\ bnnz;
180warning('on','MATLAB:singularMatrix');