LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
initDefault.m
1function initDefault(self, nodes)
2% INITDEFAULT(NODES)
3
4% open classes empty
5% closed classes initialized at ref station
6% running jobs are allocated in class id order until all
7% servers are busy
8
9%refreshStruct(self); % we force update of the model before we initialize
10
11sn = self.getStruct(false);
12
13R = sn.nclasses;
14N = sn.njobs';
15if nargin < 2
16 nodes = 1:self.getNumberOfNodes;
17end
18
19% Feasible placement of closed-class jobs: all at the reference station when it has
20% capacity, otherwise spill the remainder over the other stations in index order.
21% Without the spill, a finite-capacity reference station with K < N leaves the
22% station state empty and default initialization fails (e.g. closed BAS networks).
23% Classes whose reference node is a Place keep the all-at-ref convention (SPN tokens).
24nplace = zeros(sn.nstations, R);
25totplace = zeros(sn.nstations, 1);
26for r=find(isfinite(N))'
27 refist = sn.refstat(r);
28 if sn.nodetype(sn.stationToNode(refist)) == NodeType.Place
29 nplace(refist,r) = N(r);
30 totplace(refist) = totplace(refist) + N(r);
31 continue
32 end
33 remaining = N(r);
34 for jst=[refist, setdiff(1:sn.nstations, refist)]
35 if remaining == 0
36 break
37 end
38 if sn.sched(jst) == SchedStrategy.EXT || sn.nodetype(sn.stationToNode(jst)) == NodeType.Place
39 continue
40 end
41 avail = min(sn.classcap(jst,r) - nplace(jst,r), sn.cap(jst) - totplace(jst));
42 take = min(remaining, max(0, avail));
43 nplace(jst,r) = nplace(jst,r) + take;
44 totplace(jst) = totplace(jst) + take;
45 remaining = remaining - take;
46 end
47 if remaining > 0
48 line_error(mfilename, sprintf('Cannot place the population of class %d: total station capacity is insufficient.', r));
49 end
50end
51
52for ind=nodes
53 if sn.isstation(ind)
54 ist = sn.nodeToStation(ind);
55 n0 = nplace(ist,:); % number of jobs in the initial state
56 s0 = zeros(1,length(N)); % number of active servers in the initial state
57 s = sn.nservers(ist); % allocate
58 for r=find(isfinite(N))' % for all closed classes
59 s0(r) = min(n0(r),s);
60 s = s - s0(r);
61 end
62 switch sn.nodetype(ind)
63 case NodeType.Cache
64 state_i = State.fromMarginalAndStarted(sn,ind,n0(:)',s0(:)');
65 % Cache state width = totalCacheCapacity + (per-item retrieval bitmap).
66 % Initialize the cache region with items 1..totalCacheCapacity and the
67 % retrieval-system region (one column per item) with zeros (nothing
68 % being retrieved). The bitmap is omitted when no retrieval system.
69 if isfield(sn.nodeparam{ind}, 'totalCacheCapacity')
70 tcc = sn.nodeparam{ind}.totalCacheCapacity;
71 else
72 tcc = sn.nvars(ind,2*R+1);
73 end
74 rbw = 0;
75 if isfield(sn.nodeparam{ind},'retrievalSystemCapacity') ...
76 && sn.nodeparam{ind}.retrievalSystemCapacity > 0
77 rbw = sn.nodeparam{ind}.nitems;
78 end
79 state_i = [state_i, 1:tcc, zeros(1,rbw)]; %#ok<AGROW>
80 case NodeType.Place
81 if sum(self.nodes{ind}.state)>0
82 % if the user pre-loaded manually some jobs, keep them
83 state_i = self.nodes{ind}.state;
84 else
85 state_i = zeros(1,self.getNumberOfClasses);
86 for r=1:sn.nclasses
87 if sn.refstat(r) == ist
88 state_i(r) = sn.njobs(r);
89 else
90 state_i(r) = 0;
91 end
92 end
93 end
94 otherwise
95 if sn.isstation(ind) && sn.sched(ist) == SchedStrategy.PAS
96 % Pass-and-swap stations: the full ordered state space (all
97 % placements of the marginal) is built independently of the
98 % initial state, while the user-specified placement (if any)
99 % is kept as the initial state. A closed PAS station holding
100 % more than one job under a non-empty swapping graph has a
101 % reducible generator (one recurrent component per placement
102 % order), so the placement is a required model input: error
103 % rather than fabricate a default ordering.
104 userState = self.nodes{ind}.getState();
105 hasUser = ~isempty(userState) && any(userState(:) > 0);
106 sg = [];
107 if numel(sn.nodeparam) >= ind && isstruct(sn.nodeparam{ind}) ...
108 && isfield(sn.nodeparam{ind}, 'swapGraph')
109 sg = sn.nodeparam{ind}.swapGraph;
110 end
111 hasSwap = ~isempty(sg) && any(sg(:) ~= 0);
112 isClosed = any(isfinite(N));
113 if hasUser
114 nUser = zeros(1, R);
115 present = userState(userState > 0);
116 for r = 1:R, nUser(r) = sum(present == r); end
117 sU = zeros(1, R); ss = sn.nservers(ist);
118 for r = 1:R, sU(r) = min(nUser(r), ss); ss = ss - sU(r); end
119 space_i = State.fromMarginalAndStarted(sn, ind, nUser, sU);
120 W = size(space_i, 2);
121 urow = zeros(1, W);
122 cols = min(numel(userState), W);
123 urow(1:cols) = userState(1:cols);
124 % keep the user placement as the initial state (row 1)
125 state_i = unique([urow; space_i], 'rows', 'stable');
126 elseif hasSwap && isClosed && sum(n0) > 1
127 line_error(mfilename, sprintf(['A closed pass-and-swap station with a non-empty swapping ' ...
128 'graph requires an explicit initial job placement (station %d). Call setState on the ' ...
129 'station with the ordered class list (oldest first) before solving.'], ind));
130 else
131 state_i = State.fromMarginalAndStarted(sn, ind, n0(:)', s0(:)');
132 end
133 else
134 state_i = State.fromMarginalAndStarted(sn,ind,n0(:)',s0(:)');
135 if sn.isstation(ind)
136 for r=1:sn.nclasses
137 switch sn.procid(sn.nodeToStation(ind),r)
138 case {ProcessType.MAP, ProcessType.MMPP2}
139 % Markov-modulated service: append the phase-restart
140 % slot tracked in sn.nvars (see refreshLocalVars)
141 %state_i = State.cartesian(state_i, [1:sn.phases(i,r)]');
142 state_i = State.cartesian(state_i, 1);
143 end
144 end
145 end
146 end
147 end
148 for r=1:sn.nclasses
149 switch sn.routing(ind,r)
150 case {RoutingStrategy.RROBIN, RoutingStrategy.WRROBIN}
151 % start from first connected queue
152 state_i = [state_i, find(sn.connmatrix(ind,:),1)];
153 end
154 end
155 if sn.sched(ist) == SchedStrategy.POLLING
156 % The polling controller trails the routing variables, matching the
157 % nvars column order used by State.fromMarginal.
158 srvclass0 = find(s0 > 0, 1);
159 if isempty(srvclass0)
160 srvclass0 = 0;
161 end
162 nbuf0 = n0;
163 if srvclass0 > 0
164 nbuf0(srvclass0) = nbuf0(srvclass0) - 1;
165 end
166 state_i = [state_i, State.pollingInit(sn, ind, nbuf0, srvclass0)];
167 end
168 if isempty(state_i)
169 line_error(mfilename,sprintf('Default initialization failed on station %d.',ind));
170 end
171 elseif sn.isstateful(ind) % not a station
172 switch sn.nodetype(ind)
173 case NodeType.Cache
174 % [class counts | cache contents (items 1..tcc) | per-item retrieval
175 % bitmap (zeros, nothing being retrieved)]. The bitmap (one column per
176 % item) is omitted when no retrieval system is configured.
177 tcc = self.nodes{ind}.totalCacheCapacity;
178 if self.nodes{ind}.retrievalSystemCapacity > 0
179 rbw = self.nodes{ind}.items.nitems;
180 else
181 rbw = 0;
182 end
183 state_i = [zeros(1,self.getNumberOfClasses), 1:tcc, zeros(1,rbw)];
184 case NodeType.Router
185 state_i = zeros(1, self.getNumberOfClasses);
186 for r=1:sn.nclasses
187 switch sn.routing(ind,r)
188 case RoutingStrategy.RROBIN
189 % RR slot holds destination value; start at first connected queue
190 state_i = [state_i, find(sn.connmatrix(ind,:),1)]; %#ok<AGROW>
191 case RoutingStrategy.WRROBIN
192 % WRR slot holds POSITION in weighted_outlinks; start at 1
193 state_i = [state_i, 1]; %#ok<AGROW>
194 case RoutingStrategy.KCHOICES
195 % KCHOICES with memory: -1 marks "no prior pick".
196 if isfield(self.nodes{ind}.output.outputStrategy{1, r}, 'withMemory') ...
197 || (iscell(self.nodes{ind}.output.outputStrategy{1, r}) ...
198 && length(self.nodes{ind}.output.outputStrategy{1, r}) >= 3 ...
199 && length(self.nodes{ind}.output.outputStrategy{1, r}{3}) >= 2 ...
200 && self.nodes{ind}.output.outputStrategy{1, r}{3}{2})
201 state_i = [state_i, -1]; %#ok<AGROW>
202 end
203 end
204 end
205 case NodeType.Fork
206 % Stateful Fork (FJ tag-augmented copies only): per-class
207 % count of parent jobs held before the fork firing
208 state_i = zeros(1, self.getNumberOfClasses);
209 case NodeType.Transition
210 % Differently from a server, the first nmodes states in a
211 % transitions count the servers that are not enabled and
212 % the last nodes count servers that just fired.
213 % This is required as the local state does not encode the
214 % buffer hence the enabling condition is not available.
215 state_i = sn.nodeparam{ind}.nmodeservers;
216 % For infinite servers, use large finite value for state (SSA needs finite states)
217 state_i(isinf(state_i)) = GlobalConstants.MaxInt();
218 % For non-Markovian distributions, firingphases is NaN - treat as 1 phase
219 firingphases = sn.nodeparam{ind}.firingphases;
220 firingphases(isnan(firingphases)) = 1;
221 state_i = [state_i, zeros(1, sum(firingphases)), zeros(size(state_i))]; %#ok<AGROW>
222 otherwise
223 state_i = [];
224 end
225 %line_error(mfilename,'Default initialization not available on stateful node %d.',i);
226 end
227
228 if sn.isstateful(ind) % not a station
229 if size(state_i,1)==1
230 self.nodes{ind}.setStateSpace(state_i);
231 self.nodes{ind}.setStatePrior(1);
232 self.nodes{ind}.setState(state_i);
233 elseif size(state_i,1)>1
234 prior_state_i = zeros(1,size(state_i,1)); prior_state_i(1) = 1;
235 self.nodes{ind}.setStateSpace(state_i);
236 self.nodes{ind}.setStatePrior(prior_state_i);
237 self.nodes{ind}.setState(state_i(1,:));
238 else
239 self.nodes{ind}.setStateSpace([]);
240 self.nodes{ind}.setStatePrior([]);
241 self.nodes{ind}.setState([]);
242 end
243 end
244end
245
246if self.isStateValid % problem with example_initState_2
247 self.hasState = true;
248else
249 line_error(mfilename,sprintf('Default initialization failed.'));
250end
251end
Definition fjtag.m:157
Definition Station.m:245