1function [simDoc, section] = saveImpatience(self, simDoc, section, ind)
2% [SIMDOC, SECTION] = SAVEIMPATIENCE(SIMDOC, SECTION, IND)
4% Generates XML
for impatience (reneging) distributions
for JMT Queue sections
6% Copyright (c) 2012-2026, Imperial College London
9impatienceNode = simDoc.createElement(
'parameter');
10impatienceNode.setAttribute(
'array',
'true');
11impatienceNode.setAttribute(
'classPath',
'jmt.engine.NetStrategies.ImpatienceStrategies.Impatience');
12impatienceNode.setAttribute(
'name',
'Impatience');
15numOfClasses = sn.nclasses;
16exportClasses = self.getExportableClasses();
17i = sn.nodeToStation(ind);
20 % Skip classes that should not be exported to JMT
25 refClassNode = simDoc.createElement(
'refClass');
26 refClassNode.appendChild(simDoc.createTextNode(sn.classnames{r}));
27 impatienceNode.appendChild(refClassNode);
29 % see _kb/06-solver-catalog.md (Wrappers: JMT impatience export)
31 if i > 0 && isfield(sn,
'balkingStrategy') && ~isempty(sn.balkingStrategy)
32 if sn.balkingStrategy(i, r) == BalkingStrategy.QUEUE_LENGTH
36 % see _kb/06-solver-catalog.md (Wrappers: JMT impatience export, RENEGING detection)
37 hasImpatience = false;
38 if i > 0 && isfield(sn, 'impatienceClass') && ~isempty(sn.impatienceClass)
39 if sn.impatienceClass(i, r) == ImpatienceType.RENEGING
44 impatienceStrategyNode = simDoc.createElement('subParameter');
47 % Balking: emit a Balking strategy wrapping a load-dependent range
48 % table {from -> probability} plus the priorityActivated flag.
49 impatienceStrategyNode.setAttribute(
'classPath',
'jmt.engine.NetStrategies.ImpatienceStrategies.Balking');
50 impatienceStrategyNode.setAttribute(
'name',
'Balking');
51 [simDoc, impatienceStrategyNode] = saveBalkingStrategy(self, simDoc, impatienceStrategyNode, sn.balkingThresholds{i, r}, sn.nservers(i));
52 impatienceNode.appendChild(impatienceStrategyNode);
56 impatienceStrategyNode.setAttribute(
'classPath',
'jmt.engine.NetStrategies.ImpatienceStrategies.Reneging');
57 impatienceStrategyNode.setAttribute(
'name',
'Reneging');
60 % No impatience defined - use null
61 subParValue = simDoc.createElement(
'value');
62 subParValue.appendChild(simDoc.createTextNode(
'null'));
63 impatienceStrategyNode.appendChild(subParValue);
65 % Impatience
is defined - generate distribution XML
66 procType = sn.impatienceType(i, r);
67 impatiencePhases = sn.impatiencePhases(i, r);
69 % see _kb/06-solver-catalog.md (Wrappers: JMT impatience export, HyperExp arity)
70 emitPhaseType = (procType == ProcessType.PH) || ...
71 (procType == ProcessType.APH) || ...
72 (procType == ProcessType.COXIAN) || ...
73 (impatiencePhases > 2 && procType == ProcessType.HYPEREXP);
75 distributionNode = simDoc.createElement(
'subParameter');
78 javaClass =
'jmt.engine.random.PhaseTypeDistr';
79 javaParClass =
'jmt.engine.random.PhaseTypePar';
83 javaClass =
'jmt.engine.random.DeterministicDistr';
84 javaParClass =
'jmt.engine.random.DeterministicDistrPar';
85 case ProcessType.ERLANG
86 javaClass =
'jmt.engine.random.Erlang';
87 javaParClass =
'jmt.engine.random.ErlangPar';
89 javaClass =
'jmt.engine.random.Exponential';
90 javaParClass =
'jmt.engine.random.ExponentialPar';
91 case ProcessType.GAMMA
92 javaClass =
'jmt.engine.random.GammaDistr';
93 javaParClass =
'jmt.engine.random.GammaDistrPar';
94 case ProcessType.HYPEREXP
95 javaClass =
'jmt.engine.random.HyperExp';
96 javaParClass =
'jmt.engine.random.HyperExpPar';
97 case ProcessType.PARETO
98 javaClass =
'jmt.engine.random.Pareto';
99 javaParClass =
'jmt.engine.random.ParetoPar';
100 case ProcessType.WEIBULL
101 javaClass =
'jmt.engine.random.Weibull';
102 javaParClass =
'jmt.engine.random.WeibullPar';
103 case ProcessType.LOGNORMAL
104 javaClass =
'jmt.engine.random.Lognormal';
105 javaParClass =
'jmt.engine.random.LognormalPar';
106 case ProcessType.UNIFORM
107 javaClass =
'jmt.engine.random.Uniform';
108 javaParClass =
'jmt.engine.random.UniformPar';
110 line_error(mfilename, sprintf(
'Unsupported impatience distribution type: %s', ProcessType.toText(procType)));
114 distributionNode.setAttribute(
'classPath', javaClass);
116 distributionNode.setAttribute(
'name',
'Phase-Type');
120 distributionNode.setAttribute(
'name',
'Exponential');
121 case ProcessType.HYPEREXP
122 distributionNode.setAttribute(
'name',
'Hyperexponential');
124 distributionNode.setAttribute(
'name', ProcessType.toText(procType));
127 impatienceStrategyNode.appendChild(distributionNode);
129 % Create distribution parameters
130 distrParNode = simDoc.createElement(
'subParameter');
131 distrParNode.setAttribute(
'classPath', javaParClass);
132 distrParNode.setAttribute(
'name',
'distrPar');
134 % Get impatience parameters
135 impatienceMu = sn.impatienceMu(i, r);
136 impatiencePhi = sn.impatiencePhi(i, r);
139 % see _kb/06-solver-catalog.md (Wrappers: JMT impatience export, cell-array deref)
140 impatienceProc = sn.impatienceProc{i, r};
141 impatiencePie = sn.impatiencePie{i, r};
142 phases = impatiencePhases;
143 PH = impatienceProc{1};
144 alpha = abs(impatiencePie);
147 subParNodeAlpha = simDoc.createElement(
'subParameter');
148 subParNodeAlpha.setAttribute(
'array',
'true');
149 subParNodeAlpha.setAttribute(
'classPath',
'java.lang.Object');
150 subParNodeAlpha.setAttribute(
'name',
'alpha');
151 subParNodeAlphaVec = simDoc.createElement(
'subParameter');
152 subParNodeAlphaVec.setAttribute(
'array',
'true');
153 subParNodeAlphaVec.setAttribute(
'classPath',
'java.lang.Object');
154 subParNodeAlphaVec.setAttribute(
'name',
'vector');
156 subParNodeAlphaElem = simDoc.createElement(
'subParameter');
157 subParNodeAlphaElem.setAttribute(
'classPath',
'java.lang.Double');
158 subParNodeAlphaElem.setAttribute(
'name',
'entry');
159 subParValue = simDoc.createElement(
'value');
160 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', alpha(k))));
161 subParNodeAlphaElem.appendChild(subParValue);
162 subParNodeAlphaVec.appendChild(subParNodeAlphaElem);
166 subParNodeT = simDoc.createElement(
'subParameter');
167 subParNodeT.setAttribute(
'array',
'true');
168 subParNodeT.setAttribute(
'classPath',
'java.lang.Object');
169 subParNodeT.setAttribute(
'name',
'T');
171 subParNodeTvec = simDoc.createElement(
'subParameter');
172 subParNodeTvec.setAttribute(
'array',
'true');
173 subParNodeTvec.setAttribute(
'classPath',
'java.lang.Object');
174 subParNodeTvec.setAttribute(
'name',
'vector');
176 subParNodeTElem = simDoc.createElement(
'subParameter');
177 subParNodeTElem.setAttribute(
'classPath',
'java.lang.Double');
178 subParNodeTElem.setAttribute(
'name',
'entry');
179 subParValue = simDoc.createElement(
'value');
181 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', -abs(PH(k,j)))));
183 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', abs(PH(k,j)))));
185 subParNodeTElem.appendChild(subParValue);
186 subParNodeTvec.appendChild(subParNodeTElem);
188 subParNodeT.appendChild(subParNodeTvec);
191 subParNodeAlpha.appendChild(subParNodeAlphaVec);
192 distrParNode.appendChild(subParNodeAlpha);
193 distrParNode.appendChild(subParNodeT);
197 subParNodeAlpha = simDoc.createElement(
'subParameter');
198 subParNodeAlpha.setAttribute(
'classPath',
'java.lang.Double');
199 subParNodeAlpha.setAttribute(
'name',
't');
200 subParValue = simDoc.createElement(
'value');
201 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', 1/impatienceMu(1))));
202 subParNodeAlpha.appendChild(subParValue);
203 distrParNode.appendChild(subParNodeAlpha);
206 subParNodeLambda = simDoc.createElement(
'subParameter');
207 subParNodeLambda.setAttribute(
'classPath',
'java.lang.Double');
208 subParNodeLambda.setAttribute(
'name',
'lambda');
209 subParValue = simDoc.createElement(
'value');
210 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', impatienceMu(1))));
211 subParNodeLambda.appendChild(subParValue);
212 distrParNode.appendChild(subParNodeLambda);
214 case ProcessType.ERLANG
215 phases = sn.impatiencePhases(i, r);
216 subParNodeAlpha = simDoc.createElement(
'subParameter');
217 subParNodeAlpha.setAttribute(
'classPath',
'java.lang.Double');
218 subParNodeAlpha.setAttribute(
'name',
'alpha');
219 subParValue = simDoc.createElement(
'value');
220 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', impatienceMu(1) * phases)));
221 subParNodeAlpha.appendChild(subParValue);
222 distrParNode.appendChild(subParNodeAlpha);
223 subParNodeR = simDoc.createElement(
'subParameter');
224 subParNodeR.setAttribute(
'classPath',
'java.lang.Long');
225 subParNodeR.setAttribute(
'name',
'r');
226 subParValue = simDoc.createElement(
'value');
227 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%d', phases)));
228 subParNodeR.appendChild(subParValue);
229 distrParNode.appendChild(subParNodeR);
231 case ProcessType.HYPEREXP
232 % 2-phase only: HyperExpPar carries exactly (p,lambda1,lambda2).
233 % Braces, not (): these sn fields are cell arrays.
234 impatienceProc = sn.impatienceProc{i, r};
235 impatiencePie = sn.impatiencePie{i, r};
236 subParNodeP = simDoc.createElement(
'subParameter');
237 subParNodeP.setAttribute(
'classPath',
'java.lang.Double');
238 subParNodeP.setAttribute(
'name',
'p');
239 subParValue = simDoc.createElement(
'value');
240 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', impatiencePie(1))));
241 subParNodeP.appendChild(subParValue);
242 distrParNode.appendChild(subParNodeP);
243 subParNodeLambda1 = simDoc.createElement(
'subParameter');
244 subParNodeLambda1.setAttribute(
'classPath',
'java.lang.Double');
245 subParNodeLambda1.setAttribute(
'name',
'lambda1');
246 subParValue = simDoc.createElement(
'value');
247 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', -impatienceProc{1}(1,1))));
248 subParNodeLambda1.appendChild(subParValue);
249 distrParNode.appendChild(subParNodeLambda1);
250 subParNodeLambda2 = simDoc.createElement(
'subParameter');
251 subParNodeLambda2.setAttribute(
'classPath',
'java.lang.Double');
252 subParNodeLambda2.setAttribute(
'name',
'lambda2');
253 subParValue = simDoc.createElement(
'value');
254 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', -impatienceProc{1}(2,2))));
255 subParNodeLambda2.appendChild(subParValue);
256 distrParNode.appendChild(subParNodeLambda2);
258 case ProcessType.GAMMA
259 scv = impatiencePhi(1);
260 subParNodeAlpha = simDoc.createElement(
'subParameter');
261 subParNodeAlpha.setAttribute(
'classPath',
'java.lang.Double');
262 subParNodeAlpha.setAttribute(
'name',
'alpha');
263 subParValue = simDoc.createElement(
'value');
264 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', 1/scv)));
265 subParNodeAlpha.appendChild(subParValue);
266 distrParNode.appendChild(subParNodeAlpha);
267 subParNodeBeta = simDoc.createElement(
'subParameter');
268 subParNodeBeta.setAttribute(
'classPath',
'java.lang.Double');
269 subParNodeBeta.setAttribute(
'name',
'beta');
270 subParValue = simDoc.createElement(
'value');
271 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', scv/impatienceMu(1))));
272 subParNodeBeta.appendChild(subParValue);
273 distrParNode.appendChild(subParNodeBeta);
275 case ProcessType.PARETO
276 scv = impatiencePhi(1);
277 shape = sqrt(1 + 1/scv) + 1;
278 scale = 1/impatienceMu(1) * (shape - 1) / shape;
279 subParNodeAlpha = simDoc.createElement(
'subParameter');
280 subParNodeAlpha.setAttribute(
'classPath',
'java.lang.Double');
281 subParNodeAlpha.setAttribute(
'name',
'alpha');
282 subParValue = simDoc.createElement(
'value');
283 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', shape)));
284 subParNodeAlpha.appendChild(subParValue);
285 distrParNode.appendChild(subParNodeAlpha);
286 subParNodeK = simDoc.createElement(
'subParameter');
287 subParNodeK.setAttribute(
'classPath',
'java.lang.Double');
288 subParNodeK.setAttribute(
'name',
'k');
289 subParValue = simDoc.createElement(
'value');
290 subParValue.appendChild(simDoc.createTextNode(sprintf(
'%.12f', scale)));
291 subParNodeK.appendChild(subParValue);
292 distrParNode.appendChild(subParNodeK);
294 case ProcessType.WEIBULL
295 scv = impatiencePhi(1);
297 rval = c^(-1.086); % Justus approximation (1976)
298 alpha = 1/impatienceMu(1) / gamma(1+1/rval);
299 subParNodeAlpha = simDoc.createElement('subParameter');
300 subParNodeAlpha.setAttribute('classPath', 'java.lang.Double');
301 subParNodeAlpha.setAttribute('name', 'alpha');
302 subParValue = simDoc.createElement('value');
303 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', alpha)));
304 subParNodeAlpha.appendChild(subParValue);
305 distrParNode.appendChild(subParNodeAlpha);
306 subParNodeR = simDoc.createElement('subParameter');
307 subParNodeR.setAttribute('classPath', 'java.lang.Double');
308 subParNodeR.setAttribute('name', 'r');
309 subParValue = simDoc.createElement('value');
310 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', rval)));
311 subParNodeR.appendChild(subParValue);
312 distrParNode.appendChild(subParNodeR);
314 case ProcessType.LOGNORMAL
315 scv = impatiencePhi(1);
317 mu = log(1/impatienceMu(1) / sqrt(c*c + 1));
318 sigma = sqrt(log(c*c + 1));
319 subParNodeMu = simDoc.createElement('subParameter');
320 subParNodeMu.setAttribute('classPath', 'java.lang.Double');
321 subParNodeMu.setAttribute('name', 'mu');
322 subParValue = simDoc.createElement('value');
323 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', mu)));
324 subParNodeMu.appendChild(subParValue);
325 distrParNode.appendChild(subParNodeMu);
326 subParNodeSigma = simDoc.createElement('subParameter');
327 subParNodeSigma.setAttribute('classPath', 'java.lang.Double');
328 subParNodeSigma.setAttribute('name', 'sigma');
329 subParValue = simDoc.createElement('value');
330 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', sigma)));
331 subParNodeSigma.appendChild(subParValue);
332 distrParNode.appendChild(subParNodeSigma);
334 case ProcessType.UNIFORM
335 mean = 1/impatienceMu(1);
336 % For uniform [a,b]: mean = (a+b)/2, use a=0 for simplicity
338 subParNodeMin = simDoc.createElement('subParameter');
339 subParNodeMin.setAttribute('classPath', 'java.lang.Double');
340 subParNodeMin.setAttribute('name', 'min');
341 subParValue = simDoc.createElement('value');
342 subParValue.appendChild(simDoc.createTextNode('0.0'));
343 subParNodeMin.appendChild(subParValue);
344 distrParNode.appendChild(subParNodeMin);
345 subParNodeMax = simDoc.createElement('subParameter');
346 subParNodeMax.setAttribute('classPath', 'java.lang.Double');
347 subParNodeMax.setAttribute('name', 'max');
348 subParValue = simDoc.createElement('value');
349 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', b)));
350 subParNodeMax.appendChild(subParValue);
351 distrParNode.appendChild(subParNodeMax);
356 impatienceStrategyNode.appendChild(distrParNode);
359 impatienceNode.appendChild(impatienceStrategyNode);
362section.appendChild(impatienceNode);
365function [simDoc, balkingNode] = saveBalkingStrategy(self, simDoc, balkingNode, thresholds, nservers) %
#ok<INUSL>
366% Populate a JMT <Balking> impatience element from LINE queue-length balking
367% thresholds. LINE stores a list of {minJobs, maxJobs, probability} closed
368% intervals; JMT
's Balking reads a LoadDependentStrategy whose LDParameter
369% ranges are {from -> probability}, selecting the last range with from <=
370% queueLength (default 0). We translate the closed intervals into from-based
371% breakpoints, inserting explicit 0-probability breakpoints at gaps so that
372% queue lengths outside any interval do not inherit a neighbour's probability.
374% Queue-length convention: LINE evaluates balking against the TOTAL station
375% population (in-service + waiting), as
do the CTMC/SSA/LDES solvers. JMT
's
376% Balking evaluates against the number WAITING only (the buffer occupancy).
377% When the servers are busy (the regime where balking is meaningful) the two
378% differ by exactly the server count S, so we shift every `from` down by S:
379% JMT waiting w maps to LINE total n = w + S. This makes the exported JMT
380% model reproduce LINE's balking numerically.
382% Build sorted (from, prob) breakpoints
383lo = zeros(numel(thresholds),1);
384hi = zeros(numel(thresholds),1);
385pr = zeros(numel(thresholds),1);
386for ti = 1:numel(thresholds)
392[lo, order] = sort(lo);
396if isempty(nservers) || ~isfinite(nservers) || nservers < 1
404 froms(end+1) = max(0, lo(ti) - S); %#ok<AGROW>
405 probs(end+1) = pr(ti); %#ok<AGROW>
413 froms(end+1) = max(0, hi(ti)+1 - S); %#ok<AGROW>
414 probs(end+1) = 0.0; %#ok<AGROW>
419% LoadDependentStrategy wrapper (Parameter #1 of Balking)
420ldStrategyNode = simDoc.createElement(
'subParameter');
421ldStrategyNode.setAttribute(
'classPath',
'jmt.engine.NetStrategies.ServiceStrategies.LoadDependentStrategy');
422ldStrategyNode.setAttribute(
'name',
'LoadDependentStrategy');
424ldArrayNode = simDoc.createElement(
'subParameter');
425ldArrayNode.setAttribute(
'array',
'true');
426ldArrayNode.setAttribute(
'classPath',
'jmt.engine.NetStrategies.ServiceStrategies.LDParameter');
427ldArrayNode.setAttribute(
'name',
'LDParameter');
429for ti = 1:numel(froms)
430 rangeNode = simDoc.createElement(
'subParameter');
431 rangeNode.setAttribute(
'classPath',
'jmt.engine.NetStrategies.ServiceStrategies.LDParameter');
432 rangeNode.setAttribute(
'name',
'LDParameter');
435 fromNode = simDoc.createElement(
'subParameter');
436 fromNode.setAttribute(
'classPath',
'java.lang.Integer');
437 fromNode.setAttribute(
'name',
'from');
438 v = simDoc.createElement(
'value');
439 v.appendChild(simDoc.createTextNode(sprintf(
'%d', froms(ti))));
440 fromNode.appendChild(v);
441 rangeNode.appendChild(fromNode);
443 % dummy distribution (only the function/probability
is read
for balking)
444 distrNode = simDoc.createElement(
'subParameter');
445 distrNode.setAttribute(
'classPath',
'jmt.engine.random.Exponential');
446 distrNode.setAttribute(
'name',
'Exponential');
447 rangeNode.appendChild(distrNode);
449 distrParNode = simDoc.createElement(
'subParameter');
450 distrParNode.setAttribute(
'classPath',
'jmt.engine.random.ExponentialPar');
451 distrParNode.setAttribute(
'name',
'distrPar');
452 lambdaNode = simDoc.createElement(
'subParameter');
453 lambdaNode.setAttribute(
'classPath',
'java.lang.Double');
454 lambdaNode.setAttribute(
'name',
'lambda');
455 v = simDoc.createElement(
'value');
456 v.appendChild(simDoc.createTextNode(
'1.0'));
457 lambdaNode.appendChild(v);
458 distrParNode.appendChild(lambdaNode);
459 rangeNode.appendChild(distrParNode);
461 % function (String) = balking probability
for this range
462 funcNode = simDoc.createElement(
'subParameter');
463 funcNode.setAttribute(
'classPath',
'java.lang.String');
464 funcNode.setAttribute(
'name',
'function');
465 v = simDoc.createElement(
'value');
466 v.appendChild(simDoc.createTextNode(sprintf(
'%.12f', probs(ti))));
467 funcNode.appendChild(v);
468 rangeNode.appendChild(funcNode);
470 ldArrayNode.appendChild(rangeNode);
473ldStrategyNode.appendChild(ldArrayNode);
474balkingNode.appendChild(ldStrategyNode);
476% priorityActivated flag (Parameter #2 of Balking)
477prioNode = simDoc.createElement(
'subParameter');
478prioNode.setAttribute(
'classPath',
'java.lang.Boolean');
479prioNode.setAttribute(
'name',
'priorityActivated');
480v = simDoc.createElement(
'value');
481v.appendChild(simDoc.createTextNode(
'false'));
482prioNode.appendChild(v);
483balkingNode.appendChild(prioNode);