1% [masses, iniF, KF, cloF, iniB, KB, cloB] = SecondOrderLevelDependentFluidSolve (Q, R, S, T, boundaryL, boundaryU, Qt, prec)
3% * Q: cell of generators in the different layers/regimes
4% * R: cell of diagonal matrices of fluid rates in the different layers/regimes
5% * S: cell of diagonal matrices of fluid variances in the different layers/regimes
6% * T: vector of thresholds
7% * boundaryL/U: vector defining the lower and the upper boundary behavior
8% one item
for each state of the background process
9% =0: reflective boundary (
default)
10% =1: absorbing boundary
12% The performance measures (pdf, cdf, etc.) can be computed by the
13% LevelDependentFluidStationaryDistr function.
15function [masses, iniF, KF, cloF, iniB, KB, cloB] = SecondOrderLevelDependentFluidSolve (Q, R, S, T, boundaryL, boundaryU, Qt, prec)
20 if ~exist(
'prec',
'var')
23 if ~exist('boundaryL','var')
24 % zeros(1,N), not zeros(K,N): boundaryL/U
is ONE flag per background
25 % state (see the header above, "vector defining the lower and the upper
26 % boundary behavior"), and there
is a single lower and a single upper
27 % boundary rather than one per regime. All four use sites below index
28 % ix = 1:N with it, so a K x N default makes the logical mask larger
29 % than the array it indexes and the function crashed on its own defaults
30 % for every K >= 2 -- that
is, for every genuinely multi-regime model.
31 % K == 1 survived by accident, zeros(1,N) being the correct shape there.
32 boundaryL = zeros(1,N);
34 if ~exist('boundaryU','var')
35 boundaryU = boundaryL;
37 if ~exist('Qt','var') || isempty(Qt)
72 ix0 = ix(abs(diag(R{k}))<=prec & diag(S{k})<=prec);
73 ixn0 = setdiff(ix,ix0);
78 Qnn = Q{k}(ixn0,ixn0);
80 Qv = Qnn + Qn0*inv(-Q00)*Q0n;
86 % partition the state space according to zero, positive and negative fluid rates
88 ixp = ix(diag(Rv)>prec & diag(Sv)<=prec);
89 ixn = ix(diag(Rv)<-prec & diag(Sv)<=prec);
90 ixs = ix(diag(Sv)>prec);
97 % obtain
"c" constant to transform matrix equations to QBD like matrix
99 c1 = max(-diag(Qv(ixp,ixp))./diag(Rv(ixp,ixp)));
100 discr = (diag(Rv(ixs,ixs)).^2 - 2*diag(2*Sv(ixs,ixs)).*diag(Qv(ixs,ixs)));
101 c2 = max((discr>0).*((-diag(Rv(ixs,ixs))+sqrt(discr))./diag(2*Sv(ixs,ixs))));
105 NbF(k) = length(ixbF);
107 Bm = blkdiag(c*Sv(ixbF,ixbF),-Rv(ixn,ixn));
108 Lm = [-Rv(ixbF,ixbF)-2*c*Sv(ixbF,ixbF),zeros(NbF(k),Nn(k));Qv(ixn,ixbF)/c,Qv(ixn,ixn)/c+Rv(ixn,ixn)];
109 Fm = [Qv(ixbF,ixbF)/c+c*Sv(ixbF,ixbF)+Rv(ixbF,ixbF),Qv(ixbF,ixn)/c;zeros(Nn(k),NbF(k)+Nn(k))];
111 % Solve QBD
for matrix R
112 [~, QBDR] = QBD_CR(Bm, Lm, Fm);
114 % extract K and Psi from the solution
115 KF{k} = (QBDR(1:NbF(k),1:NbF(k)) - eye(NbF(k))) * c;
116 PsiF = QBDR(1:NbF(k),NbF(k)+1:end);
118 % closing matrix of the stationary density of the fluid level
120 clovF = zeros(NbF(k),NbF(k)+Nn(k));
121 clovF(:,ixbF) = eye(NbF(k));
124 cloF{k} = zeros(NbF(k),N);
125 cloF{k}(:,ixn0) = clovF;
126 cloF{k}(:,ix0) = clovF*Qn0*inv(-Q00);
128 % BACKWARD parameters
130 % obtain
"c" constant to transform matrix equations to QBD like matrix
131 % quadratic equations
132 c1 = max(-diag(Qv(ixn,ixn))./diag(-Rv(ixn,ixn)));
133 discr = (diag(Rv(ixs,ixs)).^2 - 2*diag(2*Sv(ixs,ixs)).*diag(Qv(ixs,ixs)));
134 c2 = max((discr>0).*((diag(Rv(ixs,ixs))+sqrt(discr))./diag(2*Sv(ixs,ixs))));
138 NbB(k) = length(ixbB);
140 Bm = blkdiag(c*Sv(ixbB,ixbB),Rv(ixp,ixp));
141 Lm = [Rv(ixbB,ixbB)-2*c*Sv(ixbB,ixbB),zeros(NbB(k),Np(k));Qv(ixp,ixbB)/c,Qv(ixp,ixp)/c-Rv(ixp,ixp)];
142 Fm = [Qv(ixbB,ixbB)/c+c*Sv(ixbB,ixbB)-Rv(ixbB,ixbB),Qv(ixbB,ixp)/c;zeros(Np(k),NbB(k)+Np(k))];
144 % Solve QBD
for matrix R
145 [~, QBDR] = QBD_CR(Bm, Lm, Fm);
147 % extract K and Psi from the solution
148 KB{k} = (QBDR(1:NbB(k),1:NbB(k)) - eye(NbB(k))) * c;
149 PsiB = QBDR(1:NbB(k),NbB(k)+1:end);
151 % closing matrix of the stationary density of the fluid level
152 clovB = zeros(NbB(k),NbB(k)+Np(k));
153 clovB(:,ixbB) = eye(NbB(k));
156 cloB{k} = zeros(NbB(k),N);
157 cloB{k}(:,ixn0) = clovB;
158 cloB{k}(:,ix0) = clovB*Qn0*inv(-Q00);
164 vixsn{k} = ixn0(diag(Sv)>prec & diag(Rv)<0);
165 vixsp{k} = ixn0(diag(Sv)>prec & diag(Rv)>=0);
166 vixs0{k} = ixn0(diag(Sv)>prec & diag(Rv)==0);
172 % Construct and solve linear set of equations
for the unknows (probability
173 % masses and density parameters iniF and iniB
for all regimes)
174 % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
175 Neqns = (K+1)*N + sum(Np) + sum(Nn) + 2*sum(Ns);
178 M = sparse(Neqns,Neqns);
184 pos = [pos, N, NbF(k), NbB(k)];
189 % equalities
for flux conservation
191 M(pp(i):pp(i)+N-1,k*N+1:(k+1)*N) = -Qt{k+1};
193 M(pp(i-2):pp(i-2)+NbF(k)-1,k*N+1:(k+1)*N) = expm(KF{k}*(T(k+1)-T(k)))*(-cloF{k}*R{k} + KF{k}*cloF{k}*S{k});
194 M(pp(i-1):pp(i-1)+NbB(k)-1,k*N+1:(k+1)*N) = -cloB{k}*R{k} - KB{k}*cloB{k}*S{k};
197 M(pp(i+1):pp(i+1)+NbF(k+1)-1,k*N+1:(k+1)*N) = cloF{k+1}*R{k+1}-KF{k+1}*cloF{k+1}*S{k+1};
198 M(pp(i+2):pp(i+2)+NbB(k+1)-1,k*N+1:(k+1)*N) = expm(KB{k+1}*(T(k+2)-T(k+1)))*(cloB{k+1}*R{k+1} + KB{k+1}*cloB{k+1}*S{k+1});
209 % mass
is zero in positive and in reflective states
210 ixr0 = intersect(ix(boundaryL==0), vixs{1});
212 ms0 = zeros(N,Np(1)+Nr0);
213 ms0([vixp{1},ixr0],:) = eye(Np(1)+Nr0);
214 M(pp(i):pp(i)+N-1,col:col+Np(1)+Nr0-1) = ms0;
215 col = col + Np(1)+Nr0;
216 % density
is zero in absorbing states
217 ixa0 = intersect(ix(boundaryL==1), vixs{1});
220 pdfB = expm(KB{1}*T(2))*cloB{1};
221 M(pp(i+1):pp(i+1)+NbF(k+1)-1,col:col+Na0-1) = pdfF(:,ixa0);
222 M(pp(i+2):pp(i+2)+NbB(k+1)-1,col:col+Na0-1) = pdfB(:,ixa0);
225 % mass
is zero in negative and in reflective states
226 ixrB = intersect(ix(boundaryU==0), vixs{K});
228 ms0 = zeros(N,Nn(K)+NrB);
229 ms0([vixn{K},ixrB],:) = eye(Nn(K)+NrB);
230 M(pp(i):pp(i)+N-1,col:col+Nn(K)+NrB-1) = ms0;
231 col = col + Nn(K)+NrB;
232 % density
is zero in absorbing states
233 ixaB = intersect(ix(boundaryU==1), vixs{K});
235 pdfF = expm(KF{K}*(T(K+1)-T(K)))*cloF{K};
237 M(pp(i-2):pp(i-2)+NbF(k)-1,col:col+NaB-1) = pdfF(:,ixaB);
238 M(pp(i-1):pp(i-1)+NbB(k)-1,col:col+NaB-1) = pdfB(:,ixaB);
241 % there
is no mass except S+(k) U S-(k+1)
242 st0 = setdiff(ix, union(intersect(vixp{k},vixn{k+1}),
union(vix0{k},vix0{k+1})));
245 ms0(st0,:) = eye(N0);
246 M(pp(i):pp(i)+N-1,col:col+N0-1) = ms0;
248 % equations
for the second-order states
249 sts = setdiff(
union(vixs{k},vixs{k+1}),
union(vixn{k+1},vixp{k}));
251 BelowF = expm(KF{k}*(T(k+1)-T(k)))*-cloF{k}*sqrt(S{k});
252 BelowB = -cloB{k}*sqrt(S{k});
253 AboveF = cloF{k+1}*sqrt(S{k+1});
254 AboveB = expm(KB{k+1}*(T(k+2)-T(k+1)))*cloB{k+1}*sqrt(S{k+1});
255 M(pp(i-2):pp(i-2)+NbF(k)-1,col:col+Nss-1) = BelowF(:,sts);
256 M(pp(i-1):pp(i-1)+NbB(k)-1,col:col+Nss-1) = BelowB(:,sts);
257 M(pp(i+1):pp(i+1)+NbF(k+1)-1,col:col+Nss-1) = AboveF(:,sts);
258 M(pp(i+2):pp(i+2)+NbB(k+1)-1,col:col+Nss-1) = AboveB(:,sts);
264 %
this function computes the integral of a matrix exponential from 0 to
265 % L
if it has a 0 eigenvalue hence can not be inverted
266 function KAi = integExp(KA,L)
270 KAi = inv(-(KA-r*l)) *(eye(size(KA,1))-expm((KA-r*l)*L)) + r*l*(L+exp(-L)-1);
273 %
this function receives two matrices and calculates the integrals of
274 % the matrix exponentials
if exactly one of them has a 0 eigenvalue
275 function [KAi,KBi] = integExp2(KA,KB,L)
276 if min(abs(eig(KA))) > min(abs(eig(KB)))
277 KAi = inv(-KA)*(eye(size(KA,1))-expm(KA*L));
278 KBi = integExp(KB, L);
280 KAi = integExp(KA, L);
281 KBi = inv(-KB)*(eye(size(KB,1))-expm(KB*L));
285 % normalizing condition
289 [sumKF, sumKB] = integExp2(KF{k}, KB{k}, T(k+1)-T(k));
290 h = [h; sum(sumKF*cloF{k},2); sum(sumKB*cloB{k},2); ones(N,1)];
291 Mi{k} = [sum(sumKF*cloF{k},2); sum(sumKB*cloB{k},2)];
294 % solve linear system
296 b = [1,zeros(1,length(h)-1)]/M;
305 iniF{k} = b(pp(i):pp(i)+NbF(k)-1);
306 iniB{k} = b(pp(i+1):pp(i+1)+NbB(k)-1);
307 masses{k+1} = b(pp(i+2):pp(i+2)+N-1);