1classdef Coxian < Markovian
2 % The coxian statistical distribution
4 % Copyright (c) 2012-2026, Imperial College London
8 function self = Coxian(varargin)
9 % SELF = COXIAN(VARARGIN)
10 % Constructs a Coxian distribution from phase rates and
11 % completion probabilities, with entry probability 1 on the
13 self@Markovian(
'Coxian',2);
14 if length(varargin)==2
17 if abs(phi(end)-1)>GlobalConstants.CoarseTol && isfinite(phi(end))
18 line_error(mfilename,sprintf(
'The completion probability in the last Cox state must be 1.0 but it is %0.1f', phi(end)));
20 setParam(self, 1,
'mu', mu);
21 setParam(self, 2,
'phi', phi); % completion probability in phase 1
22 elseif length(varargin)==3
26 setParam(self, 1,
'lambda0', mu1);
27 setParam(self, 2,
'lambda1', mu2);
28 setParam(self, 3,
'phi0', phi1); % completion probability in phase 1
30 line_error(mfilename,
'Coxian accepts at most 3 parameters.');
32 jline_mu = java.util.ArrayList();
33 jline_phi = java.util.ArrayList();
34 if length(self.params) == 3
35 jline_mu.add(self.getParam(1).paramValue);
36 jline_mu.add(self.getParam(2).paramValue);
37 jline_phi.add(self.getParam(3).paramValue);
39 mu = self.getParam(1).paramValue;
40 phi = self.getParam(2).paramValue;
46 jline_phi.add(phi(i));
49 self.obj = jline.lang.processes.Coxian(jline_mu, jline_phi);
50 if length(self.params) == 2
53 ph = {diag(-mu)+diag(mu(1:end-1).*(1-phi(1:end-1)),1),[phi.*mu,zeros(length(mu),length(mu)-1)]};
55 mu1 = self.getParam(1).paramValue;
56 mu2 = self.getParam(2).paramValue;
57 phi1 = self.getParam(3).paramValue;
58 ph={[-mu1,(1-phi1)*mu1;0,-mu2],[phi1*mu1,0;mu2,0]};
61 self.nPhases = length(ph{1});
66 function phases = getNumberOfPhases(self)
67 % PHASES = GETNUMBEROFPHASES()
68 % Return number of phases in the distribution
69 if length(self.params) == 2
70 phases = length(self.getParam(1).paramValue);
76 function ex = getMean(self)
78 % Get distribution mean
79 if length(self.params) == 2
82 ex = map_mean({diag(-mu)+diag(mu(1:end-1).*(1-phi(1:end-1)),1),[phi.*mu,zeros(length(mu),length(mu)-1)]});
84 % Get distribution mean
85 mu1 = self.getParam(1).paramValue;
86 mu2 = self.getParam(2).paramValue;
87 phi1 = self.getParam(3).paramValue;
88 ex = 1/mu1 + (1-phi1)/mu2;
92 function SCV = getSCV(self)
94 % Get the squared coefficient of variation of the distribution (SCV = variance / mean^2)
95 if length(self.params) == 2
98 SCV = map_scv({diag(-mu)+diag(mu(1:end-1).*(1-phi(1:end-1)),1),[phi.*mu,zeros(length(mu),length(mu)-1)]});
100 mu1 = self.getParam(1).paramValue;
101 mu2 = self.getParam(2).paramValue;
102 phi1 = self.getParam(3).paramValue;
103 mean = 1/mu1 + (1-phi1)/mu2;
104 var = ((2*mu2*(mu1 - mu1*phi1))/(mu1 + mu2 - mu1*phi1) + (2*mu1*mu2*phi1)/(mu1 + mu2 - mu1*phi1))/(mu1*mu1*((mu2*(mu1 - mu1*phi1))/(mu1 + mu2 - mu1*phi1) + (mu1*mu2*phi1)/(mu1 + mu2 - mu1*phi1))) - (1/mu1 - (phi1 - 1)/mu2)*(1/mu1 - (phi1 - 1)/mu2) - (((phi1 - 1)/(mu2*mu2) + (phi1 - 1)/(mu1*mu2))*((2*mu2*(mu1 - mu1*phi1))/(mu1 + mu2 - mu1*phi1) + (2*mu1*mu2*phi1)/(mu1 + mu2 - mu1*phi1)))/((mu2*(mu1 - mu1*phi1))/(mu1 + mu2 - mu1*phi1) + (mu1*mu2*phi1)/(mu1 + mu2 - mu1*phi1));
109 function mu = getMu(self)
111 % Get vector of rates
112 if length(self.params) == 2
113 mu = self.getParam(1).paramValue(:);
115 mu1 = self.getParam(1).paramValue;
116 mu2 = self.getParam(2).paramValue;
121 function phi = getPhi(self)
123 % Get vector of completion probabilities
124 if length(self.params) == 2
125 phi = self.getParam(2).paramValue(:);
127 phi1 = self.getParam(3).paramValue;
135 function cx = fitCentral(MEAN, VAR, SKEW)
136 % CX = FITCENTRAL(MEAN, VAR, SKEW)
137 cx = Cox2.fitCentral(MEAN, VAR, SKEW);
139 if abs(1-map_scv(cx.getProcess)/SCV) > 0.01
140 cx = Coxian.fitMeanAndSCV(MEAN, SCV);
142 cx.immediate = MEAN < GlobalConstants.CoarseTol;
145 function [cx,mu,phi] = fitMeanAndSCV(MEAN, SCV)
146 % [CX,MU,PHI] = FITMEANANDSCV(MEAN, SCV)
147 % Fit a Coxian distribution with given mean and squared coefficient of variation (SCV=variance/mean^2)
148 if SCV >= 1-GlobalConstants.CoarseTol && SCV <= 1+GlobalConstants.CoarseTol
152 elseif SCV > 0.5+GlobalConstants.CoarseTol && SCV<1-GlobalConstants.CoarseTol
156 mu(1) = 2/MEAN/(1+sqrt(1+2*(SCV-1)));
157 mu(2) = 2/MEAN/(1-sqrt(1+2*(SCV-1)));
158 elseif SCV <= 0.5+GlobalConstants.CoarseTol
161 mu = lambda*ones(n,1);
163 else % SCV > 1+GlobalConstants.CoarseTol
165 %transform hyperexp into coxian
168 mu(2) = mu(1)/( 2*SCV );
170 phi(1) = 1-mu(2)/mu(1);
175 cx.immediate = MEAN < GlobalConstants.CoarseTol;