LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
JLINE.m
1classdef JLINE
2 % JLINE Conversion utilities for JLINE format models
3 %
4 % JLINE provides static methods to convert between LINE MATLAB models
5 % and JLINE Java/Kotlin models. This class serves as the primary interface
6 % for interoperability between the MATLAB and Java implementations of LINE.
7 %
8 % @brief JLINE format conversion and Java interoperability utilities
9 %
10 % Main functionality:
11 % - Convert LINE MATLAB models to JLINE Java models
12 % - Convert JLINE Java models back to LINE MATLAB format
13 % - Access JLINE solvers from MATLAB
14 % - Handle serialization between MATLAB and Java representations
15 %
16 % Example:
17 % @code
18 % % Convert a LINE model to JLINE format
19 % jnetwork = JLINE.from_model(network);
20 % % Get a JLINE solver
21 % jssa = JLINE.get_solver(jnetwork, 'ssa');
22 % @endcode
23
24 properties (Constant)
25 jar_loc = which('jline.jar');
26 end
27
28 methods(Static)
29
30 function model = from_line_layered_network(line_layered_network)
31 sn = line_layered_network.getStruct;
32
33 %% initialization
34 model = javaObject('jline.lang.layered.LayeredNetwork', line_layered_network.getName);
35
36 %% host processors
37 P = cell(1,sn.nhosts);
38 for h=1:sn.nhosts
39 if isinf(sn.mult(h))
40 sn_mult_h = java.lang.Integer.MAX_VALUE;
41 else
42 sn_mult_h = sn.mult(h);
43 end
44 switch sn.sched(h)
45 case SchedStrategy.REF
46 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.REF);
47 case SchedStrategy.INF
48 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.INF);
49 case SchedStrategy.FCFS
50 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.FCFS);
51 case SchedStrategy.LCFS
52 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.LCFS);
53 case SchedStrategy.SIRO
54 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.SIRO);
55 case SchedStrategy.SJF
56 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.SJF);
57 case SchedStrategy.LJF
58 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.LJF);
59 case SchedStrategy.PS
60 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.PS);
61 case SchedStrategy.DPS
62 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.DPS);
63 case SchedStrategy.GPS
64 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.GPS);
65 case SchedStrategy.SEPT
66 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.SEPT);
67 case SchedStrategy.LEPT
68 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.LEPT);
69 case {SchedStrategy.HOL, SchedStrategy.FCFSPRIO}
70 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.FCFSPRIO);
71 case SchedStrategy.FORK
72 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.FORK);
73 case SchedStrategy.EXT
74 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.EXT);
75 case SchedStrategy.LCFSPR
76 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.LCFSPR);
77 case SchedStrategy.LCFSPI
78 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.LCFSPI);
79 case SchedStrategy.LCFSPRIO
80 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.LCFSPRIO);
81 case SchedStrategy.LCFSPRPRIO
82 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.LCFSPRPRIO);
83 case SchedStrategy.LCFSPIPRIO
84 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.LCFSPIPRIO);
85 case SchedStrategy.PSPRIO % todo
86 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.PSPRIO);
87 case SchedStrategy.DPSPRIO % todo
88 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.DPSPRIO);
89 case SchedStrategy.GPSPRIO % todo
90 P{h} = javaObject('jline.lang.layered.Processor', model, sn.names{h}, sn_mult_h, jline.lang.constant.SchedStrategy.GPSPRIO);
91 end
92 if sn.repl(h)~=1
93 P{h}.setReplication(sn.repl(h));
94 end
95 end
96
97 %% tasks
98 T = cell(1,sn.ntasks);
99 for t=1:sn.ntasks
100 tidx = sn.tshift+t;
101 if isinf(sn.mult(tidx))
102 sn_mult_tidx = java.lang.Integer.MAX_VALUE;
103 else
104 sn_mult_tidx = sn.mult(tidx);
105 end
106 % Check if this is a CacheTask
107 if sn.iscache(tidx)
108 % Get replacement strategy from ordinal
109 switch sn.replacestrat(tidx)
110 case ReplacementStrategy.RR
111 jReplacestrat = jline.lang.constant.ReplacementStrategy.RR;
112 case ReplacementStrategy.FIFO
113 jReplacestrat = jline.lang.constant.ReplacementStrategy.FIFO;
114 case ReplacementStrategy.SFIFO
115 jReplacestrat = jline.lang.constant.ReplacementStrategy.SFIFO;
116 case ReplacementStrategy.LRU
117 jReplacestrat = jline.lang.constant.ReplacementStrategy.LRU;
118 otherwise
119 jReplacestrat = jline.lang.constant.ReplacementStrategy.FIFO;
120 end
121 T{t} = javaObject('jline.lang.layered.CacheTask', model, sn.names{tidx}, sn.nitems(tidx), sn.itemcap{tidx}, jReplacestrat, sn_mult_tidx);
122 elseif sn.isfunction(tidx)
123 % FunctionTask (has setupTime/delayOffTime)
124 jSchedStrategy = JLINE.to_jline_sched_strategy(sn.sched(tidx));
125 T{t} = javaObject('jline.lang.layered.FunctionTask', model, sn.names{tidx}, sn_mult_tidx, jSchedStrategy);
126 else
127 jSchedStrategy = JLINE.to_jline_sched_strategy(sn.sched(tidx));
128 T{t} = javaObject('jline.lang.layered.Task', model, sn.names{tidx}, sn_mult_tidx, jSchedStrategy);
129 end
130 T{t}.on(P{sn.parent(tidx)});
131 if sn.repl(tidx)~=1
132 T{t}.setReplication(sn.repl(tidx));
133 end
134 if ~isempty(sn.think{tidx}) && sn.think_type(tidx) ~= ProcessType.DISABLED
135 switch sn.think_type(tidx)
136 case ProcessType.IMMEDIATE
137 T{t}.setThinkTime(jline.lang.processes.Immediate);
138 case ProcessType.EXP
139 T{t}.setThinkTime(jline.lang.processes.Exp(1/sn.think_mean(tidx)));
140 case ProcessType.ERLANG
141 T{t}.setThinkTime(jline.lang.processes.Erlang.fitMeanAndSCV(sn.think_mean(tidx), sn.think_scv(tidx)));
142 case ProcessType.HYPEREXP
143 if ~isempty(sn.think_params{tidx}) && length(sn.think_params{tidx}) >= 3
144 T{t}.setThinkTime(jline.lang.processes.HyperExp(sn.think_params{tidx}(1), sn.think_params{tidx}(2), sn.think_params{tidx}(3)));
145 else
146 T{t}.setThinkTime(jline.lang.processes.HyperExp.fitMeanAndSCV(sn.think_mean(tidx), sn.think_scv(tidx)));
147 end
148 case ProcessType.COXIAN
149 T{t}.setThinkTime(jline.lang.processes.Coxian.fitMeanAndSCV(sn.think_mean(tidx), sn.think_scv(tidx)));
150 case ProcessType.APH
151 T{t}.setThinkTime(jline.lang.processes.APH.fitMeanAndSCV(sn.think_mean(tidx), sn.think_scv(tidx)));
152 case ProcessType.PH
153 if ~isempty(sn.think_proc{tidx})
154 proc = sn.think_proc{tidx};
155 T{t}.setThinkTime(jline.lang.processes.PH(JLINE.from_line_matrix(proc{1}), JLINE.from_line_matrix(proc{2})));
156 else
157 T{t}.setThinkTime(jline.lang.processes.Exp(1/sn.think_mean(tidx)));
158 end
159 case ProcessType.MAP
160 if ~isempty(sn.think_proc{tidx})
161 proc = sn.think_proc{tidx};
162 T{t}.setThinkTime(jline.lang.processes.MAP(JLINE.from_line_matrix(proc{1}), JLINE.from_line_matrix(proc{2})));
163 else
164 T{t}.setThinkTime(jline.lang.processes.Exp(1/sn.think_mean(tidx)));
165 end
166 case ProcessType.DET
167 T{t}.setThinkTime(jline.lang.processes.Det(sn.think_mean(tidx)));
168 case ProcessType.UNIFORM
169 p = sn.think_params{tidx};
170 T{t}.setThinkTime(jline.lang.processes.Uniform(p(1), p(2)));
171 case ProcessType.GAMMA
172 p = sn.think_params{tidx};
173 T{t}.setThinkTime(jline.lang.processes.Gamma(p(1), p(2)));
174 case ProcessType.PARETO
175 p = sn.think_params{tidx};
176 T{t}.setThinkTime(jline.lang.processes.Pareto(p(1), p(2)));
177 case ProcessType.WEIBULL
178 p = sn.think_params{tidx};
179 T{t}.setThinkTime(jline.lang.processes.Weibull(p(1), p(2)));
180 case ProcessType.LOGNORMAL
181 p = sn.think_params{tidx};
182 T{t}.setThinkTime(jline.lang.processes.Lognormal(p(1), p(2)));
183 otherwise
184 line_error(mfilename,sprintf('JLINE conversion does not support the %s distribution for task think time yet.',char(sn.think_type(tidx))));
185 end
186 end
187 % Setup time
188 if sn.isfunction(tidx) && ~isnan(sn.setuptime_mean(tidx)) && sn.setuptime_mean(tidx) > 1e-8
189 T{t}.setSetupTime(sn.setuptime_mean(tidx));
190 end
191 % Delay-off time
192 if sn.isfunction(tidx) && ~isnan(sn.delayofftime_mean(tidx)) && sn.delayofftime_mean(tidx) > 1e-8
193 T{t}.setDelayOffTime(sn.delayofftime_mean(tidx));
194 end
195 end
196 %% entries
197 E = cell(1,sn.nentries);
198 for e=1:sn.nentries
199 eidx = sn.eshift+e;
200 % Check if this is an ItemEntry (has nitems > 0)
201 if sn.nitems(eidx) > 0
202 % ItemEntry requires cardinality and popularity distribution
203 if ~isempty(sn.itemproc) && ~isempty(sn.itemproc{eidx})
204 jPopularity = JLINE.from_line_distribution(sn.itemproc{eidx});
205 else
206 % Default to uniform distribution
207 jPopularity = javaObject('jline.lang.processes.DiscreteSampler', jline.util.matrix.Matrix.uniformDistribution(sn.nitems(eidx)));
208 end
209 E{e} = javaObject('jline.lang.layered.ItemEntry', model, sn.names{eidx}, sn.nitems(eidx), jPopularity);
210 else
211 E{e} = javaObject('jline.lang.layered.Entry', model, sn.names{eidx});
212 end
213 E{e}.on(T{sn.parent(eidx)-sn.tshift});
214 end
215
216 %% activities
217 A = cell(1,sn.nacts);
218 for a=1:sn.nacts
219 aidx = sn.ashift+a;
220 tidx = sn.parent(aidx);
221 onTask = tidx-sn.tshift;
222 % Convert host demand from primitives to Java distribution
223 switch sn.hostdem_type(aidx)
224 case ProcessType.IMMEDIATE
225 jHostDem = jline.lang.processes.Immediate;
226 case ProcessType.DISABLED
227 jHostDem = jline.lang.processes.Disabled;
228 case ProcessType.EXP
229 jHostDem = javaObject('jline.lang.processes.Exp', 1/sn.hostdem_mean(aidx));
230 case ProcessType.ERLANG
231 jHostDem = jline.lang.processes.Erlang.fitMeanAndSCV(sn.hostdem_mean(aidx), sn.hostdem_scv(aidx));
232 case ProcessType.HYPEREXP
233 if ~isempty(sn.hostdem_params{aidx}) && length(sn.hostdem_params{aidx}) >= 3
234 jHostDem = javaObject('jline.lang.processes.HyperExp', sn.hostdem_params{aidx}(1), sn.hostdem_params{aidx}(2), sn.hostdem_params{aidx}(3));
235 else
236 jHostDem = jline.lang.processes.HyperExp.fitMeanAndSCV(sn.hostdem_mean(aidx), sn.hostdem_scv(aidx));
237 end
238 case ProcessType.COXIAN
239 jHostDem = jline.lang.processes.Coxian.fitMeanAndSCV(sn.hostdem_mean(aidx), sn.hostdem_scv(aidx));
240 case ProcessType.APH
241 jHostDem = jline.lang.processes.APH.fitMeanAndSCV(sn.hostdem_mean(aidx), sn.hostdem_scv(aidx));
242 case ProcessType.PH
243 if ~isempty(sn.hostdem_proc{aidx})
244 proc = sn.hostdem_proc{aidx};
245 jHostDem = javaObject('jline.lang.processes.PH', JLINE.from_line_matrix(proc{1}), JLINE.from_line_matrix(proc{2}));
246 else
247 jHostDem = javaObject('jline.lang.processes.Exp', 1/sn.hostdem_mean(aidx));
248 end
249 case ProcessType.MAP
250 if ~isempty(sn.hostdem_proc{aidx})
251 proc = sn.hostdem_proc{aidx};
252 jHostDem = javaObject('jline.lang.processes.MAP', JLINE.from_line_matrix(proc{1}), JLINE.from_line_matrix(proc{2}));
253 else
254 jHostDem = javaObject('jline.lang.processes.Exp', 1/sn.hostdem_mean(aidx));
255 end
256 case ProcessType.DET
257 jHostDem = javaObject('jline.lang.processes.Det', sn.hostdem_mean(aidx));
258 case ProcessType.UNIFORM
259 p = sn.hostdem_params{aidx};
260 jHostDem = javaObject('jline.lang.processes.Uniform', p(1), p(2));
261 case ProcessType.GAMMA
262 p = sn.hostdem_params{aidx};
263 jHostDem = javaObject('jline.lang.processes.Gamma', p(1), p(2));
264 case ProcessType.PARETO
265 p = sn.hostdem_params{aidx};
266 jHostDem = javaObject('jline.lang.processes.Pareto', p(1), p(2));
267 case ProcessType.WEIBULL
268 p = sn.hostdem_params{aidx};
269 jHostDem = javaObject('jline.lang.processes.Weibull', p(1), p(2));
270 case ProcessType.LOGNORMAL
271 p = sn.hostdem_params{aidx};
272 jHostDem = javaObject('jline.lang.processes.Lognormal', p(1), p(2));
273 otherwise
274 line_error(mfilename,sprintf('JLINE conversion does not support the %s distribution for host demand yet.',char(sn.hostdem_type(aidx))));
275 end
276 A{a} = javaObject('jline.lang.layered.Activity', model, sn.names{aidx}, jHostDem);
277 A{a}.on(T{onTask});
278
279 boundTo = find(sn.graph((sn.eshift+1):(sn.eshift+sn.nentries),aidx));
280
281 if ~isempty(boundTo)
282 A{a}.boundTo(E{boundTo});
283 end
284
285 if sn.sched(tidx) ~= SchedStrategy.REF % ref tasks don't reply
286 repliesTo = find(sn.replygraph(a,:)); % index of entry
287 if ~isempty(repliesTo)
288 if ~sn.isref(sn.parent(sn.eshift+repliesTo))
289 A{a}.repliesTo(E{repliesTo});
290 end
291 end
292 end
293
294 if ~isempty(sn.callpair)
295 cidxs = find(sn.callpair(:,1)==aidx);
296 calls = sn.callpair(:,2);
297 for c = cidxs(:)'
298 switch sn.calltype(c)
299 case CallType.SYNC
300 A{a}.synchCall(E{calls(c)-sn.eshift},sn.callproc_mean(c));
301 case CallType.ASYNC
302 A{a}.asynchCall(E{calls(c)-sn.eshift},sn.callproc_mean(c));
303 end
304 end
305 end
306
307 end
308
309 %% think times
310 for h=1:sn.nhosts
311 if ~isempty(sn.think{h}) && sn.think_type(h) ~= ProcessType.DISABLED
312 switch sn.think_type(h)
313 case ProcessType.IMMEDIATE
314 P{h}.setThinkTime(jline.lang.processes.Immediate);
315 case ProcessType.EXP
316 P{h}.setThinkTime(jline.lang.processes.Exp(1/sn.think_mean(h)));
317 case ProcessType.ERLANG
318 P{h}.setThinkTime(jline.lang.processes.Erlang.fitMeanAndSCV(sn.think_mean(h),sn.think_scv(h)));
319 case ProcessType.HYPEREXP
320 % For HyperExp, reconstruct from params if available, otherwise use fitMeanAndSCV
321 if ~isempty(sn.think_params{h}) && length(sn.think_params{h}) >= 3
322 P{h}.setThinkTime(jline.lang.processes.HyperExp(sn.think_params{h}(1), sn.think_params{h}(2), sn.think_params{h}(3)));
323 else
324 P{h}.setThinkTime(jline.lang.processes.HyperExp.fitMeanAndSCV(sn.think_mean(h), sn.think_scv(h)));
325 end
326 case ProcessType.COXIAN
327 % For Coxian, use fitMeanAndSCV
328 P{h}.setThinkTime(jline.lang.processes.Coxian.fitMeanAndSCV(sn.think_mean(h), sn.think_scv(h)));
329 case ProcessType.APH
330 % For APH, reconstruct from params if available
331 if ~isempty(sn.think_params{h})
332 P{h}.setThinkTime(jline.lang.processes.APH.fitMeanAndSCV(sn.think_mean(h), sn.think_scv(h)));
333 else
334 P{h}.setThinkTime(jline.lang.processes.Exp(1/sn.think_mean(h)));
335 end
336 case ProcessType.DET
337 P{h}.setThinkTime(jline.lang.processes.Det(sn.think_mean(h)));
338 case ProcessType.UNIFORM
339 p = sn.think_params{h};
340 P{h}.setThinkTime(jline.lang.processes.Uniform(p(1), p(2)));
341 case ProcessType.GAMMA
342 p = sn.think_params{h};
343 P{h}.setThinkTime(jline.lang.processes.Gamma(p(1), p(2)));
344 case ProcessType.PARETO
345 p = sn.think_params{h};
346 P{h}.setThinkTime(jline.lang.processes.Pareto(p(1), p(2)));
347 case ProcessType.WEIBULL
348 p = sn.think_params{h};
349 P{h}.setThinkTime(jline.lang.processes.Weibull(p(1), p(2)));
350 case ProcessType.LOGNORMAL
351 p = sn.think_params{h};
352 P{h}.setThinkTime(jline.lang.processes.Lognormal(p(1), p(2)));
353 otherwise
354 line_error(mfilename,sprintf('JLINE conversion does not support the %s distribution yet.',char(sn.think_type(h))));
355 end
356 end
357 end
358
359 %% Sequential precedences
360 for ai = 1:sn.nacts
361 aidx = sn.ashift + ai;
362 tidx = sn.parent(aidx);
363 % for all successors
364 for bidx=find(sn.graph(aidx,:))
365 if bidx > sn.ashift % ignore precedence between entries and activities
366 % Serial pattern (SEQ)
367 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_SEQ && full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_SEQ
368 T{tidx-sn.tshift}.addPrecedence(jline.lang.layered.ActivityPrecedence.Serial(sn.names{aidx}, sn.names{bidx}));
369 end
370 end
371 end
372 end
373
374 %%%%%%%%%%%%%%%%%%%%%%%%%%% translated up to here
375
376 %% Loop precedences (POST_LOOP)
377 % Loop structure in sn.graph:
378 % - Entry activity (preAct) has edge to first loop body activity
379 % - Last loop body activity has back-edge to first loop body (weight = 1-1/counts)
380 % - Last loop body activity has edge to end activity (weight = 1/counts)
381 % - All loop body and end activities have POST_LOOP type
382 processedLoops = false(1, sn.nacts);
383 for ai = 1:sn.nacts
384 aidx = sn.ashift + ai;
385 tidx = sn.parent(aidx);
386 % Check if this activity starts a loop (has a successor with POST_LOOP type)
387 % and hasn't been processed as part of another loop
388 if processedLoops(ai)
389 continue;
390 end
391
392 successors = find(sn.graph(aidx,:));
393 for bidx = successors
394 if bidx > sn.ashift && full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_LOOP
395 % Skip if this loop body activity was already processed
396 if processedLoops(bidx - sn.ashift)
397 continue;
398 end
399 % Found start of a loop: aidx is the entry, bidx is first loop body activity
400 loopStart = bidx;
401 precActs = java.util.ArrayList();
402
403 % Follow the chain of POST_LOOP activities
404 curIdx = loopStart;
405 while true
406 precActs.add(sprintf("%s", sn.names{curIdx}));
407 processedLoops(curIdx - sn.ashift) = true;
408
409 % Find successors of current activity
410 curSuccessors = find(sn.graph(curIdx,:));
411 curSuccessors = curSuccessors(curSuccessors > sn.ashift);
412
413 % Check for loop termination: find the end activity
414 % End activity has weight = 1/counts (not the back-edge weight)
415 endIdx = 0;
416 nextIdx = 0;
417 for succIdx = curSuccessors
418 if full(sn.actposttype(succIdx)) == ActivityPrecedenceType.POST_LOOP
419 if succIdx == loopStart
420 % This is the back-edge, skip it
421 continue;
422 end
423 weight = full(sn.graph(curIdx, succIdx));
424 if weight > 0 && weight < 1
425 % This is the end activity (weight = 1/counts)
426 endIdx = succIdx;
427 else
428 % This is the next activity in the loop body (weight = 1.0)
429 nextIdx = succIdx;
430 end
431 end
432 end
433
434 if endIdx > 0
435 % Found end activity - calculate counts and output
436 weight = full(sn.graph(curIdx, endIdx));
437 if weight > 0
438 counts = 1/weight;
439 else
440 counts = 1; % Fallback to prevent division by zero
441 end
442 precActs.add(sprintf("%s", sn.names{endIdx}));
443 processedLoops(endIdx - sn.ashift) = true;
444
445 T{tidx-sn.tshift}.addPrecedence(jline.lang.layered.ActivityPrecedence.Loop(sn.names{aidx}, precActs, jline.util.matrix.Matrix(counts)));
446 break;
447 elseif nextIdx > 0
448 % Continue to next activity in loop body
449 curIdx = nextIdx;
450 else
451 % No more successors - shouldn't happen in valid loop
452 break;
453 end
454 end
455 break; % Only process one loop starting from this activity
456 end
457 end
458 end
459
460 %% OrFork precedences (POST_OR)
461 precMarker = 0;
462 for ai = 1:sn.nacts
463 probs = [];
464 aidx = sn.ashift + ai;
465 tidx = sn.parent(aidx);
466 prob_ctr = 0;
467 % for all successors
468 for bidx=find(sn.graph(aidx,:))
469 if bidx > sn.ashift % ignore precedence between entries and activities
470 % Or pattern (POST_OR)
471 if full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_OR
472 if precMarker == 0 % start a new orjoin
473 precActs = java.util.ArrayList();
474 precMarker = aidx-sn.ashift;
475 precActs.add(sprintf("%s", sn.names{bidx}));
476 probs=full(sn.graph(aidx,bidx));
477 else
478 precActs.add(sprintf("%s", sn.names{bidx}));
479 probs(end+1)=full(sn.graph(aidx,bidx));
480 end
481 end
482 end
483 end
484
485
486 if precMarker > 0
487 probsMatrix = jline.util.matrix.Matrix(1,length(probs));
488 for i=1:length(probs)
489 probsMatrix.set(0,i-1,probs(i));
490 end
491 T{tidx-sn.tshift}.addPrecedence(jline.lang.layered.ActivityPrecedence.OrFork(sn.names{precMarker+sn.ashift}, precActs, probsMatrix));
492 precMarker = 0;
493 end
494 end
495
496 %% AndFork precedences (POST_AND)
497 precMarker = 0;
498 postActs = '';
499 for ai = 1:sn.nacts
500 aidx = sn.ashift + ai;
501 tidx = sn.parent(aidx);
502 % for all successors
503 for bidx=find(sn.graph(aidx,:))
504 if bidx > sn.ashift % ignore precedence between entries and activities
505 % Or pattern (POST_AND)
506 if full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_AND
507 if isempty(postActs)
508 postActs = java.util.ArrayList();
509 postActs.add(sprintf("%s", sn.names{bidx}));
510 else
511 postActs.add(sprintf("%s", sn.names{bidx}));
512 end
513
514 if precMarker == 0 % start a new orjoin
515 precMarker = aidx-sn.ashift;
516 end
517 end
518 end
519 end
520 if precMarker > 0
521 T{tidx-sn.tshift}.addPrecedence(jline.lang.layered.ActivityPrecedence.AndFork(sn.names{precMarker+sn.ashift}, postActs));
522 precMarker = 0;
523 end
524 end
525
526 %% CacheAccess precedences (POST_CACHE)
527 precMarker = 0;
528 postActs = '';
529 for ai = 1:sn.nacts
530 aidx = sn.ashift + ai;
531 tidx = sn.parent(aidx);
532 % for all successors
533 for bidx=find(sn.graph(aidx,:))
534 if bidx > sn.ashift % ignore precedence between entries and activities
535 % CacheAccess pattern (POST_CACHE)
536 if full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_CACHE
537 if isempty(postActs)
538 postActs = java.util.ArrayList();
539 postActs.add(sprintf("%s", sn.names{bidx}));
540 else
541 postActs.add(sprintf("%s", sn.names{bidx}));
542 end
543
544 if precMarker == 0 % start a new cache access
545 precMarker = aidx-sn.ashift;
546 end
547 end
548 end
549 end
550 if precMarker > 0
551 T{tidx-sn.tshift}.addPrecedence(jline.lang.layered.ActivityPrecedence.CacheAccess(sn.names{precMarker+sn.ashift}, postActs));
552 precMarker = 0;
553 postActs = '';
554 end
555 end
556
557 %% OrJoin precedences (PRE_OR)
558 precMarker = 0;
559 for bi = sn.nacts:-1:1
560 bidx = sn.ashift + bi;
561 tidx = sn.parent(bidx);
562 % for all predecessors
563 for aidx=find(sn.graph(:,bidx))'
564 if aidx > sn.ashift % ignore precedence between entries and activities
565 % OrJoin pattern (PRE_OR)
566 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_OR
567 if precMarker == 0 % start a new orjoin
568 precActs = java.util.ArrayList();
569 precMarker = bidx-sn.ashift;
570 precActs.add(sprintf("%s", sn.names{aidx}));
571 else
572 precActs.add(sprintf("%s", sn.names{aidx}));
573 end
574 end
575 end
576 end
577 if precMarker > 0
578 T{tidx-sn.tshift}.addPrecedence(jline.lang.layered.ActivityPrecedence.OrJoin(precActs, sn.names{precMarker+sn.ashift}));
579 precMarker = 0;
580 end
581 end
582
583 %% AndJoin precedences (PRE_AND)
584 precMarker = 0;
585 for bi = sn.nacts:-1:1
586 bidx = sn.ashift + bi;
587 tidx = sn.parent(bidx);
588 % for all predecessors
589 for aidx=find(sn.graph(:,bidx))'
590 if aidx > sn.ashift % ignore precedence between entries and activities
591 % OrJoin pattern (PRE_AND)
592 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_AND
593 if precMarker == 0 % start a new orjoin
594 precActs = java.util.ArrayList();
595 precMarker = bidx-sn.ashift;
596 precActs.add(sprintf("%s", sn.names{aidx}));
597 else
598 precActs.add(sprintf("%s", sn.names{aidx}));
599 end
600 end
601 end
602 end
603 if precMarker > 0
604 % Find quorum parameter from original precedence structure
605 postActName = sn.names{precMarker+sn.ashift};
606 localTaskIdx = tidx - sn.tshift;
607 quorum = [];
608 for ap = 1:length(line_layered_network.tasks{localTaskIdx}.precedences)
609 precedence = line_layered_network.tasks{localTaskIdx}.precedences(ap);
610 if precedence.preType == ActivityPrecedenceType.PRE_AND
611 % Check if this precedence contains our post activity
612 if any(strcmp(precedence.postActs, postActName))
613 quorum = precedence.preParams;
614 break;
615 end
616 end
617 end
618
619 if isempty(quorum)
620 T{tidx-sn.tshift}.addPrecedence(jline.lang.layered.ActivityPrecedence.AndJoin(precActs, sn.names{precMarker+sn.ashift}));
621 else
622 T{tidx-sn.tshift}.addPrecedence(jline.lang.layered.ActivityPrecedence.AndJoin(precActs, sn.names{precMarker+sn.ashift}, quorum));
623 end
624 precMarker = 0;
625 end
626 end
627
628 end
629
630 function jdist = from_line_distribution(line_dist)
631 if isa(line_dist, 'Exp')
632 jdist = javaObject('jline.lang.processes.Exp', line_dist.getParam(1).paramValue);
633 elseif isa(line_dist, "APH")
634 alpha = line_dist.getParam(1).paramValue;
635 T = line_dist.getParam(2).paramValue;
636 jline_alpha = java.util.ArrayList();
637 for i = 1:length(alpha)
638 jline_alpha.add(alpha(i));
639 end
640 jline_T = JLINE.from_line_matrix(T);
641 jdist = javaObject('jline.lang.processes.APH', jline_alpha, jline_T);
642 elseif isa(line_dist, 'Coxian')
643 jline_mu = java.util.ArrayList();
644 jline_phi = java.util.ArrayList();
645 if length(line_dist.params) == 3
646 jline_mu.add(line_dist.getParam(1).paramValue);
647 jline_mu.add(line_dist.getParam(2).paramValue);
648 jline_phi.add(line_dist.getParam(3).paramValue);
649 else
650 mu = line_dist.getParam(1).paramValue;
651 phi = line_dist.getParam(2).paramValue;
652 for i = 1:length(mu)
653 jline_mu.add(mu(i));
654 end
655 for i = 1:length(phi)
656 jline_phi.add(phi(i));
657 end
658 end
659 jdist = javaObject('jline.lang.processes.Coxian', jline_mu, jline_phi);
660 elseif isa(line_dist, 'Det')
661 jdist = javaObject('jline.lang.processes.Det', line_dist.getParam(1).paramValue);
662 elseif isa(line_dist, 'DiscreteSampler')
663 popularity_p = JLINE.from_line_matrix(line_dist.getParam(1).paramValue);
664 popularity_val = JLINE.from_line_matrix(line_dist.getParam(2).paramValue);
665 jdist = javaObject('jline.lang.processes.DiscreteSampler', popularity_p, popularity_val);
666 elseif isa(line_dist, 'Erlang')
667 jdist = javaObject('jline.lang.processes.Erlang', line_dist.getParam(1).paramValue, line_dist.getParam(2).paramValue);
668 elseif isa(line_dist, 'Gamma')
669 jdist = javaObject('jline.lang.processes.Gamma', line_dist.getParam(1).paramValue, line_dist.getParam(2).paramValue);
670 elseif isa(line_dist, "HyperExp")
671 jdist = javaObject('jline.lang.processes.HyperExp', line_dist.getParam(1).paramValue, line_dist.getParam(2).paramValue, line_dist.getParam(3).paramValue);
672 elseif isa(line_dist, 'Lognormal')
673 jdist = javaObject('jline.lang.processes.Lognormal', line_dist.getParam(1).paramValue, line_dist.getParam(2).paramValue);
674 elseif isa(line_dist, 'Pareto')
675 jdist = javaObject('jline.lang.processes.Pareto', line_dist.getParam(1).paramValue, line_dist.getParam(2).paramValue);
676 elseif isa(line_dist, 'MAP')
677 D0 = line_dist.D(0);
678 D1 = line_dist.D(1);
679 jdist = javaObject('jline.lang.processes.MAP', JLINE.from_line_matrix(D0), JLINE.from_line_matrix(D1));
680 elseif isa(line_dist, 'MMPP2')
681 lambda0 = line_dist.getParam(1).paramValue;
682 lambda1 = line_dist.getParam(2).paramValue;
683 sigma0 = line_dist.getParam(3).paramValue;
684 sigma1 = line_dist.getParam(4).paramValue;
685 jdist = javaObject('jline.lang.processes.MMPP2', lambda0, lambda1, sigma0, sigma1);
686 elseif isa(line_dist, 'CyclicPoisson')
687 jdist = javaObject('jline.lang.processes.CyclicPoisson', line_dist.getRates(), line_dist.getDurations());
688 elseif isa(line_dist, 'PH')
689 alpha = line_dist.getParam(1).paramValue;
690 T = line_dist.getParam(2).paramValue;
691 jdist = javaObject('jline.lang.processes.PH', JLINE.from_line_matrix(alpha), JLINE.from_line_matrix(T));
692 elseif isa(line_dist, 'Uniform')
693 jdist = javaObject('jline.lang.processes.Uniform', line_dist.getParam(1).paramValue, line_dist.getParam(2).paramValue);
694 elseif isa(line_dist, 'Weibull')
695 jdist = javaObject('jline.lang.processes.Weibull', line_dist.getParam(1).paramValue, line_dist.getParam(2).paramValue);
696 elseif isa(line_dist, 'Zipf')
697 jdist = javaObject('jline.lang.processes.Zipf', line_dist.getParam(3).paramValue, line_dist.getParam(4).paramValue);
698 elseif isa(line_dist, 'Immediate')
699 jdist = javaObject('jline.lang.processes.Immediate');
700 elseif isempty(line_dist) || isa(line_dist, 'Disabled')
701 jdist = javaObject('jline.lang.processes.Disabled');
702 return;
703 elseif isa(line_dist, 'Replayer')
704 jdist = javaObject('jline.lang.processes.Replayer', line_dist.params{1}.paramValue);
705 elseif isa(line_dist, 'Trace')
706 jdist = javaObject('jline.lang.processes.Trace', line_dist.params{1}.paramValue);
707 elseif isa(line_dist, 'Prior')
708 % Convert Prior: each alternative is a distribution
709 dists = line_dist.getParam(1).paramValue;
710 probs = line_dist.getParam(2).paramValue;
711 jdists = java.util.ArrayList();
712 for k = 1:length(dists)
713 jdists.add(JLINE.from_line_distribution(dists{k}));
714 end
715 jdist = javaObject('jline.lang.processes.Prior', jdists, probs);
716 else
717 line_error(mfilename,'Distribution not supported by JLINE.');
718 end
719 end
720
721 function matlab_dist = from_jline_distribution(jdist)
722 if isa(jdist, 'jline.lang.processes.Exp')
723 matlab_dist = Exp(jdist.getRate());
724 elseif isa(jdist, 'jline.lang.processes.Det')
725 matlab_dist = Det(jdist.getParam(1).getValue);
726 elseif isa(jdist, 'jline.lang.processes.Erlang')
727 matlab_dist = Erlang(jdist.getParam(1).getValue(),jdist.getNumberOfPhases());
728 elseif isa(jdist, 'jline.lang.processes.Gamma')
729 matlab_dist = Gamma(jdist.getParam(1).getValue,jdist.getParam(2).getValue);
730 elseif isa(jdist, 'jline.lang.processes.HyperExp')
731 matlab_dist = HyperExp(jdist.getParam(1).getValue, jdist.getParam(2).getValue, jdist.getParam(3).getValue);
732 elseif isa(jdist, 'jline.lang.processes.Lognormal')
733 matlab_dist = Lognormal(jdist.getParam(1).getValue,jdist.getParam(2).getValue);
734 elseif isa(jdist, 'jline.lang.processes.Pareto')
735 matlab_dist = Pareto(jdist.getParam(1).getValue,jdist.getParam(2).getValue);
736 elseif isa(jdist, 'jline.lang.processes.Uniform')
737 matlab_dist = Uniform(jdist.getParam(1).getValue,jdist.getParam(2).getValue);
738 elseif isa(jdist, 'jline.lang.processes.Weibull')
739 matlab_dist = Weibull(jdist.getParam(1).getValue,jdist.getParam(2).getValue);
740 elseif isa(jdist, 'jline.lang.processes.MAP')
741 D0 = JLINE.from_jline_matrix(jdist.D(0));
742 D1 = JLINE.from_jline_matrix(jdist.D(1));
743 matlab_dist = MAP({D0, D1});
744 elseif isa(jdist, 'jline.lang.processes.APH')
745 alpha = JLINE.from_jline_matrix(jdist.getInitProb());
746 T = JLINE.from_jline_matrix(jdist.getSubgenerator());
747 matlab_dist = APH(alpha(:)', T);
748 elseif isa(jdist, 'jline.lang.processes.PH')
749 alpha = JLINE.from_jline_matrix(jdist.getInitProb());
750 T = JLINE.from_jline_matrix(jdist.getSubgenerator());
751 matlab_dist = PH(alpha(:)', T);
752 elseif isa(jdist, 'jline.lang.processes.Coxian')
753 if jdist.getNumberOfPhases == 2
754 matlab_dist = Coxian([jdist.getParam(1).getValue.get(0), jdist.getParam(1).getValue.get(1)], [jdist.getParam(2).getValue.get(0),1]);
755 else
756 jmu = jdist.getParam(1).getValue;
757 jphi = jdist.getParam(2).getValue;
758 mu = zeros(1, jmu.size);
759 phi = zeros(1, jphi.size);
760 for i = 1:jmu.size
761 mu(i) = jmu.get(i-1);
762 end
763 for i = 1:jphi.size
764 phi(i) = jphi.get(i-1);
765 end
766 matlab_dist = Coxian(mu, phi);
767 end
768 elseif isa(jdist, 'jline.lang.processes.Zipf')
769 matlab_dist = Zipf(jdist.getParam(3).getValue, jdist.getParam(4).getValue);
770 elseif isa(jdist, 'jline.lang.processes.DiscreteSampler')
771 jpMat = jdist.getParam(1).getValue;
772 jxMat = jdist.getParam(2).getValue;
773 p = zeros(1, jpMat.length);
774 x = zeros(1, jxMat.length);
775 for i = 1:jpMat.length
776 p(i) = jpMat.get(i-1);
777 end
778 for i = 1:jxMat.length
779 x(i) = jxMat.get(i-1);
780 end
781 matlab_dist = DiscreteSampler(p, x);
782 elseif isa(jdist, 'jline.lang.processes.Immediate')
783 matlab_dist = Immediate();
784 elseif isa(jdist, 'jline.lang.processes.Disabled')
785 matlab_dist = Disabled();
786 elseif isa(jdist, 'jline.lang.processes.MMPP2')
787 matlab_dist = MMPP2(jdist.getParam(1).getValue, jdist.getParam(2).getValue, jdist.getParam(3).getValue, jdist.getParam(4).getValue);
788 elseif isa(jdist, 'jline.lang.processes.CyclicPoisson')
789 jRates = jdist.getRates();
790 jDurs = jdist.getDurations();
791 rates = zeros(1, length(jRates));
792 durs = zeros(1, length(jDurs));
793 for k = 1:length(jRates)
794 rates(k) = jRates(k);
795 durs(k) = jDurs(k);
796 end
797 matlab_dist = CyclicPoisson(rates, durs);
798 elseif isa(jdist, 'jline.lang.processes.Prior')
799 % Convert Prior from JAR to MATLAB
800 jdists = jdist.getDistributions();
801 nalt = jdists.size();
802 dists = cell(1, nalt);
803 for k = 1:nalt
804 dists{k} = JLINE.from_jline_distribution(jdists.get(k-1));
805 end
806 probs = jdist.getProbabilities();
807 matlab_dist = Prior(dists, probs);
808 else
809 line_error(mfilename,'Distribution not supported by JLINE.');
810 end
811 end
812
813 function set_csMatrix(line_node, jnode, jclasses)
814 nClasses = length(line_node.model.classes);
815 csMatrix = jnode.initClassSwitchMatrix();
816 for i = 1:nClasses
817 for j = 1:nClasses
818 csMatrix.set(jclasses{i}, jclasses{j}, line_node.server.csFun(i,j,0,0));
819 end
820 end
821 jnode.setClassSwitchingMatrix(csMatrix);
822 end
823
824 function set_service(line_node, jnode, job_classes)
825 if (isa(line_node, 'Sink') || isa(line_node, 'Router') || isa(line_node, 'Cache') || isa(line_node, 'Logger') || isa(line_node, 'ClassSwitch') || isa(line_node, 'Fork') || isa(line_node, 'Join') || isa(line_node, 'Place') || isa(line_node, 'Transition'))
826 return;
827 end
828
829 for n = 1 : length(job_classes)
830 if (isa(line_node, 'Queue') || isa(line_node, 'Delay'))
831 matlab_dist = line_node.getService(job_classes{n});
832 elseif (isa(line_node, 'Source'))
833 matlab_dist = line_node.getArrivalProcess(job_classes{n});
834 else
835 line_error(mfilename,'Node not supported by JLINE.');
836 end
837 service_dist = JLINE.from_line_distribution(matlab_dist);
838
839 if (isa(line_node,'Queue') || isa(line_node, 'Delay'))
840 jnode.setService(jnode.getModel().getClasses().get(n-1), service_dist, line_node.schedStrategyPar(n));
841 elseif (isa(line_node, 'Source'))
842 jnode.setArrival(jnode.getModel().getClasses().get(n-1), service_dist);
843 end
844 end
845 end
846
847 function set_delayoff(line_node, jnode, job_classes)
848 % Transfer setup and delayoff times from MATLAB Queue to Java Queue
849 if ~isa(line_node, 'Queue')
850 return;
851 end
852
853 % Check if setupTime property exists and is not empty
854 if ~isprop(line_node, 'setupTime') || isempty(line_node.setupTime)
855 return;
856 end
857
858 for n = 1 : length(job_classes)
859 c = job_classes{n}.index;
860 % Check if both setupTime and delayoffTime are set for this class
861 if c <= length(line_node.setupTime) && ~isempty(line_node.setupTime{1, c}) && ...
862 c <= length(line_node.delayoffTime) && ~isempty(line_node.delayoffTime{1, c})
863 % Convert MATLAB distributions to Java distributions
864 setup_dist = JLINE.from_line_distribution(line_node.setupTime{1, c});
865 delayoff_dist = JLINE.from_line_distribution(line_node.delayoffTime{1, c});
866 % Set delayoff on the Java Queue
867 jnode.setDelayOff(jnode.getModel().getClasses().get(n-1), setup_dist, delayoff_dist);
868 end
869 end
870 end
871
872 function set_line_service(jline_node, line_node, job_classes, line_classes)
873 if (isa(line_node,'Sink')) || isa(line_node, 'ClassSwitch') || isa(line_node, 'Fork') || isa(line_node, 'Join') || isa(line_node, 'Place') || isa(line_node, 'Transition') || isa(line_node, 'Cache')
874 return;
875 end
876 for n = 1:job_classes.size()
877 if (isa(line_node, 'Queue') || isa(line_node, 'Delay'))
878 jdist = jline_node.getServiceProcess(job_classes.get(n-1));
879 matlab_dist = JLINE.from_jline_distribution(jdist);
880 weight = jline_node.getSchedStrategyPar(job_classes.get(n-1));
881 line_node.setService(line_classes{n}, matlab_dist, weight);
882 elseif (isa(line_node, 'Source'))
883 jdist = jline_node.getArrivalProcess(job_classes.get(n-1));
884 matlab_dist = JLINE.from_jline_distribution(jdist);
885 line_node.setArrival(line_classes{n}, matlab_dist);
886 elseif (isa(line_node, 'Router'))
887 % no-op
888 else
889 line_error(mfilename,'Node not supported by JLINE.');
890 end
891 end
892 end
893
894 function node_object = from_line_node(line_node, jnetwork, ~, forkNode, sn)
895 % Handle optional sn argument
896 if nargin < 5
897 sn = [];
898 end
899 if isa(line_node, 'Delay')
900 node_object = javaObject('jline.lang.nodes.Delay', jnetwork, line_node.getName);
901 elseif isa(line_node, 'Queue')
902 switch line_node.schedStrategy
903 case SchedStrategy.INF
904 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.INF);
905 case SchedStrategy.FCFS
906 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.FCFS);
907 case SchedStrategy.LCFS
908 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LCFS);
909 case SchedStrategy.SIRO
910 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.SIRO);
911 case SchedStrategy.SJF
912 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.SJF);
913 case SchedStrategy.LJF
914 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LJF);
915 case SchedStrategy.PS
916 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.PS);
917 case SchedStrategy.DPS
918 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.DPS);
919 case SchedStrategy.GPS
920 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.GPS);
921 case SchedStrategy.SEPT
922 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.SEPT);
923 case SchedStrategy.LEPT
924 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LEPT);
925 case {SchedStrategy.HOL, SchedStrategy.FCFSPRIO}
926 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.FCFSPRIO);
927 case SchedStrategy.FORK
928 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.FORK);
929 case SchedStrategy.EXT
930 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.EXT);
931 case SchedStrategy.REF
932 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.REF);
933 case SchedStrategy.LCFSPR
934 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LCFSPR);
935 case SchedStrategy.LCFSPI
936 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LCFSPI);
937 case SchedStrategy.LCFSPRIO
938 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LCFSPRIO);
939 case SchedStrategy.LCFSPRPRIO
940 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LCFSPRPRIO);
941 case SchedStrategy.LCFSPIPRIO
942 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LCFSPIPRIO);
943 case SchedStrategy.FCFSPR
944 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.FCFSPR);
945 case SchedStrategy.FCFSPI
946 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.FCFSPI);
947 case SchedStrategy.FCFSPRPRIO
948 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.FCFSPRPRIO);
949 case SchedStrategy.FCFSPIPRIO
950 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.FCFSPIPRIO);
951 case SchedStrategy.PSPRIO
952 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.PSPRIO);
953 case SchedStrategy.DPSPRIO
954 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.DPSPRIO);
955 case SchedStrategy.GPSPRIO
956 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.GPSPRIO);
957 case SchedStrategy.POLLING
958 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.POLLING);
959 case SchedStrategy.SRPT
960 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.SRPT);
961 case SchedStrategy.SRPTPRIO
962 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.SRPTPRIO);
963 case SchedStrategy.PSJF
964 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.PSJF);
965 case SchedStrategy.FB
966 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.FB);
967 case SchedStrategy.LRPT
968 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LRPT);
969 case SchedStrategy.EDD
970 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.EDD);
971 case SchedStrategy.EDF
972 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.EDF);
973 case SchedStrategy.LPS
974 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.LPS);
975 case SchedStrategy.SETF
976 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.SETF);
977 case SchedStrategy.FSP
978 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.FSP);
979 case SchedStrategy.PAS
980 node_object = javaObject('jline.lang.nodes.Queue', jnetwork, line_node.getName, jline.lang.constant.SchedStrategy.PAS);
981 otherwise
982 line_error(mfilename, sprintf('JLINE conversion does not support the %s scheduling strategy yet.', char(SchedStrategy.toText(line_node.schedStrategy))));
983 end
984 nservers = line_node.getNumberOfServers;
985 if isinf(nservers)
986 node_object.setNumberOfServers(java.lang.Integer.MAX_VALUE);
987 elseif nservers > 1
988 node_object.setNumberOfServers(line_node.getNumberOfServers);
989 end
990 if ~isempty(line_node.lldScaling)
991 node_object.setLoadDependence(JLINE.from_line_matrix(line_node.lldScaling));
992 end
993 if ~isempty(line_node.lcdScaling)
994 if isempty(sn)
995 line_error(mfilename, "Class-dependent models require sn struct for MATLAB-to-JAVA translation.");
996 end
997 node_object.setLimitedClassDependence(JLINE.handle_to_serializablefun(line_node.lcdScaling, sn));
998 end
999 % Transfer LJD (Limited Joint Dependence) scaling
1000 if ~isempty(line_node.ljdScaling) && ~isempty(line_node.ljdCutoffs)
1001 jScaling = JLINE.from_line_matrix(line_node.ljdScaling(:));
1002 jCutoffs = JLINE.from_line_matrix(line_node.ljdCutoffs(:));
1003 node_object.setLimitedJointDependence(jScaling, jCutoffs);
1004 end
1005 % NOTE: LJCD (Limited Joint Class Dependence) is transferred in
1006 % from_line_network after classes are created
1007 % Set queue capacity if finite
1008 if ~isinf(line_node.cap)
1009 node_object.setCapacity(line_node.cap);
1010 end
1011 % Transfer LPS job limit (stored in schedStrategyPar(1))
1012 if line_node.schedStrategy == SchedStrategy.LPS && ~isempty(line_node.schedStrategyPar) && line_node.schedStrategyPar(1) >= 1
1013 node_object.setLimit(int32(line_node.schedStrategyPar(1)));
1014 end
1015 elseif isa(line_node, 'Source')
1016 node_object = javaObject('jline.lang.nodes.Source', jnetwork, line_node.getName);
1017 elseif isa(line_node, 'Sink')
1018 node_object = javaObject('jline.lang.nodes.Sink', jnetwork, line_node.getName);
1019 elseif isa(line_node, 'Router')
1020 node_object = javaObject('jline.lang.nodes.Router', jnetwork, line_node.getName);
1021 elseif isa(line_node, 'ClassSwitch')
1022 node_object = javaObject('jline.lang.nodes.ClassSwitch', jnetwork, line_node.getName);
1023 elseif isa(line_node, 'Fork')
1024 node_object = javaObject('jline.lang.nodes.Fork', jnetwork, line_node.name);
1025 node_object.setTasksPerLink(line_node.output.tasksPerLink);
1026 elseif isa(line_node, 'Join')
1027 node_object = javaObject('jline.lang.nodes.Join', jnetwork, line_node.name, forkNode);
1028 elseif isa(line_node, 'Logger')
1029 node_object = javaObject('jline.lang.nodes.Logger', jnetwork, line_node.name, [line_node.filePath,line_node.fileName]);
1030 elseif isa(line_node, 'Cache')
1031 nitems = line_node.items.nitems;
1032 switch line_node.replacestrategy
1033 case ReplacementStrategy.RR
1034 repStrategy = jline.lang.constant.ReplacementStrategy.RR;
1035 case ReplacementStrategy.FIFO
1036 repStrategy = jline.lang.constant.ReplacementStrategy.FIFO;
1037 case ReplacementStrategy.SFIFO
1038 repStrategy = jline.lang.constant.ReplacementStrategy.SFIFO;
1039 case ReplacementStrategy.LRU
1040 repStrategy = jline.lang.constant.ReplacementStrategy.LRU;
1041 end
1042 if ~isempty(line_node.graph)
1043 node_object = javaObject('jline.lang.nodes.Cache', jnetwork, line_node.name, nitems, JLINE.from_line_matrix(line_node.itemLevelCap), repStrategy, JLINE.from_line_matrix(line_node.graph));
1044 else
1045 node_object = javaObject('jline.lang.nodes.Cache', jnetwork, line_node.name, nitems, JLINE.from_line_matrix(line_node.itemLevelCap), repStrategy);
1046 end
1047 elseif isa(line_node, 'Place')
1048 node_object = javaObject('jline.lang.nodes.Place', jnetwork, line_node.getName);
1049 elseif isa(line_node, 'Transition')
1050 node_object = javaObject('jline.lang.nodes.Transition', jnetwork, line_node.getName);
1051 % Modes are added later in from_line_network after classes are created
1052 else
1053 line_error(mfilename,'Node not supported by JLINE.');
1054 end
1055 end
1056
1057 function node_object = from_jline_node(jline_node, model, job_classes)
1058 if isa(jline_node, 'jline.lang.nodes.Delay')
1059 node_object = Delay(model, jline_node.getName.toCharArray');
1060 elseif isa(jline_node, 'jline.lang.nodes.Queue')
1061 schedStrategy = jline_node.getSchedStrategy;
1062 switch schedStrategy.name().toCharArray'
1063 case 'INF'
1064 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.INF);
1065 case 'FCFS'
1066 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.FCFS);
1067 case 'LCFS'
1068 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.LCFS);
1069 case 'SIRO'
1070 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.SIRO);
1071 case 'SJF'
1072 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.SJF);
1073 case 'LJF'
1074 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.LJF);
1075 case 'PS'
1076 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.PS);
1077 case 'DPS'
1078 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.DPS);
1079 case 'GPS'
1080 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.GPS);
1081 case 'SEPT'
1082 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.SEPT);
1083 case 'LEPT'
1084 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.LEPT);
1085 case {'HOL', 'FCFSPRIO'}
1086 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.FCFSPRIO);
1087 case 'FORK'
1088 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.FORK);
1089 case 'EXT'
1090 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.EXT);
1091 case 'REF'
1092 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.REF);
1093 case 'LCFSPR'
1094 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.LCFSPR);
1095 case 'SRPT'
1096 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.SRPT);
1097 case 'SRPTPRIO'
1098 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.SRPTPRIO);
1099 case 'PSJF'
1100 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.PSJF);
1101 case 'FB'
1102 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.FB);
1103 case 'LRPT'
1104 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.LRPT);
1105 case 'PSPRIO'
1106 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.PSPRIO);
1107 case 'DPSPRIO'
1108 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.DPSPRIO);
1109 case 'GPSPRIO'
1110 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.GPSPRIO);
1111 case 'LCFSPI'
1112 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.LCFSPI);
1113 case 'LCFSPRIO'
1114 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.LCFSPRIO);
1115 case 'LCFSPRPRIO'
1116 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.LCFSPRPRIO);
1117 case 'LCFSPIPRIO'
1118 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.LCFSPIPRIO);
1119 case 'FCFSPR'
1120 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.FCFSPR);
1121 case 'FCFSPI'
1122 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.FCFSPI);
1123 case 'FCFSPRPRIO'
1124 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.FCFSPRPRIO);
1125 case 'FCFSPIPRIO'
1126 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.FCFSPIPRIO);
1127 case 'POLLING'
1128 node_object = Queue(model, jline_node.getName.toCharArray', SchedStrategy.POLLING);
1129 end
1130 node_object.setNumberOfServers(jline_node.getNumberOfServers);
1131 cap = jline_node.getCap();
1132 if cap < intmax && cap > 0
1133 node_object.setCapacity(cap);
1134 end
1135 if ~isempty(JLINE.from_jline_matrix(jline_node.getLimitedLoadDependence))
1136 node_object.setLoadDependence(JLINE.from_jline_matrix(jline_node.getLimitedLoadDependence));
1137 end
1138 elseif isa(jline_node, 'jline.lang.nodes.Source')
1139 node_object = Source(model, jline_node.getName.toCharArray');
1140 elseif isa(jline_node, 'jline.lang.nodes.Sink')
1141 node_object = Sink(model, jline_node.getName.toCharArray');
1142 elseif isa(jline_node, 'jline.lang.nodes.Router')
1143 node_object = Router(model, jline_node.getName.toCharArray');
1144 elseif isa(jline_node, 'jline.lang.nodes.ClassSwitch')
1145 nClasses = job_classes.size;
1146 csMatrix = zeros(nClasses, nClasses);
1147 for r = 1:nClasses
1148 for s = 1:nClasses
1149 csMatrix(r,s) = jline_node.getServer.applyCsFun(r-1,s-1);
1150 end
1151 end
1152 node_object = ClassSwitch(model, jline_node.getName.toCharArray', csMatrix);
1153 elseif isa(jline_node, 'jline.lang.nodes.Cache')
1154 numItems = jline_node.getNumberOfItems();
1155 itemLevelCap = JLINE.from_jline_matrix(jline_node.getItemLevelCap());
1156 replPolicy = jline_node.getReplacementStrategy();
1157 switch char(replPolicy)
1158 case 'LRU'
1159 rp = ReplacementStrategy.LRU;
1160 case 'FIFO'
1161 rp = ReplacementStrategy.FIFO;
1162 case 'RR'
1163 rp = ReplacementStrategy.RR;
1164 otherwise
1165 rp = ReplacementStrategy.LRU;
1166 end
1167 node_object = Cache(model, jline_node.getName.toCharArray', numItems, itemLevelCap, rp);
1168 % hitClass, missClass, and popularity set later in jline_to_line
1169 elseif isa(jline_node, 'jline.lang.nodes.Fork')
1170 node_object = Fork(model, jline_node.getName.toCharArray');
1171 tpl = jline_node.getOutput().tasksPerLink;
1172 if tpl > 1
1173 node_object.setTasksPerLink(tpl);
1174 end
1175 elseif isa(jline_node, 'jline.lang.nodes.Join')
1176 node_object = Join(model, jline_node.getName.toCharArray');
1177 % joinOf is set later in jline_to_line after all nodes are created
1178 elseif isa(jline_node, 'jline.lang.nodes.Place')
1179 node_object = Place(model, jline_node.getName.toCharArray');
1180 elseif isa(jline_node, 'jline.lang.nodes.Transition')
1181 node_object = Transition(model, jline_node.getName.toCharArray');
1182 % Note: Mode configurations need to be set after classes are created
1183 else
1184 line_error(mfilename,'Node not supported by JLINE.');
1185 end
1186 end
1187
1188 function node_class = from_line_class(line_class, jnetwork)
1189 % Check signal classes first (before their base classes)
1190 if isa(line_class, 'ClosedSignal')
1191 % ClosedSignal -> jline.lang.ClosedSignal
1192 jSignalType = jline.lang.constant.SignalType.fromID(line_class.signalType);
1193 node_class = javaObject('jline.lang.ClosedSignal', jnetwork, line_class.getName, jSignalType, jnetwork.getNodeByName(line_class.refstat.getName), line_class.priority);
1194 elseif isa(line_class, 'Signal') || isa(line_class, 'OpenSignal')
1195 % Signal/OpenSignal -> jline.lang.Signal (includes CATASTROPHE type)
1196 jSignalType = jline.lang.constant.SignalType.fromID(line_class.signalType);
1197 node_class = javaObject('jline.lang.Signal', jnetwork, line_class.getName, jSignalType, line_class.priority);
1198 elseif isa(line_class, 'OpenClass')
1199 node_class = javaObject('jline.lang.OpenClass', jnetwork, line_class.getName, line_class.priority);
1200 elseif isa(line_class, 'SelfLoopingClass')
1201 node_class = javaObject('jline.lang.SelfLoopingClass', jnetwork, line_class.getName, line_class.population, jnetwork.getNodeByName(line_class.refstat.getName), line_class.priority);
1202 elseif isa(line_class, 'ClosedClass')
1203 node_class = javaObject('jline.lang.ClosedClass', jnetwork, line_class.getName, line_class.population, jnetwork.getNodeByName(line_class.refstat.getName), line_class.priority);
1204 else
1205 line_error(mfilename,'Class type not supported by JLINE.');
1206 end
1207 % Transfer relative deadline (used by EDD/EDF scheduling)
1208 if isprop(line_class, 'deadline') && ~isempty(line_class.deadline) && ~isinf(line_class.deadline)
1209 node_class.setDeadline(line_class.deadline);
1210 end
1211 if line_class.isReferenceClass()
1212 node_class.setReferenceClass(true);
1213 end
1214 end
1215
1216 function node_class = from_jline_class(jclass, model)
1217 if isa(jclass, 'jline.lang.OpenClass')
1218 node_class = OpenClass(model, jclass.getName.toCharArray', jclass.getPriority);
1219 elseif isa(jclass, 'jline.lang.SelfLoopingClass')
1220 node_class = SelfLoopingClass(model, jclass.getName.toCharArray', jclass.getNumberOfJobs, model.getNodeByName(jclass.getReferenceStation.getName), jclass.getPriority);
1221 elseif isa(jclass, 'jline.lang.ClosedClass')
1222 node_class = ClosedClass(model, jclass.getName.toCharArray', jclass.getNumberOfJobs, model.getNodeByName(jclass.getReferenceStation.getName), jclass.getPriority);
1223 else
1224 line_error(mfilename,'Class type not supported by JLINE.');
1225 end
1226 end
1227
1228 function from_line_links(model, jmodel)
1229 connections = model.getConnectionMatrix();
1230 [m, ~] = size(connections);
1231 jnodes = jmodel.getNodes();
1232 jclasses = jmodel.getClasses();
1233 njclasses = jclasses.size();
1234 line_nodes = model.getNodes;
1235 sn = model.getStruct;
1236
1237 % Build mapping from MATLAB node index to Java node index
1238 % (accounting for skipped auto-added ClassSwitch nodes)
1239 matlab2java_node_idx = zeros(1, length(line_nodes));
1240 jidx = 0;
1241 for i = 1:length(line_nodes)
1242 if isa(line_nodes{i}, 'ClassSwitch') && line_nodes{i}.autoAdded
1243 matlab2java_node_idx(i) = -1; % Mark as skipped
1244 else
1245 matlab2java_node_idx(i) = jidx;
1246 jidx = jidx + 1;
1247 end
1248 end
1249
1250 %nodevisits = cellsum(sn.nodevisits);
1251 % [ ] Update to consider different weights/routing for classes
1252 if isempty(sn.rtorig)
1253 useLinkMethod = false; % this model did not call link()
1254 else
1255 jrt_matrix = jmodel.initRoutingMatrix();
1256 useLinkMethod = true;
1257 end
1258
1259 % For models with auto-added ClassSwitch nodes, use sn.rtorig directly
1260 % to set up routing with proper class switching
1261 hasAutoCS = false;
1262 for i = 1:length(line_nodes)
1263 if isa(line_nodes{i}, 'ClassSwitch') && line_nodes{i}.autoAdded
1264 hasAutoCS = true;
1265 break;
1266 end
1267 end
1268
1269 if useLinkMethod && hasAutoCS
1270 % Use sn.rtorig directly - it contains the full routing with class switching
1271 % sn.rtorig already excludes auto-added ClassSwitch nodes (it's based on nstations)
1272 % So we iterate over the rtorig matrix dimensions directly
1273 for r = 1:njclasses
1274 for s = 1:njclasses
1275 if ~isempty(sn.rtorig{r,s})
1276 Prs = sn.rtorig{r,s};
1277 [nrows, ncols] = size(Prs);
1278 for i = 1:nrows
1279 for j = 1:ncols
1280 if Prs(i,j) > 0
1281 % sn.rtorig uses station indices which map to non-CS nodes
1282 % Find the java node indices by matching station index to node
1283 jsrc_idx = i - 1; % Direct mapping since rtorig excludes CS
1284 jdest_idx = j - 1;
1285 jrt_matrix.set(jclasses.get(r-1), jclasses.get(s-1), jnodes.get(jsrc_idx), jnodes.get(jdest_idx), Prs(i,j));
1286 end
1287 end
1288 end
1289 end
1290 end
1291 end
1292 else
1293 % Original logic for models without auto-added ClassSwitch
1294 for i = 1:m
1295 line_node = line_nodes{i};
1296
1297 % Skip auto-added ClassSwitch nodes - Java will add them automatically
1298 if isa(line_node, 'ClassSwitch') && line_node.autoAdded
1299 continue;
1300 end
1301
1302 jnode_idx = matlab2java_node_idx(i);
1303 for k = 1:njclasses
1304 output_strat = line_node.output.outputStrategy{k};
1305 switch RoutingStrategy.fromText(output_strat{2})
1306 case RoutingStrategy.DISABLED
1307 jnodes.get(jnode_idx).setRouting(jclasses.get(k-1),jline.lang.constant.RoutingStrategy.DISABLED);
1308 case RoutingStrategy.RAND
1309 jnodes.get(jnode_idx).setRouting(jclasses.get(k-1),jline.lang.constant.RoutingStrategy.RAND);
1310 outlinks_i=find(connections(i,:));
1311 if useLinkMethod
1312 % Do NOT add routing matrix entries for RAND routing.
1313 % JAR's getRoutingMatrix computes RAND routing from
1314 % the connection matrix (matching MATLAB behavior).
1315 % Adding entries would cause link() to convert RAND
1316 % to PROB, and for closed classes would incorrectly
1317 % include Sink connections.
1318 else
1319 for j= outlinks_i(:)'
1320 jdest_idx = matlab2java_node_idx(j);
1321 if jdest_idx >= 0
1322 jmodel.addLink(jnodes.get(jnode_idx), jnodes.get(jdest_idx));
1323 end
1324 end
1325 end
1326 case RoutingStrategy.RROBIN
1327 jnodes.get(jnode_idx).setRouting(jclasses.get(k-1),jline.lang.constant.RoutingStrategy.RROBIN);
1328 outlinks_i=find(connections(i,:))';
1329 if useLinkMethod
1330 line_error(mfilename,'RROBIN cannot be used together with the link() command.');
1331 end
1332 for j= outlinks_i(:)'
1333 jdest_idx = matlab2java_node_idx(j);
1334 if jdest_idx >= 0
1335 jmodel.addLink(jnodes.get(jnode_idx), jnodes.get(jdest_idx));
1336 end
1337 end
1338 case RoutingStrategy.WRROBIN
1339 outlinks_i=find(connections(i,:))';
1340 for j= outlinks_i(:)'
1341 jdest_idx = matlab2java_node_idx(j);
1342 if jdest_idx >= 0
1343 jmodel.addLink(jnodes.get(jnode_idx), jnodes.get(jdest_idx));
1344 end
1345 end
1346 if useLinkMethod
1347 line_error(mfilename,'RROBIN cannot be used together with the link() command.');
1348 end
1349 for j= 1:length(output_strat{3})
1350 node_target = jmodel.getNodeByName(output_strat{3}{j}{1}.getName());
1351 weight = output_strat{3}{j}{2};
1352 jnodes.get(jnode_idx).setRouting(jclasses.get(k-1),jline.lang.constant.RoutingStrategy.WRROBIN, node_target, weight);
1353 end
1354 case RoutingStrategy.PROB
1355 outlinks_i=find(connections(i,:));
1356 jnodes.get(jnode_idx).setRouting(jclasses.get(k-1), jline.lang.constant.RoutingStrategy.PROB);
1357 if ~useLinkMethod
1358 for j= outlinks_i(:)'
1359 jdest_idx = matlab2java_node_idx(j);
1360 if jdest_idx >= 0
1361 jmodel.addLink(jnodes.get(jnode_idx), jnodes.get(jdest_idx));
1362 end
1363 end
1364 end
1365 if length(output_strat) >= 3
1366 probabilities = output_strat{3};
1367 for j = 1:length(probabilities)
1368 dest_idx = probabilities{j}{1}.index;
1369 jdest_idx = matlab2java_node_idx(dest_idx);
1370 if (connections(i, dest_idx) ~= 0) && jdest_idx >= 0
1371 if useLinkMethod
1372 jrt_matrix.set(jclasses.get(k-1), jclasses.get(k-1), jnodes.get(jnode_idx), jnodes.get(jdest_idx), probabilities{j}{2});
1373 else
1374 jnodes.get(jnode_idx).setProbRouting(jclasses.get(k-1), jnodes.get(jdest_idx), probabilities{j}{2});
1375 end
1376 end
1377 end
1378 end
1379 case RoutingStrategy.JSQ
1380 jnodes.get(jnode_idx).setRouting(jclasses.get(k-1),jline.lang.constant.RoutingStrategy.JSQ);
1381 outlinks_i=find(connections(i,:))';
1382 if ~useLinkMethod
1383 for j= outlinks_i(:)'
1384 jdest_idx = matlab2java_node_idx(j);
1385 if jdest_idx >= 0
1386 jmodel.addLink(jnodes.get(jnode_idx), jnodes.get(jdest_idx));
1387 end
1388 end
1389 end
1390 case RoutingStrategy.KCHOICES
1391 jnodes.get(jnode_idx).setRouting(jclasses.get(k-1),jline.lang.constant.RoutingStrategy.KCHOICES);
1392 if length(output_strat) >= 3 && length(output_strat{3}) >= 2
1393 kparam = output_strat{3}{1};
1394 memparam = logical(output_strat{3}{2});
1395 jnodes.get(jnode_idx).setKChoicesRouting(jclasses.get(k-1), int32(kparam), memparam);
1396 end
1397 outlinks_i=find(connections(i,:))';
1398 if ~useLinkMethod
1399 for j= outlinks_i(:)'
1400 jdest_idx = matlab2java_node_idx(j);
1401 if jdest_idx >= 0
1402 jmodel.addLink(jnodes.get(jnode_idx), jnodes.get(jdest_idx));
1403 end
1404 end
1405 end
1406 case RoutingStrategy.RL
1407 jnodes.get(jnode_idx).setRouting(jclasses.get(k-1),jline.lang.constant.RoutingStrategy.RL);
1408 outlinks_i=find(connections(i,:))';
1409 if ~useLinkMethod
1410 for j= outlinks_i(:)'
1411 jdest_idx = matlab2java_node_idx(j);
1412 if jdest_idx >= 0
1413 jmodel.addLink(jnodes.get(jnode_idx), jnodes.get(jdest_idx));
1414 end
1415 end
1416 end
1417 % Forward the value function, action nodes, and
1418 % state size from outputStrategy{r}{3..5} so the
1419 % JAR sub_rl can replicate MATLAB's decisions.
1420 if length(output_strat) >= 5
1421 valFnRaw = output_strat{3};
1422 nodesNeedAction = output_strat{4};
1423 stateSize = output_strat{5};
1424 if ~isempty(valFnRaw)
1425 if stateSize == 0
1426 % Tabular: flatten N-D array to a row vector and pass shape.
1427 shp = size(valFnRaw);
1428 jvfFlat = jline.util.matrix.Matrix(1, numel(valFnRaw));
1429 flat = valFnRaw(:);
1430 for f = 1:numel(flat)
1431 jvfFlat.set(0, f-1, double(flat(f)));
1432 end
1433 jshape = int32(shp(:)');
1434 jnna = int32(nodesNeedAction(:)' - 1); % MATLAB->Java 0-based
1435 jnodes.get(jnode_idx).setRLRouting(jclasses.get(k-1), jvfFlat, jshape, jnna, int32(stateSize));
1436 else
1437 % Linear approx: coefficient row vector.
1438 coeff = valFnRaw(:)';
1439 jvf = jline.util.matrix.Matrix(1, numel(coeff));
1440 for f = 1:numel(coeff)
1441 jvf.set(0, f-1, double(coeff(f)));
1442 end
1443 jnna = int32(nodesNeedAction(:)' - 1);
1444 jnodes.get(jnode_idx).setRLRouting(jclasses.get(k-1), jvf, int32([]), jnna, int32(stateSize));
1445 end
1446 end
1447 end
1448 otherwise
1449 line_warning(mfilename, sprintf('''%s'' routing strategy not supported by JLINE, setting as Disabled.\n',output_strat{2}));
1450 jnodes.get(jnode_idx).setRouting(jclasses.get(k-1),jline.lang.constant.RoutingStrategy.DISABLED);
1451 end
1452 end
1453 end
1454 end
1455 if useLinkMethod
1456 jmodel.link(jrt_matrix);
1457 % Align the sn.rtorig be the same, treating artificial
1458 % ClassSwitch nodes as if they were explicitly specified
1459 jsn = jmodel.getStruct(true);
1460 rtorig = java.util.HashMap();
1461 if ~isempty(model.sn.rtorig)
1462 if iscell(model.sn.rtorig)
1463 for r = 1:njclasses
1464 sub_rtorig = java.util.HashMap();
1465 for s = 1:njclasses
1466 sub_rtorig.put(jclasses.get(s-1), JLINE.from_line_matrix(model.sn.rtorig{r,s}));
1467 end
1468 rtorig.put(jclasses.get(r-1), sub_rtorig);
1469 end
1470 end
1471 end
1472 jsn.rtorig = rtorig;
1473 end
1474 end
1475
1476 function model = from_jline_routing(model, jnetwork)
1477 jnodes = jnetwork.getNodes();
1478 jclasses = jnetwork.getClasses();
1479 n_nodes = jnodes.size();
1480 network_nodes = model.getNodes;
1481 network_classes = model.getClasses;
1482
1483 % Build name-to-MATLAB-node map (JAR and MATLAB may order nodes differently)
1484 node_by_name = containers.Map();
1485 for nn = 1:length(network_nodes)
1486 node_by_name(network_nodes{nn}.name) = network_nodes{nn};
1487 end
1488
1489 connections = JLINE.from_jline_matrix(jnetwork.getConnectionMatrix());
1490 [row,col] = find(connections);
1491 for i=1:length(row)
1492 from_name = char(jnodes.get(row(i)-1).getName());
1493 to_name = char(jnodes.get(col(i)-1).getName());
1494 model.addLink(node_by_name(from_name), node_by_name(to_name));
1495 end
1496
1497 for n = 1 : n_nodes
1498 jnode = jnodes.get(n-1);
1499 cur_node = node_by_name(char(jnode.getName()));
1500 output_strategies = jnode.getOutputStrategies();
1501 n_strategies = output_strategies.size();
1502 for m = 1 : n_strategies
1503 output_strat = output_strategies.get(m-1);
1504 routing_strat = output_strat.getRoutingStrategy;
1505 routing_strat_classidx = output_strat.getJobClass.getIndex();
1506 switch char(routing_strat)
1507 case 'RAND'
1508 cur_node.setRouting(network_classes{routing_strat_classidx}, RoutingStrategy.RAND);
1509 case 'RROBIN'
1510 cur_node.setRouting(network_classes{routing_strat_classidx}, RoutingStrategy.RROBIN);
1511 case 'WRROBIN'
1512 dest = output_strat.getDestination();
1513 if ~isempty(dest)
1514 dest_name = char(dest.getName());
1515 if node_by_name.isKey(dest_name)
1516 weight = output_strat.getProbability();
1517 cur_node.setRouting(network_classes{routing_strat_classidx}, RoutingStrategy.WRROBIN, node_by_name(dest_name), weight);
1518 end
1519 end
1520 case 'DISABLED'
1521 cur_node.setRouting(network_classes{routing_strat_classidx}, RoutingStrategy.DISABLED);
1522 end
1523 end
1524 end
1525 end
1526
1527 function model = from_jline_links(model, jnetwork)
1528 P = model.initRoutingMatrix;
1529 jnodes = jnetwork.getNodes();
1530 jclasses = jnetwork.getClasses();
1531 n_classes = jclasses.size();
1532 n_nodes = jnodes.size();
1533 network_nodes = model.getNodes;
1534
1535 % Build JAR-to-MATLAB node index mapping (node orders may differ)
1536 jar2ml = zeros(1, n_nodes);
1537 for jj = 1:n_nodes
1538 jar_name = char(jnodes.get(jj-1).getName());
1539 for mm = 1:length(network_nodes)
1540 if strcmp(network_nodes{mm}.name, jar_name)
1541 jar2ml(jj) = mm;
1542 break;
1543 end
1544 end
1545 end
1546
1547 hasDestinations = false;
1548 for n = 1 : n_nodes
1549 jnode = jnodes.get(n-1);
1550 output_strategies = jnode.getOutputStrategies();
1551 n_strategies = output_strategies.size();
1552 for m = 1 : n_strategies
1553 output_strat = output_strategies.get(m-1);
1554 dest = output_strat.getDestination();
1555 if~isempty(dest) % disabled strategy
1556 hasDestinations = true;
1557 in_idx = jar2ml(jnetwork.getNodeIndex(jnode)+1);
1558 out_idx = jar2ml(jnetwork.getNodeIndex(dest)+1);
1559 if n_classes == 1
1560 P{1}(in_idx,out_idx) = output_strat.getProbability();
1561 else
1562 strat_class = output_strat.getJobClass();
1563 class_idx = jnetwork.getJobClassIndex(strat_class)+1;
1564 P{class_idx,class_idx}(in_idx,out_idx) = output_strat.getProbability();
1565 end
1566 end
1567 end
1568 end
1569
1570 % If no OutputStrategy entries had destinations (e.g., model
1571 % loaded from JSON via LineModelIO.load), fall back to rtorig
1572 if ~hasDestinations
1573 sn = jnetwork.getStruct;
1574 if ~isempty(sn.rtorig)
1575 % rtorig is station-indexed (no permutation needed —
1576 % station ordering matches between JAR and MATLAB)
1577 for r = 1:n_classes
1578 for s = 1:n_classes
1579 rtMat = JLINE.from_jline_matrix(sn.rtorig.get(jclasses.get(r-1)).get(jclasses.get(s-1)));
1580 if ~isempty(rtMat)
1581 P{r,s} = rtMat;
1582 end
1583 end
1584 end
1585 end
1586 end
1587
1588 model.link(P);
1589
1590 % Restore non-PROB routing strategies (RROBIN, WRROBIN, etc.)
1591 % after link(), which sets all routing to PROB
1592 network_nodes = model.getNodes;
1593 network_classes = model.getClasses;
1594 node_by_name = containers.Map();
1595 for nn = 1:length(network_nodes)
1596 node_by_name(network_nodes{nn}.name) = network_nodes{nn};
1597 end
1598 for n = 1 : n_nodes
1599 jnode = jnodes.get(n-1);
1600 cur_node = node_by_name(char(jnode.getName()));
1601 output_strategies = jnode.getOutputStrategies();
1602 n_strategies = output_strategies.size();
1603 for m = 1 : n_strategies
1604 output_strat = output_strategies.get(m-1);
1605 routing_strat = output_strat.getRoutingStrategy;
1606 routing_strat_classidx = output_strat.getJobClass.getIndex();
1607 switch char(routing_strat)
1608 case 'RROBIN'
1609 cur_node.setRouting(network_classes{routing_strat_classidx}, RoutingStrategy.RROBIN);
1610 case 'WRROBIN'
1611 dest = output_strat.getDestination();
1612 if ~isempty(dest)
1613 dest_name = char(dest.getName());
1614 if node_by_name.isKey(dest_name)
1615 % Clear stale PROB entries before first WRROBIN weight
1616 classIdx = routing_strat_classidx;
1617 if length(cur_node.output.outputStrategy) >= classIdx && ...
1618 length(cur_node.output.outputStrategy{1, classIdx}) >= 3
1619 curStrat = cur_node.output.outputStrategy{1, classIdx}{2};
1620 if ~strcmp(curStrat, 'WeightedRoundRobin')
1621 cur_node.output.outputStrategy{1, classIdx}{3} = {};
1622 end
1623 end
1624 weight = output_strat.getProbability();
1625 cur_node.setRouting(network_classes{routing_strat_classidx}, RoutingStrategy.WRROBIN, node_by_name(dest_name), weight);
1626 end
1627 end
1628 end
1629 end
1630 end
1631
1632 % Invalidate cached struct after modifying routing strategies
1633 model.resetStruct();
1634
1635 %Align the sn.rtorig be the same (Assume Java network is
1636 %created by calling Network.link)
1637 sn = jnetwork.getStruct;
1638 rtorig = cell(n_classes, n_classes);
1639 for r = 1:n_classes
1640 for s = 1:n_classes
1641 rtorig{r,s} = JLINE.from_jline_matrix(sn.rtorig.get(jclasses.get(r-1)).get(jclasses.get(s-1)));
1642 end
1643 end
1644 model.sn.rtorig = rtorig;
1645 end
1646
1647 function [jnetwork] = from_line_network(model)
1648 %w = warning;
1649 %warning('off');
1650 sn = model.getStruct;
1651
1652 jnetwork = javaObject('jline.lang.Network', model.getName);
1653 line_nodes = model.getNodes;
1654 line_classes = model.getClasses;
1655
1656 jnodes = cell(1,length(line_nodes));
1657 jclasses = cell(1,length(line_classes));
1658
1659 for n = 1 : length(line_nodes)
1660 % Skip auto-added ClassSwitch nodes - Java's link() will add them automatically
1661 if isa(line_nodes{n}, 'ClassSwitch') && line_nodes{n}.autoAdded
1662 continue;
1663 end
1664 if isa(line_nodes{n}, 'Join')
1665 jnodes{n} = JLINE.from_line_node(line_nodes{n}, jnetwork, line_classes, jnodes{line_nodes{n}.joinOf.index}, sn);
1666 else
1667 jnodes{n} = JLINE.from_line_node(line_nodes{n}, jnetwork, line_classes, [], sn);
1668 end
1669 end
1670
1671 for n = 1 : length(line_classes)
1672 jclasses{n} = JLINE.from_line_class(line_classes{n}, jnetwork);
1673 end
1674
1675 % Set up forJobClass associations for signal classes
1676 for n = 1 : length(line_classes)
1677 if (isa(line_classes{n}, 'Signal') || isa(line_classes{n}, 'OpenSignal') || isa(line_classes{n}, 'ClosedSignal'))
1678 if ~isempty(line_classes{n}.targetJobClass)
1679 targetIdx = line_classes{n}.targetJobClass.index;
1680 jclasses{n}.forJobClass(jclasses{targetIdx});
1681 end
1682 end
1683 end
1684
1685 for n = 1: length(jnodes)
1686 if isempty(jnodes{n})
1687 continue; % Skip nodes that were not converted (e.g., auto-added ClassSwitch)
1688 end
1689 JLINE.set_service(line_nodes{n}, jnodes{n}, line_classes);
1690 JLINE.set_delayoff(line_nodes{n}, jnodes{n}, line_classes);
1691 end
1692
1693 % Set drop rules for stations (after classes are created)
1694 for n = 1: length(jnodes)
1695 if isempty(jnodes{n})
1696 continue; % Skip nodes that were not converted
1697 end
1698 if isa(line_nodes{n}, 'Station') && ~isa(line_nodes{n}, 'Source')
1699 for r = 1:length(line_classes)
1700 if length(line_nodes{n}.dropRule) >= r && ~isempty(line_nodes{n}.dropRule(r))
1701 dropRule = line_nodes{n}.dropRule(r);
1702 switch dropRule
1703 case DropStrategy.DROP
1704 jnodes{n}.setDropRule(jclasses{r}, jline.lang.constant.DropStrategy.Drop);
1705 case DropStrategy.BAS
1706 jnodes{n}.setDropRule(jclasses{r}, jline.lang.constant.DropStrategy.BlockingAfterService);
1707 case DropStrategy.WAITQ
1708 jnodes{n}.setDropRule(jclasses{r}, jline.lang.constant.DropStrategy.WaitingQueue);
1709 end
1710 end
1711 end
1712 end
1713 end
1714
1715 % Transfer LJCD (Limited Joint Class Dependence) scaling for stations
1716 % This must be done after classes are created since LJCD is indexed per-class
1717 for n = 1:length(jnodes)
1718 if isempty(jnodes{n})
1719 continue;
1720 end
1721 if isa(line_nodes{n}, 'Station') && ~isempty(line_nodes{n}.ljcdScaling) && ~isempty(line_nodes{n}.ljcdCutoffs)
1722 jCutoffs = JLINE.from_line_matrix(line_nodes{n}.ljcdCutoffs(:));
1723 K = length(line_nodes{n}.ljcdScaling);
1724 jScalingMap = java.util.HashMap();
1725 for c = 1:K
1726 if ~isempty(line_nodes{n}.ljcdScaling{c})
1727 jScalingVec = JLINE.from_line_matrix(line_nodes{n}.ljcdScaling{c}(:));
1728 jScalingMap.put(jclasses{c}, jScalingVec);
1729 end
1730 end
1731 jnodes{n}.setLimitedJointClassDependence(jScalingMap, jCutoffs);
1732 end
1733 end
1734
1735 % Set polling type and switchover times for polling queues
1736 for n = 1: length(jnodes)
1737 if isempty(jnodes{n})
1738 continue;
1739 end
1740 if isa(line_nodes{n}, 'Queue') && line_nodes{n}.schedStrategy == SchedStrategy.POLLING
1741 % Set polling type
1742 if ~isempty(line_nodes{n}.pollingType) && ~isempty(line_nodes{n}.pollingType{1})
1743 pollingType = line_nodes{n}.pollingType{1};
1744 switch pollingType
1745 case PollingType.GATED
1746 jPollingType = jline.lang.constant.PollingType.GATED;
1747 case PollingType.EXHAUSTIVE
1748 jPollingType = jline.lang.constant.PollingType.EXHAUSTIVE;
1749 case PollingType.KLIMITED
1750 jPollingType = jline.lang.constant.PollingType.KLIMITED;
1751 end
1752 if pollingType == PollingType.KLIMITED && ~isempty(line_nodes{n}.pollingPar)
1753 jnodes{n}.setPollingType(jPollingType, int32(line_nodes{n}.pollingPar));
1754 else
1755 jnodes{n}.setPollingType(jPollingType);
1756 end
1757 end
1758 % Set switchover times
1759 if ~isempty(line_nodes{n}.switchoverTime)
1760 for r = 1:length(line_classes)
1761 if length(line_nodes{n}.switchoverTime) >= r && ~isempty(line_nodes{n}.switchoverTime{r})
1762 soTime = line_nodes{n}.switchoverTime{r};
1763 if ~isa(soTime, 'Immediate')
1764 jnodes{n}.setSwitchover(jclasses{r}, JLINE.from_line_distribution(soTime));
1765 end
1766 end
1767 end
1768 end
1769 end
1770 end
1771
1772 % Transfer impatience features (reneging, balking, retrial) for queues
1773 % These require classes to be created first.
1774 for n = 1: length(jnodes)
1775 if isempty(jnodes{n})
1776 continue;
1777 end
1778 if ~isa(line_nodes{n}, 'Queue')
1779 continue;
1780 end
1781 for r = 1:length(line_classes)
1782 % Reneging (timer-based patience). Only RENEGING is supported;
1783 % BALKING via setPatience is rejected by both MATLAB and the JAR.
1784 if ~isempty(line_nodes{n}.patienceDistributions) && ...
1785 r <= length(line_nodes{n}.patienceDistributions) && ...
1786 ~isempty(line_nodes{n}.patienceDistributions{1, r})
1787 patDist = line_nodes{n}.patienceDistributions{1, r};
1788 if ~isa(patDist, 'Disabled')
1789 impType = ImpatienceType.RENEGING;
1790 if ~isempty(line_nodes{n}.impatienceTypes) && ...
1791 r <= length(line_nodes{n}.impatienceTypes) && ...
1792 ~isempty(line_nodes{n}.impatienceTypes{1, r})
1793 impType = line_nodes{n}.impatienceTypes{1, r};
1794 end
1795 jImpType = jline.lang.constant.ImpatienceType.fromID(int32(impType));
1796 jnodes{n}.setPatience(jclasses{r}, jImpType, JLINE.from_line_distribution(patDist));
1797 end
1798 end
1799 % Balking (state-based, queue-length/expected-wait thresholds)
1800 if ~isempty(line_nodes{n}.balkingStrategies) && ...
1801 r <= length(line_nodes{n}.balkingStrategies) && ...
1802 ~isempty(line_nodes{n}.balkingStrategies{1, r})
1803 balkStrat = line_nodes{n}.balkingStrategies{1, r};
1804 switch balkStrat
1805 case BalkingStrategy.QUEUE_LENGTH
1806 jBalkStrat = jline.lang.constant.BalkingStrategy.QUEUE_LENGTH;
1807 case BalkingStrategy.EXPECTED_WAIT
1808 jBalkStrat = jline.lang.constant.BalkingStrategy.EXPECTED_WAIT;
1809 case BalkingStrategy.COMBINED
1810 jBalkStrat = jline.lang.constant.BalkingStrategy.COMBINED;
1811 otherwise
1812 jBalkStrat = jline.lang.constant.BalkingStrategy.QUEUE_LENGTH;
1813 end
1814 thresholds = line_nodes{n}.balkingThresholds{1, r};
1815 jThresholds = java.util.ArrayList();
1816 for ti = 1:length(thresholds)
1817 th = thresholds{ti};
1818 minJobs = th{1};
1819 maxJobs = th{2};
1820 if isinf(maxJobs)
1821 maxJobs = java.lang.Integer.MAX_VALUE;
1822 end
1823 jThresholds.add(javaObject('jline.lang.constant.BalkingThreshold', int32(minJobs), int32(maxJobs), th{3}));
1824 end
1825 jnodes{n}.setBalking(jclasses{r}, jBalkStrat, jThresholds);
1826 end
1827 % Retrial (orbit + retrial delay distribution)
1828 if ~isempty(line_nodes{n}.retrialDelays) && ...
1829 r <= length(line_nodes{n}.retrialDelays) && ...
1830 ~isempty(line_nodes{n}.retrialDelays{1, r})
1831 retDist = line_nodes{n}.retrialDelays{1, r};
1832 if ~isa(retDist, 'Disabled')
1833 maxAttempts = -1;
1834 if ~isempty(line_nodes{n}.retrialMaxAttempts) && r <= length(line_nodes{n}.retrialMaxAttempts)
1835 maxAttempts = line_nodes{n}.retrialMaxAttempts(r);
1836 end
1837 jnodes{n}.setRetrial(jclasses{r}, JLINE.from_line_distribution(retDist), int32(maxAttempts));
1838 end
1839 end
1840 % Orbit impatience (abandonment from the retrial orbit)
1841 if ~isempty(line_nodes{n}.orbitImpatienceDistributions) && ...
1842 r <= length(line_nodes{n}.orbitImpatienceDistributions) && ...
1843 ~isempty(line_nodes{n}.orbitImpatienceDistributions{1, r})
1844 orbDist = line_nodes{n}.orbitImpatienceDistributions{1, r};
1845 if ~isa(orbDist, 'Disabled')
1846 jnodes{n}.setOrbitImpatience(jclasses{r}, JLINE.from_line_distribution(orbDist));
1847 end
1848 end
1849 end
1850 end
1851
1852 % Transfer pass-and-swap (PAS) parameters: the total service rate
1853 % function mu(c) and the swap graph. Requires classes to be created
1854 % first (the JAR setServiceRateFunction derives per-class rates and
1855 % setSwapGraph validates against the class count).
1856 for n = 1: length(jnodes)
1857 if isempty(jnodes{n})
1858 continue;
1859 end
1860 if ~isa(line_nodes{n}, 'Queue') || line_nodes{n}.schedStrategy ~= SchedStrategy.PAS
1861 continue;
1862 end
1863 if isempty(line_nodes{n}.svcRateFun)
1864 line_error(mfilename, sprintf('PAS queue ''%s'' has no service rate function mu(c); set it via setService(@(c) ...).', line_nodes{n}.getName));
1865 end
1866 if isinf(line_nodes{n}.cap)
1867 line_error(mfilename, sprintf('PAS queue ''%s'' requires a finite capacity for JLINE conversion; set it via setCap(...).', line_nodes{n}.getName));
1868 end
1869 jSerFun = JLINE.pas_handle_to_serializablefun(line_nodes{n}.svcRateFun, sn.nclasses, line_nodes{n}.cap);
1870 jnodes{n}.setServiceRateFunction(jSerFun);
1871 % Transfer the swap graph if explicitly set (otherwise the JAR
1872 % defaults to a complete graph at struct refresh, as MATLAB does)
1873 if ~isempty(line_nodes{n}.swapGraph)
1874 jnodes{n}.setSwapGraph(JLINE.from_line_matrix(line_nodes{n}.swapGraph));
1875 end
1876 end
1877
1878 % Transfer heterogeneous server types and their per-(serverType,class)
1879 % service distributions. Requires classes to be created first.
1880 for n = 1: length(jnodes)
1881 if isempty(jnodes{n})
1882 continue;
1883 end
1884 if ~isa(line_nodes{n}, 'Queue') || isempty(line_nodes{n}.serverTypes)
1885 continue;
1886 end
1887 % Map MATLAB class names to Java class objects
1888 % Add each server type with its compatible classes
1889 jServerTypes = cell(1, length(line_nodes{n}.serverTypes));
1890 for st = 1:length(line_nodes{n}.serverTypes)
1891 serverType = line_nodes{n}.serverTypes{st};
1892 jCompat = java.util.ArrayList();
1893 compatClasses = serverType.getCompatibleClasses();
1894 for cc = 1:length(compatClasses)
1895 jCompat.add(jclasses{compatClasses{cc}.index});
1896 end
1897 jST = javaObject('jline.lang.constant.ServerType', serverType.getName(), int32(serverType.getNumOfServers()), jCompat);
1898 jnodes{n}.addServerType(jST);
1899 jServerTypes{st} = jST;
1900 end
1901 % Set heterogeneous scheduling policy
1902 switch line_nodes{n}.heteroSchedPolicy
1903 case HeteroSchedPolicy.ORDER
1904 jHetPol = jline.lang.constant.HeteroSchedPolicy.ORDER;
1905 case HeteroSchedPolicy.ALIS
1906 jHetPol = jline.lang.constant.HeteroSchedPolicy.ALIS;
1907 case HeteroSchedPolicy.ALFS
1908 jHetPol = jline.lang.constant.HeteroSchedPolicy.ALFS;
1909 case HeteroSchedPolicy.FAIRNESS
1910 jHetPol = jline.lang.constant.HeteroSchedPolicy.FAIRNESS;
1911 case HeteroSchedPolicy.FSF
1912 jHetPol = jline.lang.constant.HeteroSchedPolicy.FSF;
1913 case HeteroSchedPolicy.RAIS
1914 jHetPol = jline.lang.constant.HeteroSchedPolicy.RAIS;
1915 otherwise
1916 jHetPol = jline.lang.constant.HeteroSchedPolicy.ORDER;
1917 end
1918 jnodes{n}.setHeteroSchedPolicy(jHetPol);
1919 % Set per-(serverType, class) service distributions
1920 for st = 1:length(line_nodes{n}.serverTypes)
1921 serverType = line_nodes{n}.serverTypes{st};
1922 for r = 1:length(line_classes)
1923 hetDist = line_nodes{n}.getHeteroService(line_classes{r}, serverType);
1924 if ~isempty(hetDist)
1925 jnodes{n}.setService(jclasses{r}, jServerTypes{st}, JLINE.from_line_distribution(hetDist));
1926 end
1927 end
1928 end
1929 end
1930
1931 for n = 1: length(jnodes)
1932 if isempty(jnodes{n})
1933 continue; % Skip nodes that were not converted
1934 end
1935 if isa(line_nodes{n},"ClassSwitch") && ~line_nodes{n}.autoAdded
1936 % Only set csMatrix for user-defined ClassSwitch nodes (not auto-added)
1937 JLINE.set_csMatrix(line_nodes{n}, jnodes{n}, jclasses);
1938 elseif isa(line_nodes{n},"Join")
1939 jnodes{n}.initJoinJobClasses();
1940 % Restore RAND routing for all classes, matching ClosedClass/OpenClass
1941 % constructor behavior (initJoinJobClasses sets DISABLED by default)
1942 for r = 1 : sn.nclasses
1943 jnodes{n}.setRouting(jclasses{r}, jline.lang.constant.RoutingStrategy.RAND);
1944 end
1945 elseif isa(line_nodes{n},"Cache")
1946 hitC = line_nodes{n}.server.hitClass;
1947 missC = line_nodes{n}.server.missClass;
1948 for r = 1 : sn.nclasses
1949 % Transfer per-class cache setup based on what each class
1950 % actually has: read (input) classes carry a popularity plus a
1951 % hit and miss class; the auto-generated retrieval classes carry
1952 % a one-hot popularity and a miss class only. Gating on hitClass
1953 % alone (as before) dropped the retrieval classes' read
1954 % distribution, leaving the JAR cache state handler with a null
1955 % popularity (NPE in AfterEventCache during SSA/CTMC).
1956 hasPop = numel(line_nodes{n}.popularity) >= r ...
1957 && ~isempty(line_nodes{n}.popularity{r}) ...
1958 && ~isa(line_nodes{n}.popularity{r},'Disabled');
1959 hasHit = length(hitC) >= r && full(hitC(r)) > 0;
1960 hasMiss = length(missC) >= r && full(missC(r)) > 0;
1961 if hasPop
1962 jnodes{n}.setRead(jclasses{r}, JLINE.from_line_distribution(line_nodes{n}.popularity{r}));
1963 end
1964 if hasHit
1965 jnodes{n}.setHitClass(jclasses{r}, jclasses{full(hitC(r))});
1966 end
1967 if hasMiss
1968 jnodes{n}.setMissClass(jclasses{r}, jclasses{full(missC(r))});
1969 end
1970 end
1971 % Transfer accessProb from MATLAB to Java
1972 if ~isempty(line_nodes{n}.accessProb)
1973 accessProbMat = line_nodes{n}.accessProb;
1974 [K1, K2] = size(accessProbMat);
1975 jAccessProb = javaArray('jline.util.matrix.Matrix', K1, K2);
1976 for k1 = 1:K1
1977 for k2 = 1:K2
1978 if ~isempty(accessProbMat{k1, k2})
1979 jAccessProb(k1, k2) = JLINE.from_line_matrix(accessProbMat{k1, k2});
1980 end
1981 end
1982 end
1983 jnodes{n}.setAccessProb(jAccessProb);
1984 end
1985 % Reconstruct the delayed-hit retrieval system bookkeeping on the
1986 % Java cache. line_to_jline already transfers the retrieval queues,
1987 % their service and the routing; attachRetrievalSystem restores the
1988 % cache-internal state (retrievalSystemCapacity, queue indices,
1989 % retrieval-class set and per-item mapping) the JAR solvers read to
1990 % detect the retrieval system. Without it the JAR routes to the plain
1991 % cache analyzer (no delayed hits; NC errors when nItems < cap+2).
1992 if ~isempty(line_nodes{n}.retrievalSystemQueueIndices) ...
1993 && line_nodes{n}.retrievalSystemQueueIndices.Count > 0
1994 rsqi = line_nodes{n}.retrievalSystemQueueIndices;
1995 rclasses = line_nodes{n}.server.retrievalClasses; % [nItems x nclasses], 1-based or -1
1996 nItemsRS = size(rclasses, 1);
1997 keysRS = keys(rsqi);
1998 for kk = 1:numel(keysRS)
1999 jobinIdx0 = double(keysRS{kk}); % 0-based arrival class index
2000 jobinClassObj = jclasses{jobinIdx0 + 1};
2001 queueIdxs = rsqi(keysRS{kk}); % 1-based MATLAB node indices
2002 qList = javaObject('java.util.ArrayList');
2003 for q = 1:numel(queueIdxs)
2004 qList.add(java.lang.Integer(int32(queueIdxs(q) - 1))); % 0-based node index
2005 end
2006 rcArr = javaArray('jline.lang.JobClass', nItemsRS);
2007 for i = 1:nItemsRS
2008 rIdx = rclasses(i, jobinIdx0 + 1);
2009 if rIdx >= 1
2010 rcArr(i) = jclasses{rIdx};
2011 end
2012 end
2013 jnodes{n}.attachRetrievalSystem(jobinClassObj, qList, rcArr);
2014 end
2015 end
2016 elseif isa(line_nodes{n}, "Transition")
2017 % First, add modes (must be done after classes are created)
2018 for m = 1:line_nodes{n}.getNumberOfModes()
2019 modeName = line_nodes{n}.modeNames{m};
2020 jmode = jnodes{n}.addMode(modeName);
2021 % Set timing strategy
2022 switch line_nodes{n}.timingStrategies(m)
2023 case TimingStrategy.TIMED
2024 jnodes{n}.setTimingStrategy(jmode, jline.lang.constant.TimingStrategy.TIMED);
2025 case TimingStrategy.IMMEDIATE
2026 jnodes{n}.setTimingStrategy(jmode, jline.lang.constant.TimingStrategy.IMMEDIATE);
2027 end
2028 % Set distribution
2029 jnodes{n}.setDistribution(jmode, JLINE.from_line_distribution(line_nodes{n}.distributions{m}));
2030 % Set firing weights and priorities
2031 jnodes{n}.setFiringWeights(jmode, line_nodes{n}.firingWeights(m));
2032 jnodes{n}.setFiringPriorities(jmode, int32(line_nodes{n}.firingPriorities(m)));
2033 % Set number of servers
2034 nsrv = line_nodes{n}.numberOfServers(m);
2035 if isinf(nsrv)
2036 jnodes{n}.setNumberOfServers(jmode, java.lang.Integer(intmax('int32')));
2037 else
2038 jnodes{n}.setNumberOfServers(jmode, java.lang.Integer(int32(nsrv)));
2039 end
2040 end
2041 % Now set enabling conditions, inhibiting conditions, and firing outcomes
2042 jmodes = jnodes{n}.getModes();
2043 for m = 1:line_nodes{n}.getNumberOfModes()
2044 jmode = jmodes.get(m-1);
2045 enabCond = line_nodes{n}.enablingConditions{m};
2046 inhibCond = line_nodes{n}.inhibitingConditions{m};
2047 firingOut = line_nodes{n}.firingOutcomes{m};
2048 for r = 1:sn.nclasses
2049 for i = 1:length(line_nodes)
2050 % Set enabling conditions
2051 if enabCond(i, r) > 0 && isa(line_nodes{i}, 'Place')
2052 jnodes{n}.setEnablingConditions(jmode, jclasses{r}, jnodes{i}, enabCond(i, r));
2053 end
2054 % Set inhibiting conditions
2055 if inhibCond(i, r) < Inf && isa(line_nodes{i}, 'Place')
2056 jnodes{n}.setInhibitingConditions(jmode, jclasses{r}, jnodes{i}, inhibCond(i, r));
2057 end
2058 % Set firing outcomes
2059 if firingOut(i, r) ~= 0
2060 jnodes{n}.setFiringOutcome(jmode, jclasses{r}, jnodes{i}, firingOut(i, r));
2061 end
2062 end
2063 end
2064 end
2065 end
2066 end
2067
2068 % Transfer the MATLAB-side node states (e.g. a closed pass-and-swap
2069 % station's required initial placement) BEFORE from_line_links, whose
2070 % internal getStruct call would otherwise trigger the JAR's initDefault
2071 % validation and error on a missing PAS placement before the states
2072 % have been provided.
2073 for n = 1: length(line_nodes)
2074 if isempty(jnodes{n})
2075 continue;
2076 end
2077 if line_nodes{n}.isStateful
2078 jnodes{n}.setState(JLINE.from_line_matrix(line_nodes{n}.getState));
2079 jnodes{n}.setStateSpace(JLINE.from_line_matrix(line_nodes{n}.getStateSpace));
2080 jnodes{n}.setStatePrior(JLINE.from_line_matrix(line_nodes{n}.getStatePrior));
2081 end
2082 end
2083
2084 % Assume JLINE and LINE network are both created via link
2085 JLINE.from_line_links(model, jnetwork);
2086
2087 % Transfer finite capacity regions from MATLAB to Java
2088 if ~isempty(model.regions)
2089 for f = 1:length(model.regions)
2090 fcr = model.regions{f};
2091 % Convert MATLAB node list to Java list
2092 javaNodeList = java.util.ArrayList();
2093 for i = 1:length(fcr.nodes)
2094 matlabNode = fcr.nodes{i};
2095 % Find corresponding Java node by name
2096 nodeName = matlabNode.getName();
2097 for j = 1:length(line_nodes)
2098 if strcmp(line_nodes{j}.getName(), nodeName) && ~isempty(jnodes{j})
2099 javaNodeList.add(jnodes{j});
2100 break;
2101 end
2102 end
2103 end
2104 % Create Java FCR
2105 jfcr = jnetwork.addRegion(javaNodeList);
2106 % Set global max jobs
2107 if fcr.globalMaxJobs > 0 && ~isinf(fcr.globalMaxJobs)
2108 jfcr.setGlobalMaxJobs(fcr.globalMaxJobs);
2109 end
2110 % Set per-class max jobs and drop rules
2111 for r = 1:length(line_classes)
2112 if length(fcr.classMaxJobs) >= r && fcr.classMaxJobs(r) > 0 && ~isinf(fcr.classMaxJobs(r))
2113 jfcr.setClassMaxJobs(jclasses{r}, fcr.classMaxJobs(r));
2114 end
2115 if length(fcr.dropRule) >= r
2116 % Convert MATLAB DropStrategy numeric to Java DropStrategy enum
2117 jDropStrategy = jline.lang.constant.DropStrategy.fromID(fcr.dropRule(r));
2118 jfcr.setDropRule(jclasses{r}, jDropStrategy);
2119 end
2120 end
2121 % Transfer linear constraints if set
2122 if fcr.hasLinearConstraints()
2123 jA = JLINE.from_line_matrix(fcr.constraintA);
2124 jb = JLINE.from_line_matrix(fcr.constraintB);
2125 jfcr.setLinearConstraints(jA, jb);
2126 end
2127 end
2128 end
2129
2130 % Transfer the MATLAB-side node states BEFORE initDefault so that the
2131 % JAR's initDefault sees user-provided initial states (e.g. a closed
2132 % pass-and-swap station's required initial placement) rather than
2133 % erroring or fabricating a default for them. initDefault then only
2134 % initializes the stateful nodes still lacking a state.
2135 for n = 1: length(line_nodes)
2136 if isempty(jnodes{n})
2137 continue; % Skip nodes that were not converted
2138 end
2139 if line_nodes{n}.isStateful
2140 jnodes{n}.setState(JLINE.from_line_matrix(line_nodes{n}.getState));
2141 jnodes{n}.setStateSpace(JLINE.from_line_matrix(line_nodes{n}.getStateSpace));
2142 jnodes{n}.setStatePrior(JLINE.from_line_matrix(line_nodes{n}.getStatePrior));
2143 end
2144 end
2145 jnetwork.initDefault;
2146 % Force struct refresh so sn.state reflects updated node states
2147 jnetwork.setHasStruct(false);
2148
2149 end
2150
2151 function jnetwork = line_to_jline(model)
2152 jnetwork = LINE2JLINE(model);
2153 end
2154
2155 function model = jline_to_line(jnetwork)
2156 if isa(jnetwork,'JNetwork')
2157 jnetwork = jnetwork.obj;
2158 end
2159 %javaaddpath(jar_loc);
2160 model = Network(char(jnetwork.getName));
2161 network_nodes = jnetwork.getNodes;
2162 job_classes = jnetwork.getClasses;
2163
2164 line_nodes = cell(network_nodes.size,1);
2165 line_classes = cell(job_classes.size,1);
2166
2167
2168 for n = 1 : network_nodes.size
2169 if ~isa(network_nodes.get(n-1), 'jline.lang.nodes.ClassSwitch')
2170 line_nodes{n} = JLINE.from_jline_node(network_nodes.get(n-1), model, job_classes);
2171 end
2172 end
2173
2174 for n = 1 : job_classes.size
2175 line_classes{n} = JLINE.from_jline_class(job_classes.get(n-1), model);
2176 end
2177
2178 for n = 1 : network_nodes.size
2179 if isa(network_nodes.get(n-1), 'jline.lang.nodes.ClassSwitch')
2180 line_nodes{n} = JLINE.from_jline_node(network_nodes.get(n-1), model, job_classes);
2181 end
2182 end
2183
2184 % Deferred Fork/Join linking: set joinOf on Join nodes
2185 for n = 1 : network_nodes.size
2186 jnode = network_nodes.get(n-1);
2187 if isa(jnode, 'jline.lang.nodes.Join') && ~isempty(jnode.joinOf)
2188 forkName = char(jnode.joinOf.getName);
2189 for m = 1 : network_nodes.size
2190 if ~isempty(line_nodes{m}) && isa(line_nodes{m}, 'Fork') && strcmp(line_nodes{m}.name, forkName)
2191 line_nodes{n}.joinOf = line_nodes{m};
2192 break;
2193 end
2194 end
2195 end
2196 end
2197
2198 % Deferred Cache setup: set hitClass, missClass, popularity
2199 for n = 1 : network_nodes.size
2200 jnode = network_nodes.get(n-1);
2201 if isa(jnode, 'jline.lang.nodes.Cache') && isa(line_nodes{n}, 'Cache')
2202 cacheNode = line_nodes{n};
2203 % hitClass and missClass are stored as index vectors
2204 hitClassVec = JLINE.from_jline_matrix(jnode.getHitClass());
2205 missClassVec = JLINE.from_jline_matrix(jnode.getMissClass());
2206 for r = 1:job_classes.size
2207 hitIdx = hitClassVec(r);
2208 if hitIdx >= 0 && (hitIdx + 1) <= job_classes.size
2209 cacheNode.setHitClass(line_classes{r}, line_classes{hitIdx + 1});
2210 end
2211 missIdx = missClassVec(r);
2212 if missIdx >= 0 && (missIdx + 1) <= job_classes.size
2213 cacheNode.setMissClass(line_classes{r}, line_classes{missIdx + 1});
2214 end
2215 end
2216 % Popularity distributions
2217 for r = 1:job_classes.size
2218 try
2219 popDist = jnode.popularityGet(0, r-1);
2220 if ~isempty(popDist) && popDist.isDiscrete()
2221 matlabDist = JLINE.from_jline_distribution(popDist);
2222 if ~isempty(matlabDist)
2223 cacheNode.setRead(line_classes{r}, matlabDist);
2224 end
2225 end
2226 catch
2227 % No popularity for this class
2228 end
2229 end
2230 end
2231 end
2232
2233 for n = 1 : network_nodes.size
2234 JLINE.set_line_service(network_nodes.get(n-1), line_nodes{n}, job_classes, line_classes);
2235 end
2236
2237 % Configure Transition modes (distributions, enabling/inhibiting/firing, etc.)
2238 for n = 1 : network_nodes.size
2239 jnode = network_nodes.get(n-1);
2240 if isa(jnode, 'jline.lang.nodes.Transition') && isa(line_nodes{n}, 'Transition')
2241 tnode = line_nodes{n};
2242 jmodes = jnode.getModes();
2243 nmodes = jmodes.size();
2244 for m = 1 : nmodes
2245 jmode = jmodes.get(m-1);
2246 modeName = char(jmode.getName());
2247 % addMode if not yet present (Transition starts with one default mode)
2248 if m > tnode.getNumberOfModes()
2249 tnode.addMode(modeName);
2250 else
2251 tnode.setModeNames(m, modeName);
2252 end
2253 % Timing strategy
2254 ts = jnode.timingStrategies.get(jmode);
2255 if ~isempty(ts)
2256 tsName = char(ts.name());
2257 if strcmp(tsName, 'IMMEDIATE')
2258 tnode.setTimingStrategy(m, TimingStrategy.IMMEDIATE);
2259 else
2260 tnode.setTimingStrategy(m, TimingStrategy.TIMED);
2261 end
2262 end
2263 % Distribution
2264 jdist = jnode.getFiringDistribution(jmode);
2265 if ~isempty(jdist)
2266 matlabDist = JLINE.from_jline_distribution(jdist);
2267 if ~isempty(matlabDist)
2268 tnode.setDistribution(m, matlabDist);
2269 end
2270 end
2271 % Number of servers
2272 numSrv = jnode.getNumberOfModeServers(jmode);
2273 if numSrv == intmax('int32') || numSrv == intmax('int64')
2274 tnode.setNumberOfServers(m, Inf);
2275 else
2276 tnode.setNumberOfServers(m, double(numSrv));
2277 end
2278 % Firing priority and weight (read from matrices by mode index)
2279 if jnode.firingPriorities.getNumElements() > (m-1)
2280 tnode.setFiringPriorities(m, jnode.firingPriorities.get(m-1));
2281 end
2282 if jnode.firingWeights.getNumElements() > (m-1)
2283 tnode.setFiringWeights(m, jnode.firingWeights.get(m-1));
2284 end
2285 % Enabling conditions
2286 ecMat = jnode.enablingConditions.get(jmode);
2287 if ~isempty(ecMat)
2288 nrows = ecMat.getNumRows();
2289 ncols = ecMat.getNumCols();
2290 for ni = 1 : nrows
2291 for ci = 1 : ncols
2292 val = ecMat.get(ni-1, ci-1);
2293 if val > 0 && ni <= length(line_nodes) && isa(line_nodes{ni}, 'Place')
2294 tnode.setEnablingConditions(m, ci, line_nodes{ni}, val);
2295 end
2296 end
2297 end
2298 end
2299 % Inhibiting conditions
2300 icMat = jnode.inhibitingConditions.get(jmode);
2301 if ~isempty(icMat)
2302 nrows = icMat.getNumRows();
2303 ncols = icMat.getNumCols();
2304 for ni = 1 : nrows
2305 for ci = 1 : ncols
2306 val = icMat.get(ni-1, ci-1);
2307 if isfinite(val) && val > 0 && ni <= length(line_nodes) && isa(line_nodes{ni}, 'Place')
2308 tnode.setInhibitingConditions(m, ci, line_nodes{ni}, val);
2309 end
2310 end
2311 end
2312 end
2313 % Firing outcomes
2314 foMat = jnode.firingOutcomes.get(jmode);
2315 if ~isempty(foMat)
2316 nrows = foMat.getNumRows();
2317 ncols = foMat.getNumCols();
2318 for ni = 1 : nrows
2319 for ci = 1 : ncols
2320 val = foMat.get(ni-1, ci-1);
2321 if val ~= 0 && ni <= length(line_nodes)
2322 tnode.setFiringOutcome(m, ci, line_nodes{ni}, val);
2323 end
2324 end
2325 end
2326 end
2327 end
2328 end
2329 end
2330
2331 % Check for state-dependent routing (RROBIN, WRROBIN, JSQ)
2332 % These cannot go through link(P) because it overrides routing strategies
2333 hasSDRouting = false;
2334 for n = 1 : network_nodes.size
2335 jnode = network_nodes.get(n-1);
2336 output_strategies = jnode.getOutputStrategies();
2337 for m = 1 : output_strategies.size()
2338 rs = char(output_strategies.get(m-1).getRoutingStrategy);
2339 if any(strcmp(rs, {'RROBIN','WRROBIN','JSQ','KCHOICES'}))
2340 hasSDRouting = true;
2341 break;
2342 end
2343 end
2344 if hasSDRouting; break; end
2345 end
2346
2347 if hasSDRouting
2348 % State-dependent routing: use addLink + setRouting
2349 model = JLINE.from_jline_routing(model, jnetwork);
2350 elseif ~isempty(jnetwork.getStruct.rtorig)
2351 % Use link() method
2352 model = JLINE.from_jline_links(model, jnetwork);
2353 else
2354 % Do not use link() method
2355 model = JLINE.from_jline_routing(model, jnetwork);
2356 end
2357
2358 % Restore initial state on Place nodes after linking
2359 for n = 1 : network_nodes.size
2360 jnode = network_nodes.get(n-1);
2361 if isa(jnode, 'jline.lang.nodes.Place') && ~isempty(line_nodes{n}) && isa(line_nodes{n}, 'Place')
2362 jst = jnode.getState();
2363 if ~isempty(jst) && ~jst.isEmpty()
2364 line_nodes{n}.setState(JLINE.from_jline_matrix(jst));
2365 end
2366 end
2367 end
2368 end
2369
2370 function matrix = arraylist_to_matrix(jline_matrix)
2371 if isempty(jline_matrix)
2372 matrix = [];
2373 else
2374 matrix = zeros(jline_matrix.size(), 1);
2375 for row = 1:jline_matrix.size()
2376 matrix(row, 1) = jline_matrix.get(row-1);
2377 end
2378 end
2379 end
2380
2381 function matrix = from_jline_matrix(jline_matrix)
2382 if isempty(jline_matrix)
2383 matrix = [];
2384 else
2385 matrix = zeros(jline_matrix.getNumRows(), jline_matrix.getNumCols());
2386 for row = 1:jline_matrix.getNumRows()
2387 for col = 1:jline_matrix.getNumCols()
2388 val = jline_matrix.get(row-1, col-1);
2389 if (val >= 33333333 && val <= 33333334)
2390 matrix(row, col) = GlobalConstants.Immediate;
2391 elseif (val >= -33333334 && val <= -33333333)
2392 matrix(row, col) = -GlobalConstants.Immediate;
2393 elseif (val >= 2147483647 - 1) % Integer.MAX_VALUE with -1 tolerance
2394 matrix(row, col) = Inf;
2395 elseif (val <= -2147483648 + 1) % Integer.MIN_VALUE with +1 tolerance
2396 matrix(row, col) = -Inf;
2397 else
2398 matrix(row, col) = val;
2399 end
2400 end
2401 end
2402 end
2403 end
2404
2405 function jline_matrix = from_line_matrix(matrix)
2406 [rows, cols] = size(matrix);
2407 jline_matrix = jline.util.matrix.Matrix(rows, cols);
2408 for row = 1:rows
2409 for col = 1:cols
2410 if matrix(row,col) ~= 0
2411 jline_matrix.set(row-1, col-1, matrix(row, col));
2412 end
2413 end
2414 end
2415 end
2416
2417 function lsn = from_jline_struct_layered(jlayerednetwork, jlsn)
2418 lsn = LayeredNetworkStruct();
2419 lsn.nidx= jlsn.nidx;
2420 lsn.nhosts= jlsn.nhosts;
2421 lsn.ntasks= jlsn.ntasks;
2422 lsn.nentries= jlsn.nentries;
2423 lsn.nacts= jlsn.nacts;
2424 lsn.ncalls= jlsn.ncalls;
2425 lsn.hshift= jlsn.hshift;
2426 lsn.tshift= jlsn.tshift;
2427 lsn.eshift= jlsn.eshift;
2428 lsn.ashift= jlsn.ashift;
2429 lsn.cshift= jlsn.cshift;
2430 for h=1:jlsn.nhosts
2431 lsn.tasksof{h,1} = JLINE.arraylist_to_matrix(jlsn.tasksof.get(uint32(h)))';
2432 end
2433 for t=1:jlsn.ntasks
2434 lsn.entriesof{lsn.tshift+t,1} = JLINE.arraylist_to_matrix(jlsn.entriesof.get(uint32(jlsn.tshift+t)))';
2435 end
2436 for t=1:(jlsn.ntasks+jlsn.nentries)
2437 lsn.actsof{lsn.tshift+t,1} = JLINE.arraylist_to_matrix(jlsn.actsof.get(uint32(jlsn.tshift+t)))';
2438 end
2439 for a=1:jlsn.nacts
2440 lsn.callsof{lsn.ashift+a,1} = JLINE.arraylist_to_matrix(jlsn.callsof.get(uint32(jlsn.ashift+a)))';
2441 end
2442 for i = 1:jlsn.sched.size
2443 lsn.sched(i,1) = SchedStrategy.(char(jlsn.sched.get(uint32(i))));
2444 end
2445 for i = 1:jlsn.names.size
2446 lsn.names{i,1} = jlsn.names.get(uint32(i));
2447 lsn.hashnames{i,1} = jlsn.hashnames.get(uint32(i));
2448 end
2449 lsn.mult = JLINE.from_jline_matrix(jlsn.mult);
2450 lsn.mult = lsn.mult(2:(lsn.eshift+1))'; % remove 0-padding
2451 lsn.maxmult = JLINE.from_jline_matrix(jlsn.maxmult);
2452 lsn.maxmult = lsn.maxmult(2:(lsn.eshift+1))'; % remove 0-padding
2453
2454 lsn.repl = JLINE.from_jline_matrix(jlsn.repl)';
2455 lsn.repl = lsn.repl(2:end); % remove 0-padding
2456 lsn.type = JLINE.from_jline_matrix(jlsn.type)';
2457 lsn.type = lsn.type(2:end); % remove 0-padding
2458 lsn.parent = JLINE.from_jline_matrix(jlsn.parent);
2459 lsn.parent = lsn.parent(2:end); % remove 0-padding
2460 lsn.nitems = JLINE.from_jline_matrix(jlsn.nitems);
2461 % Ensure proper column vector format matching MATLAB's (nhosts+ntasks+nentries) x 1
2462 if isrow(lsn.nitems)
2463 lsn.nitems = lsn.nitems(2:end)'; % remove 0-padding and transpose
2464 else
2465 lsn.nitems = lsn.nitems(2:end); % remove 0-padding (already column)
2466 end
2467 % Ensure correct size
2468 expectedSize = lsn.nhosts + lsn.ntasks + lsn.nentries;
2469 if length(lsn.nitems) < expectedSize
2470 lsn.nitems(expectedSize,1) = 0;
2471 elseif length(lsn.nitems) > expectedSize
2472 lsn.nitems = lsn.nitems(1:expectedSize);
2473 end
2474 lsn.replacestrat = JLINE.from_jline_matrix(jlsn.replacestrat);
2475 lsn.replacestrat = lsn.replacestrat(2:end)'; % remove 0-padding
2476 for i = 1:jlsn.callnames.size
2477 lsn.callnames{i,1} = jlsn.callnames.get(uint32(i));
2478 lsn.callhashnames{i,1} = jlsn.callhashnames.get(uint32(i));
2479 end
2480 for i = 1:jlsn.calltype.size % calltype may be made into a matrix in Java
2481 ct = char(jlsn.calltype.get(uint32(i)));
2482 lsn.calltype(i) = CallType.(ct);
2483 end
2484 lsn.calltype = sparse(lsn.calltype'); % remove 0-padding
2485 lsn.callpair = JLINE.from_jline_matrix(jlsn.callpair);
2486 lsn.callpair = lsn.callpair(2:end,2:end); % remove 0-paddings
2487 if isempty(lsn.callpair)
2488 lsn.callpair=[];
2489 end
2490 lsn.actpretype = sparse(JLINE.from_jline_matrix(jlsn.actpretype)');
2491 lsn.actpretype = lsn.actpretype(2:end); % remove 0-padding
2492 lsn.actposttype = sparse(JLINE.from_jline_matrix(jlsn.actposttype)');
2493 lsn.actposttype = lsn.actposttype(2:end); % remove 0-padding
2494 lsn.graph = JLINE.from_jline_matrix(jlsn.graph);
2495 lsn.graph = lsn.graph(2:end,2:end); % remove 0-paddings
2496 lsn.dag = JLINE.from_jline_matrix(jlsn.dag);
2497 lsn.dag = lsn.dag(2:end,2:end); % remove 0-paddings
2498 lsn.taskgraph = JLINE.from_jline_matrix(jlsn.taskgraph);
2499 lsn.taskgraph = sparse(lsn.taskgraph(2:end,2:end)); % remove 0-paddings
2500 lsn.replygraph = JLINE.from_jline_matrix(jlsn.replygraph);
2501 lsn.replygraph = logical(lsn.replygraph(2:end,2:end)); % remove 0-paddings
2502 lsn.iscache = JLINE.from_jline_matrix(jlsn.iscache);
2503 % Ensure proper column vector format matching MATLAB's (nhosts+ntasks) x 1
2504 expectedCacheSize = lsn.nhosts + lsn.ntasks;
2505 if isrow(lsn.iscache)
2506 if length(lsn.iscache) > expectedCacheSize
2507 lsn.iscache = lsn.iscache(2:(expectedCacheSize+1))'; % remove 0-padding and transpose
2508 else
2509 lsn.iscache = lsn.iscache'; % just transpose
2510 end
2511 end
2512 % Ensure correct size
2513 if length(lsn.iscache) < expectedCacheSize
2514 lsn.iscache(expectedCacheSize,1) = 0;
2515 elseif length(lsn.iscache) > expectedCacheSize
2516 lsn.iscache = lsn.iscache(1:expectedCacheSize);
2517 end
2518 lsn.iscaller = JLINE.from_jline_matrix(jlsn.iscaller);
2519 lsn.iscaller = full(lsn.iscaller(2:end,2:end)); % remove 0-paddings
2520 lsn.issynccaller = JLINE.from_jline_matrix(jlsn.issynccaller);
2521 lsn.issynccaller = full(lsn.issynccaller(2:end,2:end)); % remove 0-paddings
2522 lsn.isasynccaller = JLINE.from_jline_matrix(jlsn.isasynccaller);
2523 lsn.isasynccaller = full(lsn.isasynccaller(2:end,2:end)); % remove 0-paddings
2524 lsn.isref = JLINE.from_jline_matrix(jlsn.isref);
2525 lsn.isref = lsn.isref(2:end)'; % remove 0-paddings
2526 end
2527
2528 function sn = from_jline_struct(jnetwork, jsn)
2529 %lst and rtfun are not implemented
2530 %Due to the transformation of Java lambda to matlab function
2531 if nargin<2
2532 jsn = jnetwork.getStruct(false);
2533 end
2534 jclasses = jnetwork.getClasses();
2535 jnodes = jnetwork.getNodes();
2536 jstateful = jnetwork.getStatefulNodes();
2537 jstations = jnetwork.getStations();
2538 sn = NetworkStruct();
2539
2540 sn.nnodes = jsn.nnodes;
2541 sn.nclasses = jsn.nclasses;
2542 sn.nclosedjobs = jsn.nclosedjobs;
2543 sn.nstations = jsn.nstations;
2544 sn.nstateful = jsn.nstateful;
2545 sn.nchains = jsn.nchains;
2546
2547 sn.refstat = JLINE.from_jline_matrix(jsn.refstat) + 1;
2548 sn.njobs = JLINE.from_jline_matrix(jsn.njobs);
2549 sn.nservers = JLINE.from_jline_matrix(jsn.nservers);
2550 sn.connmatrix = JLINE.from_jline_matrix(jsn.connmatrix);
2551 % Fix for Java getConnectionMatrix bug: ensure connmatrix is nnodes x nnodes
2552 if size(sn.connmatrix,1) < sn.nnodes
2553 sn.connmatrix(sn.nnodes,1) = 0;
2554 end
2555 if size(sn.connmatrix,2) < sn.nnodes
2556 sn.connmatrix(1,sn.nnodes) = 0;
2557 end
2558 sn.scv = JLINE.from_jline_matrix(jsn.scv);
2559 sn.isstation = logical(JLINE.from_jline_matrix(jsn.isstation));
2560 sn.isstateful = logical(JLINE.from_jline_matrix(jsn.isstateful));
2561 sn.isstatedep = logical(JLINE.from_jline_matrix(jsn.isstatedep));
2562 sn.nodeToStateful = JLINE.from_jline_matrix(jsn.nodeToStateful)+1;
2563 sn.nodeToStateful(sn.nodeToStateful==0) = nan;
2564 sn.nodeToStation = JLINE.from_jline_matrix(jsn.nodeToStation)+1;
2565 sn.nodeToStation(sn.nodeToStation==0) = nan;
2566 sn.stationToNode = JLINE.from_jline_matrix(jsn.stationToNode)+1;
2567 sn.stationToNode(sn.stationToNode==0) = nan;
2568 sn.stationToStateful = JLINE.from_jline_matrix(jsn.stationToStateful)+1;
2569 sn.stationToStateful(sn.stationToStateful==0) = nan;
2570 sn.statefulToStation = JLINE.from_jline_matrix(jsn.statefulToStation)+1;
2571 sn.statefulToStation(sn.statefulToStation==0) = nan;
2572 sn.statefulToNode = JLINE.from_jline_matrix(jsn.statefulToNode)+1;
2573 sn.statefulToNode(sn.statefulToNode==0) = nan;
2574 sn.rates = JLINE.from_jline_matrix(jsn.rates);
2575 sn.fj = JLINE.from_jline_matrix(jsn.fj);
2576 sn.classprio = JLINE.from_jline_matrix(jsn.classprio);
2577 sn.phases = JLINE.from_jline_matrix(jsn.phases);
2578 sn.phasessz = JLINE.from_jline_matrix(jsn.phasessz);
2579 sn.phaseshift = JLINE.from_jline_matrix(jsn.phaseshift);
2580 sn.schedparam = JLINE.from_jline_matrix(jsn.schedparam);
2581 sn.chains = logical(JLINE.from_jline_matrix(jsn.chains));
2582 sn.rt = JLINE.from_jline_matrix(jsn.rt);
2583 sn.nvars = JLINE.from_jline_matrix(jsn.nvars);
2584 sn.rtnodes = JLINE.from_jline_matrix(jsn.rtnodes);
2585 sn.csmask = logical(JLINE.from_jline_matrix(jsn.csmask));
2586 sn.isslc = logical(JLINE.from_jline_matrix(jsn.isslc));
2587 sn.cap = JLINE.from_jline_matrix(jsn.cap);
2588 sn.classcap = JLINE.from_jline_matrix(jsn.classcap);
2589 sn.refclass = JLINE.from_jline_matrix(jsn.refclass)+1;
2590 sn.lldscaling = JLINE.from_jline_matrix(jsn.lldscaling);
2591
2592 if ~isempty(jsn.cdscaling) && jsn.cdscaling.size() > 0
2593 % Convert Java SerializableFunction to MATLAB function handles
2594 sn.cdscaling = cell(sn.nstations, 1);
2595 % Iterate through the map entries to handle null values properly
2596 entrySet = jsn.cdscaling.entrySet();
2597 entryIter = entrySet.iterator();
2598 stationFunMap = containers.Map();
2599 while entryIter.hasNext()
2600 entry = entryIter.next();
2601 stationName = char(entry.getKey().getName());
2602 try
2603 jfun = entry.getValue();
2604 if ~isempty(jfun)
2605 stationFunMap(stationName) = jfun;
2606 end
2607 catch
2608 % getValue() returns null for default lambda functions
2609 % Skip and use default value
2610 end
2611 end
2612 % Assign functions to stations
2613 for i = 1:sn.nstations
2614 jstation = jstations.get(i-1);
2615 stationName = char(jstation.getName());
2616 if isKey(stationFunMap, stationName)
2617 jfun = stationFunMap(stationName);
2618 % Create a MATLAB function handle that calls the Java apply() method
2619 sn.cdscaling{i} = @(ni) JLINE.call_java_cdscaling(jfun, ni);
2620 else
2621 sn.cdscaling{i} = @(ni) 1;
2622 end
2623 end
2624 else
2625 sn.cdscaling = cell(sn.nstations, 0);
2626 end
2627
2628 if ~isempty(jsn.nodetype)
2629 sn.nodetype = zeros(sn.nnodes, 1);
2630 for i = 1:jsn.nodetype.size
2631 nodetype = jsn.nodetype.get(i-1);
2632 switch nodetype.name().toCharArray'
2633 case 'Queue'
2634 sn.nodetype(i) = NodeType.Queue;
2635 case 'Delay'
2636 sn.nodetype(i) = NodeType.Delay;
2637 case 'Source'
2638 sn.nodetype(i) = NodeType.Source;
2639 case 'Sink'
2640 sn.nodetype(i) = NodeType.Sink;
2641 case 'Join'
2642 sn.nodetype(i) = NodeType.Join;
2643 case 'Fork'
2644 sn.nodetype(i) = NodeType.Fork;
2645 case 'ClassSwitch'
2646 sn.nodetype(i) = NodeType.ClassSwitch;
2647 case 'Logger'
2648 sn.nodetype(i) = NodeType.Logger;
2649 case 'Cache'
2650 sn.nodetype(i) = NodeType.Cache;
2651 case 'Place'
2652 sn.nodetype(i) = NodeType.Place;
2653 case 'Transition'
2654 sn.nodetype(i) = NodeType.Transition;
2655 case 'Router'
2656 sn.nodetype(i) = NodeType.Router;
2657 end
2658 end
2659 else
2660 sn.nodetype = [];
2661 end
2662
2663 if ~isempty(jsn.classnames)
2664 for i = 1:jsn.classnames.size
2665 sn.classnames(i,1) = jsn.classnames.get(i-1);
2666 end
2667 else
2668 sn.classnames = [];
2669 end
2670
2671 if ~isempty(jsn.nodenames)
2672 for i = 1:jsn.nodenames.size
2673 sn.nodenames(i,1) = jsn.nodenames.get(i-1);
2674 end
2675 else
2676 sn.nodenames = [];
2677 end
2678
2679 if ~isempty(jsn.rtorig) && jsn.rtorig.size()>0
2680 sn.rtorig = cell(sn.nclasses, sn.nclasses);
2681 for r = 1:sn.nclasses
2682 for s = 1:sn.nclasses
2683 sn.rtorig{r,s} = JLINE.from_jline_matrix(jsn.rtorig.get(jclasses.get(r-1)).get(jclasses.get(s-1)));
2684 end
2685 end
2686 else
2687 sn.rtorig = {};
2688 end
2689
2690 if ~isempty(jsn.state)
2691 sn.state = cell(sn.nstateful, 1);
2692 for i = 1:sn.nstateful
2693 sn.state{i} = JLINE.from_jline_matrix(jstateful.get(i-1).getState());
2694 end
2695 else
2696 sn.state = {};
2697 end
2698
2699 if ~isempty(jsn.stateprior)
2700 sn.stateprior = cell(sn.nstateful, 1);
2701 for i = 1:sn.nstateful
2702 sn.stateprior{i} = JLINE.from_jline_matrix(jstateful.get(i-1).getStatePrior());
2703 end
2704 else
2705 sn.stateprior = {};
2706 end
2707
2708 if ~isempty(jsn.space)
2709 sn.space = cell(sn.nstateful, 1);
2710 for i = 1:sn.nstateful
2711 sn.space{i} = JLINE.from_jline_matrix(jstateful.get(i-1).getStateSpace());
2712 end
2713 else
2714 sn.space = {};
2715 end
2716
2717 if ~isempty(jsn.routing)
2718 sn.routing = zeros(sn.nnodes, sn.nclasses);
2719 for i = 1:sn.nnodes
2720 for j = 1:sn.nclasses
2721 routingStrategy = jsn.routing.get(jnodes.get(i-1)).get(jclasses.get(j-1));
2722 switch routingStrategy.name().toCharArray'
2723 case 'PROB'
2724 sn.routing(i,j) = RoutingStrategy.PROB;
2725 case 'RAND'
2726 sn.routing(i,j) = RoutingStrategy.RAND;
2727 case 'RROBIN'
2728 sn.routing(i,j) = RoutingStrategy.RROBIN;
2729 case 'WRROBIN'
2730 sn.routing(i,j) = RoutingStrategy.WRROBIN;
2731 case 'JSQ'
2732 sn.routing(i,j) = RoutingStrategy.JSQ;
2733 case 'DISABLED'
2734 sn.routing(i,j) = RoutingStrategy.DISABLED;
2735 case 'FIRING'
2736 sn.routing(i,j) = RoutingStrategy.FIRING;
2737 case 'KCHOICES'
2738 sn.routing(i,j) = RoutingStrategy.KCHOICES;
2739 end
2740 end
2741 end
2742 else
2743 sn.routing = [];
2744 end
2745
2746 if ~isempty(jsn.procid)
2747 sn.procid = nan(sn.nstations, sn.nclasses); % Initialize with NaN to match MATLAB behavior
2748 for i = 1:sn.nstations
2749 for j = 1:sn.nclasses
2750 stationMap = jsn.procid.get(jstations.get(i-1));
2751 if isempty(stationMap)
2752 sn.procid(i,j) = ProcessType.DISABLED;
2753 continue;
2754 end
2755 processType = stationMap.get(jclasses.get(j-1));
2756 if isempty(processType)
2757 sn.procid(i,j) = ProcessType.DISABLED;
2758 continue;
2759 end
2760 switch processType.name.toCharArray'
2761 case 'EXP'
2762 sn.procid(i,j) = ProcessType.EXP;
2763 case 'ERLANG'
2764 sn.procid(i,j) = ProcessType.ERLANG;
2765 case 'HYPEREXP'
2766 sn.procid(i,j) = ProcessType.HYPEREXP;
2767 case 'PH'
2768 sn.procid(i,j) = ProcessType.PH;
2769 case 'APH'
2770 sn.procid(i,j) = ProcessType.APH;
2771 case 'MAP'
2772 sn.procid(i,j) = ProcessType.MAP;
2773 case 'UNIFORM'
2774 sn.procid(i,j) = ProcessType.UNIFORM;
2775 case 'DET'
2776 sn.procid(i,j) = ProcessType.DET;
2777 case 'COXIAN'
2778 sn.procid(i,j) = ProcessType.COXIAN;
2779 case 'GAMMA'
2780 sn.procid(i,j) = ProcessType.GAMMA;
2781 case 'PARETO'
2782 sn.procid(i,j) = ProcessType.PARETO;
2783 case 'WEIBULL'
2784 sn.procid(i,j) = ProcessType.WEIBULL;
2785 case 'LOGNORMAL'
2786 sn.procid(i,j) = ProcessType.LOGNORMAL;
2787 case 'MMPP2'
2788 sn.procid(i,j) = ProcessType.MMPP2;
2789 case 'REPLAYER'
2790 sn.procid(i,j) = ProcessType.REPLAYER;
2791 case 'TRACE'
2792 sn.procid(i,j) = ProcessType.TRACE;
2793 case 'IMMEDIATE'
2794 sn.procid(i,j) = ProcessType.IMMEDIATE;
2795 case 'DISABLED'
2796 sn.procid(i,j) = ProcessType.DISABLED;
2797 case 'COX2'
2798 sn.procid(i,j) = ProcessType.COX2;
2799 case 'BMAP'
2800 sn.procid(i,j) = ProcessType.BMAP;
2801 case 'ME'
2802 sn.procid(i,j) = ProcessType.ME;
2803 case 'RAP'
2804 sn.procid(i,j) = ProcessType.RAP;
2805 case 'BINOMIAL'
2806 sn.procid(i,j) = ProcessType.BINOMIAL;
2807 case 'POISSON'
2808 sn.procid(i,j) = ProcessType.POISSON;
2809 case 'GEOMETRIC'
2810 sn.procid(i,j) = ProcessType.GEOMETRIC;
2811 case 'DUNIFORM'
2812 sn.procid(i,j) = ProcessType.DUNIFORM;
2813 case 'BERNOULLI'
2814 sn.procid(i,j) = ProcessType.BERNOULLI;
2815 case 'PRIOR'
2816 sn.procid(i,j) = ProcessType.PRIOR;
2817 otherwise
2818 % Unknown ProcessType - default to DISABLED
2819 sn.procid(i,j) = ProcessType.DISABLED;
2820 end
2821 end
2822 end
2823 else
2824 sn.procid = [];
2825 end
2826
2827 if ~isempty(jsn.mu)
2828 sn.mu = cell(sn.nstations, 1);
2829 for i = 1:sn.nstations
2830 sn.mu{i} = cell(1, sn.nclasses);
2831 for j = 1:sn.nclasses
2832 sn.mu{i}{j} = JLINE.from_jline_matrix(jsn.mu.get(jstations.get(i-1)).get(jclasses.get(j-1)));
2833 end
2834 end
2835 else
2836 sn.mu = {};
2837 end
2838
2839 if ~isempty(jsn.phi)
2840 sn.phi = cell(sn.nstations, 1);
2841 for i = 1:sn.nstations
2842 sn.phi{i} = cell(1, sn.nclasses);
2843 for j = 1:sn.nclasses
2844 sn.phi{i}{j} = JLINE.from_jline_matrix(jsn.phi.get(jstations.get(i-1)).get(jclasses.get(j-1)));
2845 end
2846 end
2847 else
2848 sn.phi = {};
2849 end
2850
2851 if ~isempty(jsn.proc)
2852 sn.proc = cell(sn.nstations, 1);
2853 for i = 1:sn.nstations
2854 sn.proc{i} = cell(1, sn.nclasses);
2855 for j = 1:sn.nclasses
2856 proc_i_j = jsn.proc.get(jstations.get(i-1)).get(jclasses.get(j-1));
2857 sn.proc{i}{j} = cell(1, proc_i_j.size);
2858 for k = 1:proc_i_j.size
2859 sn.proc{i}{j}{k} = JLINE.from_jline_matrix(proc_i_j.get(uint32(k-1)));
2860 end
2861 end
2862 end
2863 else
2864 sn.proc = {};
2865 end
2866
2867 if ~isempty(jsn.pie)
2868 sn.pie = cell(sn.nstations, 1);
2869 for i = 1:sn.nstations
2870 sn.pie{i} = cell(1, sn.nclasses);
2871 for j = 1:sn.nclasses
2872 sn.pie{i}{j} = JLINE.from_jline_matrix(jsn.pie.get(jstations.get(i-1)).get(jclasses.get(j-1)));
2873 end
2874 end
2875 else
2876 sn.pie = {};
2877 end
2878
2879 if ~isempty(jsn.sched)
2880 sn.sched = zeros(sn.nstations, 1);
2881 for i = 1:sn.nstations
2882 schedStrategy = jsn.sched.get(jstations.get(i-1));
2883 switch schedStrategy.name.toCharArray'
2884 case 'INF'
2885 sn.sched(i) = SchedStrategy.INF;
2886 case 'FCFS'
2887 sn.sched(i) = SchedStrategy.FCFS;
2888 case 'LCFS'
2889 sn.sched(i) = SchedStrategy.LCFS;
2890 case 'LCFSPR'
2891 sn.sched(i) = SchedStrategy.LCFSPR;
2892 case 'SIRO'
2893 sn.sched(i) = SchedStrategy.SIRO;
2894 case 'SJF'
2895 sn.sched(i) = SchedStrategy.SJF;
2896 case 'LJF'
2897 sn.sched(i) = SchedStrategy.LJF;
2898 case 'PS'
2899 sn.sched(i) = SchedStrategy.PS;
2900 case 'DPS'
2901 sn.sched(i) = SchedStrategy.DPS;
2902 case 'GPS'
2903 sn.sched(i) = SchedStrategy.GPS;
2904 case 'PSPRIO'
2905 sn.sched(i) = SchedStrategy.PSPRIO;
2906 case 'DPSPRIO'
2907 sn.sched(i) = SchedStrategy.DPSPRIO;
2908 case 'GPSPRIO'
2909 sn.sched(i) = SchedStrategy.GPSPRIO;
2910 case 'SEPT'
2911 sn.sched(i) = SchedStrategy.SEPT;
2912 case 'LEPT'
2913 sn.sched(i) = SchedStrategy.LEPT;
2914 case {'HOL', 'FCFSPRIO'}
2915 sn.sched(i) = SchedStrategy.FCFSPRIO;
2916 case 'FORK'
2917 sn.sched(i) = SchedStrategy.FORK;
2918 case 'EXT'
2919 sn.sched(i) = SchedStrategy.EXT;
2920 case 'REF'
2921 sn.sched(i) = SchedStrategy.REF;
2922 end
2923 end
2924 else
2925 sn.sched = [];
2926 end
2927
2928 if ~isempty(jsn.inchain)
2929 sn.inchain = cell(1, sn.nchains);
2930 for i = 1:sn.nchains
2931 sn.inchain{1,i} = JLINE.from_jline_matrix(jsn.inchain.get(uint32(i-1)))+1;
2932 end
2933 else
2934 sn.inchain = {};
2935 end
2936
2937 if ~isempty(jsn.visits)
2938 sn.visits = cell(sn.nchains, 1);
2939 for i = 1:sn.nchains
2940 sn.visits{i,1} = JLINE.from_jline_matrix(jsn.visits.get(uint32(i-1)));
2941 end
2942 else
2943 sn.visits = {};
2944 end
2945
2946 if ~isempty(jsn.nodevisits)
2947 sn.nodevisits = cell(1, sn.nchains);
2948 for i = 1:sn.nchains
2949 sn.nodevisits{1,i} = JLINE.from_jline_matrix(jsn.nodevisits.get(uint32(i-1)));
2950 end
2951 else
2952 sn.nodevisits = {};
2953 end
2954
2955 if ~isempty(jsn.droprule)
2956 sn.droprule = zeros(sn.nstations, sn.nclasses);
2957 for i = 1:sn.nstations
2958 for j = 1:sn.nclasses
2959 dropStrategy = jsn.droprule.get(jstations.get(i-1)).get(jclasses.get(j-1));
2960 switch dropStrategy.name.toCharArray'
2961 case 'WaitingQueue'
2962 sn.droprule(i,j) = DropStrategy.WAITQ;
2963 case 'Drop'
2964 sn.droprule(i,j) = DropStrategy.DROP;
2965 case 'BlockingAfterService'
2966 sn.droprule(i,j) = DropStrategy.BAS;
2967 end
2968 end
2969 end
2970 else
2971 sn.droprule = [];
2972 end
2973
2974 if ~isempty(jsn.nodeparam)
2975 sn.nodeparam = cell(sn.nnodes, 1);
2976
2977 for i = 1:sn.nnodes
2978 jnode = jnodes.get(i-1);
2979 jparam = jsn.nodeparam.get(jnode);
2980
2981 %if jparam.isEmpty
2982 % sn.nodeparam{i} = [];
2983 % continue;
2984 %end
2985
2986 % StationNodeParam
2987 if isa(jparam, 'jline.lang.nodeparam.StationNodeParam')
2988 if ~isempty(jparam.fileName)
2989 sn.nodeparam{i}.fileName = cell(1, sn.nclasses);
2990 for r = 1:sn.nclasses
2991 fname = jparam.fileName.get(r-1);
2992 if ~isempty(fname)
2993 sn.nodeparam{i}.fileName{r} = char(fname);
2994 end
2995 end
2996 end
2997 end
2998
2999 % TransitionNodeParam
3000 if isa(jparam, 'jline.lang.nodeparam.TransitionNodeParam')
3001 if ~isempty(jparam.firingprocid)
3002 sn.nodeparam{i}.firingprocid = containers.Map('KeyType', 'char', 'ValueType', 'any');
3003 keys = jparam.firingprocid.keySet.iterator;
3004 while keys.hasNext
3005 key = keys.next;
3006 proc = jparam.firingprocid.get(key);
3007 sn.nodeparam{i}.firingprocid(char(key.toString)) = char(proc.toString);
3008 end
3009 end
3010 if ~isempty(jparam.firingphases)
3011 sn.nodeparam{i}.firingphases = JLINE.from_jline_matrix(jparam.firingphases);
3012 end
3013 if ~isempty(jparam.fireweight)
3014 sn.nodeparam{i}.fireweight = JLINE.from_jline_matrix(jparam.fireweight);
3015 end
3016 end
3017
3018 % JoinNodeParam
3019 if isa(jparam, 'jline.lang.nodeparam.JoinNodeParam')
3020 if ~isempty(jparam.joinStrategy)
3021 sn.nodeparam{i}.joinStrategy = cell(1, sn.nclasses);
3022 sn.nodeparam{i}.fanIn = cell(1, sn.nclasses);
3023 for r = 1:sn.nclasses
3024 jclass = jclasses.get(r-1);
3025 joinStrategy = jparam.joinStrategy.get(jclass);
3026 if ~isempty(joinStrategy)
3027 strategyStr = char(joinStrategy.name.toString);
3028 switch strategyStr
3029 case 'STD'
3030 sn.nodeparam{i}.joinStrategy{r} = JoinStrategy.STD;
3031 case 'PARTIAL'
3032 sn.nodeparam{i}.joinStrategy{r} = JoinStrategy.PARTIAL;
3033 otherwise
3034 sn.nodeparam{i}.joinStrategy{r} = strategyStr;
3035 end
3036 sn.nodeparam{i}.fanIn{r} = jparam.fanIn.get(jclass);
3037 end
3038 end
3039 end
3040 end
3041
3042 % RoutingNodeParam
3043 if isa(jparam, 'jline.lang.nodeparam.RoutingNodeParam')
3044 for r = 1:sn.nclasses
3045 jclass = jclasses.get(r-1);
3046
3047 if ~isempty(jparam.weights) && jparam.weights.containsKey(jclass)
3048 sn.nodeparam{i}.weights{r} = JLINE.from_jline_matrix(jparam.weights.get(jclass));
3049 end
3050
3051 if ~isempty(jparam.outlinks) && jparam.outlinks.containsKey(jclass)
3052 sn.nodeparam{i}.outlinks{r} = JLINE.from_jline_matrix(jparam.outlinks.get(jclass));
3053 end
3054 end
3055 end
3056
3057 % ForkNodeParam
3058 if isa(jparam, 'jline.lang.nodeparam.ForkNodeParam')
3059 if ~isnan(jparam.fanOut)
3060 sn.nodeparam{i}.fanOut = jparam.fanOut;
3061 end
3062 end
3063
3064 % CacheNodeParam
3065 if isa(jparam, 'jline.lang.nodeparam.CacheNodeParam')
3066 % nitems
3067 if ~isnan(jparam.nitems)
3068 sn.nodeparam{i}.nitems = jparam.nitems;
3069 end
3070
3071 % accost
3072 if ~isempty(jparam.accost)
3073 % For Java 2D arrays (Matrix[][]), size(arr,2) returns 1 in MATLAB
3074 % We need to get length of first row to get actual second dimension
3075 K1 = size(jparam.accost, 1);
3076 if K1 > 0
3077 firstRow = jparam.accost(1); % Get first row (Java array)
3078 K2 = length(firstRow);
3079 else
3080 K2 = 0;
3081 end
3082 sn.nodeparam{i}.accost = cell(K1, K2);
3083 for k1 = 1:K1
3084 for k2 = 1:K2
3085 mat = jparam.accost(k1, k2); % MATLAB handles Java array indexing
3086 if ~isempty(mat)
3087 sn.nodeparam{i}.accost{k1, k2} = JLINE.from_jline_matrix(mat);
3088 end
3089 end
3090 end
3091 end
3092
3093 % itemcap
3094 if ~isempty(jparam.itemcap)
3095 sn.nodeparam{i}.itemcap = JLINE.from_jline_matrix(jparam.itemcap);
3096 end
3097
3098 % pread - convert from Java Map<Integer, List<Double>> to MATLAB cell array {R}
3099 if ~isempty(jparam.pread)
3100 nclasses = sn.nclasses;
3101 sn.nodeparam{i}.pread = cell(1, nclasses);
3102 for r = 1:nclasses
3103 list = jparam.pread.get(int32(r-1)); % Java 0-based indexing
3104 if ~isempty(list)
3105 values = zeros(1, list.size);
3106 for j = 1:list.size
3107 values(j) = list.get(j-1);
3108 end
3109 sn.nodeparam{i}.pread{r} = values;
3110 else
3111 sn.nodeparam{i}.pread{r} = NaN;
3112 end
3113 end
3114 end
3115
3116 % replacestrat
3117 if ~isempty(jparam.replacestrat)
3118 switch char(jparam.replacestrat)
3119 case 'RR'
3120 sn.nodeparam{i}.replacestrat = ReplacementStrategy.RR;
3121 case 'FIFO'
3122 sn.nodeparam{i}.replacestrat = ReplacementStrategy.FIFO;
3123 case 'SFIFO'
3124 sn.nodeparam{i}.replacestrat = ReplacementStrategy.SFIFO;
3125 case 'LRU'
3126 sn.nodeparam{i}.replacestrat = ReplacementStrategy.LRU;
3127 end
3128 end
3129
3130 % hitclass
3131 if ~isempty(jparam.hitclass)
3132 sn.nodeparam{i}.hitclass = 1+JLINE.from_jline_matrix(jparam.hitclass);
3133 end
3134
3135 % missclass
3136 if ~isempty(jparam.missclass)
3137 sn.nodeparam{i}.missclass =1+ JLINE.from_jline_matrix(jparam.missclass);
3138 end
3139
3140 % actual hit/miss probabilities
3141 if ~isempty(jparam.actualhitprob)
3142 sn.nodeparam{i}.actualhitprob = JLINE.from_jline_matrix(jparam.actualhitprob);
3143 end
3144 if ~isempty(jparam.actualmissprob)
3145 sn.nodeparam{i}.actualmissprob = JLINE.from_jline_matrix(jparam.actualmissprob);
3146 end
3147 end
3148 end
3149 else
3150 sn.nodeparam = {};
3151 end
3152
3153 % if ~isempty(jsn.nodeparam)
3154 % sn.nodeparam = cell(sn.nnodes, 1);
3155 % % Note that JLINE only support node parameters related to
3156 % % Fork, Join, WWROBIN and RROBIN
3157 % for i = 1:sn.nnodes
3158 % if jsn.nodeparam.get(jnodes.get(i-1)).isEmpty
3159 % sn.nodeparam{i} = [];
3160 % else
3161 % if ~isnan(jsn.nodeparam.get(jnodes.get(i-1)).nitems)
3162 % sn.nodeparam{i}.nitems = jsn.nodeparam.get(jnodes.get(i-1)).nitems;
3163 % end
3164 % if ~isnan(jsn.nodeparam.get(jnodes.get(i-1)).fanOut)
3165 % sn.nodeparam{i}.fanOut = jsn.nodeparam.get(jnodes.get(i-1)).fanOut;
3166 % end
3167 % if ~isempty(jsn.nodeparam.get(jnodes.get(i-1)).joinStrategy)
3168 % if ~jsn.nodeparam.get(jnodes.get(i-1)).joinStrategy.isEmpty
3169 % sn.nodeparam{i}.joinStrategy = cell(1, sn.nclasses);
3170 % sn.nodeparam{i}.fanIn = cell(1, sn.nclasses);
3171 % for r = 1:sn.nclasses
3172 % joinStrategy = jsn.nodeparam.get(jnodes.get(i-1)).joinStrategy.get(jclasses.get(r-1));
3173 % switch joinStrategy.name.toCharArray'
3174 % case 'STD'
3175 % sn.nodeparam{i}.joinStrategy{r} = JoinStrategy.STD;
3176 % case 'PARTIAL'
3177 % sn.nodeparam{i}.joinStrategy{r} = JoinStrategy.PARTIAL;
3178 % end
3179 % sn.nodeparam{i}.fanIn{r} = jsn.nodeparam.get(jnodes.get(i-1)).fanIn.get(jclasses.get(r-1));
3180 % end
3181 % end
3182 % end
3183 %
3184 % if ~isempty(jsn.nodeparam.get(jnodes.get(i-1)).weights)
3185 % for r = 1:sn.nclasses
3186 % sn.nodeparam{i}{r}.weights = JLINE.from_jline_matrix(jsn.nodeparam.get(jnodes.get(i-1)).weights.get(jclasses.get(r-1)));
3187 % end
3188 % end
3189 %
3190 % if ~isempty(jsn.nodeparam.get(jnodes.get(i-1)).outlinks)
3191 % for r = 1:sn.nclasses
3192 % sn.nodeparam{i}{r}.outlinks = JLINE.from_jline_matrix(jsn.nodeparam.get(jnodes.get(i-1)).outlinks.get(jclasses.get(r-1)));
3193 % end
3194 % end
3195 % end
3196 % end
3197 % else
3198 % sn.nodeparam = {};
3199 % end
3200
3201 if ~isempty(jsn.sync)
3202 jsync = jsn.sync;
3203 sn.sync = cell(jsync.size, 1);
3204 for i = 1:jsync.size
3205 jsync_i = jsync.get(uint32(i-1));
3206 sn.sync{i,1} = struct('active',cell(1),'passive',cell(1));
3207
3208 jactive = jsync_i.active.get(uint32(0));
3209 jpassive = jsync_i.passive.get(uint32(0));
3210
3211 %Currently assume that prob would always be a value
3212 %instead of lambda function (No idea of how to convert
3213 %Java lambda function to matlab lambda function)
3214 switch jactive.getEvent.name.toCharArray'
3215 case 'INIT'
3216 sn.sync{i,1}.active{1} = Event(EventType.INIT, jactive.getNode+1, jactive.getJobClass+1, ...
3217 jactive.getProb, JLINE.from_jline_matrix(jactive.getState), ...
3218 jactive.getT, jactive.getJob);
3219 case 'LOCAL'
3220 sn.sync{i,1}.active{1} = Event(EventType.LOCAL, jactive.getNode+1, jactive.getJobClass+1, ...
3221 jactive.getProb, JLINE.from_jline_matrix(jactive.getState), ...
3222 jactive.getT, jactive.getJob);
3223 case 'ARV'
3224 sn.sync{i,1}.active{1} = Event(EventType.ARV, jactive.getNode+1, jactive.getJobClass+1, ...
3225 jactive.getProb, JLINE.from_jline_matrix(jactive.getState), ...
3226 jactive.getT, jactive.getJob);
3227 case 'DEP'
3228 sn.sync{i,1}.active{1} = Event(EventType.DEP, jactive.getNode+1, jactive.getJobClass+1, ...
3229 jactive.getProb, JLINE.from_jline_matrix(jactive.getState), ...
3230 jactive.getT, jactive.getJob);
3231 case 'PHASE'
3232 sn.sync{i,1}.active{1} = Event(EventType.PHASE, jactive.getNode+1, jactive.getJobClass+1, ...
3233 jactive.getProb, JLINE.from_jline_matrix(jactive.getState), ...
3234 jactive.getT, jactive.getJob);
3235 case 'READ'
3236 sn.sync{i,1}.active{1} = Event(EventType.READ, jactive.getNode+1, jactive.getJobClass+1, ...
3237 jactive.getProb, JLINE.from_jline_matrix(jactive.getState), ...
3238 jactive.getT, jactive.getJob);
3239 case 'STAGE'
3240 sn.sync{i,1}.active{1} = Event(EventType.STAGE, jactive.getNode+1, jactive.getJobClass+1, ...
3241 jactive.getProb, JLINE.from_jline_matrix(jactive.getState), ...
3242 jactive.getT, jactive.getJob);
3243 end
3244
3245 switch jpassive.getEvent.name.toCharArray'
3246 case 'INIT'
3247 sn.sync{i,1}.passive{1} = Event(EventType.INIT, jpassive.getNode+1, jpassive.getJobClass+1, ...
3248 jpassive.getProb, JLINE.from_jline_matrix(jpassive.getState), ...
3249 jpassive.getT, jpassive.getJob);
3250 case 'LOCAL'
3251 sn.sync{i,1}.passive{1} = Event(EventType.LOCAL, jpassive.getNode+1, jpassive.getJobClass+1, ...
3252 jpassive.getProb, JLINE.from_jline_matrix(jpassive.getState), ...
3253 jpassive.getT, jpassive.getJob);
3254 case 'ARV'
3255 sn.sync{i,1}.passive{1} = Event(EventType.ARV, jpassive.getNode+1, jpassive.getJobClass+1, ...
3256 jpassive.getProb, JLINE.from_jline_matrix(jpassive.getState), ...
3257 jpassive.getT, jpassive.getJob);
3258 case 'DEP'
3259 sn.sync{i,1}.passive{1} = Event(EventType.DEP, jpassive.getNode+1, jpassive.getJobClass+1, ...
3260 jpassive.getProb, JLINE.from_jline_matrix(jpassive.getState), ...
3261 jpassive.getT, jpassive.getJob);
3262 case 'PHASE'
3263 sn.sync{i,1}.passive{1} = Event(EventType.PHASE, jpassive.getNode+1, jpassive.getJobClass+1, ...
3264 jpassive.getProb, JLINE.from_jline_matrix(jpassive.getState), ...
3265 jpassive.getT, jpassive.getJob);
3266 case 'READ'
3267 sn.sync{i,1}.passive{1} = Event(EventType.READ, jpassive.getNode+1, jpassive.getJobClass+1, ...
3268 jpassive.getProb, JLINE.from_jline_matrix(jpassive.getState), ...
3269 jpassive.getT, jpassive.getJob);
3270 case 'STAGE'
3271 sn.sync{i,1}.passive{1} = Event(EventType.STAGE, jpassive.getNode+1, jpassive.getJobClass+1, ...
3272 jpassive.getProb, JLINE.from_jline_matrix(jpassive.getState), ...
3273 jpassive.getT, jpassive.getJob);
3274 end
3275 end
3276 else
3277 sn.sync = {};
3278 end
3279 end
3280
3281 function [QN,UN,RN,WN,AN,TN] = arrayListToResults(alist)
3282 switch class(alist)
3283 case 'jline.solvers.LayeredNetworkAvgTable'
3284 QN = JLINE.arraylist_to_matrix(alist.getQLen());
3285 UN = JLINE.arraylist_to_matrix(alist.getUtil());
3286 RN = JLINE.arraylist_to_matrix(alist.getRespT());
3287 WN = JLINE.arraylist_to_matrix(alist.getResidT());
3288 AN = JLINE.arraylist_to_matrix(alist.getArvR());
3289 TN = JLINE.arraylist_to_matrix(alist.getTput());
3290 otherwise
3291 QN = JLINE.arraylist_to_matrix(alist.getQLen());
3292 UN = JLINE.arraylist_to_matrix(alist.getUtil());
3293 RN = JLINE.arraylist_to_matrix(alist.getRespT());
3294 WN = JLINE.arraylist_to_matrix(alist.getResidT());
3295 AN = JLINE.arraylist_to_matrix(alist.getArvR());
3296 TN = JLINE.arraylist_to_matrix(alist.getTput());
3297 end
3298 end
3299
3300 function featSupported = getFeatureSet()
3301 % FEATSUPPORTED = GETFEATURESET()
3302
3303 featSupported = SolverFeatureSet;
3304 featSupported.setTrue({'Sink','Source',...
3305 'ClassSwitch','Delay','DelayStation','Queue',...
3306 'APH','Coxian','Erlang','Exp','HyperExp',...
3307 'StatelessClassSwitcher','InfiniteServer','SharedServer','Buffer','Dispatcher',...
3308 'Server','JobSink','RandomSource','ServiceTunnel',...
3309 'SchedStrategy_INF','SchedStrategy_PS',...
3310 'RoutingStrategy_PROB','RoutingStrategy_RAND',...
3311 'ClosedClass','OpenClass'});
3312 end
3313
3314 function [bool, featSupported] = supports(model)
3315 % [BOOL, FEATSUPPORTED] = SUPPORTS(MODEL)
3316
3317 featUsed = model.getUsedLangFeatures();
3318 featSupported = JLINE.getFeatureSet();
3319 bool = SolverFeatureSet.supports(featSupported, featUsed);
3320 end
3321
3322
3323 function solverOptions = parseSolverOptions(solverOptions, options)
3324 fn = fieldnames(options);
3325 fn2 = fieldnames(solverOptions);
3326 for f = 1:length(fn)
3327 found = 0;
3328 for j = 1:length(fn2)
3329 if strcmp(fn{f}, fn2{j})
3330 found = 1;
3331 switch fn{f}
3332 case 'seed'
3333 solverOptions.seed = options.seed;
3334 case 'samples'
3335 solverOptions.samples = options.samples;
3336 case 'confint'
3337 % Parse confint - can be a level (0.95) or 0 to disable
3338 [confintEnabled, confintLevel] = Solver.parseConfInt(options.confint);
3339 if confintEnabled
3340 solverOptions.confint = confintLevel;
3341 else
3342 solverOptions.confint = 0;
3343 end
3344 case 'method'
3345 solverOptions.method = options.method;
3346 case 'config'
3347 if isfield(options.config,'eventcache')
3348 solverOptions.config.eventcache = options.config.eventcache;
3349 end
3350 if isfield(options.config,'fork_join')
3351 solverOptions.config.fork_join = options.config.fork_join;
3352 end
3353 if isfield(options.config,'highvar')
3354 solverOptions.config.highvar = options.config.highvar;
3355 end
3356 if isfield(options.config,'multiserver')
3357 solverOptions.config.multiserver = options.config.multiserver;
3358 end
3359 if isfield(options.config,'np_priority')
3360 solverOptions.config.np_priority = options.config.np_priority;
3361 end
3362 case 'verbose'
3363 switch options.(fn{f})
3364 case {VerboseLevel.SILENT}
3365 solverOptions.verbose = solverOptions.verbose.SILENT;
3366 case {VerboseLevel.STD}
3367 solverOptions.verbose = solverOptions.verbose.STD;
3368 case {VerboseLevel.DEBUG}
3369 solverOptions.verbose = solverOptions.verbose.DEBUG;
3370 end
3371 case 'init_sol'
3372 solverOptions.(fn{f}) = JLINE.from_line_matrix(options.init_sol);
3373 case 'cutoff'
3374 if isscalar(options.cutoff)
3375 solverOptions.(fn{f}) = jline.util.matrix.Matrix.singleton(options.cutoff);
3376 else
3377 solverOptions.(fn{f}) = JLINE.from_line_matrix(options.cutoff);
3378 end
3379 case 'odesolvers'
3380 case 'rewardIterations'
3381 solverOptions.rewardIterations = java.lang.Integer(options.rewardIterations);
3382 otherwise
3383 solverOptions.(fn{f}) = options.(fn{f});
3384 end
3385
3386 break;
3387 end
3388 end
3389 if ~found
3390 line_printf('Could not find option %s in the JLINE options.\n', fn{f});
3391 end
3392 end
3393 end
3394
3395 function [ssa] = SolverSSA(network_object, options)
3396 solverOptions = jline.solvers.SolverOptions(jline.lang.constant.SolverType.SSA);
3397 if nargin>1
3398 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3399 end
3400 jline.util.Maths.setRandomNumbersMatlab(true);
3401 ssa = jline.solvers.ssa.SolverSSA(network_object, solverOptions);
3402 end
3403
3404 function [qns] = SolverQNS(network_object, options)
3405 solverOptions = jline.solvers.SolverOptions(jline.lang.constant.SolverType.QNS);
3406 if nargin>1
3407 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3408 end
3409 qns = jline.solvers.qns.SolverQNS(network_object, solverOptions);
3410 end
3411
3412 function [mam] = SolverMAM(network_object, options)
3413 solverOptions = jline.solvers.SolverOptions(jline.lang.constant.SolverType.MAM);
3414 if nargin>1
3415 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3416 end
3417 mam = jline.solvers.mam.SolverMAM(network_object, solverOptions);
3418 end
3419
3420 function [jmt] = SolverJMT(network_object, options)
3421 solverOptions = jline.solvers.SolverOptions(jline.lang.constant.SolverType.JMT);
3422 if nargin>1
3423 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3424 end
3425 jmt = jline.solvers.jmt.SolverJMT(network_object, solverOptions);
3426 end
3427
3428 function [ctmc] = SolverCTMC(network_object, options)
3429 solverOptions = jline.solvers.SolverOptions(jline.lang.constant.SolverType.CTMC);
3430 if nargin>1
3431 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3432 end
3433 ctmc = jline.solvers.ctmc.SolverCTMC(network_object,solverOptions);
3434 end
3435
3436 function [fluid] = SolverFluid(network_object, options)
3437 solverOptions = jline.solvers.SolverOptions(jline.lang.constant.SolverType.FLUID);
3438 if nargin>1
3439 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3440 end
3441 fluid = jline.solvers.fluid.SolverFluid(network_object, solverOptions);
3442 end
3443
3444 function [QN, UN, RN, TN, CN, XN, t, QNt, UNt, TNt, xvec] = runFluidAnalyzer(network, options)
3445 % RUNFLUIDANALYZER Run JLINE fluid analyzer and return results
3446 %
3447 % [QN, UN, RN, TN, CN, XN, T, QNT, UNT, TNT, XVEC] = JLINE.runFluidAnalyzer(NETWORK, OPTIONS)
3448 %
3449 % Runs the JLINE fluid solver on the given network and converts
3450 % results back to MATLAB data structures.
3451 %
3452 % Input:
3453 % network - LINE Network model
3454 % options - Solver options structure with fields:
3455 % .method - solver method
3456 % .stiff - use stiff ODE solver
3457 %
3458 % Output:
3459 % QN, UN, RN, TN - Steady-state metrics [M x K]
3460 % CN, XN - System metrics [1 x K]
3461 % t - Time vector [Tmax x 1]
3462 % QNt, UNt, TNt - Transient metrics {M x K} cells
3463 % xvec - State vector structure
3464
3465 jmodel = LINE2JLINE(network);
3466 jsolver = JLINE.SolverFluid(jmodel);
3467 import jline.solvers.fluid.*;
3468
3469 jsolver.options.method = options.method;
3470 jsolver.options.stiff = options.stiff;
3471 result = jsolver.runMethodSpecificAnalyzerViaLINE();
3472
3473 % Convert JLINE result to MATLAB data structures
3474 M = jmodel.getNumberOfStatefulNodes();
3475 K = jmodel.getNumberOfClasses();
3476
3477 QN = NaN * zeros(M, K);
3478 UN = NaN * zeros(M, K);
3479 RN = NaN * zeros(M, K);
3480 TN = NaN * zeros(M, K);
3481 CN = NaN * zeros(1, K);
3482 XN = NaN * zeros(1, K);
3483
3484 QNt = cell(M, K);
3485 UNt = cell(M, K);
3486 TNt = cell(M, K);
3487
3488 Tmax = result.t.length();
3489 t = NaN * zeros(Tmax, 1);
3490
3491 for ist = 1:M
3492 for jst = 1:K
3493 QN(ist, jst) = result.QN.get(ist-1, jst-1);
3494 UN(ist, jst) = result.UN.get(ist-1, jst-1);
3495 RN(ist, jst) = result.RN.get(ist-1, jst-1);
3496 TN(ist, jst) = result.TN.get(ist-1, jst-1);
3497 end
3498 end
3499
3500 for jst = 1:K
3501 CN(1, jst) = result.CN.get(0, jst-1);
3502 XN(1, jst) = result.XN.get(0, jst-1);
3503 end
3504
3505 for ist = 1:M
3506 for jst = 1:K
3507 for p = 1:Tmax
3508 QNt{ist, jst}(p, 1) = result.QNt(ist, jst).get(p-1, 0);
3509 UNt{ist, jst}(p, 1) = result.UNt(ist, jst).get(p-1, 0);
3510 TNt{ist, jst}(p, 1) = result.TNt(ist, jst).get(p-1, 0);
3511 end
3512 end
3513 end
3514
3515 for p = 1:Tmax
3516 t(p, 1) = result.t.get(p-1, 0);
3517 end
3518
3519 % JLINE does not return odeStateVec
3520 xvec.odeStateVec = [];
3521 xvec.sn = network;
3522 end
3523
3524 function [ldes] = SolverLDES(network_object, options)
3525 % Create LDES-specific options object
3526 ldesOptions = jline.solvers.ldes.LDESOptions();
3527 if nargin>1
3528 % Copy standard options
3529 ldesOptions.samples = options.samples;
3530 ldesOptions.seed = options.seed;
3531 % Parse confint
3532 [confintEnabled, confintLevel] = Solver.parseConfInt(options.confint);
3533 if confintEnabled
3534 ldesOptions.confint = confintLevel;
3535 else
3536 ldesOptions.confint = 0;
3537 end
3538 % Pass timespan for transient analysis
3539 if isfield(options, 'timespan') && length(options.timespan) >= 2
3540 ldesOptions.timespan = options.timespan;
3541 end
3542 % Pass LDES-specific options if configured
3543 if isfield(options, 'config')
3544 % Transient detection options
3545 if isfield(options.config, 'tranfilter')
3546 ldesOptions.tranfilter = options.config.tranfilter;
3547 end
3548 if isfield(options.config, 'mserbatch')
3549 ldesOptions.mserbatch = options.config.mserbatch;
3550 end
3551 if isfield(options.config, 'warmupfrac')
3552 ldesOptions.warmupfrac = options.config.warmupfrac;
3553 end
3554 % Confidence interval options
3555 if isfield(options.config, 'cimethod')
3556 ldesOptions.cimethod = options.config.cimethod;
3557 end
3558 if isfield(options.config, 'obmoverlap')
3559 ldesOptions.obmoverlap = options.config.obmoverlap;
3560 end
3561 if isfield(options.config, 'ciminbatch')
3562 ldesOptions.ciminbatch = options.config.ciminbatch;
3563 end
3564 if isfield(options.config, 'ciminobs')
3565 ldesOptions.ciminobs = options.config.ciminobs;
3566 end
3567 if isfield(options.config, 'spectralLowFreqFrac')
3568 ldesOptions.spectralLowFreqFrac = options.config.spectralLowFreqFrac;
3569 end
3570 % Convergence options
3571 if isfield(options.config, 'cnvgon')
3572 ldesOptions.cnvgon = options.config.cnvgon;
3573 end
3574 if isfield(options.config, 'cnvgtol')
3575 ldesOptions.cnvgtol = options.config.cnvgtol;
3576 end
3577 if isfield(options.config, 'cnvgbatch')
3578 ldesOptions.cnvgbatch = options.config.cnvgbatch;
3579 end
3580 if isfield(options.config, 'cnvgchk')
3581 ldesOptions.cnvgchk = options.config.cnvgchk;
3582 end
3583 end
3584 end
3585 ldes = jline.solvers.ldes.SolverLDES(network_object, ldesOptions);
3586 end
3587
3588 function [mva] = SolverMVA(network_object, options)
3589 solverOptions = jline.solvers.SolverOptions(jline.lang.constant.SolverType.MVA);
3590 if nargin>1
3591 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3592 end
3593 mva = jline.solvers.mva.SolverMVA(network_object, solverOptions);
3594 end
3595
3596 function [nc] = SolverNC(network_object, options)
3597 solverOptions = jline.solvers.SolverOptions(jline.lang.constant.SolverType.NC);
3598 if nargin>1
3599 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3600 end
3601 nc = jline.solvers.nc.SolverNC(network_object, solverOptions);
3602 end
3603
3604 function [auto] = SolverAuto(network_object, options)
3605 solverOptions = jline.solvers.auto.AUTOptions();
3606 if nargin>1
3607 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3608 end
3609 auto = jline.solvers.auto.SolverAUTO(network_object, solverOptions);
3610 end
3611
3612 function streamOpts = StreamingOptions(varargin)
3613 % STREAMINGOPTIONS Create Java StreamingOptions for SSA/LDES stream() method
3614 %
3615 % @brief Creates StreamingOptions for streaming simulation metrics
3616 %
3617 % @param varargin Name-value pairs for options:
3618 % 'transport' - 'http' (recommended) or 'grpc' (default: 'http')
3619 % 'endpoint' - Receiver endpoint (default: 'localhost:8080/metrics' for HTTP)
3620 % 'mode' - 'sampled' or 'time_window' (default: 'sampled')
3621 % 'sampleFrequency' - Push every N events in sampled mode (default: 100)
3622 % 'timeWindowSeconds' - Window duration in time_window mode (default: 1.0)
3623 % 'serviceName' - Service identifier (default: 'line-stream')
3624 % 'includeQueueLength' - Include queue length metrics (default: true)
3625 % 'includeUtilization' - Include utilization metrics (default: true)
3626 % 'includeThroughput' - Include throughput metrics (default: true)
3627 % 'includeResponseTime' - Include response time metrics (default: true)
3628 % 'includeArrivalRate' - Include arrival rate metrics (default: true)
3629 %
3630 % @return streamOpts Java StreamingOptions object
3631 %
3632 % Example:
3633 % @code
3634 % streamOpts = JLINE.StreamingOptions('transport', 'http', 'sampleFrequency', 50);
3635 % @endcode
3636
3637 streamOpts = jline.streaming.StreamingOptions();
3638
3639 % Parse optional arguments
3640 p = inputParser;
3641 addParameter(p, 'transport', 'http', @ischar);
3642 addParameter(p, 'endpoint', '', @ischar); % Empty means use default for transport
3643 addParameter(p, 'mode', 'sampled', @ischar);
3644 addParameter(p, 'sampleFrequency', 100, @isnumeric);
3645 addParameter(p, 'timeWindowSeconds', 1.0, @isnumeric);
3646 addParameter(p, 'serviceName', 'line-stream', @ischar);
3647 addParameter(p, 'includeQueueLength', true, @islogical);
3648 addParameter(p, 'includeUtilization', true, @islogical);
3649 addParameter(p, 'includeThroughput', true, @islogical);
3650 addParameter(p, 'includeResponseTime', true, @islogical);
3651 addParameter(p, 'includeArrivalRate', true, @islogical);
3652 parse(p, varargin{:});
3653
3654 % Set transport type
3655 transportTypes = javaMethod('values', 'jline.streaming.StreamingOptions$TransportType');
3656 switch lower(p.Results.transport)
3657 case 'http'
3658 streamOpts.transport = transportTypes(1); % HTTP
3659 case 'grpc'
3660 streamOpts.transport = transportTypes(2); % GRPC
3661 otherwise
3662 streamOpts.transport = transportTypes(1); % Default to HTTP
3663 end
3664
3665 % Set endpoint (use provided or default based on transport)
3666 if ~isempty(p.Results.endpoint)
3667 streamOpts.endpoint = p.Results.endpoint;
3668 end
3669 % If empty, StreamingOptions uses its default for the transport type
3670
3671 % Set mode
3672 streamModes = javaMethod('values', 'jline.streaming.StreamingOptions$StreamMode');
3673 switch lower(p.Results.mode)
3674 case 'sampled'
3675 streamOpts.mode = streamModes(1); % SAMPLED
3676 case 'time_window'
3677 streamOpts.mode = streamModes(2); % TIME_WINDOW
3678 otherwise
3679 streamOpts.mode = streamModes(1); % Default to SAMPLED
3680 end
3681
3682 % Set other options
3683 streamOpts.sampleFrequency = p.Results.sampleFrequency;
3684 streamOpts.timeWindowSeconds = p.Results.timeWindowSeconds;
3685 streamOpts.serviceName = p.Results.serviceName;
3686 streamOpts.includeQueueLength = p.Results.includeQueueLength;
3687 streamOpts.includeUtilization = p.Results.includeUtilization;
3688 streamOpts.includeThroughput = p.Results.includeThroughput;
3689 streamOpts.includeResponseTime = p.Results.includeResponseTime;
3690 streamOpts.includeArrivalRate = p.Results.includeArrivalRate;
3691 end
3692
3693 function result = convertSampleResult(jresult)
3694 % CONVERTSAMPLERESULT Convert Java sample result to MATLAB struct
3695 %
3696 % @brief Converts Java SampleNodeState to MATLAB structure
3697 %
3698 % @param jresult Java SampleNodeState object
3699 % @return result MATLAB struct with fields: t, state, isaggregate
3700
3701 result = struct();
3702
3703 % Convert time matrix
3704 if ~isempty(jresult.t)
3705 result.t = JLINE.from_jline_matrix(jresult.t);
3706 else
3707 result.t = [];
3708 end
3709
3710 % Convert state matrix
3711 if ~isempty(jresult.state) && isa(jresult.state, 'jline.util.matrix.Matrix')
3712 result.state = JLINE.from_jline_matrix(jresult.state);
3713 else
3714 result.state = [];
3715 end
3716
3717 result.isaggregate = jresult.isaggregate;
3718 end
3719
3720 function [ln] = SolverLN(layered_network_object, options)
3721 solverOptions = jline.solvers.SolverOptions(jline.lang.constant.SolverType.LN);
3722 if nargin>1
3723 solverOptions = JLINE.parseSolverOptions(solverOptions, options);
3724 end
3725 ln = jline.solvers.ln.SolverLN(layered_network_object, solverOptions);
3726 end
3727
3728 function serfun = pas_handle_to_serializablefun(handle, nclasses, cap)
3729 % PAS_HANDLE_TO_SERIALIZABLEFUN Convert a PAS service rate function
3730 % mu(c) (MATLAB handle of the ordered class list) to a Java
3731 % SerializableFunction by pre-computing mu over every ordered prefix
3732 % up to the queue capacity.
3733 %
3734 % The JAR queries mu(c) with the ordered prefix as a row vector of
3735 % 0-based class indices (jline.lang.state.AfterEventStation), and the
3736 % PrecomputedCDFunction keys on the stringified vector, so values are
3737 % stored under the matching 0-based key.
3738 %
3739 % @param handle MATLAB mu(c) handle taking a 1-based ordered class list
3740 % @param nclasses Number of classes
3741 % @param cap Station capacity (max ordered-list length)
3742 % @return serfun Java PrecomputedCDFunction
3743
3744 % Guard against combinatorial explosion of ordered sequences
3745 nseq = 0; term = 1;
3746 for k = 1:cap
3747 term = term * nclasses;
3748 nseq = nseq + term;
3749 end
3750 if nseq > 5e6
3751 line_error(mfilename, sprintf('PAS service rate pre-computation would enumerate %d ordered states (nclasses=%d, cap=%d); too large for JLINE conversion.', nseq, nclasses, cap));
3752 end
3753
3754 serfun = jline.util.PrecomputedCDFunction(nclasses, 0.0);
3755 JLINE.pas_enumerate_seqs(handle, serfun, nclasses, cap, []);
3756 end
3757
3758 function pas_enumerate_seqs(handle, serfun, nclasses, cap, prefix)
3759 % PAS_ENUMERATE_SEQS Recursively enumerate ordered class sequences
3760 % (1-based, length 1..cap) and store mu(prefix) under the matching
3761 % 0-based key expected by the JAR.
3762 if ~isempty(prefix)
3763 val = handle(prefix); % mu(c), 1-based ordered list
3764 keyMat = JLINE.from_line_matrix(prefix - 1); % 0-based key (1 x p)
3765 serfun.addValue(keyMat, double(val));
3766 end
3767 if length(prefix) >= cap
3768 return;
3769 end
3770 for r = 1:nclasses
3771 JLINE.pas_enumerate_seqs(handle, serfun, nclasses, cap, [prefix, r]);
3772 end
3773 end
3774
3775 function serfun = handle_to_serializablefun(handle, sn)
3776 % HANDLE_TO_SERIALIZABLEFUN Convert MATLAB function handle to Java SerializableFunction
3777 %
3778 % This function pre-computes the function values for all possible state
3779 % combinations and creates a Java PrecomputedCDFunction object.
3780 %
3781 % @param handle MATLAB function handle that takes a vector ni and returns a scalar
3782 % @param sn Network struct containing njobs (population per class)
3783 % @return serfun Java PrecomputedCDFunction object
3784
3785 % Get number of classes and maximum populations
3786 nclasses = sn.nclasses;
3787 njobs = sn.njobs; % Population per class
3788
3789 % For open classes (njobs=0), use a reasonable bound
3790 maxPop = njobs;
3791 for r = 1:nclasses
3792 if maxPop(r) == 0 || isinf(maxPop(r))
3793 % For open classes, use sum of closed class populations or 100 as bound
3794 maxPop(r) = max(100, sum(njobs(isfinite(njobs) & njobs > 0)));
3795 end
3796 end
3797
3798 % Create Java PrecomputedCDFunction object
3799 serfun = jline.util.PrecomputedCDFunction(nclasses);
3800
3801 % Enumerate all possible state combinations and pre-compute function values
3802 % Use recursive enumeration to handle arbitrary number of classes
3803 JLINE.enumerate_states(handle, serfun, maxPop, zeros(1, nclasses), 1);
3804 end
3805
3806 function enumerate_states(handle, serfun, maxPop, currentState, classIdx)
3807 % ENUMERATE_STATES Recursively enumerate all state combinations
3808 %
3809 % @param handle MATLAB function handle
3810 % @param serfun Java PrecomputedCDFunction object to populate
3811 % @param maxPop Maximum population per class
3812 % @param currentState Current state being built
3813 % @param classIdx Current class index being enumerated
3814
3815 nclasses = length(maxPop);
3816
3817 if classIdx > nclasses
3818 % We have a complete state, compute and store the function value
3819 try
3820 value = handle(currentState);
3821 % Convert to Java int array and add to serfun
3822 jstate = jline.util.matrix.Matrix(1, nclasses);
3823 for r = 1:nclasses
3824 jstate.set(0, r-1, currentState(r));
3825 end
3826 serfun.addValue(jstate, value);
3827 catch
3828 % If function evaluation fails, skip this state
3829 end
3830 return;
3831 end
3832
3833 % Enumerate all populations for current class
3834 for n = 0:maxPop(classIdx)
3835 currentState(classIdx) = n;
3836 JLINE.enumerate_states(handle, serfun, maxPop, currentState, classIdx + 1);
3837 end
3838 end
3839
3840 function result = call_java_cdscaling(jfun, ni)
3841 % CALL_JAVA_CDSCALING Call a Java SerializableFunction for class dependence
3842 %
3843 % This function converts a MATLAB vector to a Java Matrix and calls
3844 % the Java function's apply() method.
3845 %
3846 % @param jfun Java SerializableFunction<Matrix, Double> object
3847 % @param ni MATLAB vector representing the state (jobs per class)
3848 % @return result The scaling factor returned by the Java function
3849
3850 % Convert MATLAB vector to Java Matrix
3851 if isrow(ni)
3852 jmatrix = jline.util.matrix.Matrix(1, length(ni));
3853 for r = 1:length(ni)
3854 jmatrix.set(0, r-1, ni(r));
3855 end
3856 else
3857 jmatrix = jline.util.matrix.Matrix(length(ni), 1);
3858 for r = 1:length(ni)
3859 jmatrix.set(r-1, 0, ni(r));
3860 end
3861 end
3862
3863 % Call the Java function and convert result to MATLAB double
3864 jresult = jfun.apply(jmatrix);
3865 result = double(jresult);
3866 end
3867
3868 function jSched = to_jline_sched_strategy(schedId)
3869 % Convert MATLAB SchedStrategy id to jline SchedStrategy enum
3870 switch schedId
3871 case SchedStrategy.REF
3872 jSched = jline.lang.constant.SchedStrategy.REF;
3873 case SchedStrategy.INF
3874 jSched = jline.lang.constant.SchedStrategy.INF;
3875 case SchedStrategy.FCFS
3876 jSched = jline.lang.constant.SchedStrategy.FCFS;
3877 case SchedStrategy.LCFS
3878 jSched = jline.lang.constant.SchedStrategy.LCFS;
3879 case SchedStrategy.SIRO
3880 jSched = jline.lang.constant.SchedStrategy.SIRO;
3881 case SchedStrategy.SJF
3882 jSched = jline.lang.constant.SchedStrategy.SJF;
3883 case SchedStrategy.LJF
3884 jSched = jline.lang.constant.SchedStrategy.LJF;
3885 case SchedStrategy.PS
3886 jSched = jline.lang.constant.SchedStrategy.PS;
3887 case SchedStrategy.DPS
3888 jSched = jline.lang.constant.SchedStrategy.DPS;
3889 case SchedStrategy.GPS
3890 jSched = jline.lang.constant.SchedStrategy.GPS;
3891 case SchedStrategy.SEPT
3892 jSched = jline.lang.constant.SchedStrategy.SEPT;
3893 case SchedStrategy.LEPT
3894 jSched = jline.lang.constant.SchedStrategy.LEPT;
3895 case {SchedStrategy.HOL, SchedStrategy.FCFSPRIO}
3896 jSched = jline.lang.constant.SchedStrategy.FCFSPRIO;
3897 case SchedStrategy.FORK
3898 jSched = jline.lang.constant.SchedStrategy.FORK;
3899 case SchedStrategy.EXT
3900 jSched = jline.lang.constant.SchedStrategy.EXT;
3901 case SchedStrategy.LCFSPR
3902 jSched = jline.lang.constant.SchedStrategy.LCFSPR;
3903 case SchedStrategy.PSPRIO
3904 jSched = jline.lang.constant.SchedStrategy.PSPRIO;
3905 case SchedStrategy.DPSPRIO
3906 jSched = jline.lang.constant.SchedStrategy.DPSPRIO;
3907 case SchedStrategy.GPSPRIO
3908 jSched = jline.lang.constant.SchedStrategy.GPSPRIO;
3909 otherwise
3910 jSched = jline.lang.constant.SchedStrategy.FCFS;
3911 end
3912 end
3913
3914 function jwf = from_line_workflow(line_wf)
3915 % Convert a MATLAB Workflow to a JAR Workflow.
3916 jwf = javaObject('jline.lang.workflow.Workflow', java.lang.String(line_wf.getName()));
3917 acts = line_wf.activities;
3918 for a = 1:length(acts)
3919 act = acts{a};
3920 actName = java.lang.String(act.name);
3921 if ~isempty(act.hostDemand) && isa(act.hostDemand, 'Distribution')
3922 jdist = JLINE.from_line_distribution(act.hostDemand);
3923 jwf.addActivity(actName, jdist);
3924 else
3925 jwf.addActivity(actName, 1.0);
3926 end
3927 end
3928 precs = line_wf.precedences;
3929 for p = 1:length(precs)
3930 prec = precs(p);
3931 preActs = java.util.ArrayList();
3932 for k = 1:length(prec.preActs)
3933 preActs.add(java.lang.String(prec.preActs{k}));
3934 end
3935 postActs = java.util.ArrayList();
3936 for k = 1:length(prec.postActs)
3937 postActs.add(java.lang.String(prec.postActs{k}));
3938 end
3939 preTypeStr = java.lang.String(ActivityPrecedenceType.toText(prec.preType));
3940 postTypeStr = java.lang.String(ActivityPrecedenceType.toText(prec.postType));
3941 if ~isempty(prec.preParams)
3942 preParamsMat = JLINE.from_line_matrix(prec.preParams(:)');
3943 else
3944 preParamsMat = javaObject('jline.util.matrix.Matrix', 0, 0);
3945 end
3946 if ~isempty(prec.postParams)
3947 postParamsMat = JLINE.from_line_matrix(prec.postParams(:)');
3948 else
3949 postParamsMat = javaObject('jline.util.matrix.Matrix', 0, 0);
3950 end
3951 jprec = javaObject('jline.lang.layered.ActivityPrecedence', ...
3952 preActs, postActs, preTypeStr, postTypeStr, preParamsMat, postParamsMat);
3953 jwf.addPrecedence(jprec);
3954 end
3955 end
3956
3957 function jenv = from_line_environment(line_env)
3958 % Convert a MATLAB Environment to a JAR Environment.
3959 E = height(line_env.envGraph.Nodes);
3960 jenv = javaObject('jline.lang.Environment', java.lang.String(line_env.getName()), int32(E));
3961 for e = 1:E
3962 stageName = char(line_env.envGraph.Nodes.Name{e});
3963 stageType = char(line_env.envGraph.Nodes.Type{e});
3964 stageModel = line_env.ensemble{e};
3965 jmodel = JLINE.from_line_network(stageModel);
3966 jenv.addStage(int32(e-1), java.lang.String(stageName), java.lang.String(stageType), jmodel);
3967 end
3968 if ~isempty(line_env.env)
3969 [Erows, Ecols] = size(line_env.env);
3970 for e = 1:Erows
3971 for h = 1:Ecols
3972 d = line_env.env{e,h};
3973 if isempty(d) || isa(d, 'Disabled')
3974 continue;
3975 end
3976 jdist = JLINE.from_line_distribution(d);
3977 jenv.addTransition(int32(e-1), int32(h-1), jdist);
3978 end
3979 end
3980 end
3981 jenv.init();
3982 end
3983
3984 end
3985end
Definition mmt.m:124