LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
CyclicPoisson.m
1classdef CyclicPoisson < ContinuousDistribution
2 % CyclicPoisson Cyclic Poisson arrival process with deterministic phase switching.
3 %
4 % In phase i, arrivals follow Poisson(rates(i)) for exactly durations(i)
5 % time units, then the rate switches deterministically to phase mod(i,n)+1.
6 % The schedule repeats cyclically.
7 %
8 % Unlike a MAP, which uses exponential holding times to approximate the
9 % phase schedule stochastically, this process fires rate-change events at
10 % exact phase boundaries in the LDES simulation engine.
11 %
12 % The process representation stores:
13 % process{1} : 1-by-n row vector of arrival rates
14 % process{2} : 1-by-n row vector of phase durations
15 %
16 % Solver support. Only the LDES simulation engine honours the exact
17 % phase schedule. CyclicPoisson is declared solely in the LDES feature
18 % set, so every analytical solver (MVA, NC, CTMC, MAM, FLD, JMT, SSA)
19 % rejects a model using it via the standard unsupported-feature check.
20 %
21 % Copyright (c) 2012-2026, Imperial College London
22 % All rights reserved.
23
24 properties
25 rates; % 1-by-n vector of arrival rates per phase
26 durations; % 1-by-n vector of phase durations
27 process; % {rates, durations} cell, for serialization
28 end
29
30 methods
31 function self = CyclicPoisson(rates, durations)
32 % SELF = CYCLICPOISSON(RATES, DURATIONS)
33 self@ContinuousDistribution('CyclicPoisson', 0, [0, Inf]);
34 if nargin < 2 || isempty(rates) || isempty(durations) ...
35 || numel(rates) ~= numel(durations)
36 line_error(mfilename, 'CyclicPoisson: rates and durations must be non-empty and equal length');
37 end
38 self.rates = rates(:).';
39 self.durations = durations(:).';
40 self.process = {self.rates, self.durations};
41 self.mean = 1.0 / self.getTimeAverageRate();
42 self.immediate = false;
43 end
44
45 function rate = getTimeAverageRate(self)
46 % RATE = GETTIMEAVERAGERATE()
47 % Time-average arrival rate: sum(rates.*durations) / sum(durations).
48 totalArrivals = sum(self.rates .* self.durations);
49 totalDuration = sum(self.durations);
50 if totalDuration > 0
51 rate = totalArrivals / totalDuration;
52 else
53 rate = 0.0;
54 end
55 end
56
57 function r = getRates(self)
58 r = self.rates;
59 end
60
61 function d = getDurations(self)
62 d = self.durations;
63 end
64
65 function n = getNumPhases(self)
66 n = numel(self.rates);
67 end
68
69 function mean = getMean(self)
70 % MEAN = GETMEAN()
71 mean = 1.0 / self.getTimeAverageRate();
72 end
73
74 function rate = getRate(self)
75 rate = self.getTimeAverageRate();
76 end
77
78 function scv = getSCV(self)
79 % SCV = GETSCV() — placeholder (used only if Erlang conversion is attempted).
80 scv = 1.0;
81 end
82
83 function skew = getSkewness(self)
84 skew = 2.0;
85 end
86
87 function F = evalCDF(self, t)
88 rate = self.getTimeAverageRate();
89 F = 1.0 - exp(-rate * t);
90 end
91
92 function L = evalLST(self, s)
93 rate = self.getTimeAverageRate();
94 L = rate ./ (rate + s);
95 end
96
97 function proc = getProcess(self)
98 proc = self.process;
99 end
100
101 function X = sample(self, n)
102 % X = SAMPLE(N) — samples Exp(time-average rate). The exact phase
103 % schedule is honoured only by the LDES simulator, not by sample().
104 if nargin < 2
105 n = 1;
106 end
107 rate = self.getTimeAverageRate();
108 X = -log(1 - rand(n, 1)) / rate;
109 end
110 end
111end