LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
fromMarginalAndStarted.m
1function space = fromMarginalAndStarted(sn, ind, n, s, options)
2% SPACE = FROMMARGINALANDSTARTED(QN, IND, N, S, OPTIONS)
3
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6
7if nargin<5 %~exist('options','var')
8 options.force = true;
9end
10if isa(sn,'Network')
11 sn = sn.getStruct();
12end
13% generate one initial state such that the marginal queue-lengths are as in vector n
14% n(r): number of jobs at the station in class r
15% s(r): jobs of class r that are running
16R = sn.nclasses;
17S = sn.nservers;
18
19% ind: node index
20ist = sn.nodeToStation(ind);
21%isf = sn.nodeToStateful(ind);
22if ~isnan(ist)
23 K = zeros(1,R);
24 for r=1:R
25 if isempty(sn.proc{ist}{r})
26 K(r) = 0;
27 else
28 K(r) = length(sn.proc{ist}{r}{1});
29 end
30 end
31else % node or stateful
32 if sn.nodetype(ind) == NodeType.Transition
33 K = zeros(1,sn.nodeparam{ind}.nmodes);
34 for m=1:sn.nodeparam{ind}.nmodes
35 if isempty(sn.nodeparam{ind}.firingproc{m})
36 K(m) = 0;
37 else
38 K(m) = length(sn.nodeparam{ind}.firingproc{m}{1});
39 end
40 end
41 end
42end
43
44state = [];
45space = [];
46if sn.isstation(ind) && any(n>sn.classcap(ist,:))
47 exceeded = n>sn.classcap(ist,:);
48 for r=find(exceeded)
49 if ~isempty(sn.proc) && ~isempty(sn.proc{ist}{r}) && any(any(isnan(sn.proc{ist}{r}{1})))
50 line_warning(mfilename,'State vector at station %d (n=%s) exceeds the class capacity (classcap=%s). Some service classes are disabled.\n',ist,mat2str(n(ist,:)),mat2str(sn.classcap(ist,:)));
51 else
52 line_warning(mfilename,'State vector at station %d (n=%s) exceeds the class capacity (classcap=%s).\n',ist,mat2str(n(ist,:)),mat2str(sn.classcap(ist,:)));
53 end
54 end
55 return
56end
57if sn.isstation(ind) && (sn.nservers(ist)>0 && sum(s) > sn.nservers(ist))
58 return
59end
60% generate local-state space
61switch sn.nodetype(ind)
62 case {NodeType.Queue, NodeType.Delay, NodeType.Source}
63 switch sn.sched(ist)
64 case SchedStrategy.EXT
65 for r=1:R
66 init = State.spaceClosedSingle(K(r),0);
67 if isinf(sn.njobs(r))
68 if ~isempty(sn.proc) && ~isempty(sn.proc{ist}{r}) && any(any(isnan(sn.proc{ist}{r}{1})))
69 init(1) = 0; % class is not processed at this source
70 else
71 % init the job generation
72 init(1) = 1;
73 end
74 end
75 state = State.cartesian(state,init);
76 end
77 space = State.cartesian(space,state);
78 space = [Inf*ones(size(space,1),1),space];
79 case {SchedStrategy.INF, SchedStrategy.PS, SchedStrategy.DPS, SchedStrategy.GPS, SchedStrategy.PSPRIO, SchedStrategy.DPSPRIO, SchedStrategy.GPSPRIO, SchedStrategy.LPS}
80 % in these policies we only track the jobs in the servers
81 for r=1:R
82 init = State.spaceClosedSingle(K(r),0);
83 init(1) = n(r);
84 state = State.cartesian(state,init);
85 end
86 space = State.cartesian(space,state);
87 case {SchedStrategy.SIRO, SchedStrategy.LEPT, SchedStrategy.SEPT, SchedStrategy.SRPT, SchedStrategy.SRPTPRIO, SchedStrategy.POLLING}
88 % in these policies we track an un-ordered buffer and
89 % the jobs in the servers
90 % build list of job classes in the node, with repetition
91 if sum(n) <= S(ist)
92 for r=1:R
93 init = State.spaceClosedSingle(K(r),0);
94 init(1) = n(r);
95 state = State.cartesian(state,init);
96 end
97 space = State.cartesian(space,[zeros(size(state,1),R),state]);
98 else
99 % si = multichoosecon(n,S(i)); % jobs of class r that are running
100 si = s;
101 mi_buf = repmat(n,size(si,1),1) - si; % jobs of class r in buffer
102 for k=1:size(si,1)
103 % determine number of classes r jobs running in phase j
104 kstate=[];
105 for r=1:R
106 init = State.spaceClosedSingle(K(r),0);
107 init(1) = si(k,r);
108 kstate = State.cartesian(kstate,init);
109 end
110 state = [repmat(mi_buf(k,:),size(kstate,1),1), kstate];
111 space = [space; state];
112 end
113 end
114 case {SchedStrategy.FCFS, SchedStrategy.HOL,SchedStrategy.FCFSPRIO, SchedStrategy.LCFS,SchedStrategy.LCFSPRIO}
115 if sum(n) == 0
116 space = zeros(1,1+max(R,sum(K)));
117 return
118 end
119 % in these policies we track an ordered buffer and
120 % the jobs in the servers
121
122 % build list of job classes in the buffer, with repetition
123 inbuf = [];
124 for r=1:R
125 if n(r)>0
126 inbuf=[inbuf, r*ones(1,n(r)-s(r))];
127 end
128 end
129
130 sizeEstimator = multinomialln(n);
131 sizeEstimator = round(sizeEstimator/log(10));
132 if sizeEstimator > 2
133 if ~isfield(options,'force') || options.force == false
134 line_warning(sprintf('State space size is very large: 1e%d states. Cannot generate valid state space. Initializing station $d from a default state.\n',sizeEstimator,ind));
135 state = inbuf;
136 return
137 end
138 end
139
140 % gen permutation of their positions in the fcfs buffer
141 mi = uniqueperms(inbuf);
142 if isempty(mi)
143 mi_buf = zeros(1,max(1,sum(n)-S(ist)));
144 state = zeros(1,sum(K));
145 state = [mi_buf,state];
146 else
147 % mi_buf: class of job in buffer position i (0=empty)
148 if sum(n)>sum(s)
149 mi_buf = mi(:,1:(sum(n)-sum(s)));
150 else % set an empty buffer
151 mi_buf = 0;
152 end
153 end
154 % mi_srv: class of jobs running in the server of i
155 mi_srv = [];
156 for r=1:R
157 mi_srv = [mi_srv, r*ones(1,s(r))];
158 end
159 % si: number of class r jobs that are running
160 si = s;
161 %si = unique(si,'rows');
162 for b=1:size(mi_buf,1)
163 for k=1:size(si,1)
164 % determine number of classs r jobs running in phase
165 % j in server state mi_srv(kjs,:) and build
166 % state
167 kstate=[];
168 for r=1:R
169 % kstate = State.cartesian(kstate,State.spaceClosedSingle(K(r),si(k,r)));
170 init = State.spaceClosedSingle(K(r),0);
171 init(1) = si(k,r);
172 kstate = State.cartesian(kstate,init);
173 end
174 state = [state; repmat(mi_buf(b,:),size(kstate,1),1), kstate];
175 end
176 end
177 space = state;
178 case {SchedStrategy.LCFSPR, SchedStrategy.LCFSPI, SchedStrategy.LCFSPRPRIO, SchedStrategy.LCFSPIPRIO}
179 %% TODO
180 if sum(n) == 0
181 space = zeros(1,1+sum(K));
182 return
183 end
184 % in these policies we track an ordered buffer and
185 % the jobs in the servers
186
187 % build list of job classes in the buffer, with repetition
188 inbuf = [];
189 for r=1:R
190 if n(r)>0
191 inbuf=[inbuf, r*ones(1,n(r)-s(r))];
192 end
193 end
194
195 sizeEstimator = multinomialln(n);
196 sizeEstimator = round(sizeEstimator/log(10));
197 if sizeEstimator > 2
198 if ~isfield(options,'force') || options.force == false
199 line_warning(sprintf('State space size is very large: 1e%d states. Cannot generate valid state space. Initializing station $d from a default state.\n',sizeEstimator,ind));
200 state = inbuf;
201 return
202 end
203 end
204
205 % gen permutation of their positions in the fcfs buffer
206 mi = uniqueperms(inbuf);
207 if isempty(mi)
208 mi_buf = zeros(1,max(1,sum(n)-S(ist)));
209 state = zeros(1,sum(K));
210 state = [mi_buf,state];
211 else
212 % mi_buf: class of job in buffer position i (0=empty)
213 if sum(n)>sum(s)
214 mi_buf = mi(:,1:(sum(n)-sum(s)));
215 else % set an empty buffer
216 mi_buf = 0;
217 end
218 end
219
220 % mi_srv: class of jobs running in the server of i
221 mi_srv = [];
222 for r=1:R
223 mi_srv = [mi_srv, r*ones(1,s(r))];
224 end
225 % si: number of class r jobs that are running
226 si = s;
227 %si = unique(si,'rows');
228 for b=1:size(mi_buf,1)
229 for k=1:size(si,1)
230 % determine number of class r jobs running in phase
231 % j in server state mi_srv(kjs,:) and build
232 % state
233 kstate=[];
234 for r=1:R
235 % kstate = State.cartesian(kstate,State.spaceClosedSingle(K(r),si(k,r)));
236 init = State.spaceClosedSingle(K(r),0);
237 init(1) = si(k,r);
238 kstate = State.cartesian(kstate,init);
239 end
240
241 bkstate = [];
242 for j=mi_buf(b,:) % for each job in the buffer
243 if j>0
244 bkstate = State.cartesian(bkstate,[1:K(j)]');
245 else
246 bkstate = 0;
247 end
248 end
249 bufstate_tmp = State.cartesian(mi_buf(b,:), bkstate);
250 % here interleave positions of class and phases in
251 % buf
252 bufstate = zeros(size(bufstate_tmp));
253 bufstate(:,1:2:end)=bufstate_tmp(:,1:size(mi_buf,2));
254 bufstate(:,2:2:end)=bufstate_tmp(:,(size(mi_buf,2)+1):end);
255 state = [state; State.cartesian(bufstate, kstate)];
256 end
257 end
258 space = state;
259 case {SchedStrategy.SJF, SchedStrategy.LJF}
260 % in these policies the state space includes continuous
261 % random variables for the service times
262 % in these policies we only track the jobs in the servers
263
264 for r=1:R
265 init = State.spaceClosedSingle(K(r),0);
266 init(1) = n(r);
267 state = State.cartesian(state,init);
268 end
269 space = State.cartesian(space,state);
270 % this is not casted as an error since this function is
271 % IS
272
273 % called to initial models with SJF and LJF
274 line_warning(mfilename,'The scheduling policy does not admit a discrete state space.\n');
275 end
276 case NodeType.Cache
277 switch sn.sched(ist)
278 case SchedStrategy.INF
279 % in this policies we only track the jobs in the servers
280 for r=1:R
281 init = State.spaceClosedSingle(K(r),n(r));
282 state = State.cartesian(state,init);
283 end
284 space = State.cartesian(space,state);
285 end
286 case NodeType.Join
287 space = 0;
288 case NodeType.Transition
289 line_error(mfilename, 'fromMarginalAndStarted cannot be used on Petri net elements');
290 case NodeType.Place
291 line_error(mfilename, 'fromMarginalAndStarted cannot be used on Petri net elements');
292end
293space = unique(space,'rows'); % do not comment, required to sort empty state as first
294space = space(end:-1:1,:); % this ensures that states where jobs start in phase 1 are first, which is used eg in SSA
295end