LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
ctmc_relsolve.m
1%{ @file ctmc_relsolve.m
2 % @brief Computes the equilibrium distribution relative to a reference state
3 %
4 % @author LINE Development Team
5%}
6
7%{
8 % @brief Computes the equilibrium distribution relative to a reference state
9 %
10 % @details
11 % Solves the global balance equations with the normalization condition p(refstate) = 1.
12 %
13 % @par Syntax:
14 % @code
15 % p = ctmc_relsolve(Q)
16 % [p, Q, nConnComp, connComp] = ctmc_relsolve(Q, refstate)
17 % [p, Q, nConnComp, connComp] = ctmc_relsolve(Q, refstate, options)
18 % @endcode
19 %
20 % @par Parameters:
21 % <table>
22 % <tr><th>Name<th>Description
23 % <tr><td>Q<td>Infinitesimal generator matrix
24 % <tr><td>refstate<td>(Optional) Index of the reference state (default: 1)
25 % <tr><td>options<td>(Optional) Solver options
26 % </table>
27 %
28 % @par Returns:
29 % <table>
30 % <tr><th>Name<th>Description
31 % <tr><td>p<td>Relative equilibrium distribution vector
32 % <tr><td>Q<td>Processed generator matrix
33 % <tr><td>nConnComp<td>Number of connected components
34 % <tr><td>connComp<td>Component assignment vector
35 % </table>
36%}
37function [p, Q, nConnComp, connComp]=ctmc_relsolve(Q,refstate,options)
38
39if nargin<2
40 refstate = 1;
41end
42
43if length(Q) > 6000 && (nargin==1 || ~options.force)
44 fprintf(1,'ctmc_solve: the order of Q is greater than 6000, i.e., %d elements. Press key to continue.',length(Q));
45 pause;
46end
47
48if size(Q)==1
49 p = 1;
50 return
51end
52
53Q = ctmc_makeinfgen(Q); % so that spurious diagonal elements are set to 0
54n = length(Q);
55
56if issym(Q)
57 symvariables = symvar(Q); % find all symbolic variables
58 B = double(subs(Q+Q',symvariables,ones(size(symvariables)))); % replace all symbolic variables with 1.0
59else
60 B = abs(Q+Q')>0;
61end
62[nConnComp, connComp] = weaklyconncomp(B);
63
64if nConnComp > 1
65 % reducible generator - solve each component recursively
66 if issym(Q)
67 p = sym(zeros(1,n));
68 else
69 p = zeros(1,n);
70 end
71 for c=1:nConnComp
72 Qc = Q(connComp==c,connComp==c);
73 Qc = ctmc_makeinfgen(Qc);
74 p(connComp==c) = ctmc_solve(Qc);
75 end
76 p = p /sum(p);
77 return
78end
79
80if all(Q==0)
81 p = ones(1,n)/n;
82 return
83end
84p = zeros(1,n);
85b = zeros(n,1);
86
87nnzel = 1:n;
88Qnnz = Q; bnnz = b;
89Qnnz_1 = Qnnz; bnnz_1 = bnnz;
90
91isReducible = false;
92goon = true;
93while goon
94
95 %
96 % zerorow=find(sum(abs(Qnnz),2)==0);
97 % if length(zerorow)>=1
98 % if nargin==1 || options.verbose
99 % %warning('ctmc_solve: the infinitesimal generator is reducible (zero row)');
100 % fprintf(1,'ctmc_solve: the infinitesimal generator is reducible.\n');
101 % isReducible = true;
102 % end
103 % end
104 % nnzrow = setdiff(nnzel, zerorow);
105 %
106 % zerocol=find(sum(abs(Qnnz),1)==0);
107 % nnzcol = setdiff(nnzel, zerocol);
108 % if length(zerocol)>=1
109 % if ~isReducible && (nargin==1 || options.verbose)
110 % %warning('ctmc_solve: the infinitesimal generator is reducible (zero column)');
111 % fprintf(1,'ctmc_solve: the infinitesimal generator is reducible.\n');
112 % end
113 % end
114 % nnzel = intersect(nnzrow, nnzcol);
115
116 nnzel = find(sum(abs(Qnnz),1)~=0 & sum(abs(Qnnz),2)'~=0);
117 if length(nnzel) < n && ~isReducible
118 isReducible = true;
119 if (nargin > 1 && options.verbose == 2) % debug
120 fprintf(1,'ctmc_solve: the infinitesimal generator is reducible.\n');
121 end
122 end
123 Qnnz = Qnnz(nnzel, nnzel);
124 bnnz = bnnz(nnzel);
125 Qnnz = ctmc_makeinfgen(Qnnz);
126 if all(size(Qnnz_1(:)) == size(Qnnz(:))) && all(size(bnnz_1(:)) == size(bnnz(:)))
127 goon = false;
128 else
129 Qnnz_1 = Qnnz; bnnz_1 = bnnz; nnzel = 1:length(Qnnz);
130 end
131end
132
133if isempty(Qnnz)
134 p = ones(1,n)/n;
135 return
136end
137Qnnz(:,end) = 0;
138Qnnz(refstate,end) = 1;
139bnnz(end) = 1;
140
141if ~isdeployed
142 if issym(Q)
143 p = sym(p);
144 end
145end
146
147if nargin == 1
148 p(nnzel)=Qnnz'\ bnnz;
149else
150 switch options.method
151 case 'gpu'
152 try
153 gQnnz = gpuArray(Qnnz');
154 gbnnz = gpuArray(bnnz);
155 pGPU = gQnnz \ gbnnz;
156 gathered_pGPU = gather(pGPU);
157 p(nnzel) = gathered_pGPU; % transfer from GPU to local env
158 catch
159 warning('ctmc_solve: GPU either not available or execution failed. Switching to default method.');
160 p(nnzel) = Qnnz'\ bnnz;
161 end
162 otherwise
163 p(nnzel)=Qnnz'\ bnnz;
164 end
165end
166
167if issym(Q)
168 Q=simplify(Q);
169end
170
171end