Finding generalized eigenvectors numerically in Matlab - matlab

I have a matrix such as this example (my actual matrices can be much larger)
A = [-1 -2 -0.5;
0 0.5 0;
0 0 -1];
that has only two linearly-independent eigenvalues (the eigenvalue -1 is repeated). I would like to obtain a complete basis with generalized eigenvectors. One way I know how to do this is with Matlab's jordan function in the Symbolic Math toolbox, but I'd prefer something designed for numeric inputs (indeed, with two outputs, jordan fails for large matrices: "Error in MuPAD command: Similarity matrix too large."). I don't need the Jordan canonical form, which is notoriously unstable in numeric contexts, just a matrix of generalized eigenvectors. Is there a function or combination of functions that automates this in a numerically stable way or must one use the generic manual method (how stable is such a procedure)?
NOTE: By "generalized eigenvector," I mean a non-zero vector that can be used to augment the incomplete basis of a so-called defective matrix. I do not mean the eigenvectors that correspond to the eigenvalues obtained from solving the generalized eigenvalue problem using eig or qz (though this latter usage is quite common, I'd say that it's best avoided). Unless someone can correct me, I don't believe the two are the same.
UPDATE 1 – Five months later:
See my answer here for how to obtain generalized eigenvectors symbolically for matrices larger than 82-by-82 (the limit for my test matrix in this question).
I'm still interested in numeric schemes (or how such schemes might be unstable if they're all related to calculating the Jordan form). I don't wish to blindly implement the linear algebra 101 method that has been marked as a duplicate of this question as it's not a numerical algorithm, but rather a pencil-and paper method used to evaluate students (I suppose that it could be implemented symbolically however). If anyone can point me to either an implementation of that scheme or a numerical analysis of it, I'd be interested in that.
UPDATE 2 – Feb. 2015: All of the above is still true as tested in R2014b.

As mentioned in my comments, if your matrix is defective, but you know which eigenvectors/eigenvalue pair you want to consider as identical given your tolerance, you can proceed as with this example below:
% example matrix A:
A = [1 0 0 0 0;
3 1 0 0 0;
6 3 2 0 0;
10 6 3 2 0;
15 10 6 3 2]
% Produce eigenvalues and eigenvectors (not generalized ones)
[vecs,vals] = eig(A)
This should output:
vecs =
0 0 0 0 0.0000
0 0 0 0.2236 -0.2236
0 0 0.0000 -0.6708 0.6708
0 0.0000 -0.0000 0.6708 -0.6708
1.0000 -1.0000 1.0000 -0.2236 0.2236
vals =
2 0 0 0 0
0 2 0 0 0
0 0 2 0 0
0 0 0 1 0
0 0 0 0 1
Where we see that the first three eigenvectors are almost identical to working precision, as are the two last ones. Here, you must know the structure of your problem and identify the identical eigenvectors of identical eigenvalues. Here, eigenvalues are exactly identical, so we know which ones to consider, and we will assume that corresponding vectors 1-2-3 are identical and vectors 4-5. (In practice you will likely check the norm of the differences of eigenvectors and compare it to your tolerance)
Now we proceed to compute the generalized eigenvectors, but this is ill-conditioned to solve simply with matlab's \, because obviously (A - lambda*I) is not full rank. So we use pseudoinverses:
genvec21 = pinv(A - vals(1,1)*eye(size(A)))*vecs(:,1);
genvec22 = pinv(A - vals(1,1)*eye(size(A)))*genvec21;
genvec1 = pinv(A - vals(4,4)*eye(size(A)))*vecs(:,4);
Which should give:
genvec21 =
-0.0000
0.0000
-0.0000
0.3333
0
genvec22 =
0.0000
-0.0000
0.1111
-0.2222
0
genvec1 =
0.0745
-0.8832
1.5317
0.6298
-3.5889
Which are our other generalized eigenvectors. If we now check these to obtain the jordan normal form like this:
jordanJ = [vecs(:,1) genvec21 genvec22 vecs(:,4) genvec1];
jordanJ^-1*A*jordanJ
We obtain:
ans =
2.0000 1.0000 0.0000 -0.0000 -0.0000
0 2.0000 1.0000 -0.0000 -0.0000
0 0.0000 2.0000 0.0000 -0.0000
0 0.0000 0.0000 1.0000 1.0000
0 0.0000 0.0000 -0.0000 1.0000
Which is our Jordan normal form (with working precision errors).

