LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
ht.m
1function [nonfjmodel, fjclassmap, fjforkmap, fj_auxiliary_delays] = ht(model)
2 % Transforms the queueing network containing a FJ subsystem into a queueing network without one.
3 % Fork node replaced by routers
4 % One artificial class is created for each parallel branch and for each class
5 % Join node replaced by delay
6 % We add another delay to model the sojourn time of the original classes.
7 % ---
8 % This approach is derived by PHILIP HEIDELBERGER and KISHOR S. TRIVEDI in
9 % "Analytic Queueing Models for Programs with Internal Concurrency"
10 sn = model.getStruct;
11 fjclassmap = []; % s = fjclassmap(r) for auxiliary class r gives the index s of the original class
12 fjforkmap = []; % f = fjforkmap(r) for auxiliary class r gives the associated fork node f
13 nonfjmodel = model.copy();
14 nonfjmodel.allowReplace = true;
15 P = nonfjmodel.getLinkedRoutingMatrix;
16 nonfjmodel.resetNetwork(true);
17 nonfjmodel.resetStruct();
18 Vnodes = cellsum(sn.nodevisits);
19 forkedClasses = {};
20 forkIndexes = find(sn.nodetype == NodeType.Fork)';
21 fj_auxiliary_delays = {}; % d = fj_auxiliary_delays{j} for join j gives the additional delay d to mimic the sojourn time of the original classes
22
23 %% Replace each fork with a router
24 for f=forkIndexes
25 nonfjmodel.nodes{f} = Router(nonfjmodel, nonfjmodel.nodes{f}.name);
26 forkedClasses{f,1} = find(Vnodes(f,:)>0);
27 end
28
29 %% Replace each join with a delay
30 for j=find(sn.nodetype == NodeType.Join)'
31 nonfjmodel.nodes{j} = Delay(nonfjmodel, nonfjmodel.nodes{j}.name);
32 nonfjmodel.stations{model.nodes{j}.stationIndex} = nonfjmodel.nodes{j};
33 for c=1:length(nonfjmodel.classes)
34 nonfjmodel.nodes{j}.setService(nonfjmodel.classes{c},Immediate());
35 end
36
37 %% Add another delay to mimic the sojourn time of the original classes for the artificial classes
38 new_delay = Delay(nonfjmodel, ['Auxiliary Delay - ', nonfjmodel.nodes{j}.name]);
39 fj_auxiliary_delays{j} = new_delay.index;
40 for r=1:length(nonfjmodel.classes)
41 new_delay.setService(nonfjmodel.classes{r}, Immediate());
42 end
43 for r=1:size(P, 1)
44 for s=1:size(P, 2)
45 P{r, s}(new_delay.index, :) = P{r,s}(j, :);
46 P{r, s}(:, new_delay.index) = 0.0;
47 end
48 P{r, r}(j, :) = 0.0;
49 P{r, r}(j, new_delay.index) = 1.0;
50 end
51 end
52
53 % nonfjmodel.stations={nonfjmodel.stations{1:model.getNumberOfStations}}'; % remove automatically added station and put it where the join was
54 nonfjmodel.connections = zeros(length(nonfjmodel.nodes));
55 %% Create the auxiliary classes
56 for f=forkIndexes
57 joinIdx = find(sn.fj(f,:));
58 if length(joinIdx)>1
59 line_error(mfilename,'SolverMVA supports at present only a single join station per fork node.');
60 end
61 forkedChains = find(sum(sn.chains(:,forkedClasses{f}),2));
62 for fc=forkedChains'
63 aux_classes = {}; % aux = aux_classes{r, par} gives the auxiliary class created for original class r and parallel branch par
64 inchain = find(sn.chains(fc,:)); inchain = inchain(:)';
65 for r=inchain
66 if sn.nodevisits{fc}(f,r) == 0
67 continue;
68 end
69 parallel_branches = length(model.nodes{f}.output.outputStrategy{r}{3}); % Assumption: every class forks into exactly the same parallel branches
70 for par=1:parallel_branches % One auxiliary class for each parallel branch
71 if model.nodes{f}.output.tasksPerLink > 1
72 line_error(mfilename, 'Multiple tasks per link are not supported in H-T.');
73 end
74 if isa(model.classes{r},'OpenClass')
75 line_error(mfilename, 'H-T method can be used only on closed models.');
76 end
77 aux_population = model.nodes{f}.output.tasksPerLink * model.classes{r}.population;
78 aux_classes{r, par} = ClosedClass(nonfjmodel, [nonfjmodel.classes{r}.name,'.',nonfjmodel.nodes{f}.name, '.B', int2str(par)], aux_population, nonfjmodel.nodes{fj_auxiliary_delays{joinIdx}}, 0);
79 fjclassmap(aux_classes{r, par}.index) = nonfjmodel.classes{r}.index;
80 fjforkmap(aux_classes{r, par}.index) = f;
81 % Set the service rates at the join node and at the stations
82 for i=1:sn.nnodes
83 if sn.isstation(i)
84 switch sn.nodetype(i)
85 case NodeType.Join
86 nonfjmodel.nodes{i}.setService(aux_classes{r, par},Immediate());
87 case {NodeType.Source, NodeType.Fork}
88 %no-op
89 otherwise
90 nonfjmodel.nodes{i}.setService(aux_classes{r, par},model.nodes{i}.getService(model.classes{r}).copy());
91 end
92 end
93 end
94 nonfjmodel.nodes{fj_auxiliary_delays{joinIdx}}.setService(aux_classes{r, par}, Immediate());
95 end
96 end
97
98 % Set the routing of the artificial classes
99 for r=inchain
100 if sn.nodevisits{fc}(f,r) == 0
101 continue;
102 end
103 parallel_branches = length(model.nodes{f}.output.outputStrategy{r}{3});
104 for s=inchain
105 if sn.nodevisits{fc}(f,s) == 0
106 continue;
107 end
108 for par=1:parallel_branches
109 P{aux_classes{r, par}, aux_classes{s, par}} = P{r, s};
110 P{aux_classes{r, par}, aux_classes{s, par}}(f, :) = 0.0;
111 P{aux_classes{r, par}, aux_classes{s, par}}(f, model.nodes{f}.output.outputStrategy{r}{3}{par}{1}.index) = 1.0;
112 P{aux_classes{r, par}, aux_classes{s, par}}(joinIdx, fj_auxiliary_delays{joinIdx}) = 1.0;
113 P{aux_classes{r, par}, aux_classes{s, par}}(fj_auxiliary_delays{joinIdx}, :) = 0.0;
114 P{aux_classes{r, par}, aux_classes{s, par}}(fj_auxiliary_delays{joinIdx}, f) = 1.0;
115 end
116 % Route the original classes straight to the join to avoid the interference with the artificial classes
117 P{r,s}(f, :) = 0.0;
118 P{r,s}(f, joinIdx) = 1.0;
119 end
120 end
121 end
122 end
123 nonfjmodel.relink(P);
124 % snPrintRoutingMatrix(nonfjmodel.getStruct)
125 % nonfjmodel.jsimgView
126end
Definition mmt.m:92