Single Value Decomposition in Matlab is slightly off

196 views Asked by At

I'm trying to create code that finds the svd of an image. We're not allowed to actually use the svd() function. I managed to get an answer that's close but not exact. I'm comparing my answers to the result of the SVD function and my middle matrix is perfect but some of the signs on my left and right matrices are flipped. Also if I try and display the image again using my SVD it looks like a low rank approximation of the original picture.

Basically what I'm doing is using eig() to take the eigenvalues and eigenvectors of AAtranspose and AtransposeA and then reordering them from largest to smallest. As far as I understand eig() puts them in order from smallest to largest so I just used the fliplr function to swap the order.

I'm not terribly experienced with Matlab so I might be making a silly mistake. I tried removing the fliplr function but I'm still getting what appears to be the exact same eigenvectors and the image is still coming out wrong. Here is the code I'm using. Is there another error I'm making?

A = imread('picture.jpg');
A2 = double(rgb2gray(A));
AT = transpose(A2);
sz = size(A2);
m = sz(1);
n = sz(2);
AAT = A2*AT;
ATA = AT*A2;
evalues = eig(AAT);
evalues = sort(evalues,'descend');
S = diag(evalues);
S(m,n) = 0;
S=S.^(.5);

[v1,e1]=eig(AAT);
e1 = diag(e1);
[~, ind] = sort(abs(e1), 'descend');
v1 = v1(:, ind);

[v2,e2]=eig(ATA);
e2 = diag(e2);
[~, ind] = sort(abs(e2), 'descend');
v2 = v2(:, ind);


final = v1*S*transpose(v2);
final = uint8(final);
imshow(final);
1

There are 1 answers

1
rayryeng On

Remember that eigenvalues and eigenvectors are not unique. If they're scaled differently, they're also an eigenvalue / eigenvector. The fact that the signs are flipped should not be alarming. However, a crucial error that you have assumed is that eig returns the eigenvalues and eigenvectors from smallest to largest. Nowhere in the eig documentation does it talk about the order. In fact, the order is totally random so fliplr actually is not the correct thing to do. What you need to do is sort based on the magnitude of the eigenvalues, so you actually need to do something like this, assuming the matrix you want to sort is A:

[V, D] = eig(A);
D = diag(D);
[~, ind] = sort(abs(D), 'descend');
V = V(:, ind);

This takes the eigenvector matrix and properly rearranges the columns so that the largest eigenvalue's eigenvector appears in the first column and then goes in decreasing order.

In any case, the left and right matrices are ultimately eigenvectors that are placed in the columns of the matrix. As long as you can see that A = U*S*V, then you should be fine for the most part. I can't determine if you're actually implementing the SVD right as you haven't attached any code so this feedback I can't provide to you, but from the sounds of your question it seems that it's fine.