Related

Normalization of inputs of a feedforward Neural network

Let's say I have a mxn matrix of different features of a time series signal (column 1 represents linear regression of the last n samples, column 2 represents the average of the last n samples, column 3 represents the local max values of a different time series but correlated signal, etc). How should I normalize these inputs? All the inputs fall into different categories, so they have a different range. One ranges from 0,1, the other ranges from -5 to 50, etc etc.
Should I normalize the WHOLE matrix? Or should I normalize each set of inputs one by one individually?
Note: I usually use mapminmax function from MATLAB for the normalization.
You should normalise each vector/column of your matrix individually, they represent different data types and shouldn't be mixed up together.
You could for example transpose your matrix to have your 3 different data types in the rows instead of in the columns of your matrix and still use mapminmax:
A = [0 0.1 -5; 0.2 0.3 50; 0.8 0.8 10; 0.7 0.9 20];
A =
0 0.1000 -5.0000
0.2000 0.3000 50.0000
0.8000 0.8000 10.0000
0.7000 0.9000 20.0000
B = mapminmax(A')
B =
-1.0000 -0.5000 1.0000 0.7500
-1.0000 -0.5000 0.7500 1.0000
-1.0000 1.0000 -0.4545 -0.0909
You should normalize each feature independently.
column 1 represents linear regression of the last n samples, column 2 represents the average of the last n samples, column 3 represents the local max values of a different time series but correlated signal, etc
I can't say for sure about your particular problem, but generally, you should normalize each feature independently. So normalize column 1, then column 2 etc.
Should I normalize the WHOLE matrix? Or should I normalize each set of inputs one by one individually?
I'm not sure what you mean here. What is an input? If by that you mean an instance (a row of your matrix), then no, you should not normalize rows individually, but columns.
I don't know how you would do this in Matlab, but I took your question more as a theoretical one than an implementation one.
If you want to have a range of [0,1] for all the columns that normalized within each column, you can use mapminmax like so (assuming A as the 2D input array) -
out = mapminmax(A.',0,1).'
You can also use bsxfun for the same output, like so -
Aoffsetted = bsxfun(#minus,A,min(A,[],1))
out = bsxfun(#rdivide,Aoffsetted,max(Aoffsetted,[],1))
Sample run -
>> A
A =
3 7 4 2 7
1 3 4 5 7
1 9 7 5 3
8 1 8 6 7
>> mapminmax(A.',0,1).'
ans =
0.28571 0.75 0 0 1
0 0.25 0 0.75 1
0 1 0.75 0.75 0
1 0 1 1 1
>> Aoffsetted = bsxfun(#minus,A,min(A,[],1));
>> bsxfun(#rdivide,Aoffsetted,max(Aoffsetted,[],1))
ans =
0.28571 0.75 0 0 1
0 0.25 0 0.75 1
0 1 0.75 0.75 0
1 0 1 1 1

Jaccard index on Matlab produces wrong results

I have the following matrix
a =
0 10 10 0 0
0 5 5 0 0
1 0 0 50 51
0 0 10 100 100
I compute the Jaccard distances
D = pdist(a,'jaccard');
D =
1.0000 1.0000 0.7500 1.0000 1.0000 1.0000
and finally I put the distances in a matrix
sim = squareform(D)
sim =
0 1.0000 1.0000 0.7500
1.0000 0 1.0000 1.0000
1.0000 1.0000 0 1.0000
0.7500 1.0000 1.0000 0
The jaccard index is computed as "One minus the Jaccard coefficient, which is the percentage of nonzero coordinates that differ." (http://www.mathworks.it/help/stats/pdist.html)
The distance between row 1 and 4 is correct (0.75), while the distance between row 1 and 2 should be 0 and is, instead, 1. It seems that when the jaccard similarity is 1, matlab doesn't execute the 1-similarity computation. What am I doing wrong?
MATLAB seems right to me.
All of the non-zero numbers in rows 1 and 2 differ (in row 1 they're all 10, in row 2 they're all 5), so rows 1 and 2 should have a distance of 1.
Three out of four of the non-zero numbers in rows 1 and 4 differ (10:0, 10:10, 0:100, 0:100), so rows 1 and 4 should have a distance of 0.75.
There seems to be a lot of disagreement about what thing is the Jaccard "coefficient", the Jaccard "index", the Jaccard "similarity" and the Jaccard "distance", and which is one minus the other. MATLAB's documentation doesn't help, as it's not obvious, in the sentence you quote, whether "which" refers to (what MATLAB is describing as) the Jaccard coefficient, or to one minus the Jaccard coefficient.
In any case, whether the terminology used by the MATLAB documentation is correct, the function pdist seems to be giving consistent results, and you can always take one minus whatever it outputs if you want something different.

MATLAB : Block diagonalize a complex antisymmetric matrix

I am using the following function to block diagonalize antisymmetric matrices.
function [R, RI , S ] = Matrix_block (A)
[U,D]= schur (A);
E=ordeig(double(D)) ;
[R, S]= ordschur (U,D, abs(E)<1000*eps ) ;
RI=R';
The code works perfectly fine for real antisymmetric matrices but fails for complex antisymmetric matrices as follows :-
a = rand(6); a = a-a'; [r,ri,s] = Matrix_block(a);
b = rand(6)+1i*rand(6); b= b-conj(b)'; [r,ri,s] = Matrix_block(b);
How can I correct my code for it to work also for complex matrices ? I want a block-diagonal matrix (of the following form) as the output for both real and complex matrices.
0 e1 -0.0000 -0.0000 0.0000 -0.0000
-e1 0 0.0000 0.0000 -0.0000 0.0000
0 0 -0.0000 e2 0.0000 -0.0000
0 0 -e2 -0.0000 0.0000 -0.0000
0 0 0 0 -0.0000 e3
0 0 0 0 -e3 -0.0000
You need a different algorithm for the complex case. The Matlab documentation says:
If A is complex, schur returns the complex Schur form in matrix T. The complex Schur form is upper triangular with the eigenvalues of A on the diagonal.
Also, I could notice that you cast your matrix D into double(D). This has no real effects since D is already double. Nevertheless I have seen that the ordeig return different values for the eigenvalues depending if you input D or double(D) even for the real case. It is something to dig more deeply.

Wrong answer for lyap() function in matlab

I'm getting a weird answer from matlab using the lyap() function for generating a stable controller
my code is
m=1;c=2;k=1;
A=[0 1;-k/m -c/m]
B=[0 1/m]'
C=[1 0;0 1];
D=[0 0]';
u=2;
Q=eye(2);
ro=60;
k=0.99*ro;
P=lyap(A,Q)
What I'm getting is
P =
1.5000 -0.5000
-0.5000 0.5000
which is giving me an unstable controller,
while when solving it alone I get
p1 =
1.5000 0.5000
0.5000 0.5000
which is a stable controller.
Any ideas?
Thanks
from Mathworks Documentation
Limitations:
The continuous Lyapunov equation has a unique solution if the eigenvalues a1,a2,...,an of A and b1,b2,...,bn of B satisfy
ai+bj ~= 0 for all i,j
and from your values
eig(A)
ans =
-1
-1
eig(Q)
ans =
1
1
we can see these add to zero, thus there is not unique solution for these inputs
However I have no idea why the error message isn't generated, possibly time to report a bug

spectral clustering

First off I must say that I'm new to matlab (and to this site...) , so please excuse my ignorance.
I'm trying to write a function in matlab that will use Spectral Clustering to split a set of points into two clusters.
my code is as follows
function Groups = TrySpectralClustering(data)
dist_mat = squareform(pdist(data));
W= zeros(length(data),length(data));
for i=1:length(data),
for j=(i+1):length(data),
W(i,j)=10^(-dist_mat(i,j));
W(j,i)=W(i,j);
end
end
D = zeros(length(data),length(data));
for i=1:length(W),
D(i,i)=sum(W(i,:));
end
L=D-W;
L=D^(-0.5)*L*D^(-0.5);
[ V E ] = eig(L);
disp ('V:');
disp (V);
If I understand correctly, then by using the second smallest eigenvector I should be able to perform a partition of the data into two clusters - If the ith member of the 2nd eigenvector is positive, the ith data point would be in the one cluster, otherwise it would be in the other cluster.
However, when I try the following
f=[1,1;0,0;1,0;0,1;100,100;100,101;101,101;101,100]
TrySpectralClustering(f)
I would expect that the first four points would form one cluster, and the last four would form another.
However, I receive
V:
-0.0000 -0.5000 0.0000 -0.5777 0.0000 0.4078 -0.0000 0.5000
-0.0000 -0.5000 0.0000 0.5777 0.0000 -0.4078 -0.0000 0.5000
-0.0000 -0.5000 0.0000 0.4078 0.0000 0.5777 -0.0000 -0.5000
-0.0000 -0.5000 0.0000 -0.4078 0.0000 -0.5777 -0.0000 -0.5000
-0.5000 -0.0000 -0.0000 -0.0000 -0.7071 -0.0000 0.5000 -0.0000
-0.5000 -0.0000 0.7071 0.0000 -0.0000 -0.0000 -0.5000 -0.0000
-0.5000 0.0000 -0.0000 0.0000 0.7071 0.0000 0.5000 0.0000
-0.5000 0 -0.7071 0 0 0 -0.5000 0
Taking the 2nd eigenvector
-0.0000 -0.5000 0.0000 0.5777 0.0000 -0.4078 -0.0000 0.5000
I find the one cluster includes the points 1,0;0,1;100,100;101,100
and the other cluster is made from the points 1,1;0,0;100,101;101,101
I wonder what am I doing wrong.
Note: I am working on the above as a part of a homework project.
Thanks in advance!
What you are getting is correct. Let U be the matrix containing the eigenvectors as shown above and let them be arranged such that the 1st column corresponds to the smallest eigenvalue and progressive columns correspond to the ascending eigenvalues. Then, take a subset of columns of U by retaining the eigenvectors corresponding to the smaller eigenvalues. Now, read these columns row-wise into a new set of vectors, call it Y. Cluster Y to get the spectral clusters. So, let us assume our subset is only the first column. We clearly see that if u were to cluster the first column, u would get the first 4 into 1 cluster and the next 4 into another cluster, which is what you want.
Take a look at the implementation on Prof. J. Shi's webpage. Pay close attention to discretisation.m function.
Moreover, your code is very inefficient. You need to take more advantage of Matlab's vectorization:
W = 10.^( - dist_mat ); % single liner of nested loop for comuting W
% computing the symmetric laplacian
d = sum( W, 2 ); % sum each row
d( d == 0 ) = 1; % avoid division by zero
d_half = 1./sqrt( d );
L = eye( n ) - bsxfun( #times, bsxfun( #times, W, d_half' ), d_half );
Two observations:
L=D-W; L=D^(-0.5)*L*D^(-0.5);
Why do you let him calculate the identity matrix? Just use the identity matrix eye(n) and substract D^(-0.5) * W * D^(-0.5) from that to calculate the Laplacian L
eig returns the eigenvectors as columns, why do you take the row? Did you check the values of the corresponding eigenvalues in E, so you can be sure you are looking at a eigenvec corresponding to the 2nd smallest eigenval?