LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
erchmm_emfit.m
1function [MAP, logL] = erchmm_emfit(trace, orders, iter_max, iter_tol, verbose)
2
3% The procedure that we use is based off the algorithms detailed in the following references:
4
5% Okamura, H. et al. (2008). An EM algorithm for a Superposition of Markovian Arrival Processes. Department of Information Engineering, Graduate School of Engineering,
6% Hiroshima University, Japan. Accessible at: http://www.kurims.kyoto-u.ac.jp/~kyodo/kokyuroku/contents/pdf/1589-28.pdf.
7
8% Horvath, G. & Okamura, H. (2013). A Fast EM algorithm for Fitting Marked Markov Arrival Processes with a new Special Structure.
9
10% Horvath, G. et al. (2018). Parallel Algorithms for Fitting Markov Arrival Processes. Preprint Submitted to Elsevier.
11
12% This algorithm was inspired and adapted from from the BUTools implementation, accessible at:
13% http://webspn.hit.bme.hu/~telek/tools/butools/doc/MAPFromTrace.html
14
15 %% define the conditions initially that we apply to EM-algorithm. Could put these inside function.
16
17 if nargin< 3
18 iter_max = 300;
19 end
20 if nargin< 4
21 iter_tol = 1e-7; % stop condition on the iterations
22 end
23
24 %% If we want to show the progress
25 if nargin<5
26 verbose = true;
27 end
28
29 %% Define a function that finds all the combinations of orders of Erlang branches from value of orders.
30
31 function erlangs = all_erlang(branches, sum_erlangs)
32 % Define a case for when we only have 1 branch.
33 if branches==1
34 erlangs={sum_erlangs};
35 else
36 % initiate set of erlangs
37 erlangs = {};
38 % create for loop to create all combinations of erlang orders
39 % for each branch.
40 for k1=1:sum_erlangs-branches+1
41 x = all_erlang (branches-1, sum_erlangs-k1);
42 for j=1:length(x)
43 sorted_erlangs = sort([x{j} k1]);
44 % check if we have the sorted erlang branch already
45 erlang_found=false;
46 for erl=1:length(erlangs)
47 if erlangs{erl}==sorted_erlangs
48 erlang_found=true;
49 break;
50 end
51 end
52 % Define condition fro when we add the erlang order to
53 % the set.
54 if ~erlang_found
55 erlangs{length(erlangs)+1}=sorted_erlangs;
56 end
57 end
58 end
59 end
60 end
61
62 %% Define a functiion to print the different Erlang numbers for when we run the algorithm.
63 function print_erlang_number(num)
64 for index=1:length(num)
65 fprintf('%g',num(index));
66 if index<length(num)
67 fprintf(',');
68 end
69 end
70 end
71
72%% Define process that runs the algorithm with lots of different orders. We then choose the algorithm with the best logli function.
73
74 % When we do the first run through we choose this method to give the
75 % different combinations of orders from the sum defined by 'orders'.
76
77 if length(orders)==1
78 % Set parameters that we will populate as empty.
79 X_chosen = [];
80 Y_chosen = [];
81 orders_best = [];
82 % Set log_li_best as -inf as initial value.
83 log_li_best = -inf;
84 for ord_num_1=2:orders
85 all_orders = all_erlang(ord_num_1, orders);
86 for ord_num_2=1:length(all_orders)
87 % Print the progress of choosing orders so we know.
88 if verbose
89 fprintf('Calculating with orders ');
90 print_erlang_number(all_orders{ord_num_2});
91 fprintf('...\n');
92 end
93 % Recursive part of EM-Algorithm. Call the function again
94 % to see if new choice of orders is better than the
95 % previous choice.
96 [ordMAP,l] = erchmm_emfit(trace, all_orders{ord_num_2}, iter_max, iter_tol, verbose);
97 ord_X=ordMAP{1};
98 ord_Y=ordMAP{1};
99 if l > log_li_best
100 X_chosen = ord_X;
101 Y_chosen = ord_Y;
102 log_li_best = l;
103 orders_best = all_orders{ord_num_2};
104 end
105 end
106 end
107 % Define D0, D1 and print the best log-likelihood
108 D0 = X_chosen;
109 D1 = Y_chosen;
110 logL = log_li_best;
111 % print results to the terminal
112 if verbose
113 fprintf('Best solution: log-likelihood=%g, orders=', log_li_best);
114 print_erlang_number(orders_best);
115 fprintf('\n');
116 end
117 MAP = {D0, D1};
118 return;
119 end
120
121 %% Define a function to find the matrix D0 from the Erlang Representation
122 function X = generate_D0_from_erlangs(lambda_init, orders_init)
123 X = zeros(sum(orders_init));
124 init_x = 1;
125 for lambda_i=1:length(lambda_init)
126 X(init_x:init_x+orders_init(lambda_i)-1, init_x:init_x+orders_init(lambda_i)-1) = lambda_init(lambda_i)*(diag(ones(1,orders_init(lambda_i)-1),1)-diag(ones(1,orders_init(lambda_i))));
127 init_x = init_x + orders_init(lambda_i);
128 end
129 end
130
131 % Define lengths of orders and length of trace.
132 M = length(orders);
133 K = length(trace);
134
135 % initialize pi and lambda parameters such that the mean is matched
136 pi_v = ones(1,M) / M;
137 lambda = diag(orders) * (1:M)';
138 trace_mean = sum(trace)/length(trace);
139 pi_mean = sum(pi_v ./ (1:M));
140 % Match the mean
141 lambda = lambda * pi_mean / trace_mean;
142 % initialize the transition vector
143 T = ones(M,1)*pi_v;
144
145 % Initialize the parameters that we will use in the main EM-algorithm
146 F = zeros(M, K); % Matrix for Densities
147 A_likelihoods = zeros(K, M); % Matrix for forward likelihoods
148 B_likelihoods = zeros(M, K); % Matrix for backward likelihoods
149 A_likelihoods_scale = zeros(1,K); % Vector to scale f. likelihoods.
150 B_likelihoods_scale = zeros(1,K); % Vector to scale b. likelihoods.
151 ologli = 1;
152 logL = 0;
153 % initialise number of steps and the time so we know both when we run
154 % the algorithm.
155 steps = 1;
156 t1 = clock();
157 %% Start of the Main Algorithm
158 while abs((ologli-logL)/logL)>iter_tol && steps<iter_max
159 ologli = logL;
160 % E-step:
161 %% Compute the branch densities:
162 for i=1:M
163 F(i,:) = ((lambda(i)*trace).^(orders(i)-1) / factorial(orders(i)-1) * lambda(i)) .* exp(-lambda(i)*trace);
164 end
165 %% Compute the forward likelihood vectors:
166 % update the pi value and initialize scale value
167 prev_pi = pi_v;
168 scaled_prev = 0;
169 for k=1:K
170 prev_pi = prev_pi*diag(F(:,k))*T;
171 scale = log2(sum(prev_pi));
172 prev_pi = prev_pi * 2^-scale;
173 A_likelihoods_scale(k) = scaled_prev + scale;
174 A_likelihoods(k,:) = prev_pi;
175 scaled_prev = A_likelihoods_scale(k);
176 end
177 a_forward_likelihoods = [pi_v; A_likelihoods(1:end-1,:)];
178 A_scaled_v = [0, A_likelihoods_scale(1:end-1)];
179 %% compute the backward likelihood vectors:
180 next_b = ones(M,1);
181 scaled_prev = 0;
182 for k=K:-1:1
183 next_b = diag(F(:,k))*T*next_b;
184 scale = log2(sum(next_b));
185 next_b = next_b * 2^-scale;
186 B_likelihoods_scale(k) = scaled_prev + scale;
187 B_likelihoods(:,k) = next_b;
188 scaled_prev = B_likelihoods_scale(k);
189 end
190 b_backward_likelihoods = [B_likelihoods(:,2:end), ones(M,1)];
191 B_scale_v = [B_likelihoods_scale(2:end), 0];
192
193 likelihood_value = pi_v*B_likelihoods(:,1);
194 logL = (log(likelihood_value) + B_likelihoods_scale(1) * log(2)) / K;
195 i_likelihood = 1.0 / likelihood_value;
196
197 %% M-step:
198
199 % Calculate new estimates for the parameters lambda and transition
200 % matrix T.
201
202 likelihoods_multiplied = a_forward_likelihoods.*B_likelihoods';
203 summed_lm = sum(likelihoods_multiplied,2);
204 % Multiply the a[k] and b[k] vectors for the lambda and T
205 % estimations.
206 for m=1:M
207 likelihoods_multiplied(:,m) = likelihoods_multiplied(:,m)./summed_lm;
208 end
209 % Compute the numerator and the denominator for the lambda
210 % estimations as well as p_{i,j} estimations
211
212 numerator_estimation = sum(likelihoods_multiplied,1);
213 denominator_estimation = trace'*likelihoods_multiplied;
214 pi_v = numerator_estimation/K;
215 lambda = (orders.*numerator_estimation ./ denominator_estimation)';
216
217 % Compute multiplication of forward likelihood and densities
218 dens_mult_a_likelihood = a_forward_likelihoods.*F';
219 % Find summed lambda values for estimation of T.
220 summed_lm = i_likelihood*2.^(A_scaled_v+B_scale_v-B_likelihoods_scale(1))';
221 for m=1:M
222 dens_mult_a_likelihood(:,m) = dens_mult_a_likelihood(:,m) .* summed_lm;
223 end
224 % Compute the matrix T.
225 T = (dens_mult_a_likelihood'*b_backward_likelihoods').*T;
226 % Normalize it
227 for m=1:M
228 T(m,:) = T(m,:) / sum(T(m,:));
229 end
230
231 % Show increase in step if you want
232 steps = steps+1;
233 % Print progress report
234 if verbose && etime(clock(),t1)>2
235 fprintf('Num of iterations: %d, log-likelihood: %g\n', steps, logL);
236 t1 = clock();
237 end
238 end
239
240 %% Show Progress if needed
241 if verbose
242 fprintf('Num of iterations: %d, log-likelihood: %g\n', steps, logL);
243 fprintf('EM algorithm terminated. (orders=');
244 for i=1:M
245 fprintf('%g',orders(i));
246 if i<M
247 fprintf(',');
248 else
249 fprintf(')\n');
250 end
251 end
252 end
253
254 %% Finalize formulation of D0 and D1 matrices
255
256 % Generate the matrix D0 from lambda and the orders
257 D0 = generate_D0_from_erlangs(lambda, orders);
258 % initialize D1 size
259 D1 = zeros(size(D0));
260 % Find indices that we will populate for D1 estimation
261 indicesTo = [1 cumsum(orders(1:end-1))+1];
262 indicesFrom = cumsum(orders);
263 % Use diagonal of lambda and the T matrix values
264 D1(indicesFrom,indicesTo) = diag(lambda)*T;
265 MAP = {D0, D1};
266end