LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
getCdfRespT.m
1function RD = getCdfRespT(self, R)
2% RD = GETCDFRESPT(R)
3%
4% Empirical response time CDF, measured on the simulated sample path.
5%
6% A simulator must report what it observed: the base NetworkSolver
7% implementation fabricates an exponential law with the right mean, which is
8% an analytical fallback and says nothing about the tail. The LDES engine
9% records every per-job response time (Solver_ssj.responseTimeSamples ->
10% LDESResult.respTimeSamples -> the JSON "transient.respTimeSamples" block,
11% exported under --trajectory), so the CDF here is the ecdf of those samples.
12%
13% RD is an (nstations x nclasses) cell of [F(t), t] matrices, the convention
14% every other getCdfRespT follows. A (station,class) pair with no observation
15% is left empty rather than filled with a guess.
16%
17% Copyright (c) 2012-2026, Imperial College London
18% All rights reserved.
19
20sn = self.getStruct;
21RD = cell(sn.nstations, sn.nclasses);
22if GlobalConstants.DummyMode
23 return
24end
25if nargin < 2
26 R = self.getAvgRespTHandles; %#ok<NASGU>
27end
28
29T0 = tic;
30% Ask the engine for the per-job response time samples. They are a
31% distributional output, not a trajectory, so they have their own CLI flag and
32% their own top-level JSON block; the flag also forces the jar runner, since
33% the AOT native binary predates it (see solveCli).
34data = self.solveCli(self.getOptions, {'--respt-samples'});
35samplesCell = ldesResptSamples(data, sn.nstations, sn.nclasses);
36if isempty(samplesCell)
37 line_error(mfilename, ['The LDES run returned no response time samples, so an empirical CDF ' ...
38 'cannot be built. Increase options.samples, or use getPerctRespT(...,''forktail'') ' ...
39 'for the analytical fork-join tail.']);
40end
41
42for i = 1:sn.nstations
43 for r = 1:sn.nclasses
44 if i <= size(samplesCell,1) && r <= size(samplesCell,2)
45 samples = samplesCell{i, r};
46 if ~isempty(samples)
47 x = sort(samples(:));
48 F = (1:numel(x))' / numel(x);
49 % collapse repeated observations, keeping the largest CDF value
50 [x, lastIdx] = unique(x, 'last');
51 RD{i, r} = [F(lastIdx), x];
52 end
53 end
54 end
55end
56
57runtime = toc(T0);
58self.setDistribResults(RD, runtime);
59end
60
61function out = ldesResptSamples(data, nstations, nclasses)
62% OUT = LDESRESPTSAMPLES(DATA, NSTATIONS, NCLASSES)
63% Normalize the engine's respTimeSamples block into an (nstations x nclasses)
64% cell of column vectors. jsondecode yields a cell of cells when the per-class
65% sample counts differ and a numeric array when they happen to match, so both
66% shapes have to be accepted.
67out = {};
68if ~isstruct(data) || ~isfield(data, 'respTimeSamples') || isempty(data.respTimeSamples)
69 return
70end
71rts = data.respTimeSamples;
72if ~iscell(rts)
73 rts = num2cell(rts, [2 3]);
74end
75out = cell(nstations, nclasses);
76for i = 1:min(numel(rts), nstations)
77 stationEntry = rts{i};
78 if ~iscell(stationEntry)
79 stationEntry = num2cell(stationEntry, 2);
80 end
81 for r = 1:min(numel(stationEntry), nclasses)
82 v = stationEntry{r};
83 if ~isempty(v)
84 out{i, r} = double(v(:));
85 end
86 end
87end
88end