1% B = TransformToMonocyclic(A, maxSize, precision)
3% Transforms an arbitrary matrix to a Markovian monocyclic
8% A : matrix, shape (N,N)
9% Matrix parameter of the initial representation
10% maxSize : int, optional
11% The maximal order of the resulting Markovian
12% representation. The
default value
is 100
13% precision : double, optional
14% Matrix entries smaller than the precision are
15% considered to be zeros. The
default value
is 1e-14
19% B : matrix, shape (M,M)
20% Transient generator matrix of the Markovian monocyclic
21% representation. Note that M>N
if there are complex
26% Raises an exception
if no Markovian monocyclic generator
27% has been found up to the given size.
31% .. [1] Mocanu, S., Commault, C.:
"Sparse representations
32% of phase-type distributions," Stoch. Models 15,
35function B = TransformToMonocyclic (A, maxSize, precision)
37 if ~exist(
'precision',
'var')
41 if ~exist(
'maxSize',
'var')
45 function [evalues, repeats] = eigvalc(A)
46 % eigval Eigenvalues and their algebraic multiplicity.
48 % evalues = eigval(A) returns the distinct eigenvalues of A,
49 % with duplicates removed and sorted in increasing order.
51 % [evalues, repeats] = eigval(A) also returns the row vector
52 % repeats that gives the multiplicity of each eigenvalue.
53 % The sum of the multiplicities
is n.
55 % Examples: Let A = eye(n) and B = diag([3 4]).
56 % For A, evalues
is 1 and repeats
is n.
57 % For B, evalues
is [4; 3] and repeats
is [1 1].
60 lambda = sort(eig(A));
61 lambda = round(lambda/tol) * tol;
63 % lambda gives all n eigenvalues (repetitions included).
65 evalues = unique(lambda);
68 A = ones(n, 1) * evalues';
69 B = lambda * ones(1, d);
70 MATCH = abs(A-B) <= tol;
72 % MATCH
is an n by d zero matrix except
73 % MATCH(i,j) = 1 when lambda(i) = evalues(j).
74 % Summing the columns gives the row vector repeats.
79 function febs = generateFEBs (A, evalues, repeats, maxSize, precision)
80 % calculate the parameters of the febs
85 while i<=length(evalues)
87 evalimag = -abs(imag(evalues(i)));
88 if -evalimag < precision
90 sigma = -real(evalues(i));
92 ev = real(evalues(i));
98 while evalimag / real(evalues(i)) >= cot(pi/n)
102 error ('The represetation
is too large (>maxSize). No result returned.');
105 sigma = -(2*real(evalues(i)) + evalimag*(cot(pi/n) - tan(pi/n))) / 2;
106 z = (-evalimag*(cot(pi/n) + tan(pi/n)) / (2*sigma))^n;
109 ev = [ev; complex(-(1-z^(1/n)*cos(2*(k-1)*pi/n))*sigma,z^(1/n)*sin(2*(k-1)*pi/n)*sigma)];
114 febs(ix).lambda = sigma;
117 febs(ix).multip = multip;
121 if -evalimag < precision
129 % ordering according to the dominant eigenvalue (simple bubble sort)
133 if max(febs(j).evals) < max(febs(j+1).evals)
142 function A = febGenerator (lambda, z, n, multip)
145 lv = ones(1,n)*lambda;
146 A((ii-1)*n+1:ii*n, (ii-1)*n+1:ii*n) = -diag(lv) + diag(lv(1:n-1),1);
147 A(ii*n,(ii-1)*n+1) = A(ii*n,(ii-1)*n+1) + z * lambda;
149 A(ii*n,ii*n+1) = (1-z)*lambda;
154 % determine eigenvalues and their multiplicities
155 [evalues, repeats] = eigvalc(A);
157 % build monocyclic representation
158 febs = generateFEBs (A, evalues, repeats, maxSize, precision);
160 % assemble generator matrix of the hyper-feb
164 Ni = febs(i).n*febs(i).multip;
165 B(pos:pos+Ni-1,pos:pos+Ni-1) = febGenerator (febs(i).lambda, febs(i).z, febs(i).n, febs(i).multip);
167 B(pos+Ni-1, pos+Ni) = -sum(B(pos+Ni-1,:));