1function [p,Qperm,Qdec,eps,epsMAX,
P,B,C,q]=ctmc_courtois(Q,MS,q)
2% CTMC_COURTOIS - Courtois decomposition
3% [p,Qperm,Qdec,eps,epsMAX,
P,B,C,q] = CTMC_COURTOIS(Q,MS)
5% Q : infinitesimal generator matrix
6% MS : cell array where MS{i}
is the set of rows of Q in macrostate i
7% q : (optional) randomization coefficient
9% p : approximate steady-state probability vector
10% Qperm : Q reordered according to macrostates
11% Qdec : infinitesimal generator for the macrostates
12%
P : probability matrix obtained from Qperm with randomization
13% B : part of
P not modelled by decomposition
14% eps : nearly-complete decomposability (NCD) index
15% epsMAX : max acceptable value for eps (otherwise Q
is not NCD)
16% q : randomization coefficient
19% The randomization coefficient q
is derived below, once Qperm
is available,
20% because it depends on Qperm. It must be a valid uniformization rate
21% (q >= max|q_ii|) or
P=I+Qperm/q
is not stochastic; 1.05*max|Qperm| exceeds
22% max|q_ii| strictly, which also keeps
P aperiodic. An
explicit q (nargin==3)
23% overrides the derived value.
25nMacroStates = size(MS,1); % Number of macro-states
26%% REARRANGE INFINITESIMAL GENERATOR ACCORDING TO THE MACROSTATES
29 v=[v,MS{n}(:)
']; % force a row: a column MS{n} made v a matrix, and
30 % length(v) then truncated the output p silently
32Qperm=Q(v,v); % reorder according to the new macro-states
34procRows=0; %processed rows
35for i = 1:size(MS,1) % for each macro-state
37 Qdec((procRows + 1):(procRows + length(MS{i})),1:procRows)=0;
39 Qdec((procRows + 1):(procRows + length(MS{i})),(procRows + length(MS{i})+1):end)=0;
40 procRows = procRows + length(MS{i});
42% now make each substochastic diagonal block a stochastic matrix
43Qdec=ctmc_makeinfgen(Qdec);
45%% COMPUTE NCD ERROR INDEX
53 q=(1.05*max(max(abs(Qperm))));
56P=ctmc_randomization(Qperm,q);
58procRows=0; %processed rows
59for i = 1:nMacroStates % for each macro-state
61 A((procRows + 1):(procRows + length(MS{i})),1:procRows)=0;
63 A((procRows + 1):(procRows + length(MS{i})),(procRows + length(MS{i})+1):end)=0;
64 procRows = procRows + length(MS{i});
67% see _kb/03-api-layer.md (mc/ additions) for the row-sum-vs-column-sum rationale
70% see _kb/03-api-layer.md (mc/ additions) -- eps/epsMAX always computed, not nargout-gated
72procRows=0; %processed rows
73for i = 1:size(MS,1) % for each macro-state
76 A(procRows+j,procRows+pos)=1-(sum(A(procRows+j,setdiff((procRows+1):(procRows+length(MS{i})),(procRows+pos)))));
78 procRows = procRows + length(MS{i});
80eigMS = zeros(1,size(MS,1));
81procRows=0; %processed rows
82for i=1:size(MS,1) % for each macro-state
83 e=sort(abs(eig(A((procRows + 1):(procRows + length(MS{i})),(procRows + 1):(procRows + length(MS{i}))))));
85 eigMS(i)=e(end-1); % take the second largest eigvalues of the block
87 eigMS(i)=0; % skip if there is no second eigenvalue
89 procRows = procRows + length(MS{i});
91epsMAX=(1-max(eigMS))/2;
93 epsMAX=0; % was epsMax, a typo that never assigned the declared output
95%% COMPUTE MICROPROBABILITIES
96procRows=0; %processed rows
97pmicro=zeros(size(Q,1),1);
98for i = 1:nMacroStates % for each macro-state
99 Qmicrostate=Qdec((procRows + 1):(procRows + length(MS{i})),(procRows + 1):(procRows + length(MS{i})));
100 pmicro((procRows + 1):(procRows + length(MS{i})),1)=ctmc_solve_reducible(Qmicrostate);
101 procRows = procRows + length(MS{i});
104%% COMPUTE MACROPROBABILITIES
105G=zeros(nMacroStates,nMacroStates);
106procRows=0; %processed rows
107for i = 1:nMacroStates % for each source macro-state
108 procCols=0; %processed cols
109 for j = 1:nMacroStates % for dest macro-state
111 for iState=1:length(MS{i})
112 G(i,j)=G(i,j)+pmicro(procRows+iState)*sum(P(procRows+iState,(procCols+1):(procCols+length(MS{j}))));
115 procCols = procCols + length(MS{j});
117 procRows = procRows + length(MS{i});
119for i = 1:nMacroStates % for each source macro-state
120 G(i,i)=1-sum(G(i,:));
123procRows=0; %processed rows
124for i = 1:nMacroStates % for each source macro-state
125 p((procRows+1):(procRows+length(MS{i})))=pMacro(i)*pmicro((procRows+1):(procRows+length(MS{i})));
126 procRows = procRows + length(MS{i});