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

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

Related

MATLAB - finding max/min in selected rows/columns of a matrix

if i have a matrix, say:
A = [ 0 2 4 0
2 0 5 0
4 5 0 3
0 0 3 0 ]
and i want to find the maximum value in the matrix i can type:
max(max(A))
or
max(A(:))
if i only want to find the maximum of rows 1 and 2 and columns 3 and 4 i can do this:
a = [1 2]
b = [3 4]
max(max(A(a,b))
but what if i want to find the indices of the rows and columns that correspond to that value?
according to the matlab documentation, if i am using the whole matrix i can use the ind2sub function:
[val,idx] = max(A(:))
[row,col] = ind2sub(size(A),idx)
but how can i get that working for my example where i am using vectors a and b to determine the rows and columns it finds the values over?
here is the only way i have been able to work it out so far:
max_val = 0;
max_idx = [1 1];
for ii = a
[val,idx] = max(A(ii,b))
if val > max_val
max_val = val
max_idx = [ii idx]
but that seems rather clunky to me.. any ideas?
Assuming that the submatrix A(a,b) is contiguous (like in your example):
A = [ 0 2 4 0
2 0 5 0
4 5 0 3
0 0 3 0 ]
a = [1 2]; b = [3 4];
B = A(a,b)
[val,idx] = max(B(:));
[row,col] = ind2sub(size(B),idx);
maxrow = row + a(1) - 1;
maxcol = col + b(1) - 1;
You are finding the relative index in the submatrix B. Which is equivalent to the additional rows and columns from the upper left corner of the submatrix.
Now assuming that a and b result in a set of rows and columns that are NOT a contiguous submatrix, e.g. a = [1 3], b = [3 4], the result is very similar. "row" and "col" are the index in the a and b vectors:
A = [ 0 2 4 0
2 0 5 0
4 5 0 3
0 0 3 0 ]
a = [1 3]; b = [3 4];
B = A(a,b)
[val,idx] = max(B(:));
[row,col] = ind2sub(size(B),idx);
maxrow = a(row);
maxcol = b(col);
Now you're working in the index of indexes.

Matlab: Add vectors not in the same length to a matrix

Is it possible to automatically add vectors that are not in the same length together for a matrix?
i.e:
a = [1 2 3 4]
b = [1 2]
How can I make C to be:
c = [1 2 3 4 ; 1 2 0 0]
or
c = [1 2 3 4 ; 1 2 NaN NaN]
or something like that
Thanks
This might help
a = [1 2 3 4];
b = [1 2];
c = a;
c(2,1:length(b)) = b;
c =
1 2 3 4
1 2 0 0
then, if you'd rather have NaN than 0, you could do what Dennis Jaheruddin suggests in a comment below.
Make a function like this
function out = cat2(a, b)
diff = length(a) - length(b)
if diff > 0
b = [b, nan(1, diff)];
else
a = [a, nan(1, -diff)];
end
out = [a;b];
end
(but also add a check to handle column vectors too)
cat2([1 2 3 4], [1 2])
ans =
1 2 3 4
1 2 NaN NaN

Matlab Extend Diagonal by one

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

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