Matlab Extend Diagonal by one - matlab

Suppose I have a matrix A, and I'd like to get the matrix [A 0; 0 1]. Is there a built function to do this?
So if my matrix is [2 3; 1 4], I'd get back [2 3 0; 1 4 0; 0 0 1]

The easiest way is:
newA = A;
newA(end+1,end+1) = 1;
This works because you can index outside an array for assignments, because end indicates the last element (here in row and column), and because Matlab pads with zeros when you grow an array. If you just want to grow A, you can even skip the creation of newA, of course.

I always use matrix concatenation for problems like this
So for your example:
A = [2 3; 1 4]
A = [A A(:,1)*0; A(1,:)*0 1]
produces
A =
2 3 0
1 4 0
0 0 1
The nice thing about this trick is that its very flexible and you can do all sorts of tranformations
very easily. For example
A = [2 3; 1 4]
A = [1 A(1,:)*0; A(:,1)*0 A]
produces
A =
1 0 0
0 2 3
0 1 4

Related

Zero pad a vector in MATLAB

I have a vector that contains 5 numbers and I want to pad it with zeros. How can I do it?
A = [1 2 3 4 5].';
I want the zero padded vector to be like this:
A_new = [0 0 0 0 0 1 2 3 4 5].';
Also, for another case, I want to assign 1, 3, 4 to matrix W as follows, with all else being zeros. The length of W is 7. W = [0 1 0 0 3 0 4].
You can use following code
newA = [zeros(5,1); A]
About another case. You need something like
inds = [2 5 7];
elems = [1 3 4];
W = zeros(7,1);
W(inds) = elems

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 group rows with same column values?

Given the matrix with coordinates in 3D space and values for two variables (say a and b) in two matrices I would like to merge rows for same points into a common matrix.
To clearly explain the matter, let's say we have matrices
A=[posX, posY, posZ, a]
and
B=[posX, posY, posZ, b]
and would like to combine them into
AB = [posX, posY, posZ, a, b]
for example
A = [0 0 1 1; 0 1 0 4; 5 0 12 8];
B = [0 0 0 5; 0 1 0 3; 5 11 7 7];
would give
AB = [0 0 0 0 5; 0 0 1 1 0; 0 1 0 4 3; 5 0 12 8 0; 5 11 7 0 7];
In order to do that I first created
ATemp = [A, zeros(length(A,0)]
and
BTemp = [B(:, [1 2 3]), zeros(length(B),1), B(:,4)]
and then tried to use functions accumarray and grpstats but haven't managed to form the AB matrix.
I would be very thankful if anyone suggested the way to get the desired matrix.
AB=union(A(:,1:3),B(:,1:3),'rows');
AB(ismember(AB,A(:,1:3),'rows'),4)=A(:,4);
AB(ismember(AB(:,1:3),B(:,1:3),'rows'),5)=B(:,4)
[edit] This solution is only valid if each (x,y,z)-point occurs only once in each matrix. If there are several, there is a dimension mismatch in the second line (and/or the third).

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))

Converting a matrix in MATLAB

Let's say I've got a vector a = [1 2 4]. I want it converted into a vector which looks like this b = [1 2 0 4], i.e. each number is placed into a correct position and since 3 is not included into the vector a, it is replaced by 0 in vector b. This can be done the following way:
a = [1 2 4]
b = zeros(1, size(a, 2));
b(1, a) = a;
I can't figure out a way to do the same for a matrix. For example,
c = [1 4 2 0; 3 1 0 0; 4 0 0 0; 1 3 4 0];
I need to convert into a matrix that looks like this:
d = [1 2 0 4; 1 0 3 0; 0 0 0 4; 1 0 3 4];
Any tips? How can this be done? How can I do this without using loops?
Here's a vectorized solution:
a = [1 4 2 0; 3 1 0 0; 4 0 0 0; 1 3 4 0];
b = zeros(size(a,1),max(a(:)));
[rowIdx,~] = find(a);
vals = a(a>0);
b( sub2ind(size(b),rowIdx,vals) ) = vals;
Does this work? (Edited: fixed mistake.)
[m,n] = size(c)
d = zeros(m,n)
for i=1:m
d(i,c(i,c(i,:)>0)) = c(i,c(i,:)>0)
end