LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pfqn_procomom.m
1%{
2%{
3 % @file pfqn_procomom.m
4 % @brief ProCoMoM algorithm for computing marginal queue-length probabilities.
5%}
6%}
7
8function [Pr,Q]=pfqn_procomom(L,N,Z,atol)
9%{
10%{
11 % @brief ProCoMoM algorithm for computing marginal queue-length probabilities.
12 % @fn pfqn_procomom(L, N, Z, atol)
13 % @param L Service demand matrix (M x R).
14 % @param N Population vector (1 x R).
15 % @param Z Think time vector (1 x R).
16 % @param atol Tolerance.
17 % @return Pr Marginal probability matrix (M x sumN+1), Pr(k,j+1) = P(n_k = j).
18 % @return Q Mean queue length vector (M x 1).
19%}
20%}
21if nargin<3 || isempty(Z)
22 Z=zeros(size(N));
23end
24if nargin<4
25 atol=1e-14;
26end
27[M,R]=size(L);
28sumN=sum(N);
29
30% rescale demands per class for numerical stability
31% normalized probabilities are invariant to per-class demand scaling
32Lmax=max(L,[],1);
33Lmax(Lmax<atol)=1;
34L=L./repmat(Lmax,M,1);
35Z=Z./Lmax;
36
37% build Dn basis: multichoose(R,M) with column R zeroed, sorted by nnzpos
38Dn=multichoose(R,M);
39Dn(:,R)=0;
40Dn=sortbynnzpos(Dn);
41numDn=size(Dn,1);
42basisSize=numDn*M;
43
44% solve with auto-perturbation on rank deficiency
45[Pr,rankdef]=solve_all(L,Z);
46if rankdef
47 % try progressively larger perturbations
48 rng(23000,'twister');
49 Lscale=max(abs(L(:)));
50 if Lscale<atol; Lscale=1; end
51 for delta_exp = [-10 -8 -6 -4]
52 delta=Lscale*10^delta_exp;
53 rng(23000,'twister');
54 Lp=L+delta*(1+rand(M,R));
55 Zp=Z+delta*(1+rand(1,R));
56 [Pr_try,rd]=solve_all(Lp,Zp);
57 if ~rd && all(Pr_try(:)>=-1e-6) && all(abs(sum(Pr_try,2)-1)<0.01)
58 Pr=Pr_try;
59 break;
60 end
61 Pr=Pr_try;
62 end
63end
64Q=Pr*(0:sumN)';
65
66 function [Pr,rankdef]=solve_all(Ls_in,Zs_in)
67 L_save=L; Z_save=Z;
68 L=Ls_in; Z=Zs_in;
69 Pr=zeros(M,sumN+1);
70 rankdef=false;
71 for station=1:M
72 Lrot=L;
73 Lrot([station M],:)=Lrot([M station],:);
74 [dist,rd]=solve_station(Lrot);
75 if rd
76 rankdef=true;
77 end
78 total=sum(dist);
79 if abs(total)>0
80 Pr(station,:)=dist/total;
81 end
82 end
83 L=L_save; Z=Z_save;
84 end
85
86 function [dist,rankdef]=solve_station(Ls)
87 rankdef=false;
88 % pk(:,j+1) holds basis coefficients for queue length n=j
89 pk=zeros(basisSize,sumN+1);
90 % pexact: for empty network, all stations have probability 1 at n=0
91 zero_dn=zeros(1,R);
92 for kk=1:M
93 pk(phash(zero_dn,kk),1)=1;
94 end
95 Ncur=zeros(1,R);
96 for r=1:R
97 for Nr=1:N(r)
98 Ncur(r)=Nr;
99 pklast=pk;
100 pk=zeros(basisSize,sumN+1);
101 [Ag,Bg,DCg,DDg]=genpmatrix(Ls,Ncur,r);
102 % SVD for rank-revealing decomposition
103 [U,S,V]=svd(Ag,0);
104 sv=diag(S);
105 tol=max(size(Ag))*eps(max(sv));
106 rk=sum(sv>tol);
107 if rk<basisSize
108 rankdef=true;
109 % use minimum-norm solution via truncated SVD
110 Ur=U(:,1:rk);
111 Vr=V(:,1:rk);
112 Si=diag(1./sv(1:rk));
113 pB=Vr*(Si*(Ur'*Bg));
114 pDC=Vr*(Si*(Ur'*DCg));
115 pDD=Vr*(Si*(Ur'*DDg));
116 sumNcur=sum(Ncur);
117 pk(:,1)=pB*pklast(:,1);
118 for n=1:sumNcur
119 pk(:,n+1)=pB*pklast(:,n+1)+n*pDC*pk(:,n)+n*pDD*pklast(:,n);
120 end
121 else
122 % full rank: use QR for speed and accuracy
123 [Qg,Rg]=qr(Ag,0);
124 QtB=Qg'*Bg;
125 QtDC=Qg'*DCg;
126 QtDD=Qg'*DDg;
127 sumNcur=sum(Ncur);
128 pk(:,1)=Rg\‍(QtB*pklast(:,1));
129 for n=1:sumNcur
130 rhs=QtB*pklast(:,n+1)+n*QtDC*pk(:,n)+n*QtDD*pklast(:,n);
131 pk(:,n+1)=Rg\rhs;
132 end
133 end
134 % rescale to prevent overflow
135 smax=max(abs(pk(:)));
136 if smax>0 && isfinite(smax)
137 pk=pk/smax;
138 end
139 end
140 end
141 % extract result: first basis element at zero Dn entry
142 dist=pk(phash(zero_dn,1),:);
143 end
144
145 function [A,B,DC,DD]=genpmatrix(Ls,Ncur,r)
146 numRows=countrows(r);
147 A=zeros(numRows,basisSize);
148 B=zeros(numRows,basisSize);
149 DC=zeros(numRows,basisSize);
150 DD=zeros(numRows,basisSize);
151 row=0;
152 for d=1:numDn
153 if r<=R-1 && sum(Dn(d,r:R-1))>0
154 % Branch A: propagation through class boundaries
155 for k=1:M
156 row=row+1;
157 colA=phash(Dn(d,:),k);
158 A(row,colA)=1;
159 if r+1<=R-1 && sum(Dn(d,r+1:R-1))>0
160 B(row,colA)=1;
161 else
162 shifted=Dn(d,:);
163 shifted(r)=shifted(r)-1;
164 colB=phash(shifted,k);
165 if colB>0 && colB<=basisSize
166 B(row,colB)=1;
167 end
168 end
169 end
170 else
171 % Branch B: CE, PC, and extra PC equations
172 if sum(Dn(d,1:r))<M
173 % CE equations: k=1..M-1
174 for k=1:M-1
175 row=row+1;
176 A(row,phash(Dn(d,:),k+1))=1;
177 A(row,phash(Dn(d,:),1))=-1;
178 for s=1:r-1
179 shifted=Dn(d,:);
180 shifted(s)=shifted(s)+1; % UP shift
181 col=phash(shifted,k+1);
182 if col>0 && col<=basisSize
183 A(row,col)=-Ls(k,s);
184 end
185 end
186 B(row,phash(Dn(d,:),k+1))=Ls(k,r);
187 end
188 % PC equations: s=1..r-1
189 for s=1:r-1
190 row=row+1;
191 nd_s=Ncur(s)-Dn(d,s);
192 A(row,phash(Dn(d,:),1))=nd_s;
193 shifted=Dn(d,:);
194 shifted(s)=shifted(s)+1; % UP shift
195 colBase=phash(shifted,1);
196 if colBase>0 && colBase<=basisSize
197 A(row,colBase)=-Z(s);
198 DC(row,colBase)=Ls(M,s);
199 end
200 for k=1:M-1
201 col=phash(shifted,k+1);
202 if col>0 && col<=basisSize
203 A(row,col)=-Ls(k,s);
204 end
205 end
206 end
207 end
208 % Extra PC for class r (always in Branch B)
209 row=row+1;
210 nd_r=Ncur(r)-Dn(d,r);
211 A(row,phash(Dn(d,:),1))=nd_r;
212 B(row,phash(Dn(d,:),1))=Z(r);
213 for k=1:M-1
214 B(row,phash(Dn(d,:),k+1))=Ls(k,r);
215 end
216 DD(row,phash(Dn(d,:),1))=Ls(M,r);
217 end
218 end
219 end
220
221 function numRows=countrows(r)
222 numRows=0;
223 for d=1:numDn
224 if r<=R-1 && sum(Dn(d,r:R-1))>0
225 numRows=numRows+M;
226 else
227 if sum(Dn(d,1:r))<M
228 numRows=numRows+M+r-1;
229 else
230 numRows=numRows+1;
231 end
232 end
233 end
234 end
235
236 function col=phash(dn,i)
237 pos=matchrow(Dn,dn);
238 if pos<0
239 col=-1;
240 return;
241 end
242 col=(pos-1)*M+i;
243 end
244
245 function I=sortbynnzpos(I)
246 for ii=1:size(I,1)-1
247 for jj=ii+1:size(I,1)
248 if nnzcmp(I(ii,:),I(jj,:))==1
249 v=I(ii,:);
250 I(ii,:)=I(jj,:);
251 I(jj,:)=v;
252 end
253 end
254 end
255 end
256
257 function r=nnzcmp(i1,i2)
258 nnz1=nnz(i1);
259 nnz2=nnz(i2);
260 if nnz1>nnz2
261 r=1;
262 elseif nnz1<nnz2
263 r=0;
264 else
265 for jj=1:length(i1)
266 if i1(jj)==0 && i2(jj)>0
267 r=1;
268 return
269 elseif i1(jj)>0 && i2(jj)==0
270 r=0;
271 return
272 end
273 end
274 r=0;
275 end
276 end
277
278end