LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_fluid_closing.m
1function [QN, UN, RN, TN, xvec_it, QNt, UNt, TNt, xvec_t, t, iters, runtime] = solver_fluid_closing(sn, options)
2% [QN, UN, RN, TN, XVEC, QNt, UNt, TNt, XVEC_T, T, ITERS, RUNTIME] = SOLVER_FLUID_CLOSING(QN, OPTIONS)
3
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6chains = sn.chains;
7
8% inner iteration of fluid analysis
9[Q,xvec_it,QNt,UNt,xvec_t,t,iters,runtime] = solver_fluid(sn, options);
10
11%% assumes the existence of a delay node through which all classes pass
12delayNodes = zeros(1,sn.nstations);
13delayrefstat = zeros(1,sn.nstations); % delay nodes that are also reference nodes
14for i = 1:sn.nstations
15 if sn.sched(i) == SchedStrategy.INF
16 delayNodes(i) = 1;
17 end
18end
19for k = 1:sn.nclasses
20 if sn.refstat(k) > 0 % artificial classes do not need to have a reference node
21 delayrefstat(sn.refstat(k)) = 1;
22 end
23end
24
25%% simpler version: no chain analysis
26M = sn.nstations;
27K = sn.nclasses;
28refstat = sn.refstat;
29Lambda = sn.mu;
30phi = sn.phi;
31phases = sn.phases;
32
33%Qlength for all stations, classes,
34QN = xvec_it{end};
35
36%% Tput for all classes in each station
37Rlittle = zeros(sn.nstations,sn.nclasses); % throughput of every class at each station
38TN = zeros(sn.nstations,sn.nclasses); % throughput of every class at each station
39TNt = cell(size(TN));
40for i=1:size(TNt,1)
41 for j=1:size(TNt,2)
42 TNt{i,j} = 0;
43 end
44end
45Xservice = cell(M,K); %throughput per class, station and phase
46for i = 1:sn.nstations
47 if delayNodes(i) == 1
48 for k = 1:sn.nclasses
49 idx = sum(sum(phases(1:i-1,:))) + sum( phases(i,1:k-1) );
50 Xservice{i,k} = zeros(phases(i,k),1);
51 for f = 1:phases(i,k)
52 TN(i,k) = TN(i,k) + QN(idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f);
53 TNt{i,k} = TNt{i,k} + QNt{i,k}*Lambda{i}{k}(f)*phi{i}{k}(f);
54 Xservice{i,k}(f) = QN(idx+f)*Lambda{i}{k}(f);
55 end
56 end
57 else
58 xi = sum(Q(i,:)); %number of jobs in the station
59 xi_t = QNt{i,1};
60 for r=2:size(QNt,2)
61 xi_t = xi_t + QNt{i,r};
62 end
63
64 if xi>0 || sn.sched(i)==SchedStrategy.EXT % step in to compute source tput in all cases
65 switch sn.sched(i)
66 case SchedStrategy.FCFS
67 wni = GlobalConstants.FineTol;
68 w = zeros(1,sn.nclasses);
69 for k = 1:sn.nclasses
70 idx = sum(sum(phases(1:i-1,:))) + sum( phases(i,1:k-1) );
71 wi(k) = map_mean(sn.proc{i}{k});
72 wni = wni + wi(k)*sum(QN((idx+1):(idx+phases(i,k))));
73 end
74 wni_t = 0*QNt{i,1};
75 for r=1:sn.nclasses
76 wni_t = wni_t + wi(r)* QNt{i,r};
77 end
78
79 end
80
81 for k = 1:sn.nclasses
82 idx = sum(sum(phases(1:i-1,:))) + sum( phases(i,1:k-1) );
83 Xservice{i,k} = zeros(phases(i,k),1);
84 for f = 1:phases(i,k)
85 switch sn.sched(i)
86 case SchedStrategy.EXT
87 if f==1
88 TN(i,k) = TN(i,k) + (1-sum(QN(idx+(2:phases(i,k)))))*Lambda{i}{k}(f)*phi{i}{k}(f);
89 TNt{i,k} = TNt{i,k} + (1-sum(xvec_t(:,idx+(2:phases(i,k))),2))*Lambda{i}{k}(f)*phi{i}{k}(f);
90 Xservice{i,k}(f) = (1-sum(QN(idx+(2:phases(i,k)))))*Lambda{i}{k}(f);
91 else
92 TN(i,k) = TN(i,k) + QN(idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f);
93 TNt{i,k} = TNt{i,k} + xvec_t(:,idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f);
94 Xservice{i,k}(f) = QN(idx+f)*Lambda{i}{k}(f);
95 end
96 case {SchedStrategy.INF, SchedStrategy.PS}
97 TN(i,k) = TN(i,k) + QN(idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)/xi*min(xi,sn.nservers(i));
98 TNt{i,k} = TNt{i,k} + xvec_t(:,idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)./xi_t.*min(xi_t,sn.nservers(i));
99 Xservice{i,k}(f) = QN(idx+f)*Lambda{i}{k}(f)/xi*min(xi,sn.nservers(i));
100 case SchedStrategy.DPS
101 w = sn.schedparam(i,:);
102 wxi = w*Q(i,:)'; %number of jobs in the station
103 wxi_t = w(1)*QNt{i,1};
104 for r=2:size(QNt,2)
105 wxi_t = wxi_t + w(r)*QNt{i,r};
106 end
107 TN(i,k) = TN(i,k) + QN(idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)*w(k)/wxi*min(xi,sn.nservers(i));
108 TNt{i,k} = TNt{i,k} + xvec_t(:,idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)*w(k)./wxi_t.*min(xi_t,sn.nservers(i));
109 Xservice{i,k}(f) = QN(idx+f)*Lambda{i}{k}(f)*w(k)/wxi*min(xi,sn.nservers(i));
110 case {SchedStrategy.FCFS, SchedStrategy.SIRO}
111 switch options.method
112 case {'default','closing','pnorm','softmin'}
113 TN(i,k) = TN(i,k) + QN(idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)/xi*min(xi,sn.nservers(i));
114 TNt{i,k} = TNt{i,k} + xvec_t(:,idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)./xi_t.*min(xi_t,sn.nservers(i));
115 Xservice{i,k}(f) = QN(idx+f)*Lambda{i}{k}(f)/xi*min(xi,sn.nservers(i));
116 case 'statedep'
117 TN(i,k) = TN(i,k) + QN(idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)*wi(k)/wni*min(xi,sn.nservers(i));
118 TNt{i,k} = TNt{i,k} + xvec_t(:,idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)./xi_t.*min(xi_t,sn.nservers(i));
119 Xservice{i,k}(f) = QN(idx+f)*Lambda{i}{k}(f)*wi(k)/wni*min(xi,sn.nservers(i));
120
121 %Tfull(i,k) = Tfull(i,k) + Qfull(idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)*min(xi,sn.nservers(i))*wi(k);
122 %Tfull_t{i,k} = Tfull_t{i,k} + ymean_t(:,idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f).*min(xi_t,sn.nservers(i)) * wi(k);
123 %Xservice{i,k}(f) = Qfull(idx+f)*Lambda{i}{k}(f)*min(xi,sn.nservers(i))*wi(k);
124
125 % Tfull(i,k) = Tfull(i,k) + Qfull(idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f)*min(xi,sn.nservers(i))*wi(k)/wni;
126 % Tfull_t{i,k} = Tfull_t{i,k} + ymean_t(:,idx+f)*Lambda{i}{k}(f)*phi{i}{k}(f).*min(xi_t,sn.nservers(i)) * wi(k)/wni;
127 % Xservice{i,k}(f) = Qfull(idx+f)*Lambda{i}{k}(f)*min(xi,sn.nservers(i))*wi(k)/wni;
128 end
129 otherwise
130 line_error(mfilename,'Unsupported scheduling policy');
131 end
132 end
133 end
134 end
135 end
136end
137for i=1:size(TNt,1)
138 for j=1:size(TNt,2)
139 if isscalar(TNt{i,j})
140 TNt{i,j} = TNt{i,j} * ones(size(xvec_t(:,1),1),1);
141 end
142 end
143end
144%% response times
145origK = size(chains,1);
146% This is approximate, Little's law does not hold in transient
147R = zeros(sn.nstations, sn.nclasses);
148for i = 1:sn.nstations
149 R(i, TN(i,:)>0) = Q(i,TN(i,:)>0) ./ TN(i,TN(i,:)>0);
150end
151%R = Rlittle;
152%Tfull = Tlittle;
153newR = zeros(sn.nstations,origK);
154X = zeros(1,origK);
155newQ = zeros(sn.nstations,origK);
156% determine eventual probability of visiting each station in each class (expected number of visits)
157% weight response time of each original class with the expected number of
158% visits to each station in each associated artificial class
159idxNR = reshape(1:sn.nstations*sn.nclasses, sn.nclasses, sn.nstations); %indices of non-delay (non-reference) nodes
160idxNR = reshape(idxNR(:,delayrefstat==0),1,[]);
161rtTrans = sn.rt(idxNR,idxNR); %transient transition matrix for non-reference nodes
162eventualVisit = pinv( eye(size(rtTrans)) - rtTrans ); % pinv handles better self-looping customers setting the relevant entries to zero instead than infinity
163idxOrigClasses = zeros(origK,1);
164
165for k = 1:origK
166 idxOrigClasses(k) = find(chains(k,:),1);
167 refNode = refstat(idxOrigClasses(k));
168
169 eventualVisitProb = reshape( sn.rt((refNode-1)*sn.nclasses+k,idxNR)*eventualVisit, sn.nclasses , sn.nstations-sum(delayrefstat>0) )'; %#ok<MINV> %probability of eventual visit
170 eventualVisitProb = eventualVisitProb(:,chains(k,:)==1);
171
172 newR(refNode,k) = sum( R(refNode,chains(k,:)==1),2 );
173 newR(delayrefstat==0,k) = sum( R(delayrefstat==0,chains(k,:)==1).*eventualVisitProb, 2 );
174 newR(refNode,chains(k,:)==1) = R(refNode,chains(k,:)==1);
175 newR(delayrefstat==0,chains(k,:)==1) = R(delayrefstat==0,chains(k,:)==1).*eventualVisitProb;
176
177 %X(k,find(chains(k,:)))= sum(Tfull(refNode,find(chains(k,:))));
178 X(1,k) = sum( TN(refNode,chains(k,:)==1) );
179 newQ(:,k) = sum( Q(:,chains(k,:)==1),2 );
180end
181QN = Q;
182RN = R;
183
184%% Utilization
185
186UN = zeros(M,K);
187for i =1:M
188 for k = 1:K
189 idx = Xservice{i,k}>0;
190 UN(i,k) = sum(Xservice{i,k}(idx)./ Lambda{i}{k}(idx));
191 switch sn.sched(i)
192 case SchedStrategy.FCFS
193 switch options.method
194 case 'statedep'
195 TN(i,k) = sum(Xservice{i,k}(idx));
196 end
197 end
198 end
199end
200
201UN(delayNodes==0,:) = UN(delayNodes==0,:)./repmat(sn.nservers(delayNodes==0),1,K);
202
203end
Definition mmt.m:92