LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
refreshRoutingMatrix.m
1function [rt, rtfun, rtnodes, sn] = refreshRoutingMatrix(self, rates)
2% [RT, RTFUN, CSMASK, RTNODES, SN] = REFRESHROUTINGMATRIX(RATES)
3%
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6
7sn = self.sn;
8if nargin == 1
9 if isempty(sn)
10 line_error(mfilename,'refreshRoutingMatrix cannot retrieve station rates, pass them as an input parameters.');
11 else
12 rates = sn.rates;
13 end
14end
15M = sn.nnodes;
16K = sn.nclasses;
17arvRates = zeros(1,K);
18stateful = find(sn.isstateful)';
19
20indSource = find(sn.nodetype == NodeType.Source);
21indOpenClasses = find(sn.njobs == Inf);
22for r = indOpenClasses
23 arvRates(r) = rates(sn.nodeToStation(indSource),r);
24end
25
26[rt, rtnodes, linksmat, chains] = self.getRoutingMatrix(arvRates);
27sn = self.sn;
28sn.chains = chains;
29
30if self.enableChecks
31 for r=1:K
32 if all(sn.routing(:,r) == -1)
33 line_error(mfilename,sprintf('Routing strategy in class %d is unspecified at all nodes.',r));
34 end
35 end
36end
37
38isStateDep = any(sn.isstatedep(:,3));
39
40rnodefuncell = cell(M*K,M*K);
41
42if isStateDep
43 for ind=1:M % from
44 for jnd=1:M % to
45 for r=1:K
46 for s=1:K
47 if sn.isstatedep(ind,3)
48 switch sn.routing(ind,r)
49 case RoutingStrategy.RROBIN
50 rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(state_before, state_after) sub_rr(ind, jnd, r, s, linksmat, state_before, state_after);
51 case RoutingStrategy.WRROBIN
52 rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(state_before, state_after) sub_wrr(ind, jnd, r, s, linksmat, state_before, state_after);
53 case RoutingStrategy.JSQ
54 rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(state_before, state_after) sub_jsq(ind, jnd, r, s, linksmat, state_before, state_after);
55 case RoutingStrategy.RL
56 rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(state_before, state_after) sub_rl(ind, jnd, r, s, linksmat, state_before, state_after);
57 otherwise
58 rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(~,~) rtnodes((ind-1)*K+r, (jnd-1)*K+s);
59 end
60 else
61 rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(~,~) rtnodes((ind-1)*K+r, (jnd-1)*K+s);
62 end
63 end
64 end
65 end
66 end
67end
68
69statefulNodesClasses = [];
70for ind=getIndexStatefulNodes(self)
71 statefulNodesClasses(end+1:end+K)= ((ind-1)*K+1):(ind*K);
72end
73
74% we now generate the node routing matrix for the given state and then
75% lump the states for non-stateful nodes so that run gives the routing
76% table for stateful nodes only
77statefulNodesClasses = [];
78for ind=stateful
79 statefulNodesClasses(end+1:end+K)= ((ind-1)*K+1):(ind*K);
80end
81
82if isStateDep
83 rtfunraw = @(state_before, state_after) dtmc_stochcomp(cell2mat(cellfun(@(f) f(state_before, state_after), rnodefuncell,'UniformOutput',false)), statefulNodesClasses);
84 rtfun = rtfunraw;
85 %rtfun = memoize(rtfunraw); % memoize to reduce the number of stoch comp calls
86 %rtfun.CacheSize = 6000^2;
87else
88 rtfun = @(state_before, state_after) dtmc_stochcomp(rtnodes, statefulNodesClasses);
89end
90
91nchains = size(chains,1);
92inchain = cell(1,nchains);
93for c=1:nchains
94 inchain{c} = find(chains(c,:));
95end
96
97sn.rt = rt;
98sn.rtnodes = rtnodes;
99%sn.rtorig = RoutingMatrix.rtnodes2rtorig(sn); %% causes issues to
100%JLINE.from_line_links in convering example_closedModel_6
101sn.rtfun = rtfun;
102sn.chains = chains;
103sn.nchains = nchains;
104sn.inchain = inchain;
105for c=1:sn.nchains
106 if range(sn.refstat(inchain{c}))>0
107 line_error(mfilename,sprintf('Classes within chain %d (classes: %s) have different reference stations.',c,mat2str(find(sn.chains(c,:)))));
108 end
109end
110self.sn = sn;
111
112 function p = sub_rr(ind, jnd, r, s, linksmat, state_before, state_after)
113 % P = SUB_RR(IND, JND, R, S, LINKSMAT, STATE_BEFORE, STATE_AFTER)
114
115 R = self.sn.nclasses;
116 isf = self.sn.nodeToStateful(ind);
117 if isempty(state_before{isf})
118 p = min(linksmat(ind,jnd),1);
119 else
120 if r==s
121 p = double(state_after{isf}(end-R+r)==jnd);
122 else
123 p = 0;
124 end
125 end
126 end
127
128 function p = sub_wrr(ind, jnd, r, s, linksmat, state_before, state_after)
129 % P = SUB_WRR(IND, JND, R, S, LINKSMAT, STATE_BEFORE, STATE_AFTER)
130
131 R = self.sn.nclasses;
132 isf = self.sn.nodeToStateful(ind);
133 if isempty(state_before{isf})
134 p = min(linksmat(ind,jnd),1);
135 else
136 if r==s
137 p = double(state_after{isf}(end-R+r)==jnd);
138 else
139 p = 0;
140 end
141 end
142 end
143
144 function p = sub_jsq(ind, jnd, r, s, linksmat, state_before, state_after) %#ok<INUSD>
145 % P = SUB_JSQ(IND, JND, R, S, LINKSMAT, STATE_BEFORE, STATE_AFTER) %#OK<INUSD>
146
147 isf = self.sn.nodeToStateful(ind);
148 if isempty(state_before{isf})
149 p = min(linksmat(ind,jnd),1);
150 else
151 if r==s
152 n = Inf*ones(1,self.sn.nnodes);
153 for knd=1:self.sn.nnodes
154 if linksmat(ind,knd)
155 ksf = self.sn.nodeToStateful(knd);
156 n(knd) = State.toMarginal(self.sn, knd, state_before{ksf});
157 end
158 end
159 if n(jnd) == min(n)
160 p = 1 / sum(n == min(n));
161 else
162 p = 0;
163 end
164 else
165 p = 0;
166 end
167 end
168 end
169
170
171 function p = sub_rl(ind, jnd, r, s, linksmat, state_before, state_after) %#ok<INUSD>
172 % P = SUB_RL(IND, JND, R, S, LINKSMAT, STATE_BEFORE, STATE_AFTER) %#OK<INUSD>
173
174 isf = self.sn.nodeToStateful(ind);
175 if isempty(state_before{isf})
176 p = min(linksmat(ind,jnd),1);
177 else
178 if r==s
179 % ----- new added contents ----- %
180 if self.nodes{ind}.output.outputStrategy{1,r}{5}==0 % state_size=0, use tabular value fn
181 if r~=1
182 line_error(mfilename,'no support for multiple classes');
183 end
184 value_function = self.nodes{ind}.output.outputStrategy{1,r}{3};
185 nodes_need_action = self.nodes{ind}.output.outputStrategy{1,r}{4};
186
187 if ~isempty(find(nodes_need_action==ind, 1))
188 indQueue = find(self.sn.nodetype == NodeType.Queue);
189 v = Inf*ones(1, self.sn.nnodes); % value fn
190 n = Inf*ones(1, self.sn.nnodes); % queue length
191 x = zeros(1, length(indQueue)); % current state
192 for knd_idx=1:length(indQueue)
193 knd = indQueue(knd_idx);
194 ksf = self.sn.nodeToStateful(knd); %% does the state removes the job from the departure node already?
195 x(knd_idx) = State.toMarginal(self.sn, knd, state_before{ksf});
196 end
197
198 for knd = 1:self.sn.nnodes
199 if linksmat(ind, knd)
200 tmp = x+1;
201 tmp(indQueue == knd) = tmp(indQueue == knd) + 1;
202 if max(tmp) <= size(value_function, 1)
203 ttmp = num2cell(tmp);
204 v(knd) = value_function(ttmp{:});
205 end
206 ksf = self.sn.nodeToStateful(knd);
207 n(knd) = State.toMarginal(self.sn, knd, state_before{ksf});
208 end
209 end
210
211 if min(v) < Inf && max(x+1) < size(value_function, 1) % in action space
212 if v(jnd) == min(v)
213 p = 1 / sum(v == min(v));
214 else
215 p = 0;
216 end
217 else % not in action space, use JSQ
218 if n(jnd) == min(n)
219 p = 1 / sum(n == min(n));
220 else
221 p = 0;
222 end
223 end
224
225 else % not in nodes_need_action: this node doesn't use RL results, use JSQ
226 n = Inf*ones(1,self.sn.nnodes);
227 for knd=1:self.sn.nnodes
228 if linksmat(ind,knd)
229 ksf = self.sn.nodeToStateful(knd);
230 n(knd) = State.toMarginal(self.sn, knd, state_before{ksf});
231 end
232 end
233 if n(jnd) == min(n)
234 p = 1 / sum(n == min(n));
235 else
236 p = 0;
237 end
238 end
239
240 elseif self.nodes{ind}.output.outputStrategy{1,r}{5}>0 % state_size>0, use fn approx for value fn
241 if r~=1
242 line_error(mfilename,'no support for multiple classes');
243 end
244 coeff = self.nodes{ind}.output.outputStrategy{1,r}{3};
245 nodes_need_action = self.nodes{ind}.output.outputStrategy{1,r}{4};
246 stateSize = self.nodes{ind}.output.outputStrategy{1,r}{5};
247
248 if ~isempty(find(nodes_need_action==ind, 1))
249 indQueue = find(self.sn.nodetype == NodeType.Queue);
250 v = Inf*ones(1, self.sn.nnodes); % value fn
251 n = Inf*ones(1, self.sn.nnodes); % queue length
252 x = zeros(1, length(indQueue)); % current state
253 for knd_idx=1:length(indQueue)
254 knd = indQueue(knd_idx);
255 ksf = self.sn.nodeToStateful(knd); %% does the state removes the job from the departure node already?
256 x(knd_idx) = State.toMarginal(self.sn, knd, state_before{ksf});
257 end
258 for knd = 1:self.sn.nnodes
259 if linksmat(ind, knd)
260 tmp = x;
261 tmp(indQueue == knd) = tmp(indQueue == knd) + 1;
262
263 tmp_vec = [1 tmp];
264 for i = 1:length(tmp)
265 for j = i:length(tmp)
266 tmp_vec(end+1) = tmp(i)* tmp(j);
267 end
268 end
269 v(knd) = tmp_vec * coeff.';
270
271 ksf = self.sn.nodeToStateful(knd);
272 n(knd) = State.toMarginal(self.sn, knd, state_before{ksf});
273 end
274 end
275 if min(v) < Inf && max(x+1) < stateSize % in action space
276 if v(jnd) == min(v)
277 p = 1 / sum(v == min(v));
278 else
279 p = 0;
280 end
281 else % not in action space, use JSQ
282 if n(jnd) == min(n)
283 p = 1 / sum(n == min(n));
284 else
285 p = 0;
286 end
287 end
288 else % not in nodes_need_action: this node doesn't use RL results, use JSQ
289 n = Inf*ones(1,self.sn.nnodes);
290 for knd=1:self.sn.nnodes
291 if linksmat(ind,knd)
292 ksf = self.sn.nodeToStateful(knd);
293 n(knd) = State.toMarginal(self.sn, knd, state_before{ksf});
294 end
295 end
296 if n(jnd) == min(n)
297 p = 1 / sum(n == min(n));
298 else
299 p = 0;
300 end
301 end
302
303 else % no value fn, use JSQ
304 % ----- end of new added contents ----- %
305
306 n = Inf*ones(1,self.sn.nnodes);
307 for knd=1:self.sn.nnodes
308 if linksmat(ind,knd)
309 ksf = self.sn.nodeToStateful(knd);
310 n(knd) = State.toMarginal(self.sn, knd, state_before{ksf});
311 end
312 end
313 if n(jnd) == min(n)
314 p = 1 / sum(n == min(n));
315 else
316 p = 0;
317 end
318 end
319 else
320 p = 0;
321 end
322 end
323 end
324
325end
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360% function [rt, rtfun, rtnodes, sn] = refreshRoutingMatrix(self, rates)
361% % [RT, RTFUN, CSMASK, RTNODES, SN] = REFRESHROUTINGMATRIX(RATES)
362% %
363% % Copyright (c) 2012-2026, Imperial College London
364% % All rights reserved.
365%
366% sn = self.sn;
367% if nargin == 1
368% if isempty(sn)
369% line_error(mfilename,'refreshRoutingMatrix cannot retrieve station rates, pass them as an input parameters.');
370% else
371% rates = sn.rates;
372% end
373% end
374% M = sn.nnodes;
375% K = sn.nclasses;
376% arvRates = zeros(1,K);
377% stateful = find(sn.isstateful)';
378%
379% indSource = find(sn.nodetype == NodeType.Source);
380% indOpenClasses = find(sn.njobs == Inf);
381% for r = indOpenClasses
382% arvRates(r) = rates(sn.nodeToStation(indSource),r);
383% end
384%
385% [rt, rtnodes, linksmat, chains] = self.getRoutingMatrix(arvRates);
386% sn = self.sn;
387% sn.chains = chains;
388%
389% if self.enableChecks
390% for r=1:K
391% if all(sn.routing(:,r) == -1)
392% line_error(mfilename,sprintf('Routing strategy in class %d is unspecified at all nodes.',r));
393% end
394% end
395% end
396%
397% isStateDep = any(sn.isstatedep(:,3));
398%
399% rnodefuncell = cell(M*K,M*K);
400%
401% if isStateDep
402% for ind=1:M % from
403% for jnd=1:M % to
404% for r=1:K
405% for s=1:K
406% if sn.isstatedep(ind,3)
407% switch sn.routing(ind,r)
408% case RoutingStrategy.RROBIN
409% rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(state_before, state_after) sub_rr(ind, jnd, r, s, linksmat, state_before, state_after);
410% case RoutingStrategy.WRROBIN
411% rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(state_before, state_after) sub_wrr(ind, jnd, r, s, linksmat, state_before, state_after);
412% case RoutingStrategy.JSQ
413% rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(state_before, state_after) sub_jsq(ind, jnd, r, s, linksmat, state_before, state_after);
414% otherwise
415% rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(~,~) rtnodes((ind-1)*K+r, (jnd-1)*K+s);
416% end
417% else
418% rnodefuncell{(ind-1)*K+r, (jnd-1)*K+s} = @(~,~) rtnodes((ind-1)*K+r, (jnd-1)*K+s);
419% end
420% end
421% end
422% end
423% end
424% end
425%
426% statefulNodesClasses = [];
427% for ind=getIndexStatefulNodes(self)
428% statefulNodesClasses(end+1:end+K)= ((ind-1)*K+1):(ind*K);
429% end
430%
431% % we now generate the node routing matrix for the given state and then
432% % lump the states for non-stateful nodes so that run gives the routing
433% % table for stateful nodes only
434% statefulNodesClasses = [];
435% for ind=stateful
436% statefulNodesClasses(end+1:end+K)= ((ind-1)*K+1):(ind*K);
437% end
438%
439% if isStateDep
440% rtfunraw = @(state_before, state_after) dtmc_stochcomp(cell2mat(cellfun(@(f) f(state_before, state_after), rnodefuncell,'UniformOutput',false)), statefulNodesClasses);
441% rtfun = rtfunraw;
442% %rtfun = memoize(rtfunraw); % memoize to reduce the number of stoch comp calls
443% %rtfun.CacheSize = 6000^2;
444% else
445% rtfun = @(state_before, state_after) dtmc_stochcomp(rtnodes, statefulNodesClasses);
446% end
447%
448% nchains = size(chains,1);
449% inchain = cell(1,nchains);
450% for c=1:nchains
451% inchain{c} = find(chains(c,:));
452% end
453%
454% sn.rt = rt;
455% sn.rtnodes = rtnodes;
456% sn.rtfun = rtfun;
457% sn.chains = chains;
458% sn.nchains = nchains;
459% sn.inchain = inchain;
460% for c=1:sn.nchains
461% if range(sn.refstat(inchain{c}))>0
462% line_error(mfilename,sprintf('Classes within chain %d (classes: %s) have different reference stations.',c,mat2str(find(sn.chains(c,:)))));
463% end
464% end
465% self.sn = sn;
466%
467% function p = sub_rr(ind, jnd, r, s, linksmat, state_before, state_after)
468% % P = SUB_RR(IND, JND, R, S, LINKSMAT, STATE_BEFORE, STATE_AFTER)
469%
470% R = sn.nclasses;
471% isf = sn.nodeToStateful(ind);
472% if isempty(state_before{isf})
473% p = min(linksmat(ind,jnd),1);
474% else
475% if r==s
476% p = double(state_after{isf}(end-R+r)==jnd);
477% else
478% p = 0;
479% end
480% end
481% end
482%
483% function p = sub_wrr(ind, jnd, r, s, linksmat, state_before, state_after)
484% % P = SUB_WRR(IND, JND, R, S, LINKSMAT, STATE_BEFORE, STATE_AFTER)
485%
486% R = sn.nclasses;
487% isf = sn.nodeToStateful(ind);
488% if isempty(state_before{isf})
489% p = min(linksmat(ind,jnd),1);
490% else
491% if r==s
492% p = double(state_after{isf}(end-R+r)==jnd);
493% else
494% p = 0;
495% end
496% end
497% end
498%
499% function p = sub_jsq(ind, jnd, r, s, linksmat, state_before, state_after) %#ok<INUSD>
500% % P = SUB_JSQ(IND, JND, R, S, LINKSMAT, STATE_BEFORE, STATE_AFTER) %#OK<INUSD>
501%
502% isf = sn.nodeToStateful(ind);
503% if isempty(state_before{isf})
504% p = min(linksmat(ind,jnd),1);
505% else
506% if r==s
507% n = Inf*ones(1,sn.nnodes);
508% for knd=1:sn.nnodes
509% if linksmat(ind,knd)
510% ksf = sn.nodeToStateful(knd);
511% n(knd) = State.toMarginal(sn, knd, state_before{ksf});
512% end
513% end
514% if n(jnd) == min(n)
515% p = 1 / sum(n == min(n));
516% else
517% p = 0;
518% end
519% else
520% p = 0;
521% end
522% end
523% end
524%
525% end
Definition mmt.m:92