LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
saveRetrialDistributions.m
1function [simDoc, section] = saveRetrialDistributions(self, simDoc, section, ind)
2% [SIMDOC, SECTION] = SAVERETRIALDISTRIBUTIONS(SIMDOC, SECTION, IND)
3%
4% Generates XML for retrial delay distributions for JMT Queue sections.
5% The retrial distribution tells JMT how long a blocked customer waits
6% in the orbit before retrying.
7%
8% Copyright (c) 2012-2026, Imperial College London
9% All rights reserved.
10
11retrialNode = simDoc.createElement('parameter');
12retrialNode.setAttribute('array', 'true');
13retrialNode.setAttribute('classPath', 'jmt.engine.NetStrategies.ServiceStrategy');
14retrialNode.setAttribute('name', 'retrialDistributions');
15
16sn = self.getStruct;
17numOfClasses = sn.nclasses;
18exportClasses = self.getExportableClasses();
19
20% Get the actual Queue node to access retrialDelays
21nodes = self.model.getNodes();
22currentNode = nodes{ind};
23
24for r=1:numOfClasses
25 if ~exportClasses(r)
26 continue;
27 end
28
29 refClassNode = simDoc.createElement('refClass');
30 refClassNode.appendChild(simDoc.createTextNode(sn.classnames{r}));
31 retrialNode.appendChild(refClassNode);
32
33 serviceTimeStrategyNode = simDoc.createElement('subParameter');
34 serviceTimeStrategyNode.setAttribute('classPath', 'jmt.engine.NetStrategies.ServiceStrategies.ServiceTimeStrategy');
35 serviceTimeStrategyNode.setAttribute('name', 'ServiceTimeStrategy');
36
37 % Check if retrial delay is defined for this class
38 hasRetrial = false;
39 retrialDist = [];
40 if isa(currentNode, 'Queue') && ~isempty(currentNode.retrialDelays)
41 if r <= size(currentNode.retrialDelays, 2) && ~isempty(currentNode.retrialDelays{1, r})
42 hasRetrial = true;
43 retrialDist = currentNode.retrialDelays{1, r};
44 end
45 end
46
47 if ~hasRetrial
48 % Default: Exp(1) placeholder
49 distributionNode = simDoc.createElement('subParameter');
50 distributionNode.setAttribute('classPath', 'jmt.engine.random.Exponential');
51 distributionNode.setAttribute('name', 'Exponential');
52 serviceTimeStrategyNode.appendChild(distributionNode);
53
54 distrParNode = simDoc.createElement('subParameter');
55 distrParNode.setAttribute('classPath', 'jmt.engine.random.ExponentialPar');
56 distrParNode.setAttribute('name', 'distrPar');
57 subParNodeLambda = simDoc.createElement('subParameter');
58 subParNodeLambda.setAttribute('classPath', 'java.lang.Double');
59 subParNodeLambda.setAttribute('name', 'lambda');
60 subParValue = simDoc.createElement('value');
61 subParValue.appendChild(simDoc.createTextNode('1.000000000000'));
62 subParNodeLambda.appendChild(subParValue);
63 distrParNode.appendChild(subParNodeLambda);
64 serviceTimeStrategyNode.appendChild(distrParNode);
65 else
66 % Write the actual retrial distribution
67 % Determine distribution type from the distribution object
68 %
69 % jmt.engine.random.HyperExpPar carries exactly (p, lambda1, lambda2)
70 % and so can only express a 2-phase hyper-exponential. An n>2 HyperExp,
71 % and any other phase-type retrial delay, is exported as the acyclic
72 % phase-type built from its OWN PH representation (alpha, T), i.e. the
73 % same distribution rather than a moment-matched refit. This mirrors
74 % saveServiceStrategy.m and saveImpatience.m.
75 emitPhaseType = isa(retrialDist, 'PH') || isa(retrialDist, 'APH') || ...
76 isa(retrialDist, 'Coxian') || ...
77 (isa(retrialDist, 'HyperExp') && retrialDist.getNumberOfPhases() > 2);
78
79 if emitPhaseType
80 javaClass = 'jmt.engine.random.PhaseTypeDistr';
81 javaParClass = 'jmt.engine.random.PhaseTypePar';
82 distName = 'Phase-Type';
83 elseif isa(retrialDist, 'Exp')
84 javaClass = 'jmt.engine.random.Exponential';
85 javaParClass = 'jmt.engine.random.ExponentialPar';
86 distName = 'Exponential';
87 elseif isa(retrialDist, 'Erlang')
88 javaClass = 'jmt.engine.random.Erlang';
89 javaParClass = 'jmt.engine.random.ErlangPar';
90 distName = 'Erlang';
91 elseif isa(retrialDist, 'HyperExp')
92 javaClass = 'jmt.engine.random.HyperExp';
93 javaParClass = 'jmt.engine.random.HyperExpPar';
94 distName = 'Hyperexponential';
95 elseif isa(retrialDist, 'Det')
96 javaClass = 'jmt.engine.random.DeterministicDistr';
97 javaParClass = 'jmt.engine.random.DeterministicDistrPar';
98 distName = 'Deterministic';
99 elseif isa(retrialDist, 'Gamma')
100 javaClass = 'jmt.engine.random.GammaDistr';
101 javaParClass = 'jmt.engine.random.GammaDistrPar';
102 distName = 'Gamma';
103 elseif isa(retrialDist, 'Uniform')
104 javaClass = 'jmt.engine.random.Uniform';
105 javaParClass = 'jmt.engine.random.UniformPar';
106 distName = 'Uniform';
107 else
108 % Fallback: treat as exponential with the distribution's rate
109 javaClass = 'jmt.engine.random.Exponential';
110 javaParClass = 'jmt.engine.random.ExponentialPar';
111 distName = 'Exponential';
112 end
113
114 distributionNode = simDoc.createElement('subParameter');
115 distributionNode.setAttribute('classPath', javaClass);
116 distributionNode.setAttribute('name', distName);
117 serviceTimeStrategyNode.appendChild(distributionNode);
118
119 distrParNode = simDoc.createElement('subParameter');
120 distrParNode.setAttribute('classPath', javaParClass);
121 distrParNode.setAttribute('name', 'distrPar');
122
123 if emitPhaseType
124 [alpha, T, phases] = phaseTypeRepres(retrialDist);
125
126 % Alpha vector
127 subParNodeAlpha = simDoc.createElement('subParameter');
128 subParNodeAlpha.setAttribute('array', 'true');
129 subParNodeAlpha.setAttribute('classPath', 'java.lang.Object');
130 subParNodeAlpha.setAttribute('name', 'alpha');
131 subParNodeAlphaVec = simDoc.createElement('subParameter');
132 subParNodeAlphaVec.setAttribute('array', 'true');
133 subParNodeAlphaVec.setAttribute('classPath', 'java.lang.Object');
134 subParNodeAlphaVec.setAttribute('name', 'vector');
135 for k=1:phases
136 subParNodeAlphaElem = simDoc.createElement('subParameter');
137 subParNodeAlphaElem.setAttribute('classPath', 'java.lang.Double');
138 subParNodeAlphaElem.setAttribute('name', 'entry');
139 subParValue = simDoc.createElement('value');
140 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', alpha(k))));
141 subParNodeAlphaElem.appendChild(subParValue);
142 subParNodeAlphaVec.appendChild(subParNodeAlphaElem);
143 end
144
145 % T matrix
146 subParNodeT = simDoc.createElement('subParameter');
147 subParNodeT.setAttribute('array', 'true');
148 subParNodeT.setAttribute('classPath', 'java.lang.Object');
149 subParNodeT.setAttribute('name', 'T');
150 for k=1:phases
151 subParNodeTvec = simDoc.createElement('subParameter');
152 subParNodeTvec.setAttribute('array', 'true');
153 subParNodeTvec.setAttribute('classPath', 'java.lang.Object');
154 subParNodeTvec.setAttribute('name', 'vector');
155 for j=1:phases
156 subParNodeTElem = simDoc.createElement('subParameter');
157 subParNodeTElem.setAttribute('classPath', 'java.lang.Double');
158 subParNodeTElem.setAttribute('name', 'entry');
159 subParValue = simDoc.createElement('value');
160 if k==j
161 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', -abs(T(k,j)))));
162 else
163 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', abs(T(k,j)))));
164 end
165 subParNodeTElem.appendChild(subParValue);
166 subParNodeTvec.appendChild(subParNodeTElem);
167 end
168 subParNodeT.appendChild(subParNodeTvec);
169 end
170
171 subParNodeAlpha.appendChild(subParNodeAlphaVec);
172 distrParNode.appendChild(subParNodeAlpha);
173 distrParNode.appendChild(subParNodeT);
174
175 elseif isa(retrialDist, 'HyperExp')
176 % 2-phase only: HyperExpPar carries exactly (p, lambda1, lambda2).
177 % Emitting a bare `lambda` here, as the generic fallback below did,
178 % silently degraded the retrial delay to an exponential.
179 [alpha, T] = phaseTypeRepres(retrialDist);
180 subParNodeP = simDoc.createElement('subParameter');
181 subParNodeP.setAttribute('classPath', 'java.lang.Double');
182 subParNodeP.setAttribute('name', 'p');
183 subParValue = simDoc.createElement('value');
184 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', alpha(1))));
185 subParNodeP.appendChild(subParValue);
186 distrParNode.appendChild(subParNodeP);
187
188 subParNodeLambda1 = simDoc.createElement('subParameter');
189 subParNodeLambda1.setAttribute('classPath', 'java.lang.Double');
190 subParNodeLambda1.setAttribute('name', 'lambda1');
191 subParValue = simDoc.createElement('value');
192 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', -T(1,1))));
193 subParNodeLambda1.appendChild(subParValue);
194 distrParNode.appendChild(subParNodeLambda1);
195
196 subParNodeLambda2 = simDoc.createElement('subParameter');
197 subParNodeLambda2.setAttribute('classPath', 'java.lang.Double');
198 subParNodeLambda2.setAttribute('name', 'lambda2');
199 subParValue = simDoc.createElement('value');
200 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', -T(2,2))));
201 subParNodeLambda2.appendChild(subParValue);
202 distrParNode.appendChild(subParNodeLambda2);
203
204 elseif isa(retrialDist, 'Exp')
205 subParNodeLambda = simDoc.createElement('subParameter');
206 subParNodeLambda.setAttribute('classPath', 'java.lang.Double');
207 subParNodeLambda.setAttribute('name', 'lambda');
208 subParValue = simDoc.createElement('value');
209 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', retrialDist.getRate())));
210 subParNodeLambda.appendChild(subParValue);
211 distrParNode.appendChild(subParNodeLambda);
212
213 elseif isa(retrialDist, 'Det')
214 subParNodeT = simDoc.createElement('subParameter');
215 subParNodeT.setAttribute('classPath', 'java.lang.Double');
216 subParNodeT.setAttribute('name', 't');
217 subParValue = simDoc.createElement('value');
218 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', retrialDist.getMean())));
219 subParNodeT.appendChild(subParValue);
220 distrParNode.appendChild(subParNodeT);
221
222 elseif isa(retrialDist, 'Erlang')
223 subParNodeAlpha = simDoc.createElement('subParameter');
224 subParNodeAlpha.setAttribute('classPath', 'java.lang.Double');
225 subParNodeAlpha.setAttribute('name', 'alpha');
226 subParValue = simDoc.createElement('value');
227 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', retrialDist.getRate())));
228 subParNodeAlpha.appendChild(subParValue);
229 distrParNode.appendChild(subParNodeAlpha);
230
231 subParNodeR = simDoc.createElement('subParameter');
232 subParNodeR.setAttribute('classPath', 'java.lang.Long');
233 subParNodeR.setAttribute('name', 'r');
234 subParValue = simDoc.createElement('value');
235 subParValue.appendChild(simDoc.createTextNode(sprintf('%d', retrialDist.getNumberOfPhases())));
236 subParNodeR.appendChild(subParValue);
237 distrParNode.appendChild(subParNodeR);
238
239 else
240 % Generic fallback: use rate as exponential
241 subParNodeLambda = simDoc.createElement('subParameter');
242 subParNodeLambda.setAttribute('classPath', 'java.lang.Double');
243 subParNodeLambda.setAttribute('name', 'lambda');
244 subParValue = simDoc.createElement('value');
245 subParValue.appendChild(simDoc.createTextNode(sprintf('%.12f', 1/retrialDist.getMean())));
246 subParNodeLambda.appendChild(subParValue);
247 distrParNode.appendChild(subParNodeLambda);
248 end
249
250 serviceTimeStrategyNode.appendChild(distrParNode);
251 end
252
253 retrialNode.appendChild(serviceTimeStrategyNode);
254end
255
256section.appendChild(retrialNode);
257end
258
259function [alpha, T, phases] = phaseTypeRepres(dist)
260% [ALPHA, T, PHASES] = PHASETYPEREPRES(DIST)
261%
262% Extracts the (alpha, T) acyclic phase-type representation of a Markovian
263% distribution DIST from its own (D0,D1) process, so that the exported JMT
264% distribution is the SAME distribution rather than a moment-matched refit.
265% T = D0 and, since D1 = (-D0*e)*alpha for a PH renewal process, alpha is
266% recovered as the row of D1 rescaled by that phase's exit rate. This is the
267% same derivation used by MNetwork/refreshStruct.m for sn.impatiencePie.
268proc = dist.getProcess();
269if ~iscell(proc) || numel(proc) < 2
270 line_error(mfilename, sprintf(['Retrial distribution %s has no (D0,D1) ', ...
271 'representation, so it cannot be exported as a phase-type.'], class(dist)));
272end
273D0 = proc{1};
274D1 = proc{2};
275T = D0;
276phases = size(D0, 1);
277exitRates = -D0 * ones(phases, 1);
278idx = find(exitRates > 1e-10, 1);
279if ~isempty(idx)
280 alpha = abs(D1(idx, :) / exitRates(idx));
281else
282 alpha = ones(1, phases) / phases;
283end
284end
Definition fjtag.m:157
Definition Station.m:245