LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pfqn_egflinearizer.m
1%{
2%{
3 % @file pfqn_egflinearizer.m
4 % @brief Extended generalized fixed-point Linearizer approximation.
5%}
6%}
7
8%{
9%{
10 % @brief Extended generalized fixed-point Linearizer approximation.
11 % @fn pfqn_egflinearizer(L, N, Z, type, tol, maxiter, alpha)
12 % @param L Service demand matrix.
13 % @param N Population vector.
14 % @param Z Think time vector.
15 % @param type Scheduling strategy type per station.
16 % @param tol Convergence tolerance (default: 1e-8).
17 % @param maxiter Maximum number of iterations (default: 1000).
18 % @param alpha Per-class scaling exponent vector.
19 % @return Q Mean queue lengths.
20 % @return U Utilization.
21 % @return W Waiting times.
22 % @return C Cycle times.
23 % @return X System throughput.
24 % @return totiter Total iterations performed.
25%}
26%}
27function [Q,U,W,C,X,totiter] = pfqn_egflinearizer(L,N,Z,type,tol,maxiter,alpha,QN0)
28% Single-server version of linearizer
29
30if nargin<8
31 QN0 = [];
32end
33if nargin<5
34 maxiter = 1000;
35end
36if nargin<4
37 tol = 1e-8;
38end
39
40[M,R]=size(L);
41if isempty(Z)
42 Z = zeros(1,R);
43end
44Z = sum(Z,1);
45if isempty(L) || all(max(L)==0)
46 X = N./Z;
47 Q = zeros(M,R);
48 U = zeros(M,R);
49 W = zeros(M,R);
50 C = zeros(1,R);
51 for r=1:R
52 for i=1:M
53 U(i,r) = X(r)*L(i,r);
54 end
55 end
56 totiter = 0;
57 return
58end
59
60% Initialize
61Q = zeros(M,R,1+R);
62Delta = zeros(M,R,R);
63for s=0:R
64 N_1 = oner(N,s);
65 if isempty(QN0)
66 [~,q] = pfqn_bs(L,N_1,Z);
67 else
68 % warm-start the Bard-Schweitzer initialization from the supplied Q
69 [~,q] = pfqn_bs(L,N_1,Z,tol,maxiter,QN0);
70 end
71 for r=1:R
72 Q(:,r,1+s) = q(:,r);
73 end
74end
75
76totiter = 0;
77% Main loop
78for I=1:3
79 for s=0:R
80 N_1 = oner(N,s); % for k=0 it just returns N
81 % Core(N_1)
82 [Q(:,:,1+s),~,~,iter] = Core(L,M,R,N_1,Z,Q(:,:,1+s),Delta,type,tol,maxiter-totiter,alpha);
83 totiter = totiter + iter;
84 end
85 % Update_Delta
86 for i=1:M
87 for r=1:R
88 if N(r)==1
89 % At population N-e_r only class r itself vanishes; the other
90 % classes keep the queue lengths Core just computed.
91 Q(i,r,1+r) = 0;
92 end
93 for s=1:R
94 Ns = oner(N,s);
95 if Ns(r) > 0
96 Delta(i,r,s) = Q(i,r,1+s)/Ns(r)^alpha(r) - Q(i,r,1+0)/N(r)^alpha(r);
97 else
98 % (N-e_s)_r = 0, i.e. r==s and N(r)==1: class r is absent at
99 % N-e_s, so F_ir(N-e_s) = 0 by the 0/0 convention of Chandy
100 % and Neuse (1982) eq (10). Their worked trace confirms it:
101 % D222 = 0 - L22(8,1)/1 = -1.
102 Delta(i,r,s) = -Q(i,r,1+0)/N(r)^alpha(r);
103 end
104 end
105 end
106 end
107end
108
109
110% Core(N)
111[Q,W,X,iter] = Core(L,M,R,N,Z,Q(:,:,1+0),Delta,type,tol,maxiter-totiter,alpha);
112totiter = totiter + iter;
113% Compute performance metrics
114U = zeros(M,R);
115for i=1:M
116 for r=1:R
117 U(i,r)=X(r)*L(i,r);
118 end
119end
120Q = Q(1:M,1:R,1+0);
121C = N./X-Z;
122end
123
124function [Q,W,T,iter] = Core(L,M,R,N_1,Z,Q,Delta,type,tol,maxiter,alpha)
125hasConverged = false;
126W = L;
127T = zeros(1,R);
128iter = 0;
129while ~hasConverged
130 Qlast = Q;
131 % Estimate population at
132 Q_1 = Estimate(L,M,R,N_1,Z,Q,Delta,W,alpha);
133 % Forward MVA
134 [Q,W,T] = ForwardMVA(L,M,R,type,N_1,Z,Q_1);
135 if enorm(Q-Qlast)<tol || iter > maxiter
136 hasConverged = true;
137 end
138 iter = iter + 1;
139end % it
140end
141
142function [Q_1,T_1] = Estimate(~,M,R,N_1,~,Q,Delta,~,alpha)
143Q_1 = zeros(M,R);
144T_1 = zeros(R,1+R);
145for i=1:M
146 for r=1:R
147 for s=1:R
148 Ns = oner(N_1,s);
149 % A class with no jobs at N_1 (or at N_1-e_s) has queue length 0
150 % there. Guarding this is required, not cosmetic: without it
151 % N_1(r)=0 divides by zero and oner returns a negative population
152 % (e.g. oner([0 2],1) = [-1 2]), so Q_1 becomes NaN for the empty
153 % class and poisons any Delta computed from this slice.
154 if N_1(r) <= 0 || Ns(r) <= 0
155 Q_1(i,r,1+s) = 0;
156 else
157 Q_1(i,r,1+s) = Ns(r)^alpha(r)*(Q(i,r,1+0)/N_1(r)^alpha(r) + Delta(i,r,s));
158 end
159 end
160 end
161end
162
163% This part is not used in Core so commented out
164% for r=1:R
165% Nr = oner(N_1,r);
166% for s=1:R
167% % initial guess based on balanced job bound
168% % helpful in case no stations with positive demand exists
169% T_1(s,1+r) = Nr(s) / (Z(s) + max(L(:,s))*(sum(Nr)-1));
170% for i=1:M
171% if W(i,s,1+0)>0
172% T_1(s,1+r) = Nr(s)*(Q(i,s)/N_1(s) + Delta(i,r,s))/W(i,s,1+0);
173% break;
174% end
175% end
176% end
177% end
178end
179
180function [Q,W,T] = ForwardMVA(L,M,R,type,N_1,Z,Q_1)
181W = zeros(M,R);
182T = zeros(1,R);
183Q = zeros(M,R);
184
185% Compute residence time
186% Note: The PS formula W = D*(1+sum(Q)) is used for all scheduling types.
187% The FCFS correction (W = D + sum_s D_s*Q_s) requires per-visit service
188% times S = D/V, but only demands D (= V*S) are available at the chain level.
189% Using D in place of S produces incorrect results when visit ratios differ
190% across chains (e.g., self-looping classes). Since for exponential FCFS the
191% per-visit response time equals the PS formula, this is the correct approach
192% for the chain-level linearizer.
193for ist=1:M
194 for r=1:R
195 W(ist,r) = L(ist,r)*(1+sum(Q_1(ist,:,1+r)));
196 end
197end
198
199% Compute throughputs and qlens
200for r=1:R
201 T(r) = N_1(r) / (Z(r)+sum(W(:,r)));
202 for ist=1:M
203 Q(ist,r) = T(r) * W(ist,r);
204 end
205end
206end
207
208
Definition Station.m:245