LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
MarkovProcess.m
1classdef MarkovProcess < Process
2 % A class for a continuous time Markov chain
3 %
4 % Copyright (c) 2012-2026, Imperial College London
5 % All rights reserved.
6
7 properties
8 infGen;
9 stateSpace;
10 isfinite;
11 end
12
13 methods
14 function self = MarkovProcess(InfGen, isFinite, stateSpace)
15 % SELF = MARKOVPROCESS(InfGen, isInfinite, stateSpace)
16 self@Process('MarkovProcess', 1);
17
18 self.infGen = ctmc_makeinfgen(InfGen);
19 if nargin < 2
20 self.isfinite = true;
21 else
22 self.isfinite = isFinite;
23 end
24 if nargin > 2
25 self.stateSpace = stateSpace;
26 else
27 self.stateSpace = [];
28 end
29 end
30
31 function A=toMarkovChain(self, q)
32 if nargin==1
33 q=(max(max(abs(self.infGen))))+rand;
34 end
35 P=self.infGen/q + eye(size(self.infGen));
36 A=MarkovChain(P);
37 A.setStateSpace(self.stateSpace);
38 end
39
40 function A=toDTMC(self, q)
41 % TODTMC - Alias for toMarkovChain for backwards compatibility
42 if nargin==1
43 A = self.toMarkovChain();
44 else
45 A = self.toMarkovChain(q);
46 end
47 end
48
49 function Qp = toTimeReversed(self)
50 Qp = MarkovProcess(ctmc_timereverse(self.infGen));
51 end
52
53 function setStateSpace(self,stateSpace)
54 self.stateSpace = stateSpace;
55 end
56
57 function plot3(self)
58 G = digraph(self.infGen-diag(diag(self.infGen)));
59 nodeLbl = {};
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));
64 else
65 nodeLbl{s} = sprintf('%d', self.stateSpace(s,end));
66 end
67 end
68 end
69 Q0 = self.infGen - diag(diag(self.infGen));
70 [I,J,q]=find(Q0);
71 edgeLbl = {};
72 if ~isempty(self.stateSpace)
73 for t=1:length(I)
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','');
77 end
78 else
79 for t=1:length(I)
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','');
83 end
84 end
85 h = plot(G,'Layout','force3','NodeLabel',nodeLbl,'EdgeLabel',edgeLbl(:,3));
86 end
87
88 function plot(self)
89 if issym(self.infGen)
90 line_error(mfilename,'CTMC.plot does not support symbolic CTMCs.');
91 end
92 G = digraph(self.infGen-diag(diag(self.infGen)));
93 nodeLbl = {};
94 if ~isempty(self.stateSpace)
95 if iscell(self.stateSpace)
96 for s=1:size(self.stateSpace,1)
97 nodeLbl{s} = self.stateSpace{s};
98 end
99 else
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));
103 else
104 nodeLbl{s} = sprintf('%d', self.stateSpace(s,end));
105 end
106 end
107 end
108 end
109 Q0 = self.infGen - diag(diag(self.infGen));
110 [I,J,q]=find(Q0);
111 [~,sortIdx] = sortrows([I,J]);
112 I=I(sortIdx);
113 J=J(sortIdx);
114 q=q(sortIdx);
115 edgeLbl = {};
116 if ~isempty(self.stateSpace)
117 for t=1:length(I)
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','');
121 end
122 else
123 for t=1:length(I)
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','');
127 end
128 end
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);
132 % else
133 % graphViz4Matlab('-adjMat',Q0,'-nodeLabels',nodeLbl,'-edgeLabels',edgeLbl,'-layout',Springlayout);
134 % end
135 h = plot(G,'Layout','force','NodeLabel',nodeLbl,'EdgeLabel',edgeLbl(:,3));
136 end
137
138 function Q = getGenerator(self)
139 % Q = GETGENERATOR()
140
141 % Get generator
142 Q = self.infGen;
143 end
144
145 function [pi_i, num, den] = getProbState(self, state)
146 % Use Cramer's rule to compute the probability of a single
147 % state
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;
151 num=det(Q_i);
152 den=det(Q);
153 if issym(Q)
154 pi_i=simplify(num/den);
155 end
156 end
157
158 function pi = solve(self)
159 if issym(self.infGen)
160 pi = ctmc_solve(self.infGen);
161 else
162 pi = ctmc_solve_reducible(self.infGen);
163 end
164 end
165
166 function X = sample(self)
167 X = ctmc_sample(self.infGen,1);
168 end
169
170 end
171
172 methods (Static)
173 function ctmcObj=rand(nStates) % creates a random CTMC
174 ctmcObj = MarkovProcess(ctmc_rand(nStates));
175 end
176
177 function ctmcObj=fromSampleSysAggr(sa)
178 isFinite = true;
179 sampleState = sa.state{1};
180 for r=2:length(sa.state)
181 sampleState = State.cartesian(sampleState, sa.state{r});
182 end
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;
189 end
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);
192 end
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);
197 end
198 end
199end