1function S = sample(self, node, numSamples)
2% S = SAMPLE(NODE, NUMSAMPLES) Returns a sample path of state evolution at a node
4% @brief Generates a discrete-
event sample path showing state transitions at a node
6% This method produces a sample path (stochastic simulation trace) showing how the
7% number of jobs at a specified station evolves over time. The sample path includes
8% detailed phase information from the underlying Markov chain, distinguishing between
9% different phases of service distributions.
11% The sample path
is obtained by simulating the CTMC underlying the queueing network,
12% filtering events to focus on the station of interest, and recording the sequence
13% of states visited along with transition times.
15% @param self SolverCTMC instance
16% @param node Queue or node object (or node index as integer) to sample
17% @param numSamples Integer number of events/transitions to simulate (e.g., 1000)
19% @
return S Structure containing the sample path with fields:
20% - S.handle: Reference to the sampled node
21% - S.t: Vector of time points when transitions occurred
22% - S.state: Matrix of states at each time point, with phase information
23% Shape: [numSamples x num_classes+1] where last column
is phase number
24% - S.event: Cell array of events that triggered transitions
25% - S.isaggregate: Boolean flag (
false, indicating phase-detailed)
26% - S.nodeIndex: Index of the sampled node
27% - S.numSamples: Number of samples collected
29% @note Phase-detailed sample paths include internal state information from
30% phase-type distributions. Use sampleAggr() for simpler class-based states.
31% Only supported by CTMC and SSA solvers.
33% @warning Results depend on the random seed and CTMC state space.
34% Use seed option in solver constructor for reproducibility.
36% @see sampleAggr - Returns sample path aggregated over phases
37% @see sample_sys - Returns system-wide sample path for all
nodes
41% solver = SolverCTMC(model, 'seed', 12345);
42% queue1 = model.
nodes{1};
44% % Get sample path with 1000 transitions
45% S = solver.sample(queue1, 1000);
49% plot(S.t, S.state(:,1)); % Plot state
for class 1
51% ylabel(
'Number of Jobs');
52% title(
'Sample Path at Queue1');
55options = self.getOptions;
57if isempty(self.result) || ~isfield(self.result,
'infGen')
60[infGen, eventFilt] = getGenerator(self);
61stateSpace = getStateSpace(self);
62%stateSpaceAggr = getStateSpaceAggr(self);
65nst = cumsum([1,cellfun(@length,initState)']);
66s0 = cell2mat(initState(:)');
69pi0 = zeros(1,size(stateSpace,1));
70pi0(matchrow(stateSpace,s0))=1;
72% filter all CTMC events as a marked Markovian arrival process
73D1 = cellsum(eventFilt);
75MMAP = mmap_normalize([{D0},{D1},eventFilt(:)
']);
78[sjt,event,~,~,sts] = mmap_sample(MMAP,numSamples, pi0);
83S.t = cumsum([0,sjt(1:end-1)']
');
85isf = sn.nodeToStateful(ind);
86S.state = stateSpace(sts,(nst(isf):nst(isf+1)-1));
89%nodeEvent = false(length(event),1);
90%nodeTS = zeros(length(event),1);
91for e = 1:length(event)
92 for a=1:length(sn.sync{event(e)}.active)
93 S.event{end+1} = sn.sync{event(e)}.active{a};
94 S.event{end}.t = S.t(e);
95% if sn.sync{event(e)}.active{a}.node == ind
97% nodeTS(e) = tranSysState.t(e);
100 for p=1:length(sn.sync{event(e)}.passive)
101 S.event{end+1} = sn.sync{event(e)}.passive{p};
102 S.event{end}.t = S.t(e);
103% if sn.sync{event(e)}.passive{p}.node == ind
104% nodeEvent(e) = true;
105% nodeTS(e) = tranSysState.t(e);
110%tranSysState.state = tranSysState.state([1;find(nodeTS>0)],:);
111%tranSysState.t = unique(nodeTS);
112%tranSysState.event = tranSysState.event(nodeEvent)';
113S.isaggregate =
false;