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})
52 switch sn.think{tidx}.name
54 fprintf(fid, '\tT%d.setThinkTime(
new Immediate());\n
',t);
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);
60 line_error(mfilename,sprintf('LQN2SCRIPT does not support the %d distribution yet.
',sn.think{tidx}.name));
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{c}.getMean);
99 callStr = sprintf(
'%s.asynchCall(E%d,%g)',callStr,calls(c)-sn.eshift,sn.callproc{c}.getMean);
103 switch sn.hostdem{aidx}.name
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{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);
111 line_error(mfilename,sprintf(
'LQN2SCRIPT does not support the %d distribution yet.',sn.hostdem{aidx}.name));
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})
128 switch sn.think{h}.name
130 fprintf(fid,
'\tP%d.setThinkTime(Immediate());\n', h);
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);
136 line_error(mfilename,sprintf(
'LQN2SCRIPT does not support the %d distribution yet.',sn.think{h}.name));
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% 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
164processedLoops =
false(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)
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)
181 % Found start of a loop: aidx is the entry, bidx is first loop body activity
186 % Follow the chain of POST_LOOP activities
189 loopActNames{end+1} = sn.names{curIdx}; %#ok<AGROW>
190 processedLoops(curIdx - sn.ashift) = true;
192 % Find successors of current activity
193 curSuccessors = find(sn.graph(curIdx,:));
194 curSuccessors = curSuccessors(curSuccessors > sn.ashift);
196 % Check for loop termination: find the end activity
197 % End activity has weight = 1/counts (not the back-edge weight)
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
206 weight = full(sn.graph(curIdx, succIdx));
207 if weight > 0 && weight < 1
208 % This is the end activity (weight = 1/counts)
211 % This is the next activity in the loop body (weight = 1.0)
218 % Found end activity - calculate counts and output
219 weight = full(sn.graph(curIdx, endIdx));
223 counts = 1; % Fallback to prevent division by zero
225 loopActNames{end+1} = sn.names{endIdx}; %#ok<AGROW>
226 processedLoops(endIdx - sn.ashift) = true;
228 % Build the precActs string
231 fprintf(fid,
'\tArrayList<String> precActs = new ArrayList<String>();\n');
234 fprintf(fid,
'\tprecActs = new ArrayList<String>();\n');
236 for k = 1:length(loopActNames)
237 fprintf(fid,
'\tprecActs.add("%s");\n', loopActNames{k});
239 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.Loop("%s", precActs, Matrix.singleton(%g)));\n', tidx-sn.tshift, sn.names{aidx}, counts);
242 % Continue to next activity in loop body
245 % No more successors - shouldn
't happen in valid loop
249 break; % Only process one loop starting from this activity
254%% OrFork precedences (POST_OR)
259 aidx = sn.ashift + ai;
260 tidx = sn.parent(aidx);
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
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)));
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)));
286 fprintf(fid,
'\tArrayList<String> precActs = new ArrayList<String>();\n');
289 fprintf(fid,
'\tprecActs = new ArrayList<String>();\n');
292 fprintf(fid,
'\tMatrix probs = new Matrix(1,%d);\n',prob_ctr);
295 fprintf(fid,
'\tprobs = new Matrix(1,%d);\n',prob_ctr);
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});
304%% AndFork precedences (POST_AND)
308 aidx = sn.ashift + ai;
309 tidx = sn.parent(aidx);
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
316 postActs = sprintf(
'\tpostActs.add("%s");\n', sn.names{bidx});
318 postActs = sprintf(
'%s\tpostActs.add("%s");\n', postActs, sn.names{bidx});
321 if precMarker == 0 % start a
new orjoin
322 precMarker = aidx-sn.ashift;
328 fprintf(fid,
'\n\t// AndFork Activity Precedence \n');
330 fprintf(fid,
'\tArrayList<String> postActs = new ArrayList<String>();\n');
333 fprintf(fid,
'\t postActs = new ArrayList<String>();\n');
336 fprintf(fid, postActs);
337 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.AndFork("%s", postActs));\n', tidx-sn.tshift, sn.names{precMarker+sn.ashift});
343%% OrJoin precedences (PRE_OR)
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});
357 precActs = sprintf('%s\tprecActs.add(
"%s");\n
', precActs, sn.names{aidx});
365 fprintf(fid,
'\tArrayList<String> precActs = new ArrayList<String>();\n');
368 fprintf(fid,
'\tprecActs = new ArrayList<String>();\n');
371 fprintf(fid, precActs);
372 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.OrJoin(precActs, "%s"));\n', tidx-sn.tshift, sn.names{precMarker+sn.ashift});
377%% AndJoin precedences (PRE_AND)
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});
391 precActs = sprintf('%s\tprecActs.add(
"%s");\n
', precActs, sn.names{aidx});
399 fprintf(fid,
'\tArrayList<String> precActs = new ArrayList<String>();\n');
402 fprintf(fid,
'\tprecActs = new ArrayList<String>();\n');
404 fprintf(fid, precActs);
406 % Find quorum parameter from original precedence structure
407 postActName = sn.names{precMarker+sn.ashift};
408 localTaskIdx = tidx - sn.tshift;
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;
422 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.AndJoin(precActs, "%s"));\n', localTaskIdx, postActName);
424 fprintf(fid,
'\tT%d.addPrecedence(ActivityPrecedence.AndJoin(precActs, "%s", %g));\n', localTaskIdx, postActName, quorum);
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');