LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_amvald.m
1function [Q,U,R,T,C,X,lG,totiter] = solver_amvald(sn, Lchain,STchain,Vchain,alpha,Nchain,SCVchain,refstatchain, options)
2totiter = 0;
3max_totiter = min(options.iter_max, 10000); % Hard cap for stability
4
5M = sn.nstations;
6K = sn.nchains;
7Nt = sum(Nchain(isfinite(Nchain)));
8delta = (Nt - 1) / Nt;
9deltaclass = (Nchain - 1) ./ Nchain;
10deltaclass(isinf(Nchain)) = 1;
11tol = options.iter_tol;
12nservers = sn.nservers;
13schedparam = sn.schedparam;
14lldscaling = sn.lldscaling;
15cdscaling = sn.cdscaling;
16sched = sn.sched;
17classprio = sn.classprio;
18
19Uchain = zeros(M,K);
20Tchain = zeros(M,K);
21Cchain_s = zeros(1,K);
22% Initialized so an early wall-clock timeout (options.timeout) that breaks before
23% any forward evaluation still yields a valid empty result instead of erroring.
24Wchain = zeros(M,K);
25Rchain = zeros(M,K);
26STeff = STchain;
27
28%% initialize Q,X, U
29Qchain = options.init_sol;
30if ~isempty(Qchain) && ~isequal(size(Qchain), [M K])
31 % stale warm-start hint from a different station/chain basis
32 Qchain = [];
33end
34if isempty(Qchain)
35 % balanced initialization
36 Qchain = ones(M,K);
37 Qchain = Qchain ./ repmat(sum(Qchain,1),size(Qchain,1),1) .* repmat(Nchain,size(Qchain,1),1);
38 Qchain(isinf(Qchain))=0; % open classes
39 for r=find(isinf(Nchain)) % open classes
40 Qchain(refstatchain(r),r)=0;
41 end
42end
43
44nnzclasses = find(Nchain>0);
45Xchain = 1./sum(STchain,1);
46for r=find(isinf(Nchain)) % open classes
47 if STchain(refstatchain(r),r) > 0
48 Xchain(r) = 1 ./ STchain(refstatchain(r),r);
49 else
50 % Open chain with no arrivals (e.g. Disabled source arrival): the
51 % throughput is 0, not 1/0 = Inf. An Inf here poisons the FCFS
52 % utilization renormalization below and zeroes the utilization of
53 % the other, active open classes.
54 Xchain(r) = 0;
55 end
56end
57
58for k=1:M
59 for r=nnzclasses
60 if isinf(nservers(k)) % infinite server
61 Uchain(k,r) = Vchain(k,r)*STchain(k,r)*Xchain(r);
62 else
63 Uchain(k,r) = Vchain(k,r)*STchain(k,r)*Xchain(r)/nservers(k);
64 end
65 end
66end
67
68switch options.method
69 case {'lin','qdlin'}
70 gamma = zeros(K,M,K); % class-based customer fraction corrections
71 tau = zeros(K,K); % throughput difference
72 otherwise
73 gamma = zeros(K,M); % total customer fraction corrections
74 tau = zeros(K,K); % throughput difference
75end
76
77%% main loop
78omicron = 0.5; % under-relaxation parameter
79outer_iter = 0;
80while (outer_iter < 2 || max(max(abs(Qchain-QchainOuter_1))) > tol) && outer_iter < sqrt(options.iter_max) && totiter <= max_totiter && ~lineTimeoutExceeded(options)
81 outer_iter = outer_iter + 1;
82 QchainOuter_1 = Qchain;
83 XchainOuter_1 = Xchain;
84 UchainOuter_1 = Uchain;
85
86 if isfinite(Nt) && Nt>0
87 switch options.method
88 %case {'aql','qdaql'}
89 %line_error(mfilename,'AQL is currently disabled in SolverMVA, please use the SolverJMT implementation (method jmva.aql).');
90 case {'lin','qdlin'}
91 % iteration at population N-1_s
92 for s=1:K
93 if isfinite(Nchain(s)) % don't recur on open classes
94 iter_s = 0;
95 Nchain_s = oner(Nchain,s);
96 Qchain_s = Qchain * (Nt-1)/Nt;
97 Xchain_s = Xchain * (Nt-1)/Nt;
98 Uchain_s = Uchain * (Nt-1)/Nt;
99 while (iter_s < 2 || max(max(abs(Qchain_s-Qchain_s_1))) > tol) && iter_s <= sqrt(options.iter_max) && ~lineTimeoutExceeded(options)
100 iter_s = iter_s + 1;
101
102 Qchain_s_1 = Qchain_s;
103 Xchain_s_1 = Xchain_s;
104 Uchain_s_1 = Uchain_s;
105
106 [Wchain_s, STeff_s] = solver_amvald_forward(M, K, nservers, schedparam, lldscaling, cdscaling, sched, classprio, gamma, tau, Qchain_s_1, Xchain_s_1, Uchain_s_1, STchain, Vchain, Nchain_s, SCVchain, options);
107 totiter = totiter + 1;
108 if totiter >= max_totiter
109 break
110 end
111
112 %% update other metrics
113 for r=nnzclasses
114 if sum(Wchain_s(:,r)) == 0
115 Xchain_s(r) = 0;
116 else
117 if isinf(Nchain_s(r))
118 Cchain_s(r) = Vchain(:,r)' * Wchain_s(:,r);
119 % X(r) remains constant
120 elseif Nchain(r)==0
121 Xchain_s(r) = 0;
122 Cchain_s(r) = 0;
123 else
124 Cchain_s(r) = Vchain(:,r)' * Wchain_s(:,r);
125 Xchain_s(r) = omicron * Nchain_s(r) / Cchain_s(r) + (1-omicron) * Xchain_s_1(r);
126 end
127 end
128 for k=1:M
129 Rchain_s(k,r) = Vchain(k,r) * Wchain_s(k,r);
130 Qchain_s(k,r) = omicron * Xchain_s(r) * Vchain(k,r) * Wchain_s(k,r) + (1-omicron) * Qchain_s_1(k,r);
131 Tchain_s(k,r) = Xchain_s(r) * Vchain(k,r);
132 Uchain_s(k,r) = omicron * Vchain(k,r) * STeff_s(k,r) * Xchain_s(r) + (1-omicron) * Uchain_s_1(k,r);
133 end
134 end
135 end
136
137 switch options.method
138 case {'lin'}
139 for k=1:M
140 for r=nnzclasses
141 if ~isinf(Nchain(r)) && Nchain_s(r)>0
142 gamma(s,k,r) = Qchain_s_1(k,r)./Nchain_s(r) - QchainOuter_1(k,r)./Nchain(r);
143 end
144 end
145 end
146 otherwise
147 for k=1:M
148 gamma(s,k) = sum(Qchain_s_1(k,:),2)/(Nt-1) - sum(QchainOuter_1(k,:),2)/Nt;
149 end
150 end
151
152 for r=nnzclasses
153 tau(s,r) = Xchain_s_1(r) - XchainOuter_1(r); % save throughput for priority AMVA
154 end
155 end
156 % Check if iteration limit exceeded (break out of for s loop)
157 if totiter >= max_totiter
158 break
159 end
160 end
161 end
162 end
163 % Check if iteration limit exceeded (break out of outer while loop)
164 if totiter >= max_totiter
165 break
166 end
167
168 iter = 0;
169 % iteration at population N
170 while (iter < 2 || max(max(abs(Qchain-Qchain_1))) > tol) && iter <= sqrt(options.iter_max) && ~lineTimeoutExceeded(options)
171 iter = iter + 1;
172
173 Qchain_1 = Qchain;
174 Xchain_1 = Xchain;
175 Uchain_1 = Uchain;
176
177 [Wchain, STeff] = solver_amvald_forward(M, K, nservers, schedparam, lldscaling, cdscaling, sched, classprio, gamma, tau, Qchain_1, Xchain_1, Uchain_1, STchain, Vchain, Nchain, SCVchain, options);
178 totiter = totiter + 1;
179 if totiter >= max_totiter
180 break
181 end
182
183
184 %% update other metrics
185 for r=nnzclasses
186 if sum(Wchain(:,r)) == 0
187 Xchain(r) = 0;
188 else
189 if isinf(Nchain(r))
190 Cchain_s(r) = Vchain(:,r)'*Wchain(:,r);
191 % X(r) remains constant
192 elseif Nchain(r)==0
193 Xchain(r) = 0;
194 Cchain_s(r) = 0;
195 else
196 Cchain_s(r) = Vchain(:,r)'*Wchain(:,r);
197 Xchain(r) = omicron * Nchain(r) / Cchain_s(r) + (1-omicron) *Xchain_1(r);
198 end
199 end
200 for k=1:M
201 Rchain(k,r) = Vchain(k,r) * Wchain(k,r);
202 Qchain(k,r) = omicron * Xchain(r) * Vchain(k,r) * Wchain(k,r) + (1-omicron) * Qchain_1(k,r);
203 Tchain(k,r) = Xchain(r) * Vchain(k,r);
204 Uchain(k,r) = omicron * Vchain(k,r) * STeff(k,r) * Xchain(r) + (1-omicron) * Uchain_1(k,r);
205 end
206 end
207 end
208end
209
210
211% the next block is a coarse approximation for LD and CD, would need
212% cdterm and qterm in it but these are hidden within the iteration calls
213for k=1:M
214 for r=1:K
215 if Vchain(k,r) * STeff(k,r) >0
216 switch sn.sched(k)
217 case {SchedStrategy.FCFS, SchedStrategy.SIRO, SchedStrategy.PS, SchedStrategy.LCFSPR, SchedStrategy.DPS, SchedStrategy.HOL}
218 if sum(Uchain(k,:))>1
219 Uchain(k,r) = min(1,sum(Uchain(k,:))) * Vchain(k,r) * STeff(k,r) * Xchain(r) / ((Vchain(k,:) .* STeff(k,:)) * Xchain(:));
220 end
221 end
222 end
223 end
224end
225
226Rchain = Qchain./Tchain;
227Xchain(~isfinite(Xchain))=0;
228Uchain(~isfinite(Uchain))=0;
229%Qchain(~isfinite(Qchain))=0;
230Rchain(~isfinite(Rchain))=0;
231
232Xchain(Nchain==0)=0;
233Uchain(:,Nchain==0)=0;
234%Qchain(:,Nchain==0)=0;
235Rchain(:,Nchain==0)=0;
236Tchain(:,Nchain==0)=0;
237
238if isempty(sn.lldscaling) && isempty(sn.cdscaling)
239 [Q,U,R,T,C,X] = sn_deaggregate_chain_results(sn, Lchain, [], STchain, Vchain, alpha, [], [], Rchain, Tchain, [], Xchain);
240else
241 [Q,U,R,T,C,X] = sn_deaggregate_chain_results(sn, Lchain, [], STchain, Vchain, alpha, [], Uchain, Rchain, Tchain, [], Xchain);
242end
243
244% Stations with limited class dependence report utilization as T*S/peak,
245% where peak is the user-declared peak rate scaling per class
246% (sn.cdscalingpeak), matching the T*S/c convention of ordinary multiserver
247% stations.
248if ~isempty(sn.cdscaling) && ~any(isinf(sn.njobs))
249 Kcls = sn.nclasses; % U and rates are class-indexed; K here counts chains
250 for ist=1:M
251 if length(sn.cdscaling) >= ist && ~isempty(sn.cdscaling{ist})
252 for k=1:Kcls
253 bmax = sn.cdscalingpeak(ist,k);
254 if isfinite(sn.rates(ist,k)) && sn.rates(ist,k) > 0 && bmax > 0
255 U(ist,k) = T(ist,k) / sn.rates(ist,k) / bmax;
256 else
257 U(ist,k) = 0;
258 end
259 end
260 end
261 end
262end
263
264% estimate normalizing constant for closed classes
265ccl = isfinite(Nchain);
266Nclosed = Nchain(ccl);
267Xclosed = Xchain(ccl);
268lG = - Nclosed(Xclosed>options.tol) * log(Xclosed(Xclosed>options.tol))'; % asymptotic approximation
269end
Definition Station.m:245