2 % Matrix Exponential (ME) distribution
4 % ME distributions are characterized by an initial vector alpha and
5 % a matrix parameter A. They generalize Phase-Type (PH) distributions
6 % by allowing alpha to have entries outside [0,1] and A to have
7 % arbitrary structure (not necessarily a valid sub-generator).
9 % Copyright (c) 2012-2026, Imperial College London
10 % All rights reserved.
13 alpha; % Initial vector
18 function self = ME(alpha, A)
19 % ME Create a Matrix Exponential distribution instance
21 % @brief Creates an ME distribution with the given initial vector and matrix parameter
22 % @param alpha Initial vector (may have negative entries or sum != 1)
23 % @param A Matrix parameter (must have all eigenvalues with negative real parts)
24 % @
return self ME distribution instance
26 % Call superclass constructor
27 self@Markovian(
'ME', 2);
29 % Validate
using BuTools
30 if ~CheckMERepresentation(alpha, A)
31 error(
'Invalid ME representation: Check that A is square, alpha and A have compatible dimensions, all eigenvalues of A have negative real parts, and the dominant eigenvalue is real.');
37 self.nPhases = length(alpha);
40 setParam(self, 1,
'alpha', alpha);
41 setParam(self, 2,
'A', A);
44 alphaMatrix = jline.util.matrix.Matrix(alpha);
45 AMatrix = jline.util.matrix.Matrix(A);
46 self.obj = jline.lang.processes.ME(alphaMatrix, AMatrix);
48 % Build process representation: {D0=A, D1=-A*e*alpha
'}
49 % where e is column vector of ones
50 e = ones(self.nPhases, 1);
51 self.process = {A, -A * e * alpha};
53 self.immediate = false;
56 function X = sample(self, n)
58 % Get n samples from the distribution using inverse CDF interpolation
64 % Use me_sample for accurate sampling
65 X = me_sample(self.process, n);
68 function phases = getNumberOfPhases(self)
69 % PHASES = GETNUMBEROFPHASES()
70 % Get number of phases in the ME representation
71 phases = self.nPhases;
74 function Ft = evalCDF(self, t)
75 % FT = EVALCDF(SELF, T)
76 % Evaluate the cumulative distribution function at t
78 % For ME distribution: CDF(t) = 1 - alpha * exp(A*t) * e
80 Ft = map_cdf(self.process, t);
83 function L = evalLST(self, s)
85 % Evaluate the Laplace-Stieltjes transform at s
87 % LST(s) = alpha * (sI - A)^(-1) * (-A) * e
88 e = ones(self.nPhases, 1);
89 sI = s * eye(self.nPhases);
90 L = self.alpha * ((sI - self.A) \ (-self.A * e));
93 function mean_val = getMean(self)
94 % MEAN_VAL = GETMEAN()
95 % Get mean of the ME distribution
97 mean_val = map_mean(self.process);
100 function var_val = getVar(self)
102 % Get variance of the ME distribution
104 var_val = map_var(self.process);
107 function scv = getSCV(self)
109 % Get squared coefficient of variation
111 scv = map_scv(self.process);
114 function proc = getProcess(self)
115 % PROC = GETPROCESS()
116 % Get process representation {D0, D1}
123 function me = fitMoments(moms)
124 % ME = FITMOMENTS(MOMS)
125 % Create ME distribution by fitting the given moments
126 % Uses BuTools MEFromMoments algorithm
128 % @param moms Array of moments (requires 2*M-1 moments for order M)
129 % @return me ME distribution matching the given moments
131 [alpha, A] = MEFromMoments(moms);
135 function me = fromExp(rate)
137 % Create ME distribution from exponential distribution
138 % Convenience method showing that Exp is a special case of ME
140 % @param rate Rate parameter (lambda)
141 % @return me ME distribution equivalent to Exp(rate)
148 function me = fromErlang(k, rate)
149 % ME = FROMERLANG(K, RATE)
150 % Create ME distribution from Erlang distribution
151 % Convenience method showing that Erlang is a special case of ME
153 % @param k Number of phases
154 % @param rate Rate parameter for each phase
155 % @return me ME distribution equivalent to Erlang(k, rate)
158 alpha(1) = 1.0; % alpha = [1, 0, 0, ..., 0]
162 A(i, i) = -rate; % diagonal
164 A(i, i+1) = rate; % super-diagonal
171 function me = fromHyperExp(p, rates)
172 % ME = FROMHYPEREXP(P, RATES)
173 % Create ME distribution from HyperExponential distribution
174 % Convenience method showing that HyperExp is a special case of ME
176 % @param p Array of probabilities for each branch
177 % @param rates Array of rates for each branch
178 % @return me ME distribution equivalent to HyperExp(p, rates)
180 if length(p) ~= length(rates)
181 error('p and rates must have the same length
');
185 alpha = p; % alpha = p
189 A(i, i) = -rates(i); % diagonal matrix of rates