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 % Unordered buffer -- see _kb/04-networkstruct.md
73 % build list of job classes in the node, with repetition
74 if sum(n) <= S(ist)
75 for r=1:R
76 init = State.spaceClosedSingle(K(r),n(r));
77 state = State.cartesian(state,init);
78 end
79 space = State.cartesian(space,[zeros(size(state,1),R),state]);
80 else
81 % si = multichoosecon(n,S(i)); % jobs of class r that are running
82 si = s;
83 mi_buf = repmat(n,size(si,1),1) - si; % jobs of class r in buffer
84 for k=1:size(si,1)
85 % determine number of classes r jobs running in phase j
86 kstate=[];
87 for r=1:R
88 init = State.spaceClosedSingle(K(r),si(k,r));
89 kstate = State.cartesian(kstate,init);
90 end
91 state = [repmat(mi_buf(k,:),size(kstate,1),1), kstate];
92 space = [space; state];
93 end
94 end
95 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.LCFS}
96 sizeEstimator = multinomialln(n-s);
97 sizeEstimator = round(sizeEstimator/log(10));
98 if sizeEstimator > 2
99 if ~isfield(options,'force') || options.force == false
100 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))));
101 end
102 end
103 if sum(n) == 0
104 space = zeros(1,1+sum(K));
105 return
106 end
107 % Ordered buffer -- see _kb/04-networkstruct.md
108
109 % build list of job classes in the buffer, with repetition
110 inbuf = [];
111 for r=1:R
112 if n(r)>s(r)
113 inbuf=[inbuf, r*ones(1,n(r)-s(r))];
114 end
115 end
116
117 % gen permutation of their positions in the fcfs buffer
118 mi = uniqueperms(inbuf); %unique(perms(vi),'rows) is notoriously slow
119 if isempty(mi)
120 mi_buf = zeros(1,max(0,sum(n)-S(ist)));
121 state = zeros(1,R);
122 state = State.cartesian(state,[mi_buf,state]);
123 else
124 % mi_buf: class of job in buffer position i (0=empty)
125 if sum(n)>sum(s)
126 mi_buf = mi(:,1:(sum(n)-sum(s)));
127 else % set an empty buffer
128 mi_buf = 0;
129 end
130 % si: number of class r jobs that are running
131 si = s;
132 %si = unique(si,'rows');
133 for b=1:size(mi_buf,1)
134 for k=1:size(si,1)
135 % determine number of classs r jobs running in phase
136 % j in server state mi_srv(kjs,:) and build
137 % state
138 kstate=[];
139 for r=1:R
140 % kstate = State.cartesian(kstate,State.spaceClosedSingle(K(r),si(k,r)));
141 init = State.spaceClosedSingle(K(r),si(k,r));
142 kstate = State.cartesian(kstate,init);
143 end
144 state = [state; repmat(mi_buf(b,:),size(kstate,1),1), kstate];
145 end
146 end
147 end
148 space = state;
149 case SchedStrategy.LCFSPR
150 %% TODO
151 sizeEstimator = multinomialln(n-s);
152 sizeEstimator = round(sizeEstimator/log(10));
153 if sizeEstimator > 2
154 if ~isfield(options,'force') || options.force == false
155 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))));
156 end
157 end
158 if sum(n) == 0
159 space = zeros(1,1+sum(K));
160 return
161 end
162 % Ordered buffer -- see _kb/04-networkstruct.md
163
164 % build list of job classes in the buffer, with repetition
165 inbuf = [];
166 for r=1:R
167 if n(r)>s(r)
168 inbuf=[inbuf, r*ones(1,n(r)-s(r))];
169 end
170 end
171
172 % gen permutation of their positions in the fcfs buffer
173 mi = uniqueperms(inbuf); %unique(perms(vi),'rows) is notoriously slow
174 if isempty(mi)
175 mi_buf = zeros(1,max(0,sum(n)-S(ist)));
176 state = zeros(1,R);
177 state = State.cartesian(state,[mi_buf,state]);
178 else
179 % mi_buf: class of job in buffer position i (0=empty)
180 if sum(n)>sum(s)
181 mi_buf = mi(:,1:(sum(n)-sum(s)));
182 else % set an empty buffer
183 mi_buf = 0;
184 end
185 % si: number of class r jobs that are running
186 si = s;
187 %si = unique(si,'rows');
188 for b=1:size(mi_buf,1)
189 for k=1:size(si,1)
190 % determine number of classs r jobs running in phase
191 % j in server state mi_srv(kjs,:) and build
192 % state
193 kstate=[];
194 for r=1:R
195 % kstate = State.cartesian(kstate,State.spaceClosedSingle(K(r),si(k,r)));
196 init = State.spaceClosedSingle(K(r),si(k,r));
197 kstate = State.cartesian(kstate,init);
198 end
199 bkstate = [];
200 for j=mi_buf(b,:) % for each job in the buffer
201 if j>0
202 bkstate = State.cartesian(bkstate,[1:K(j)]');
203 else
204 bkstate = 0;
205 end
206 end
207 bufstate_tmp = State.cartesian(mi_buf(b,:), bkstate);
208 % here interleave positions of class and phases in
209 % buf
210 bufstate = zeros(size(bufstate_tmp));
211 bufstate(:,1:2:end)=bufstate_tmp(:,1:size(mi_buf,2));
212 bufstate(:,2:2:end)=bufstate_tmp(:,(size(mi_buf,2)+1):end);
213 state = [state; State.cartesian(bufstate, kstate)];
214 end
215 end
216 end
217 space = state;
218 case {SchedStrategy.SJF, SchedStrategy.LJF}
219 % in these policies the state space includes continuous
220 % random variables for the service times
221 line_warning(mfilename,'The scheduling policy does not admit a discrete state space.\n');
222 end
223 case NodeType.Cache
224 switch sn.sched(ist)
225 case SchedStrategy.INF
226 % in this policies we only track the jobs in the servers
227 for r=1:R
228 init = State.spaceClosedSingle(K(r),n(r));
229 state = State.cartesian(state,init);
230 end
231 space = State.cartesian(space,state);
232 end
233end
234space = unique(space,'rows'); % do not comment, required to sort empty state as first
235space = space(end:-1:1,:); % so that states with jobs in phase 1 comes earlier
236end