LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
saveImpatience.m
1function [simDoc, section] = saveImpatience(self, simDoc, section, ind)
2% [SIMDOC, SECTION] = SAVEIMPATIENCE(SIMDOC, SECTION, IND)
3%
4% Generates XML for impatience (reneging) distributions for JMT Queue sections
5%
6% Copyright (c) 2012-2026, Imperial College London
7% All rights reserved.
8
9impatienceNode = simDoc.createElement('parameter');
10impatienceNode.setAttribute('array', 'true');
11impatienceNode.setAttribute('classPath', 'jmt.engine.NetStrategies.ImpatienceStrategies.Impatience');
12impatienceNode.setAttribute('name', 'Impatience');
13
14sn = self.getStruct;
15numOfClasses = sn.nclasses;
16exportClasses = self.getExportableClasses();
17i = sn.nodeToStation(ind);
18
19for r=1:numOfClasses
20 % Skip classes that should not be exported to JMT
21 if ~exportClasses(r)
22 continue;
23 end
24
25 refClassNode = simDoc.createElement('refClass');
26 refClassNode.appendChild(simDoc.createTextNode(sn.classnames{r}));
27 impatienceNode.appendChild(refClassNode);
28
29 % see _kb/06-solver-catalog.md (Wrappers: JMT impatience export)
30 hasBalking = false;
31 if i > 0 && isfield(sn, 'balkingStrategy') && ~isempty(sn.balkingStrategy)
32 if sn.balkingStrategy(i, r) == BalkingStrategy.QUEUE_LENGTH
33 hasBalking = true;
34 end
35 end
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
40 hasImpatience = true;
41 end
42 end
43
44 impatienceStrategyNode = simDoc.createElement('subParameter');
45
46 if hasBalking
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);
53 continue;
54 end
55
56 impatienceStrategyNode.setAttribute('classPath', 'jmt.engine.NetStrategies.ImpatienceStrategies.Reneging');
57 impatienceStrategyNode.setAttribute('name', 'Reneging');
58
59 if ~hasImpatience
60 % No impatience defined - use null
61 subParValue = simDoc.createElement('value');
62 subParValue.appendChild(simDoc.createTextNode('null'));
63 impatienceStrategyNode.appendChild(subParValue);
64 else
65 % Impatience is defined - generate distribution XML
66 procType = sn.impatienceType(i, r);
67 impatiencePhases = sn.impatiencePhases(i, r);
68
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);
74
75 distributionNode = simDoc.createElement('subParameter');
76
77 if emitPhaseType
78 javaClass = 'jmt.engine.random.PhaseTypeDistr';
79 javaParClass = 'jmt.engine.random.PhaseTypePar';
80 else
81 switch procType
82 case ProcessType.DET
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';
88 case ProcessType.EXP
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';
109 otherwise
110 line_error(mfilename, sprintf('Unsupported impatience distribution type: %s', ProcessType.toText(procType)));
111 end
112 end
113
114 distributionNode.setAttribute('classPath', javaClass);
115 if emitPhaseType
116 distributionNode.setAttribute('name', 'Phase-Type');
117 else
118 switch procType
119 case ProcessType.EXP
120 distributionNode.setAttribute('name', 'Exponential');
121 case ProcessType.HYPEREXP
122 distributionNode.setAttribute('name', 'Hyperexponential');
123 otherwise
124 distributionNode.setAttribute('name', ProcessType.toText(procType));
125 end
126 end
127 impatienceStrategyNode.appendChild(distributionNode);
128
129 % Create distribution parameters
130 distrParNode = simDoc.createElement('subParameter');
131 distrParNode.setAttribute('classPath', javaParClass);
132 distrParNode.setAttribute('name', 'distrPar');
133
134 % Get impatience parameters
135 impatienceMu = sn.impatienceMu(i, r);
136 impatiencePhi = sn.impatiencePhi(i, r);
137
138 if emitPhaseType
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);
145
146 % Alpha vector
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');
155 for k=1:phases
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);
163 end
164
165 % T matrix
166 subParNodeT = simDoc.createElement('subParameter');
167 subParNodeT.setAttribute('array', 'true');
168 subParNodeT.setAttribute('classPath', 'java.lang.Object');
169 subParNodeT.setAttribute('name', 'T');
170 for k=1:phases
171 subParNodeTvec = simDoc.createElement('subParameter');
172 subParNodeTvec.setAttribute('array', 'true');
173 subParNodeTvec.setAttribute('classPath', 'java.lang.Object');
174 subParNodeTvec.setAttribute('name', 'vector');
175 for j=1:phases
176 subParNodeTElem = simDoc.createElement('subParameter');
177 subParNodeTElem.setAttribute('classPath', 'java.lang.Double');
178 subParNodeTElem.setAttribute('name', 'entry');
179 subParValue = simDoc.createElement('value');
180 if k==j
181 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', -abs(PH(k,j)))));
182 else
183 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', abs(PH(k,j)))));
184 end
185 subParNodeTElem.appendChild(subParValue);
186 subParNodeTvec.appendChild(subParNodeTElem);
187 end
188 subParNodeT.appendChild(subParNodeTvec);
189 end
190
191 subParNodeAlpha.appendChild(subParNodeAlphaVec);
192 distrParNode.appendChild(subParNodeAlpha);
193 distrParNode.appendChild(subParNodeT);
194 else
195 switch procType
196 case ProcessType.DET
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);
204
205 case ProcessType.EXP
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);
213
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);
230
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);
257
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);
274
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);
293
294 case ProcessType.WEIBULL
295 scv = impatiencePhi(1);
296 c = sqrt(scv);
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);
313
314 case ProcessType.LOGNORMAL
315 scv = impatiencePhi(1);
316 c = sqrt(scv);
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);
333
334 case ProcessType.UNIFORM
335 mean = 1/impatienceMu(1);
336 % For uniform [a,b]: mean = (a+b)/2, use a=0 for simplicity
337 b = 2 * mean;
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);
352
353 end
354 end
355
356 impatienceStrategyNode.appendChild(distrParNode);
357 end
358
359 impatienceNode.appendChild(impatienceStrategyNode);
360end
361
362section.appendChild(impatienceNode);
363end
364
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.
373%
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.
381
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)
387 th = thresholds{ti};
388 lo(ti) = th{1};
389 hi(ti) = th{2};
390 pr(ti) = th{3};
391end
392[lo, order] = sort(lo);
393hi = hi(order);
394pr = pr(order);
395
396if isempty(nservers) || ~isfinite(nservers) || nservers < 1
397 S = 1;
398else
399 S = nservers;
400end
401froms = [];
402probs = [];
403for ti = 1:numel(lo)
404 froms(end+1) = max(0, lo(ti) - S); %#ok<AGROW>
405 probs(end+1) = pr(ti); %#ok<AGROW>
406 if ~isinf(hi(ti))
407 if ti < numel(lo)
408 nextLo = lo(ti+1);
409 else
410 nextLo = Inf;
411 end
412 if hi(ti)+1 < nextLo
413 froms(end+1) = max(0, hi(ti)+1 - S); %#ok<AGROW>
414 probs(end+1) = 0.0; %#ok<AGROW>
415 end
416 end
417end
418
419% LoadDependentStrategy wrapper (Parameter #1 of Balking)
420ldStrategyNode = simDoc.createElement('subParameter');
421ldStrategyNode.setAttribute('classPath', 'jmt.engine.NetStrategies.ServiceStrategies.LoadDependentStrategy');
422ldStrategyNode.setAttribute('name', 'LoadDependentStrategy');
423
424ldArrayNode = simDoc.createElement('subParameter');
425ldArrayNode.setAttribute('array', 'true');
426ldArrayNode.setAttribute('classPath', 'jmt.engine.NetStrategies.ServiceStrategies.LDParameter');
427ldArrayNode.setAttribute('name', 'LDParameter');
428
429for ti = 1:numel(froms)
430 rangeNode = simDoc.createElement('subParameter');
431 rangeNode.setAttribute('classPath', 'jmt.engine.NetStrategies.ServiceStrategies.LDParameter');
432 rangeNode.setAttribute('name', 'LDParameter');
433
434 % from (Integer)
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);
442
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);
448
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);
460
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);
469
470 ldArrayNode.appendChild(rangeNode);
471end
472
473ldStrategyNode.appendChild(ldArrayNode);
474balkingNode.appendChild(ldStrategyNode);
475
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);
484end