Singular value decomposition approximation - matlab

I was asked in school to do a SVD on the matrix:
A = [1 3 1 2;
0 2 1 4;
6 5 2 1]
and then: calculate an approximation of A called A_hat by setting the third singular value σ_3 to zero.
I have done the SVD, but I'm kind of clueless about the second part. Can somebody please help me?

Assuming MATLAB (or Octave):
A = [1 3 1 2;
0 2 1 4;
6 5 2 1];
[U,S,V] = svd(A);
S(3,3) = 0;
A_hat = U*S*V';
This gives:
A_hat =
1.37047 2.50649 1.03003 2.30320
-0.20009 2.26654 0.98378 3.83625
5.90727 5.12352 1.99248 0.92411

Related

Mahalanobis distance to find out nearest neighbor

Suppose I have some original data in a matrix a and measured data in matrix b. now i want to find out nearest point to matrix a 's element from matrix b.
The output should be ans = [1; 2; 3; 4;].
But when I try to do it, it does not give an output but error as a and b need to have same number of columns. How to solve this problem?
a = [1; 2; 3; 4];
b = [1 2 3 4; 2 3 4 5; 3 4 5 6; 4 5 6 7];
k=1 ;
L = pdist2(a,b,'mahalanobis','smallest',K);

Assign zero to specific indices of a matrix in MATLAB

For example:
a = [1 2 3; 4 5 6; 7 8 9];
b = [2 4]; %//Indices I got
How can I set to zero every element of a not indexed in b in order to obtain:
0 2 0
4 0 0
0 0 0
I tried for loop:
for i = 1:numel(a)
if i ~= b
a(i) = 0;
end
end
but the matrix I cope with is really large and it takes ridiculously long time to finish running.
Is there any smart way to do it? Thank you.
Try this:
a = [1 2 3; 4 5 6; 7 8 9];
b = [2 4];
a(setdiff(1:length(a(:)),b)) = 0;
UPDATE
As proposed by #Daniel, for large matrices is better to use
a(setdiff(1:numel(a),b)) = 0;
An alternative to Anton's direct solution is one based on copying:
a = [1 2 3; 4 5 6; 7 8 9];
b = [2 4];
atmp = a(b);
a = zeros(size(a));
a(b) = atmp; %// copy needed elements
I guess efficiency of the two approaches boils down to allocation vs setdiff. Also, if your resulting matrix has many zeroes, you should perhaps consider using a sparse matrix.

Create a matrix by sliding down a given vector by one step for every column

Given this vector
a = [1 2 3 4]
I want to create a matrix like this
b = [1 0 0 0;
2 1 0 0;
3 2 1 0;
4 3 2 1;
0 4 3 2;
0 0 4 3;
0 0 0 4]
in a vectorized way not using loops.
Hint: use conv2 (hover mouse to see code):
a = [1 2 3 4];
b = conv2(a(:), eye(numel(a)));
Or, in a similar mood, you can use convmtx (from the Signal Processing Toolbox):
a = [1 2 3 4];
b = convmtx(a(:), numel(a));
One way to do it:
a = [1 2 3 4]
n = numel(a);
%// create circulant matrix from input vector
b = gallery('circul',[a zeros(1,n-1)]).' %'
%// crop the result
c = b(:,1:n)
Another way:
b = union( tril(toeplitz(a)), triu(toeplitz(fliplr(a))),'rows','stable')
or its slightly variation
b = union( toeplitz(a,a.*0),toeplitz(fliplr(a),a.*0).','rows','stable')
and probably even faster:
b = [ toeplitz(a,a.*0) ; toeplitz(fliplr(a),a.*0).' ]
b(numel(a),:) = []
With bsxfun -
na = numel(a)
b = zeros(2*na-1,na)
b(bsxfun(#plus,[1:na]',[0:na-1]*2*na)) = repmat(a(:),1,na)
If you are looking for a faster pre-allocation, you can do -
b(2*na-1,na) = 0;.
Another bsxfun -
a=[1 2 3 4];
m=numel(a);
b=[a,zeros(1,m-1)].';
Q=bsxfun(#circshift, b, [0:m-1])

How to add boundary to a matrix

I am quite new to MATLAB. I would like to know how can I transfer the matrix A to matrix B as shown below?
A = 1 2
3 4
5 6
B=0 0 0 0
1 1 2 1
1 3 4 1
1 5 6 1
0 0 0 0
Essentially I would like to add a boundary to A.
Thank you!
padarray implementation -
%// pad ones on left-right and then pad zeros on top-bottom
B = padarray(padarray(A,[0 1],1),[1 0],0)
If I understand your question correctly, you wish to insert a 1 element boundary surrounding the matrix. In that case, try something like this:
A = [1 2; 3 4; 5 6];
[rows,cols] = size(A);
B = zeros(rows+2, cols+2);
B(2:end-1,[1 end]) = 1;
B(2:end-1,2:end-1) = A;
However, you can also use padarray like what #Divakar has suggested. Much more elegant!

How to vectorize row-wise diagonalization of a matrix

I have an n-by-m matrix that I want to convert to a mn-by-m matrix, with each m-by-m block of the result containing the diagonal of each row.
For example, if the input is:
[1 2; 3 4; 5 6]
the output should be:
[1 0; 0 2; 3 0; 0 4; 5 0; 0 6]
Of course, I don't want to assemble the matrix step by step myself with a for loop.
Is there a vectorized and simple way to achieve this?
For a vectorized way to do this, create the linear indices of the diagonal elements into the resulting matrix, and assign directly.
%# create some input data
inArray = [10 11;12 13;14 15];
%# make the index array
[nr,nc]=size(inArray);
idxArray = reshape(1:nr*nc,nc,nr)';
idxArray = bsxfun(#plus,idxArray,0:nr*nc:nr*nc^2-1);
%# create output
out = zeros(nr*nc,nc);
out(idxArray) = inArray(:);
out =
10 0
0 11
12 0
0 13
14 0
0 15
Here's a simple vectorized solution, assuming X is the input matrix:
Y = repmat(eye(size(X, 2)), size(X, 1), 1);
Y(find(Y)) = X;
Another alternative is to use sparse, and this can be written as a neat one-liner:
Y = full(sparse(1:numel(X), repmat(1:size(X, 2), 1, size(X, 1)), X'));
The easiest way I see to do this is actually quite simple, using simple index referencing and the reshape function:
I = [1 2; 3 4; 5 6];
J(:,[1,4]) = I;
K = reshape(J',2,6)';
If you examine J, it looks like this:
J =
1 0 0 2
3 0 0 4
5 0 0 6
Matrix K is just what wanted:
K =
1 0
0 2
3 0
0 4
5 0
0 6
As Eitan T has noted in the comments, the above is specific to the example, and doesn't cover the general solution. So below is the general solution, with m and n as described in the question.
J(:,1:(m+1):m^2) = I;
K=reshape(J',m,m*n)';
If you want to test it to see it working, just use
I=reshape(1:(m*n),m,n)';
Note: if J already exists, this can cause problems. In this case, you need to also use
J=zeros(n,m^2);
It may not be the most computationally efficient solution, but here's a 1-liner using kron:
A = [1 2; 3 4; 5 6];
B = diag(reshape(A', 6, 1) * kron(ones(3, 1), eye(2))
% B =
% 1 0
% 0 2
% 3 0
% 0 4
% 5 0
% 0 6
This can be generalized if A is n x m:
diag(reshape(A.', n*m, 1)) * kron(ones(n,1), eye(m))