1function LQN2SCRIPT(lqnmodel, modelName, fid)
2% LQN2SCRIPT(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,'model = LayeredNetwork(''%s'');\n',modelName);
23 fprintf(fid, '
P{%d} = Processor(model,
''%s
'', %d, %s);\n
', h, sn.names{h}, sn.mult(h), strrep(SchedStrategy.toFeature(SchedStrategy.fromText(sn.sched(h))),'_
','.
'));
25 fprintf(fid, 'P{%d}.setReplication(%d);\n
', h, sn.repl(h));
32 fprintf(fid, 'T{%d} = Task(model,
''%s
'', %d, %s).on(
P{%d})
', t, sn.names{tidx}, sn.mult(tidx), strrep(SchedStrategy.toFeature(SchedStrategy.fromText(sn.sched(tidx))),'_
','.
'),sn.parent(tidx));
34 fprintf(fid, 'T{%d}.setReplication
', t, sn.repl(tidx));
36 if ~isempty(sn.think{tidx})
37 switch sn.think{tidx}.name
39 fprintf(fid, '.setThinkTime(Immediate())
');
41 fprintf(fid, '.setThinkTime(Exp.fitMean(%g))
', sn.think{tidx}.getMean);
42 case {'Erlang
','HyperExp
', 'Coxian
', 'APH
'}
43 fprintf(fid, '.setThinkTime(%s.fitMeanAndSCV(%g,%g))
', sn.think{tidx}.name, sn.think{tidx}.getMean, sn.think{tidx}.getSCV);
45 line_error(mfilename,sprintf('LQN2SCRIPT does not support the %d distribution yet.
',sn.think{tidx}.name));
54 fprintf(fid, 'E{%d} = Entry(model,
''%s
'').on(T{%d});\n
', e, sn.names{eidx},sn.parent(eidx)-sn.tshift);
60 tidx = sn.parent(aidx);
61 onTask = tidx-sn.tshift;
62 boundTo = find(sn.graph((sn.eshift+1):(sn.eshift+sn.nentries),aidx));
65 boundToStr = sprintf('.boundTo(E{%d})
',boundTo);
67 if sn.sched(tidx) ~= SchedStrategy.REF % ref tasks don't reply
69 repliesTo = find(sn.replygraph(a,:)); % index of entry
70 if ~isempty(repliesTo)
71 if ~sn.isref(sn.parent(sn.eshift+repliesTo))
72 repliesToStr = sprintf(
'.repliesTo(E{%d})',repliesTo);
77 if ~isempty(sn.callpair)
78 cidxs = find(sn.callpair(:,1)==aidx);
79 calls = sn.callpair(:,2);
83 callStr = sprintf('%s.synchCall(E{%d},%g)
',callStr,calls(c)-sn.eshift,sn.callproc{c}.getMean);
85 callStr = sprintf('%s.asynchCall(E{%d},%g)
',callStr,calls(c)-sn.eshift,sn.callproc{c}.getMean);
89 switch sn.hostdem{aidx}.name
91 fprintf(fid, 'A{%d} = Activity(model,
''%s
'', Immediate()).on(T{%d})%s%s%s;\n
', a, sn.names{aidx}, onTask, boundToStr, callStr, repliesToStr);
93 fprintf(fid, 'A{%d} = Activity(model,
''%s
'', Exp.fitMean(%g)).on(T{%d})%s%s%s;\n
', a, sn.names{aidx},sn.hostdem{aidx}.getMean, onTask, boundToStr, callStr, repliesToStr);
94 case {'Erlang
','HyperExp
','Coxian
','APH
'}
95 fprintf(fid, 'A{%d} = Activity(model,
''%s
'', %s.fitMeanAndSCV(%g,%g)).on(T{%d})%s%s%s;\n
', a, sn.names{aidx},sn.hostdem{aidx}.name,sn.hostdem{aidx}.getMean,sn.hostdem{aidx}.getSCV, onTask, boundToStr, callStr, repliesToStr);
97 line_error(mfilename,sprintf('LQN2SCRIPT does not support the %d distribution yet.
',sn.hostdem{aidx}.name));
103 if ~isempty(sn.think{h})
104 switch sn.think{h}.name
106 fprintf(fid, 'P{%d}.setThinkTime(Immediate());\n
', h);
108 fprintf(fid, 'P{%d}.setThinkTime(Exp.fitMean(%g));\n
', h, sn.think{h}.getMean);
109 case {'Erlang
','HyperExp
','Coxian
','APH
'}
110 fprintf(fid, 'P{%d}.setThinkTime(%s.fitMeanAndSCV(%g,%g));\n
', h, sn.think{h}.name, sn.think{h}.getMean, sn.think{h}.getSCV);
112 line_error(mfilename,sprintf('LQN2SCRIPT does not support the %d distribution yet.
',sn.think{h}.name));
117%% Sequential precedences
119 aidx = sn.ashift + ai;
120 tidx = sn.parent(aidx);
122 for bidx=find(sn.graph(aidx,:))
123 if bidx > sn.ashift % ignore precedence between entries and activities
124 % Serial pattern (SEQ)
125 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_SEQ && full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_SEQ
126 fprintf(fid, 'T{%d}.addPrecedence(ActivityPrecedence.Serial(A{%d}, A{%d}));\n
', tidx-sn.tshift, aidx-sn.ashift, bidx-sn.ashift);
132%% Loop precedences (POST_LOOP)
133% Loop structure in sn.graph:
134% - Entry activity (preAct) has edge to first loop body activity
135% - Last loop body activity has back-edge to first loop body (weight = 1-1/counts)
136% - Last loop body activity has edge to end activity (weight = 1/counts)
137% - All loop body and end activities have POST_LOOP type
138processedLoops = false(1, sn.nacts);
140 aidx = sn.ashift + ai;
141 tidx = sn.parent(aidx);
142 % Check if this activity starts a loop (has a successor with POST_LOOP type)
143 % and hasn't been processed as part of another loop
144 if processedLoops(ai)
148 successors = find(sn.graph(aidx,:));
149 for bidx = successors
150 if bidx > sn.ashift && full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_LOOP
151 % Skip
if this loop body activity was already processed
152 if processedLoops(bidx - sn.ashift)
155 % Found start of a loop: aidx
is the entry, bidx
is first loop body activity
160 % Follow the chain of POST_LOOP activities
163 loopActs{end+1} = curIdx - sn.ashift; %#ok<AGROW>
164 processedLoops(curIdx - sn.ashift) =
true;
166 % Find successors of current activity
167 curSuccessors = find(sn.graph(curIdx,:));
168 curSuccessors = curSuccessors(curSuccessors > sn.ashift);
170 % Check
for loop termination: find the end activity
171 % End activity has weight = 1/counts (not the back-edge weight)
174 for succIdx = curSuccessors
175 if full(sn.actposttype(succIdx)) == ActivityPrecedenceType.POST_LOOP
176 if succIdx == loopStart
177 % This
is the back-edge, skip it
180 weight = full(sn.graph(curIdx, succIdx));
181 if weight > 0 && weight < 1
182 % This
is the end activity (weight = 1/counts)
185 % This
is the next activity in the loop body (weight = 1.0)
192 % Found end activity - calculate counts and output
193 weight = full(sn.graph(curIdx, endIdx));
197 counts = 1; % Fallback to prevent division by zero
199 loopActs{end+1} = endIdx - sn.ashift; %#ok<AGROW>
200 processedLoops(endIdx - sn.ashift) =
true;
202 % Build the activity list
string
203 precActs = sprintf(
'A{%d}', loopActs{1});
204 for k = 2:length(loopActs)
205 precActs = sprintf(
'%s, A{%d}', precActs, loopActs{k});
207 fprintf(fid,
'T{%d}.addPrecedence(ActivityPrecedence.Loop(A{%d}, {%s}, %g));\n', tidx-sn.tshift, precMarker, precActs, counts);
210 % Continue to next activity in loop body
213 % No more successors - shouldn
't happen in valid loop
217 break; % Only process one loop starting from this activity
222%% OrFork precedences (POST_OR)
225 aidx = sn.ashift + ai;
226 tidx = sn.parent(aidx);
228 for bidx=find(sn.graph(aidx,:))
229 if bidx > sn.ashift % ignore precedence between entries and activities
230 % Or pattern (POST_OR)
231 if full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_OR
232 if precMarker == 0 % start a new orjoin
233 precMarker = aidx-sn.ashift;
234 precActs = sprintf('A{%d}
', bidx-sn.ashift);
235 probs = sprintf('%g
',full(sn.graph(aidx,bidx)));
237 precActs = sprintf('%s, A{%d}
', precActs, bidx-sn.ashift);
238 probs = sprintf('%s,%g
',probs,full(sn.graph(aidx,bidx)));
244 fprintf(fid, 'T{%d}.addPrecedence(ActivityPrecedence.OrFork(A{%d},{%s},[%s]));\n
', tidx-sn.tshift, precMarker, precActs, probs);
249%% AndFork precedences (POST_AND)
252 aidx = sn.ashift + ai;
253 tidx = sn.parent(aidx);
255 for bidx=find(sn.graph(aidx,:))
256 if bidx > sn.ashift % ignore precedence between entries and activities
257 % Or pattern (POST_AND)
258 if full(sn.actposttype(bidx)) == ActivityPrecedenceType.POST_AND
259 if precMarker == 0 % start a new orjoin
260 precMarker = aidx-sn.ashift;
261 precActs = sprintf('A{%d}
', bidx-sn.ashift);
263 precActs = sprintf('%s, A{%d}
', precActs, bidx-sn.ashift);
269 fprintf(fid, 'T{%d}.addPrecedence(ActivityPrecedence.AndFork(A{%d},{%s}));\n
', tidx-sn.tshift, precMarker, precActs);
275%% OrJoin precedences (PRE_OR)
277for bi = sn.nacts:-1:1
278 bidx = sn.ashift + bi;
279 tidx = sn.parent(bidx);
280 % for all predecessors
281 for aidx=find(sn.graph(:,bidx))'
282 if aidx > sn.ashift % ignore precedence between entries and activities
283 % OrJoin pattern (PRE_OR)
284 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_OR
285 if precMarker == 0 % start a
new orjoin
286 precMarker = bidx-sn.ashift;
287 precActs = sprintf(
'A{%d}', aidx-sn.ashift);
289 precActs = sprintf(
'%s, A{%d}',precActs, aidx-sn.ashift);
295 fprintf(fid,
'T{%d}.addPrecedence(ActivityPrecedence.OrJoin({%s}, A{%d}));\n', tidx-sn.tshift, precActs, precMarker);
300%% OrJoin precedences (PRE_AND)
302for bi = sn.nacts:-1:1
303 bidx = sn.ashift + bi;
304 tidx = sn.parent(bidx);
305 %
for all predecessors
306 for aidx=find(sn.graph(:,bidx))
'
307 if aidx > sn.ashift % ignore precedence between entries and activities
308 % OrJoin pattern (PRE_AND)
309 if full(sn.actpretype(aidx)) == ActivityPrecedenceType.PRE_AND
310 if precMarker == 0 % start a new orjoin
311 precMarker = bidx-sn.ashift;
312 precActs = sprintf('A{%d}
', aidx-sn.ashift);
314 precActs = sprintf('%s, A{%d}
',precActs, aidx-sn.ashift);
320 fprintf(fid, 'T{%d}.addPrecedence(ActivityPrecedence.AndJoin({%s}, A{%d}));\n
', tidx-sn.tshift, precActs, precMarker);