LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
LQN2JAVA.m
1function LQN2JAVA(lqnmodel, modelName, fid)
2% LQN2JAVA(MODEL, MODELNAME, FID)
3
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6
7if nargin<2%~exist('modelName','var')
8 modelName='myLayeredModel';
9end
10if nargin<3%~exist('fid','var')
11 fid=1;
12end
13if ischar(fid)
14 fid = fopen(fid,'w');
15end
16sn = lqnmodel.getStruct;
17
18%% initialization
19fprintf(fid,'package jline.examples;\n\n');
20fprintf(fid,'import jline.lang.*;\n');
21fprintf(fid,'import jline.lang.constant.*;\n');
22fprintf(fid,'import jline.lang.processes.*;\n');
23fprintf(fid,'import jline.solvers.ln.SolverLN;\n\n');
24fprintf(fid,'public class TestSolver%s {\n\n',upper(strrep(modelName,' ','')));
25fprintf(fid,'\tpublic static void main(String[] args) throws Exception{\n\n');
26fprintf(fid,'\tLayeredNetwork model = new LayeredNetwork("%s");\n',modelName);
27fprintf(fid,'\n');
28%% host processors
29for h=1:sn.nhosts
30 if isinf(sn.mult(h))
31 fprintf(fid, '\tProcessor P%d = new Processor(model, "%s", Integer.MAX_VALUE, %s);\n', h, sn.names{h}, strrep(SchedStrategy.toFeature(sn.sched(h)),'_','.'));
32 else
33 fprintf(fid, '\tProcessor P%d = new Processor(model, "%s", %d, %s);\n', h, sn.names{h}, sn.mult(h), strrep(SchedStrategy.toFeature(sn.sched(h)),'_','.'));
34 end
35 if sn.repl(h)~=1
36 fprintf(fid, 'P%d.setReplication(%d);\n', h, sn.repl(h));
37 end
38end
39fprintf(fid,'\n');
40%% tasks
41for t=1:sn.ntasks
42 tidx = sn.tshift+t;
43 if isinf(sn.mult(tidx))
44 fprintf(fid, '\tTask T%d = new Task(model, "%s", Integer.MAX_VALUE, %s).on(P%d);\n', t, sn.names{tidx}, strrep(SchedStrategy.toFeature(sn.sched(tidx)),'_','.'), sn.parent(tidx));
45 else
46 fprintf(fid, '\tTask T%d = new Task(model, "%s", %d, %s).on(P%d);\n', t, sn.names{tidx}, sn.mult(tidx), strrep(SchedStrategy.toFeature(sn.sched(tidx)),'_','.'), sn.parent(tidx));
47 end
48 if sn.repl(tidx)~=1
49 fprintf(fid, '\tT%d.setReplication(%d);\n', t, sn.repl(tidx));
50 end
51 if ~isempty(sn.think{tidx})
52 switch sn.think{tidx}.name
53 case 'Immediate'
54 fprintf(fid, '\tT%d.setThinkTime(new Immediate());\n',t);
55 case 'Exp'
56 fprintf(fid, '\tT%d.setThinkTime(new Exp(%g));\n',t, 1/sn.think{tidx}.getMean);
57 case {'Erlang','HyperExp', 'Coxian', 'APH'}
58 fprintf(fid, '\tT%d.setThinkTime(%s.fitMeanAndSCV(%g,%g));\n', t, sn.think{tidx}.name, sn.think{tidx}.getMean, sn.think{tidx}.getSCV);
59 otherwise
60 line_error(mfilename,sprintf('LQN2SCRIPT does not support the %d distribution yet.',sn.think{tidx}.name));
61 end
62 end
63end
64fprintf(fid,'\n');
65%% entries
66for e=1:sn.nentries
67 eidx = sn.eshift+e;
68 fprintf(fid, '\tEntry E%d = new Entry(model, "%s").on(T%d);\n', e, sn.names{eidx},sn.parent(eidx)-sn.tshift);
69end
70fprintf(fid,'\n');
71%% activities
72for a=1:sn.nacts
73 aidx = sn.ashift+a;
74 tidx = sn.parent(aidx);
75 onTask = tidx-sn.tshift;
76 boundTo = find(sn.graph((sn.eshift+1):(sn.eshift+sn.nentries),aidx));
77 boundToStr = '';
78 if ~isempty(boundTo)
79 boundToStr = sprintf('.boundTo(E%d)',boundTo);
80 end
81 repliesToStr = '';
82 if sn.sched(tidx) ~= SchedStrategy.REF % ref tasks don't reply
83 repliesTo = find(sn.replygraph(a,:)); % index of entry
84 if ~isempty(repliesTo)
85 if ~sn.isref(sn.parent(sn.eshift+repliesTo))
86 repliesToStr = sprintf('.repliesTo(E%d)',repliesTo);
87 end
88 end
89 end
90 callStr = '';
91 if ~isempty(sn.callpair)
92 cidxs = find(sn.callpair(:,1)==aidx);
93 calls = sn.callpair(:,2);
94 for c=cidxs(:)'
95 switch sn.calltype(c)
96 case CallType.SYNC
97 callStr = sprintf('%s.synchCall(E%d,%g)',callStr,calls(c)-sn.eshift,sn.callproc{c}.getMean);
98 case CallType.ASYNC
99 callStr = sprintf('%s.asynchCall(E%d,%g)',callStr,calls(c)-sn.eshift,sn.callproc{c}.getMean);
100 end
101 end
102 end
103 switch sn.hostdem{aidx}.name
104 case 'Immediate'
105 fprintf(fid, '\tActivity A%d = new Activity(model, "%s", new Immediate()).on(T%d);', a, sn.names{aidx}, onTask);
106 case 'Exp'
107 fprintf(fid, '\tActivity A%d = new Activity(model, "%s", new Exp(%g)).on(T%d);', a, sn.names{aidx},1/sn.hostdem{aidx}.getMean, onTask);
108 case {'Erlang','HyperExp','Coxian','APH'}
109 fprintf(fid, '\tActivity A%d = new Activity(model, "%s", %s.fitMeanAndSCV(%g,%g)).on(T%d);', a, sn.names{aidx},sn.hostdem{aidx}.name,sn.hostdem{aidx}.getMean,sn.hostdem{aidx}.getSCV, onTask);
110 otherwise
111 line_error(mfilename,sprintf('LQN2SCRIPT does not support the %d distribution yet.',sn.hostdem{aidx}.name));
112 end
113 if ~isempty(boundToStr)
114 fprintf(fid, ' A%d%s;', a, boundToStr);
115 end
116 if ~isempty(callStr)
117 fprintf(fid, ' A%d%s;', a, callStr);
118 end
119 if ~isempty(repliesToStr)
120 fprintf(fid, ' A%d%s;', a, repliesToStr);
121 end
122 fprintf(fid,'\n');
123end
124fprintf(fid,'\n');
125%% think times
126for h=1:sn.nhosts
127 if ~isempty(sn.think{h})
128 switch sn.think{h}.name
129 case 'Immediate'
130 fprintf(fid, '\tP%d.setThinkTime(Immediate());\n', h);
131 case 'Exp'
132 fprintf(fid, '\tP%d.setThinkTime(Exp(%g));\n', h, sn.think{h}.getMean);
133 case {'Erlang','HyperExp','Coxian','APH'}
134 fprintf(fid, '\tP%d.setThinkTime(%s.fitMeanAndSCV(%g,%g));\n', h, sn.think{h}.name, sn.think{h}.getMean, sn.think{h}.getSCV);
135 otherwise
136 line_error(mfilename,sprintf('LQN2SCRIPT does not support the %d distribution yet.',sn.think{h}.name));
137 end
138 end
139end
140
141%% Sequential precedences
142for ai = 1:sn.nacts
143 aidx = sn.ashift + ai;
144 tidx = sn.parent(aidx);
145 % for all successors
146 for bidx=find(sn.graph(aidx,:))
147 if bidx > sn.ashift % ignore precedence between entries and activities
148 % Serial pattern (SEQ)
149 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_SEQ && full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_SEQ
150 fprintf(fid, '\tT%d.addPrecedence(ActivityPrecedence.Serial("%s", "%s"));\n', tidx-sn.tshift, sn.names{aidx}, sn.names{bidx});
151 end
152 end
153 end
154end
155
156%% Loop precedences (POST_LOOP)
157% Loop structure in sn.graph:
158% - Entry activity (preAct) has edge to first loop body activity
159% - Last loop body activity has back-edge to first loop body (weight = 1-1/counts)
160% - Last loop body activity has edge to end activity (weight = 1/counts)
161% - All loop body and end activities have POST_LOOP type
162hasPreActs = false;
163hasPostActs = false;
164processedLoops = false(1, sn.nacts);
165for ai = 1:sn.nacts
166 aidx = sn.ashift + ai;
167 tidx = sn.parent(aidx);
168 % Check if this activity starts a loop (has a successor with POST_LOOP type)
169 % and hasn't been processed as part of another loop
170 if processedLoops(ai)
171 continue;
172 end
173
174 successors = find(sn.graph(aidx,:));
175 for bidx = successors
176 if bidx > sn.ashift && full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_LOOP
177 % Skip if this loop body activity was already processed
178 if processedLoops(bidx - sn.ashift)
179 continue;
180 end
181 % Found start of a loop: aidx is the entry, bidx is first loop body activity
182 loopStart = bidx;
183 precMarker = ai;
184 loopActNames = {};
185
186 % Follow the chain of POST_LOOP activities
187 curIdx = loopStart;
188 while true
189 loopActNames{end+1} = sn.names{curIdx}; %#ok<AGROW>
190 processedLoops(curIdx - sn.ashift) = true;
191
192 % Find successors of current activity
193 curSuccessors = find(sn.graph(curIdx,:));
194 curSuccessors = curSuccessors(curSuccessors > sn.ashift);
195
196 % Check for loop termination: find the end activity
197 % End activity has weight = 1/counts (not the back-edge weight)
198 endIdx = 0;
199 nextIdx = 0;
200 for succIdx = curSuccessors
201 if full(sn.actposttype(succIdx)) == ActivityPrecedenceType.POST_LOOP
202 if succIdx == loopStart
203 % This is the back-edge, skip it
204 continue;
205 end
206 weight = full(sn.graph(curIdx, succIdx));
207 if weight > 0 && weight < 1
208 % This is the end activity (weight = 1/counts)
209 endIdx = succIdx;
210 else
211 % This is the next activity in the loop body (weight = 1.0)
212 nextIdx = succIdx;
213 end
214 end
215 end
216
217 if endIdx > 0
218 % Found end activity - calculate counts and output
219 weight = full(sn.graph(curIdx, endIdx));
220 if weight > 0
221 counts = 1/weight;
222 else
223 counts = 1; % Fallback to prevent division by zero
224 end
225 loopActNames{end+1} = sn.names{endIdx}; %#ok<AGROW>
226 processedLoops(endIdx - sn.ashift) = true;
227
228 % Build the precActs string
229 fprintf(fid, '\n\t// Loop Activity Precedence \n');
230 if ~hasPreActs
231 fprintf(fid, '\tArrayList<String> precActs = new ArrayList<String>();\n');
232 hasPreActs = true;
233 else
234 fprintf(fid, '\tprecActs = new ArrayList<String>();\n');
235 end
236 for k = 1:length(loopActNames)
237 fprintf(fid, '\tprecActs.add("%s");\n', loopActNames{k});
238 end
239 fprintf(fid, '\tT%d.addPrecedence(ActivityPrecedence.Loop("%s", precActs, Matrix.singleton(%g)));\n', tidx-sn.tshift, sn.names{aidx}, counts);
240 break;
241 elseif nextIdx > 0
242 % Continue to next activity in loop body
243 curIdx = nextIdx;
244 else
245 % No more successors - shouldn't happen in valid loop
246 break;
247 end
248 end
249 break; % Only process one loop starting from this activity
250 end
251 end
252end
253
254%% OrFork precedences (POST_OR)
255hasProbs = false;
256precMarker = 0;
257precActs = '';
258for ai = 1:sn.nacts
259 aidx = sn.ashift + ai;
260 tidx = sn.parent(aidx);
261 prob_ctr = 0;
262 % for all successors
263 for bidx=find(sn.graph(aidx,:))
264 if bidx > sn.ashift % ignore precedence between entries and activities
265 % Or pattern (POST_OR)
266 if full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_OR
267 if precMarker == 0 % start a new orjoin
268 precActs = '';
269 precMarker = aidx-sn.ashift;
270 prob_ctr = prob_ctr + 1;
271 precActs = sprintf('\tprecActs.add("%s");\n', sn.names{bidx});
272 probString = sprintf('\tprobs.set(0,%d,%g);\n', prob_ctr-1, full(sn.graph(aidx,bidx)));
273 else
274 prob_ctr = prob_ctr + 1;
275 precActs = sprintf('%s\tprecActs.add("%s");\n', precActs, sn.names{bidx});
276 probString = sprintf('%s\tprobs.set(0,%d,%g);\n', probString, prob_ctr-1, full(sn.graph(aidx,bidx)));
277 end
278 end
279 end
280 end
281
282
283 if precMarker > 0
284 fprintf(fid, '\n\t// OrFork Activity Precedence \n');
285 if ~hasPreActs
286 fprintf(fid, '\tArrayList<String> precActs = new ArrayList<String>();\n');
287 hasPreActs = true;
288 else
289 fprintf(fid, '\tprecActs = new ArrayList<String>();\n');
290 end
291 if ~hasProbs
292 fprintf(fid, '\tMatrix probs = new Matrix(1,%d);\n',prob_ctr);
293 hasProbs = true;
294 else
295 fprintf(fid, '\tprobs = new Matrix(1,%d);\n',prob_ctr);
296 end
297 fprintf(fid, precActs);
298 fprintf(fid, probString);
299 fprintf(fid, '\tT%d.addPrecedence(ActivityPrecedence.OrFork("%s", precActs, probs));\n', tidx-sn.tshift, sn.names{precMarker+sn.ashift});
300 precMarker = 0;
301 end
302end
303
304%% AndFork precedences (POST_AND)
305precMarker = 0;
306postActs = '';
307for ai = 1:sn.nacts
308 aidx = sn.ashift + ai;
309 tidx = sn.parent(aidx);
310 % for all successors
311 for bidx=find(sn.graph(aidx,:))
312 if bidx > sn.ashift % ignore precedence between entries and activities
313 % Or pattern (POST_AND)
314 if full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_AND
315 if isempty(postActs)
316 postActs = sprintf('\tpostActs.add("%s");\n', sn.names{bidx});
317 else
318 postActs = sprintf('%s\tpostActs.add("%s");\n', postActs, sn.names{bidx});
319 end
320
321 if precMarker == 0 % start a new orjoin
322 precMarker = aidx-sn.ashift;
323 end
324 end
325 end
326 end
327 if precMarker > 0
328 fprintf(fid, '\n\t// AndFork Activity Precedence \n');
329 if ~hasPostActs
330 fprintf(fid, '\tArrayList<String> postActs = new ArrayList<String>();\n');
331 hasPostActs = true;
332 else
333 fprintf(fid, '\t postActs = new ArrayList<String>();\n');
334 end
335
336 fprintf(fid, postActs);
337 fprintf(fid, '\tT%d.addPrecedence(ActivityPrecedence.AndFork("%s", postActs));\n', tidx-sn.tshift, sn.names{precMarker+sn.ashift});
338 precMarker = 0;
339 end
340end
341
342
343%% OrJoin precedences (PRE_OR)
344precMarker = 0;
345for bi = sn.nacts:-1:1
346 bidx = sn.ashift + bi;
347 tidx = sn.parent(bidx);
348 % for all predecessors
349 for aidx=find(sn.graph(:,bidx))'
350 if aidx > sn.ashift % ignore precedence between entries and activities
351 % OrJoin pattern (PRE_OR)
352 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_OR
353 if precMarker == 0 % start a new orjoin
354 precMarker = bidx-sn.ashift;
355 precActs = sprintf('\tprecActs.add("%s");\n', sn.names{aidx});
356 else
357 precActs = sprintf('%s\tprecActs.add("%s");\n', precActs, sn.names{aidx});
358 end
359 end
360 end
361 end
362 if precMarker > 0
363 fprintf(fid, '\n\t// OrJoin Activity Precedence \n');
364 if ~hasPreActs
365 fprintf(fid, '\tArrayList<String> precActs = new ArrayList<String>();\n');
366 hasPreActs = true;
367 else
368 fprintf(fid, '\tprecActs = new ArrayList<String>();\n');
369 end
370
371 fprintf(fid, precActs);
372 fprintf(fid, '\tT%d.addPrecedence(ActivityPrecedence.OrJoin(precActs, "%s"));\n', tidx-sn.tshift, sn.names{precMarker+sn.ashift});
373 precMarker = 0;
374 end
375end
376
377%% AndJoin precedences (PRE_AND)
378precMarker = 0;
379for bi = sn.nacts:-1:1
380 bidx = sn.ashift + bi;
381 tidx = sn.parent(bidx);
382 % for all predecessors
383 for aidx=find(sn.graph(:,bidx))'
384 if aidx > sn.ashift % ignore precedence between entries and activities
385 % OrJoin pattern (PRE_AND)
386 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_AND
387 if precMarker == 0 % start a new orjoin
388 precMarker = bidx-sn.ashift;
389 precActs = sprintf('\tprecActs.add("%s");\n', sn.names{aidx});
390 else
391 precActs = sprintf('%s\tprecActs.add("%s");\n', precActs, sn.names{aidx});
392 end
393 end
394 end
395 end
396 if precMarker > 0
397 fprintf(fid, '\n\t// AndJoin Activity Precedence \n');
398 if ~hasPreActs
399 fprintf(fid, '\tArrayList<String> precActs = new ArrayList<String>();\n');
400 hasPreActs = true;
401 else
402 fprintf(fid, '\tprecActs = new ArrayList<String>();\n');
403 end
404 fprintf(fid, precActs);
405
406 % Find quorum parameter from original precedence structure
407 postActName = sn.names{precMarker+sn.ashift};
408 localTaskIdx = tidx - sn.tshift;
409 quorum = [];
410 for ap = 1:length(lqnmodel.tasks{localTaskIdx}.precedences)
411 precedence = lqnmodel.tasks{localTaskIdx}.precedences(ap);
412 if precedence.preType == ActivityPrecedenceType.PRE_AND
413 % Check if this precedence contains our post activity
414 if any(strcmp(precedence.postActs, postActName))
415 quorum = precedence.preParams;
416 break;
417 end
418 end
419 end
420
421 if isempty(quorum)
422 fprintf(fid, '\tT%d.addPrecedence(ActivityPrecedence.AndJoin(precActs, "%s"));\n', localTaskIdx, postActName);
423 else
424 fprintf(fid, '\tT%d.addPrecedence(ActivityPrecedence.AndJoin(precActs, "%s", %g));\n', localTaskIdx, postActName, quorum);
425 end
426 precMarker = 0;
427 end
428end
429
430fprintf(fid, '\n\t// Model solution \n');
431fprintf(fid,'\tSolverLN solver = new SolverLN(model);\n');
432fprintf(fid,'\tsolver.getEnsembleAvg();\n');
433fprintf(fid,'\t}\n}\n');
434
435if ischar(fid)
436 fclose(fid);
437end
438end