1function [MAP, logL] = erchmm_emfit(trace, orders, iter_max, iter_tol, verbose)
3% The procedure that we use
is based off the algorithms detailed in the following references:
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:
8% Horvath, G. & Okamura, H. (2013). A Fast EM algorithm for Fitting Marked Markov Arrival Processes with a new Special Structure.
10% Horvath, G. et al. (2018). Parallel Algorithms for Fitting Markov Arrival Processes. Preprint Submitted to Elsevier.
12% This algorithm was inspired and adapted from from the BUTools implementation, accessible at:
15 %% define the conditions initially that we apply to EM-algorithm. Could put these inside function.
21 iter_tol = 1e-7; % stop condition on the iterations
24 %% If we want to show the progress
29 %% Define a function that finds all the combinations of orders of Erlang branches from value of orders.
31 function erlangs = all_erlang(branches, sum_erlangs)
32 % Define a
case for when we only have 1 branch.
34 erlangs={sum_erlangs};
36 % initiate set of erlangs
38 % create
for loop to create all combinations of erlang orders
40 for k1=1:sum_erlangs-branches+1
41 x = all_erlang (branches-1, sum_erlangs-k1);
43 sorted_erlangs = sort([x{j} k1]);
44 % check
if we have the sorted erlang branch already
46 for erl=1:length(erlangs)
47 if erlangs{erl}==sorted_erlangs
52 % Define condition fro when we add the erlang order to
55 erlangs{length(erlangs)+1}=sorted_erlangs;
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));
72%% Define process that runs the algorithm with lots of different orders. We then choose the algorithm with the best logli function.
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'.
78 % Set parameters that we will populate as empty.
82 % Set log_li_best as -inf as initial value.
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.
89 fprintf(
'Calculating with orders ');
90 print_erlang_number(all_orders{ord_num_2});
93 % Recursive part of EM-Algorithm. Call the function again
94 % to see
if new choice of orders
is better than the
96 [ordMAP,l] = erchmm_emfit(trace, all_orders{ord_num_2}, iter_max, iter_tol, verbose);
103 orders_best = all_orders{ord_num_2};
107 % Define D0, D1 and print the best log-likelihood
111 % print results to the terminal
113 fprintf(
'Best solution: log-likelihood=%g, orders=', log_li_best);
114 print_erlang_number(orders_best);
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));
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);
131 % Define lengths of orders and length of trace.
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));
141 lambda = lambda * pi_mean / trace_mean;
142 % initialize the transition vector
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.
153 % initialise number of steps and the time so we know both when we run
157 %% Start of the Main Algorithm
158 while abs((ologli-logL)/logL)>iter_tol && steps<iter_max
161 %% Compute the branch densities:
163 F(i,:) = ((lambda(i)*trace).^(orders(i)-1) / factorial(orders(i)-1) * lambda(i)) .* exp(-lambda(i)*trace);
165 %% Compute the forward likelihood vectors:
166 % update the pi value and initialize scale value
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);
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:
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);
190 b_backward_likelihoods = [B_likelihoods(:,2:end), ones(M,1)];
191 B_scale_v = [B_likelihoods_scale(2:end), 0];
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;
199 % Calculate new estimates for the parameters lambda and transition
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
207 likelihoods_multiplied(:,m) = likelihoods_multiplied(:,m)./summed_lm;
209 % Compute the numerator and the denominator
for the lambda
210 % estimations as well as p_{i,j} estimations
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)';
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))';
222 dens_mult_a_likelihood(:,m) = dens_mult_a_likelihood(:,m) .* summed_lm;
224 % Compute the matrix T.
225 T = (dens_mult_a_likelihood
'*b_backward_likelihoods').*T;
228 T(m,:) = T(m,:) / sum(T(m,:));
231 % Show increase in step
if you want
233 % Print progress report
234 if verbose && etime(clock(),t1)>2
235 fprintf(
'Num of iterations: %d, log-likelihood: %g\n', steps, logL);
240 %% Show Progress
if needed
242 fprintf(
'Num of iterations: %d, log-likelihood: %g\n', steps, logL);
243 fprintf(
'EM algorithm terminated. (orders=');
245 fprintf(
'%g',orders(i));
254 %% Finalize formulation of D0 and D1 matrices
256 % Generate the matrix D0 from lambda and the orders
257 D0 = generate_D0_from_erlangs(lambda, orders);
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;