1classdef MarkovProcess < Process
2 % A
class for a continuous time Markov chain
4 % Copyright (c) 2012-2026, Imperial College London
14 function self = MarkovProcess(InfGen, isFinite, stateSpace)
15 % SELF = MARKOVPROCESS(InfGen, isInfinite, stateSpace)
16 self@Process(
'MarkovProcess', 1);
18 self.infGen = ctmc_makeinfgen(InfGen);
22 self.isfinite = isFinite;
25 self.stateSpace = stateSpace;
31 function A=toMarkovChain(self, q)
33 q=(max(max(abs(self.infGen))))+rand;
35 P=self.infGen/q + eye(size(self.infGen));
37 A.setStateSpace(self.stateSpace);
40 function A=toDTMC(self, q)
41 % TODTMC - Alias
for toMarkovChain
for backwards compatibility
43 A = self.toMarkovChain();
45 A = self.toMarkovChain(q);
49 function Qp = toTimeReversed(self)
50 Qp = MarkovProcess(ctmc_timereverse(self.infGen));
53 function setStateSpace(self,stateSpace)
54 self.stateSpace = stateSpace;
58 G = digraph(self.infGen-diag(diag(self.infGen)));
60 if ~isempty(self.stateSpace)
61 for s=1:size(self.stateSpace,1)
62 if size(self.stateSpace,2)>1
63 nodeLbl{s} = sprintf(
'%s%d', sprintf(
'%d,', self.stateSpace(s,1:end-1)), self.stateSpace(s,end));
65 nodeLbl{s} = sprintf(
'%d', self.stateSpace(s,end));
69 Q0 = self.infGen - diag(diag(self.infGen));
72 if ~isempty(self.stateSpace)
74 edgeLbl{end+1,1} = nodeLbl{I(t)};
75 edgeLbl{end,2} = nodeLbl{J(t)};
76 edgeLbl{end,3} = strrep(strrep(sprintf(
'%.4f',q(t)),
'000',
''),
'00',
'');
80 edgeLbl{end+1,1} = num2str(I(t));
81 edgeLbl{end,2} = num2str(J(t));
82 edgeLbl{end,3} = strrep(strrep(sprintf(
'%.4f',q(t)),
'000',
''),
'00',
'');
85 h = plot(G,
'Layout',
'force3',
'NodeLabel',nodeLbl,
'EdgeLabel',edgeLbl(:,3));
90 line_error(mfilename,'CTMC.plot does not support symbolic CTMCs.');
92 G = digraph(self.infGen-diag(diag(self.infGen)));
94 if ~isempty(self.stateSpace)
95 if iscell(self.stateSpace)
96 for s=1:size(self.stateSpace,1)
97 nodeLbl{s} = self.stateSpace{s};
100 for s=1:size(self.stateSpace,1)
101 if size(self.stateSpace,2)>1
102 nodeLbl{s} = sprintf(
'%s%d', sprintf(
'%d,', self.stateSpace(s,1:end-1)), self.stateSpace(s,end));
104 nodeLbl{s} = sprintf(
'%d', self.stateSpace(s,end));
109 Q0 = self.infGen - diag(diag(self.infGen));
111 [~,sortIdx] = sortrows([I,J]);
116 if ~isempty(self.stateSpace)
118 edgeLbl{end+1,1} = nodeLbl{I(t)};
119 edgeLbl{end,2} = nodeLbl{J(t)};
120 edgeLbl{end,3} = strrep(strrep(sprintf(
'%.4f',q(t)),
'000',
''),
'00',
'');
124 edgeLbl{end+1,1} = num2str(I(t));
125 edgeLbl{end,2} = num2str(J(t));
126 edgeLbl{end,3} = strrep(strrep(sprintf(
'%.4f',q(t)),
'000',
''),
'00',
'');
129 %
if length(nodeLbl) <= 6
130 % colors = cell(1,length(nodeLbl));
for i=1:length(nodeLbl), colors{i}=
'w'; end
131 % graphViz4Matlab(
'-adjMat',Q0,
'-nodeColors',colors,
'-nodeLabels',nodeLbl,
'-edgeLabels',edgeLbl,
'-layout',Circularlayout);
133 % graphViz4Matlab(
'-adjMat',Q0,
'-nodeLabels',nodeLbl,
'-edgeLabels',edgeLbl,
'-layout',Springlayout);
135 h = plot(G,
'Layout',
'force',
'NodeLabel',nodeLbl,
'EdgeLabel',edgeLbl(:,3));
138 function Q = getGenerator(self)
145 function [pi_i, num, den] = getProbState(self, state)
146 % Use Cramer
's rule to compute the probability of a single
148 i = matchrow(self.stateSpace, state);
149 Q = self.infGen; Q(:,1)=1;
150 Q_i=Q; Q_i(i,:)=0; Q_i(i,1)=1;
154 pi_i=simplify(num/den);
158 function pi = solve(self)
159 if issym(self.infGen)
160 pi = ctmc_solve(self.infGen);
162 pi = ctmc_solve_reducible(self.infGen);
166 function X = sample(self)
167 X = ctmc_sample(self.infGen,1);
173 function ctmcObj=rand(nStates) % creates a random CTMC
174 ctmcObj = MarkovProcess(ctmc_rand(nStates));
177 function ctmcObj=fromSampleSysAggr(sa)
179 sampleState = sa.state{1};
180 for r=2:length(sa.state)
181 sampleState = State.cartesian(sampleState, sa.state{r});
183 [stateSpace,~,stateHash] = unique(sampleState,'rows
');
184 dtmc = spalloc(length(stateSpace),length(stateSpace),length(stateSpace)); % assume O(n) elements with n states
185 holdTime = zeros(length(stateSpace),1);
186 for i=2:length(stateHash)
187 if isempty(dtmc(stateHash(i-1),stateHash(i)))
188 dtmc(stateHash(i-1),stateHash(i)) = 0;
190 dtmc(stateHash(i-1),stateHash(i)) = dtmc(stateHash(i-1),stateHash(i)) + 1;
191 holdTime(stateHash(i-1)) = holdTime(stateHash(i-1)) + sa.t(i) - sa.t(i-1);
193 % at this point, dtmc has absolute counts so not yet normalized
194 holdTime = holdTime ./ sum(dtmc,2);
195 infGen = ctmc_makeinfgen(dtmc_makestochastic(dtmc)./(holdTime*ones(1,length(stateSpace))));
196 ctmcObj = MarkovProcess(infGen,isFinite,stateSpace);