diff mftoolbox/rootpm_real.m @ 0:8f23314345f4 draft

Create local repository for matrix toolboxes. Step #0 done.
author Antonio Pino Robles <data.script93@gmail.com>
date Wed, 06 May 2015 14:56:53 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mftoolbox/rootpm_real.m	Wed May 06 14:56:53 2015 +0200
@@ -0,0 +1,99 @@
+function X = rootpm_real(A,p)
+%ROOTPM_REAL  Pth root of real matrix via real Schur form.
+%   X = ROOTPM_REAL(A,P) is a Pth root of the nonsingular matrix A
+%   (A = X^P).  When A has no eigenvalues on the negative real axis
+%   then X is the principal pth root, which is real when A is real.
+
+%   Implementation is complicated by use of zero (and even "-1")
+%   subscripts in algorithm.  Dealt with by increasing "k" by 1
+%   each time and moving "-1" cases in front of loops.
+
+if norm(imag(A),1), error('A must be real.'), end
+if p == 1, X = A; return; end
+
+n = length(A);
+[Q,R] = schur(A,'real');
+
+% m blocks: i'th has order s(i), starts at t(i).
+[m,s,t] = quasitriang_struct(R);
+U = zeros(n); B = cell(p); V = cell(p-1);
+V{1} = eye(n);  % U^k == V{k+1}.
+
+for j=1:m
+    rj = t(j):t(j)+s(j)-1;
+    if s(j) == 1
+       % If A is real, X will be real unless R(p,p)<0 on the next line.
+       U(rj,rj) = R(rj,rj)^(1/p);
+    else
+       U(rj,rj) = root_block(R(rj,rj),p);
+    end
+    for k = 0:p-2, kk = k+1; V{kk}(rj,rj) = U(rj,rj)^(k+1); end
+    for i=j-1:-1:1
+        ri = t(i):t(i)+s(i)-1;
+        for k = 0:p-2
+            kk = k+1;
+            B{kk} = zeros(s(i),s(j));
+            for ell = i+1:j-1
+                rell = t(ell):t(ell)+s(ell)-1;
+                B{kk} = B{kk} + U(ri,rell)*V{kk}(rell,rj);
+            end
+        end
+        rhs = R(ri,rj) - B{p-2 +1};
+        for k = 0:p-3
+            rhs = rhs - V{p-3-k +1}(ri,ri)*B{k+1};
+        end
+        coeff = kron( eye(s(j)), V{p-2 +1}(ri,ri) ) ...
+               + kron( V{p-2 +1}(rj,rj).', eye(s(i)) );
+        for k = 1:p-2
+            coeff = coeff + kron( V{k-1 +1}(rj,rj).', V{p-2-k +1}(ri,ri) );
+        end
+        y = coeff\rhs(:);
+        rhs(:) = y;                  % `Un-vec' the solution.
+        U(ri,rj) = rhs;
+        for k = 0:p-2
+            if k == 0
+               S = U(ri,rj);
+            else
+               S = V{k-1 +1}(ri,ri)*U(ri,rj) + U(ri,rj)*V{k-1 +1}(rj,rj) ...
+                   + B{k-1 +1};
+               for ell = 1:k-1
+                   S = S + V{k-ell-1 +1}(ri,ri)*U(ri,rj)*V{ell-1 +1}(rj,rj);
+               end
+               for ell = 0:k-2
+                   S = S + V{k-2-ell +1}(ri,ri)*B{ell +1};
+               end
+            end
+            V{k+1}(ri,rj) = S;
+        end
+   end
+end
+
+X = Q*U*Q';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function X = root_block(R,p)
+%ROOT_BLOCK  Pth root of a real 2x2 matrix with complex conjugate eigenvalues.
+
+if norm(imag(R)) ~= 0 || any(size(R) - [2,2])
+   error('Matrix must be real, of dimension 2.')
+end
+
+r11 = R(1,1); r12 = R(1,2);
+r21 = R(2,1); r22 = R(2,2);
+
+theta = (r11 + r22) / 2;
+musq = (-(r11 - r22)^2 - 4*r21*r12) / 4;
+mu = sqrt(musq);
+
+if musq <= 0
+   error('Matrix must have non-real complex conjugate eigenvalues.')
+end
+
+r = sqrt(theta^2+musq);
+phi = angle(complex(theta,mu));
+rootp = r^(1/p)*exp(i*phi/p);
+
+alpha = real(rootp);
+beta = imag(rootp);
+
+X = alpha*eye(2) + (beta/mu)*(R - theta*eye(2));