1function LQN2JAVA(lqnmodel, modelName, fid)
2% LQN2JAVA(MODEL, MODELNAME, FID)
4% Copyright (c) 2012-2026, Imperial College London
7if nargin<2%~exist(
'modelName',
'var')
8 modelName='myLayeredModel';
10if nargin<3%~exist('fid','var')
16sn = lqnmodel.getStruct;
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);
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)),'_
','.
'));
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)),'_
','.
'));
36 fprintf(fid, 'P%d.setReplication(%d);\n
', h, sn.repl(h));
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));
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));
49 fprintf(fid, '\tT%d.setReplication(%d);\n
', t, sn.repl(tidx));
51 if ~isempty(sn.think{tidx}) && sn.think_type(tidx) ~= ProcessType.DISABLED
52 switch sn.think_type(tidx)
53 case ProcessType.IMMEDIATE
54 fprintf(fid, '\tT%d.setThinkTime(
new Immediate());\n
',t);
56 fprintf(fid, '\tT%d.setThinkTime(
new Exp(%g));\n
',t, 1/sn.think_mean(tidx));
57 case {ProcessType.ERLANG, ProcessType.HYPEREXP, ProcessType.COXIAN, ProcessType.APH}
58 fprintf(fid, '\tT%d.setThinkTime(%s.fitMeanAndSCV(%g,%g));\n
', t, char(sn.think_type(tidx)), sn.think_mean(tidx), sn.think_scv(tidx));
60 line_error(mfilename,sprintf('LQN2JAVA does not support the %s distribution yet.
',char(sn.think_type(tidx))));
68 fprintf(fid, '\tEntry E%d =
new Entry(model,
"%s").on(T%d);\n
', e, sn.names{eidx},sn.parent(eidx)-sn.tshift);
74 tidx = sn.parent(aidx);
75 onTask = tidx-sn.tshift;
76 boundTo = find(sn.graph((sn.eshift+1):(sn.eshift+sn.nentries),aidx));
79 boundToStr = sprintf('.boundTo(E%d)
',boundTo);
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);
91 if ~isempty(sn.callpair)
92 cidxs = find(sn.callpair(:,1)==aidx);
93 calls = sn.callpair(:,2);
97 callStr = sprintf('%s.synchCall(E%d,%g)',callStr,calls(c)-sn.eshift,sn.callproc_mean(c));
99 callStr = sprintf('%s.asynchCall(E%d,%g)',callStr,calls(c)-sn.eshift,sn.callproc_mean(c));
103 switch sn.hostdem_type(aidx)
104 case ProcessType.IMMEDIATE
105 fprintf(fid, '\tActivity A%d = new Activity(model, "%s", new Immediate()).on(T%d);', a, sn.names{aidx}, onTask);
107 fprintf(fid,
'\tActivity A%d = new Activity(model, "%s", new Exp(%g)).on(T%d);', a, sn.names{aidx},1/sn.hostdem_mean(aidx), onTask);
108 case {ProcessType.ERLANG, ProcessType.HYPEREXP, ProcessType.COXIAN, ProcessType.APH}
109 fprintf(fid,
'\tActivity A%d = new Activity(model, "%s", %s.fitMeanAndSCV(%g,%g)).on(T%d);', a, sn.names{aidx},
char(sn.hostdem_type(aidx)),sn.hostdem_mean(aidx),sn.hostdem_scv(aidx), onTask);
111 line_error(mfilename,sprintf(
'LQN2JAVA does not support the %s distribution yet.',
char(sn.hostdem_type(aidx))));
113 if ~isempty(boundToStr)
114 fprintf(fid,
' A%d%s;', a, boundToStr);
117 fprintf(fid,
' A%d%s;', a, callStr);
119 if ~isempty(repliesToStr)
120 fprintf(fid,
' A%d%s;', a, repliesToStr);
127 if ~isempty(sn.think{h}) && sn.think_type(h) ~= ProcessType.DISABLED
128 switch sn.think_type(h)
129 case ProcessType.IMMEDIATE
130 fprintf(fid,
'\tP%d.setThinkTime(Immediate());\n', h);
132 fprintf(fid,
'\tP%d.setThinkTime(Exp(%g));\n', h, sn.think_mean(h));
133 case {ProcessType.ERLANG, ProcessType.HYPEREXP, ProcessType.COXIAN, ProcessType.APH}
134 fprintf(fid,
'\tP%d.setThinkTime(%s.fitMeanAndSCV(%g,%g));\n', h,
char(sn.think_type(h)), sn.think_mean(h), sn.think_scv(h));
136 line_error(mfilename,sprintf(
'LQN2JAVA does not support the %s distribution yet.',
char(sn.think_type(h))));
141%% Sequential precedences
143 aidx = sn.ashift + ai;
144 tidx = sn.parent(aidx);
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});
156%% Loop precedences (POST_LOOP)
157% see _kb/12-interfaces-and-docs.md (LQN2JAVA.m loop-precedence encoding)
160processedLoops =
false(1, sn.nacts);
162 aidx = sn.ashift + ai;
163 tidx = sn.parent(aidx);
164 % Check
if this activity starts a loop (has a successor with POST_LOOP type)
165 % and hasn
't been processed as part of another loop
166 if processedLoops(ai)
170 successors = find(sn.graph(aidx,:));
171 for bidx = successors
172 if bidx > sn.ashift && full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_LOOP
173 % Skip if this loop body activity was already processed
174 if processedLoops(bidx - sn.ashift)
177 % Found start of a loop: aidx is the entry, bidx is first loop body activity
182 % Follow the chain of POST_LOOP activities
185 loopActNames{end+1} = sn.names{curIdx}; %#ok<AGROW>
186 processedLoops(curIdx - sn.ashift) = true;
188 % Find successors of current activity
189 curSuccessors = find(sn.graph(curIdx,:));
190 curSuccessors = curSuccessors(curSuccessors > sn.ashift);
192 % Check for loop termination: find the end activity
193 % End activity has weight = 1/counts (not the back-edge weight)
196 for succIdx = curSuccessors
197 if full(sn.actposttype(succIdx)) == ActivityPrecedenceType.POST_LOOP
198 if succIdx == loopStart
199 % This is the back-edge, skip it
202 weight = full(sn.graph(curIdx, succIdx));
203 if weight > 0 && weight < 1
204 % This is the end activity (weight = 1/counts)
207 % This is the next activity in the loop body (weight = 1.0)
214 % Found end activity - calculate counts and output
215 weight = full(sn.graph(curIdx, endIdx));
219 counts = 1; % Fallback to prevent division by zero
221 loopActNames{end+1} = sn.names{endIdx}; %#ok<AGROW>
222 processedLoops(endIdx - sn.ashift) = true;
224 % Build the precActs string
227 fprintf(fid,
'\tArrayList<String> precActs = new ArrayList<String>();\n');
230 fprintf(fid,
'\tprecActs = new ArrayList<String>();\n');
232 for k = 1:length(loopActNames)
233 fprintf(fid,
'\tprecActs.add("%s");\n', loopActNames{k});
235 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.Loop("%s", precActs, Matrix.singleton(%g)));\n', tidx-sn.tshift, sn.names{aidx}, counts);
238 % Continue to next activity in loop body
241 % No more successors - shouldn
't happen in valid loop
245 break; % Only process one loop starting from this activity
250%% OrFork precedences (POST_OR)
255 aidx = sn.ashift + ai;
256 tidx = sn.parent(aidx);
259 for bidx=find(sn.graph(aidx,:))
260 if bidx > sn.ashift % ignore precedence between entries and activities
261 % Or pattern (POST_OR)
262 if full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_OR
263 if precMarker == 0 % start a new orjoin
265 precMarker = aidx-sn.ashift;
266 prob_ctr = prob_ctr + 1;
267 precActs = sprintf('\tprecActs.add(
"%s");\n
', sn.names{bidx});
268 probString = sprintf('\tprobs.set(0,%d,%g);\n
', prob_ctr-1, full(sn.graph(aidx,bidx)));
270 prob_ctr = prob_ctr + 1;
271 precActs = sprintf('%s\tprecActs.add(
"%s");\n
', precActs, sn.names{bidx});
272 probString = sprintf('%s\tprobs.set(0,%d,%g);\n
', probString, prob_ctr-1, full(sn.graph(aidx,bidx)));
282 fprintf(fid,
'\tArrayList<String> precActs = new ArrayList<String>();\n');
285 fprintf(fid,
'\tprecActs = new ArrayList<String>();\n');
288 fprintf(fid,
'\tMatrix probs = new Matrix(1,%d);\n',prob_ctr);
291 fprintf(fid,
'\tprobs = new Matrix(1,%d);\n',prob_ctr);
293 fprintf(fid, precActs);
294 fprintf(fid, probString);
295 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.OrFork("%s", precActs, probs));\n', tidx-sn.tshift, sn.names{precMarker+sn.ashift});
300%% AndFork precedences (POST_AND)
304 aidx = sn.ashift + ai;
305 tidx = sn.parent(aidx);
307 for bidx=find(sn.graph(aidx,:))
308 if bidx > sn.ashift % ignore precedence between entries and activities
309 % Or pattern (POST_AND)
310 if full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_AND
312 postActs = sprintf(
'\tpostActs.add("%s");\n', sn.names{bidx});
314 postActs = sprintf(
'%s\tpostActs.add("%s");\n', postActs, sn.names{bidx});
317 if precMarker == 0 % start a
new orjoin
318 precMarker = aidx-sn.ashift;
324 fprintf(fid,
'\n\t// AndFork Activity Precedence \n');
326 fprintf(fid,
'\tArrayList<String> postActs = new ArrayList<String>();\n');
329 fprintf(fid,
'\t postActs = new ArrayList<String>();\n');
332 fprintf(fid, postActs);
333 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.AndFork("%s", postActs));\n', tidx-sn.tshift, sn.names{precMarker+sn.ashift});
339%% OrJoin precedences (PRE_OR)
341for bi = sn.nacts:-1:1
342 bidx = sn.ashift + bi;
343 tidx = sn.parent(bidx);
344 %
for all predecessors
345 for aidx=find(sn.graph(:,bidx))
'
346 if aidx > sn.ashift % ignore precedence between entries and activities
347 % OrJoin pattern (PRE_OR)
348 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_OR
349 if precMarker == 0 % start a new orjoin
350 precMarker = bidx-sn.ashift;
351 precActs = sprintf('\tprecActs.add(
"%s");\n
', sn.names{aidx});
353 precActs = sprintf('%s\tprecActs.add(
"%s");\n
', precActs, sn.names{aidx});
361 fprintf(fid,
'\tArrayList<String> precActs = new ArrayList<String>();\n');
364 fprintf(fid,
'\tprecActs = new ArrayList<String>();\n');
367 fprintf(fid, precActs);
368 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.OrJoin(precActs, "%s"));\n', tidx-sn.tshift, sn.names{precMarker+sn.ashift});
373%% AndJoin precedences (PRE_AND)
375for bi = sn.nacts:-1:1
376 bidx = sn.ashift + bi;
377 tidx = sn.parent(bidx);
378 %
for all predecessors
379 for aidx=find(sn.graph(:,bidx))
'
380 if aidx > sn.ashift % ignore precedence between entries and activities
381 % OrJoin pattern (PRE_AND)
382 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_AND
383 if precMarker == 0 % start a new orjoin
384 precMarker = bidx-sn.ashift;
385 precActs = sprintf('\tprecActs.add(
"%s");\n
', sn.names{aidx});
387 precActs = sprintf('%s\tprecActs.add(
"%s");\n
', precActs, sn.names{aidx});
395 fprintf(fid,
'\tArrayList<String> precActs = new ArrayList<String>();\n');
398 fprintf(fid,
'\tprecActs = new ArrayList<String>();\n');
400 fprintf(fid, precActs);
402 % Find quorum parameter from original precedence structure
403 postActName = sn.names{precMarker+sn.ashift};
404 localTaskIdx = tidx - sn.tshift;
406 for ap = 1:length(lqnmodel.tasks{localTaskIdx}.precedences)
407 precedence = lqnmodel.tasks{localTaskIdx}.precedences(ap);
408 if precedence.preType == ActivityPrecedenceType.PRE_AND
409 % Check
if this precedence contains our post activity
410 if any(strcmp(precedence.postActs, postActName))
411 quorum = precedence.preParams;
418 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.AndJoin(precActs, "%s"));\n', localTaskIdx, postActName);
420 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.AndJoin(precActs, "%s", %g));\n', localTaskIdx, postActName, quorum);
426fprintf(fid,
'\n\t// Model solution \n');
427fprintf(fid,
'\tSolverLN solver = new SolverLN(model);\n');
428fprintf(fid,
'\tsolver.getEnsembleAvg();\n');
429fprintf(fid,
'\t}\n}\n');