LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
sample.m
1function sampleNodeState = sample(self, node, numSamples, markActivePassive)
2% TRANNODESTATE = SAMPLE(NODE, NUMSAMPLES, MARKACTIVEPASSIVE)
3% Returns a sample path simulation trace showing state evolution at a node
4%
5% @brief Generates a stochastic simulation sample path with phase information at a node
6%
7% This method runs a discrete-event stochastic simulation and records the sequence
8% of states visited at a specified station along with timing information. The sample
9% path includes detailed phase information from the service distributions, capturing
10% all internal phases experienced during service.
11%
12% The SSA solver uses the Next Reaction Method (NRM) for efficient stochastic
13% sampling when possible, or general serial CTMC simulation otherwise.
14%
15% @param self SolverSSA instance
16% @param node Queue or node object (or node index as integer) to sample
17% @param numSamples (optional) Number of events to simulate (default: solver's samples option)
18% Use more samples for longer traces and better statistics.
19% @param markActivePassive (optional) Boolean flag to distinguish active vs passive events
20% - false (default): Mixed event list
21% - true: Separate 'active' and 'passive' event arrays per time
22%
23% @return sampleNodeState Structure containing the sample path with fields:
24% - sampleNodeState.handle: Reference to the sampled node
25% - sampleNodeState.t: Vector of event times (increasing sequence)
26% - sampleNodeState.state: Matrix of states at event times
27% Shape: [num_events x (num_classes + phase_dimension)]
28% - sampleNodeState.event: Cell array of event information at each time
29% - sampleNodeState.isaggregate: Boolean false (phase-detailed sample)
30% - sampleNodeState.nodeIndex: Index of the sampled node
31% - sampleNodeState.numSamples: Number of events generated
32%
33% @note Phase information allows detailed analysis of service behavior including
34% time spent in each phase of phase-type distributions. For simpler class-only
35% analysis, use sampleAggr() instead.
36% Supported by CTMC and SSA solvers.
37%
38% @warning Simulation-based trace - results are stochastic and depend on random seed.
39% Set seed option in solver constructor for reproducibility:
40% solver = SolverSSA(model, 'seed', 12345);
41%
42% @see sampleAggr - Returns sample path aggregated over phases (simpler output)
43% @see sample_sys - Returns system-wide sample path for all stations
44%
45% Example:
46% @code
47% model = Network('M_M_1');
48% % ... model setup ...
49% solver = SolverSSA(model, 'samples', 5000, 'seed', 54321);
50% queue1 = model.nodes{1};
51%
52% % Generate sample path with 1000 events
53% S = solver.sample(queue1, 1000);
54%
55% % Access and plot sample path
56% times = S.t;
57% states = S.state;
58%
59% % Plot number of jobs of class 1 vs time
60% figure;
61% plot(times, states(:,1));
62% xlabel('Time');
63% ylabel('Number of Jobs (Class 1)');
64% title('Sample Path at Queue');
65%
66% % Mark active/passive events if needed
67% S_marked = solver.sample(queue1, 1000, true);
68% @endcode
69
70if GlobalConstants.DummyMode
71 sampleNodeState = NaN;
72 return
73end
74
75options = self.getOptions;
76
77if nargin<4
78 markActivePassive = false;
79end
80
81if nargin>=3 %exist('numSamples','var')
82 options.samples = numSamples;
83else
84 numSamples = options.samples;
85end
86switch options.method
87 case {'default','serial'}
88 options.method = 'serial'; % nrm does not support tran*
89 [~, tranSystemState, tranSync] = self.runAnalyzer(options);
90 event = tranSync;
91 sn = self.getStruct;
92 isf = sn.nodeToStateful(node.index);
93 sampleNodeState = struct();
94 sampleNodeState.handle = node;
95 sampleNodeState.t = tranSystemState{1};
96 sampleNodeState.state = tranSystemState{1+isf};
97
98 sn = self.getStruct;
99 sampleNodeState.event = {};
100 for e = 1:length(event)
101 for a=1:length(sn.sync{event(e)}.active)
102 sampleNodeState.event{end+1} = sn.sync{event(e)}.active{a};
103 sampleNodeState.event{end}.t = sampleNodeState.t(e);
104 end
105 for p=1:length(sn.sync{event(e)}.passive)
106 sampleNodeState.event{end+1} = sn.sync{event(e)}.passive{p};
107 sampleNodeState.event{end}.t = sampleNodeState.t(e);
108 end
109 end
110 sampleNodeState.isaggregate = false;
111
112 otherwise
113 line_error(mfilename,'sample is not available in SolverSSA with the chosen method.');
114end
115%sampleNodeState.t = [0; sampleNodeState.t(2:end)];
116
117if markActivePassive
118 apevent = cell(1,length(sampleNodeState.t)-1);
119 for ti = 1:length(apevent)
120 apevent{ti} = struct('active',[],'passive',[]);
121 end
122 for e=1:length(sampleNodeState.event)
123 ti = find(sampleNodeState.event{e}.t == sampleNodeState.t);
124 if ~isempty(ti) && ti<length(sampleNodeState.t)
125 switch sampleNodeState.event{e}.event
126 case EventType.ARV
127 apevent{ti}.passive = sampleNodeState.event{e};
128 otherwise
129 apevent{ti}.active = sampleNodeState.event{e};
130 end
131 end
132 end
133 sampleNodeState.event = apevent';
134end
135
136end