LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
fromMarginalAndRunning.m
1function space = fromMarginalAndRunning(sn, ind, n, s, options)
2% SPACE = FROMMARGINALANDRUNNING(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 = false;
9end
10if isa(sn,'Network')
11 sn=sn.getStruct();
12end
13% ind: node index
14ist = sn.nodeToStation(ind);
15isf = sn.nodeToStateful(ind);
16
17% generate one initial state such that the marginal queue-lengths are as in vector n
18% n(r): number of jobs at the station in class r
19% s(r): jobs of class r that are running
20R = sn.nclasses;
21S = sn.nservers;
22K = zeros(1,R);
23for r=1:R
24 if isempty(sn.proc{ist}{r})
25 K(r) = 0;
26 else
27 K(r) = length(sn.proc{ist}{r}{1});
28 end
29end
30state = [];
31space = [];
32if any(n>sn.classcap(ist,:))
33 exceeded = n>sn.classcap(ist,:);
34 for r=find(exceeded)
35 if ~isempty(sn.proc) && ~isempty(sn.proc{ist}{r}) && any(any(isnan(sn.proc{ist}{r}{1})))
36 line_warning(mfilename,sprintf('State vector at station %d (n=%s) exceeds the class capacity (classcap=%s). Some service classes are disabled.\n',ist,mat2str(n),mat2str(sn.classcap(ist,:))));
37 else
38 line_warning(mfilename,sprintf('State vector at station %d (n=%s) exceeds the class capacity (classcap=%s).\n',ist,mat2str(n),mat2str(sn.classcap(ist,:))));
39 end
40 end
41 return
42end
43if (sn.nservers(ist)>0 && sum(s) > sn.nservers(ist))
44 return
45end
46% generate local-state space
47switch sn.nodetype(ind)
48 case {NodeType.Queue, NodeType.Delay, NodeType.Source}
49 switch sn.sched(ist)
50 case SchedStrategy.EXT
51 for r=1:R
52 init = State.spaceClosedSingle(K(r),0);
53 if isinf(sn.njobs(r))
54 if isnan(sn.rates(ist,r))
55 init(1) = 0; % class is not processed at this source
56 else
57 init(1) = 1;
58 end
59 end
60 state = State.cartesian(state,init);
61 end
62 space = State.cartesian(space,state);
63 space = [Inf*ones(size(space,1),1),space];
64 case {SchedStrategy.INF, SchedStrategy.PS, SchedStrategy.DPS, SchedStrategy.GPS, SchedStrategy.PSPRIO, SchedStrategy.DPSPRIO, SchedStrategy.GPSPRIO, SchedStrategy.LPS}
65 % in these policies we only track the jobs in the servers
66 for r=1:R
67 init = State.spaceClosedSingle(K(r),n(r));
68 state = State.cartesian(state,init);
69 end
70 space = State.cartesian(space,state);
71 case {SchedStrategy.SIRO, SchedStrategy.LEPT, SchedStrategy.SEPT, SchedStrategy.SRPT, SchedStrategy.SRPTPRIO}
72 % in these policies we track an un-ordered buffer and
73 % the jobs in the servers
74 % build list of job classes in the node, with repetition
75 if sum(n) <= S(ist)
76 for r=1:R
77 init = State.spaceClosedSingle(K(r),n(r));
78 state = State.cartesian(state,init);
79 end
80 space = State.cartesian(space,[zeros(size(state,1),R),state]);
81 else
82 % si = multichoosecon(n,S(i)); % jobs of class r that are running
83 si = s;
84 mi_buf = repmat(n,size(si,1),1) - si; % jobs of class r in buffer
85 for k=1:size(si,1)
86 % determine number of classes r jobs running in phase j
87 kstate=[];
88 for r=1:R
89 init = State.spaceClosedSingle(K(r),si(k,r));
90 kstate = State.cartesian(kstate,init);
91 end
92 state = [repmat(mi_buf(k,:),size(kstate,1),1), kstate];
93 space = [space; state];
94 end
95 end
96 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.LCFS}
97 sizeEstimator = multinomialln(n-s);
98 sizeEstimator = round(sizeEstimator/log(10));
99 if sizeEstimator > 2
100 if ~isfield(options,'force') || options.force == false
101 line_warning(mfilename,sprintf('State space size is very large: 1e%d states. Stopping execution. Set options.force=true to bypass this control.\n',round(sizeEstimator/log(10))));
102 end
103 end
104 if sum(n) == 0
105 space = zeros(1,1+sum(K));
106 return
107 end
108 % in these policies we track an ordered buffer and
109 % the jobs in the servers
110
111 % build list of job classes in the buffer, with repetition
112 inbuf = [];
113 for r=1:R
114 if n(r)>s(r)
115 inbuf=[inbuf, r*ones(1,n(r)-s(r))];
116 end
117 end
118
119 % gen permutation of their positions in the fcfs buffer
120 mi = uniqueperms(inbuf); %unique(perms(vi),'rows) is notoriously slow
121 if isempty(mi)
122 mi_buf = zeros(1,max(0,sum(n)-S(ist)));
123 state = zeros(1,R);
124 state = State.cartesian(state,[mi_buf,state]);
125 else
126 % mi_buf: class of job in buffer position i (0=empty)
127 if sum(n)>sum(s)
128 mi_buf = mi(:,1:(sum(n)-sum(s)));
129 else % set an empty buffer
130 mi_buf = 0;
131 end
132 % si: number of class r jobs that are running
133 si = s;
134 %si = unique(si,'rows');
135 for b=1:size(mi_buf,1)
136 for k=1:size(si,1)
137 % determine number of classs r jobs running in phase
138 % j in server state mi_srv(kjs,:) and build
139 % state
140 kstate=[];
141 for r=1:R
142 % kstate = State.cartesian(kstate,State.spaceClosedSingle(K(r),si(k,r)));
143 init = State.spaceClosedSingle(K(r),si(k,r));
144 kstate = State.cartesian(kstate,init);
145 end
146 state = [state; repmat(mi_buf(b,:),size(kstate,1),1), kstate];
147 end
148 end
149 end
150 space = state;
151 case SchedStrategy.LCFSPR
152 %% TODO
153 sizeEstimator = multinomialln(n-s);
154 sizeEstimator = round(sizeEstimator/log(10));
155 if sizeEstimator > 2
156 if ~isfield(options,'force') || options.force == false
157 line_warning(mfilename,sprintf('State space size is very large: 1e%d states. Stopping execution. Set options.force=true to bypass this control.\n',round(sizeEstimator/log(10))));
158 end
159 end
160 if sum(n) == 0
161 space = zeros(1,1+sum(K));
162 return
163 end
164 % in these policies we track an ordered buffer and
165 % the jobs in the servers
166
167 % build list of job classes in the buffer, with repetition
168 inbuf = [];
169 for r=1:R
170 if n(r)>s(r)
171 inbuf=[inbuf, r*ones(1,n(r)-s(r))];
172 end
173 end
174
175 % gen permutation of their positions in the fcfs buffer
176 mi = uniqueperms(inbuf); %unique(perms(vi),'rows) is notoriously slow
177 if isempty(mi)
178 mi_buf = zeros(1,max(0,sum(n)-S(ist)));
179 state = zeros(1,R);
180 state = State.cartesian(state,[mi_buf,state]);
181 else
182 % mi_buf: class of job in buffer position i (0=empty)
183 if sum(n)>sum(s)
184 mi_buf = mi(:,1:(sum(n)-sum(s)));
185 else % set an empty buffer
186 mi_buf = 0;
187 end
188 % si: number of class r jobs that are running
189 si = s;
190 %si = unique(si,'rows');
191 for b=1:size(mi_buf,1)
192 for k=1:size(si,1)
193 % determine number of classs r jobs running in phase
194 % j in server state mi_srv(kjs,:) and build
195 % state
196 kstate=[];
197 for r=1:R
198 % kstate = State.cartesian(kstate,State.spaceClosedSingle(K(r),si(k,r)));
199 init = State.spaceClosedSingle(K(r),si(k,r));
200 kstate = State.cartesian(kstate,init);
201 end
202 bkstate = [];
203 for j=mi_buf(b,:) % for each job in the buffer
204 if j>0
205 bkstate = State.cartesian(bkstate,[1:K(j)]');
206 else
207 bkstate = 0;
208 end
209 end
210 bufstate_tmp = State.cartesian(mi_buf(b,:), bkstate);
211 % here interleave positions of class and phases in
212 % buf
213 bufstate = zeros(size(bufstate_tmp));
214 bufstate(:,1:2:end)=bufstate_tmp(:,1:size(mi_buf,2));
215 bufstate(:,2:2:end)=bufstate_tmp(:,(size(mi_buf,2)+1):end);
216 state = [state; State.cartesian(bufstate, kstate)];
217 end
218 end
219 end
220 space = state;
221 case {SchedStrategy.SJF, SchedStrategy.LJF}
222 % in these policies the state space includes continuous
223 % random variables for the service times
224 line_warning(mfilename,'The scheduling policy does not admit a discrete state space.\n');
225 end
226 case NodeType.Cache
227 switch sn.sched(ist)
228 case SchedStrategy.INF
229 % in this policies we only track the jobs in the servers
230 for r=1:R
231 init = State.spaceClosedSingle(K(r),n(r));
232 state = State.cartesian(state,init);
233 end
234 space = State.cartesian(space,state);
235 end
236end
237space = unique(space,'rows'); % do not comment, required to sort empty state as first
238space = space(end:-1:1,:); % so that states with jobs in phase 1 comes earlier
239end