LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
ctmc_courtois.m
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)
4% -- Input
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
8% -- Output
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
17
18%% INIT
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.
24v=[];
25nMacroStates = size(MS,1); % Number of macro-states
26%% REARRANGE INFINITESIMAL GENERATOR ACCORDING TO THE MACROSTATES
27
28for n=1:nMacroStates
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
31end
32Qperm=Q(v,v); % reorder according to the new macro-states
33Qdec=Qperm;
34procRows=0; %processed rows
35for i = 1:size(MS,1) % for each macro-state
36 if procRows >0
37 Qdec((procRows + 1):(procRows + length(MS{i})),1:procRows)=0;
38 end
39 Qdec((procRows + 1):(procRows + length(MS{i})),(procRows + length(MS{i})+1):end)=0;
40 procRows = procRows + length(MS{i});
41end
42% now make each substochastic diagonal block a stochastic matrix
43Qdec=ctmc_makeinfgen(Qdec);
44
45%% COMPUTE NCD ERROR INDEX
46epsC=Qperm-Qdec;
47epsC=0;
48C=epsC;
49eps=1;
50
51% apply randomization
52if nargin==2
53 q=(1.05*max(max(abs(Qperm))));
54end
55
56P=ctmc_randomization(Qperm,q);
57A=P;
58procRows=0; %processed rows
59for i = 1:nMacroStates % for each macro-state
60 if procRows >0
61 A((procRows + 1):(procRows + length(MS{i})),1:procRows)=0;
62 end
63 A((procRows + 1):(procRows + length(MS{i})),(procRows + length(MS{i})+1):end)=0;
64 procRows = procRows + length(MS{i});
65end
66B=P-A;
67% see _kb/03-api-layer.md (mc/ additions) for the row-sum-vs-column-sum rationale
68eps=max(sum(B,2));
69%% COMPUTE epsMAX
70% see _kb/03-api-layer.md (mc/ additions) -- eps/epsMAX always computed, not nargout-gated
71if true
72procRows=0; %processed rows
73for i = 1:size(MS,1) % for each macro-state
74 for j=1:length(MS{i})
75 pos=j;
76 A(procRows+j,procRows+pos)=1-(sum(A(procRows+j,setdiff((procRows+1):(procRows+length(MS{i})),(procRows+pos)))));
77 end
78 procRows = procRows + length(MS{i});
79end
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}))))));
84 if length(e)>1
85 eigMS(i)=e(end-1); % take the second largest eigvalues of the block
86 else
87 eigMS(i)=0; % skip if there is no second eigenvalue
88 end
89 procRows = procRows + length(MS{i});
90end
91epsMAX=(1-max(eigMS))/2;
92else
93 epsMAX=0; % was epsMax, a typo that never assigned the declared output
94end
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});
102end
103
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
110 if i~=j
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}))));
113 end
114 end
115 procCols = procCols + length(MS{j});
116 end
117 procRows = procRows + length(MS{i});
118end
119for i = 1:nMacroStates % for each source macro-state
120 G(i,i)=1-sum(G(i,:));
121end
122pMacro=dtmc_solve(G);
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});
127end
128%% OUTPUT
129for i=1:length(v)
130pout(v(i))=p(i);
131end
132p=pout;
133