How to used a for loop to determine the set of index? - matlab

I trying to make a program that uses the for loop to calculate the set of index D. But I have a problem because the length of index are not the same.
Example:
z = [0 0 0 0 0 0 1]
v(1,:) = [1 0 0 0 1 0 1]
v(2,:) = [0 1 0 0 1 1 1]
v(3,:) = [0 0 1 0 1 1 0]
v(4,:) = [0 0 0 1 0 1 1]
v(1,:) = find(v(1,:)~=z);
v(2,:) = find(v(2,:)~=z);
v(3,:) = find(v(3,:)~=z);
v(4,:) = find(v(4,:)~=z);
we obtain :
D(1,:) = [1 5];
D(2,:) = [2 5 6];
D(3,:) = [3 5 6 7];
D(4,:) = [4 6];
Code :
for aa = 1:4
D(aa,:) = [find(v(aa,:)~=z)];
end
not work because length(D(1,:))~=length(D(2,:))~=length(D(3,:))
How I can use a loop to determine set of index D?
Thank you for any help!

One solution can be using cell like the following:
for aa = 1:4
D{aa} = [find(v(aa,:)~=z)];
end

You can use the matrix D, but initialize it beforehand like:
D = ones(size(v)) + length(z)
Then fill it like:
for ii = 1:size(z,1)
D(ii,v(ii,:)~=z) = find(v(ii,:)~=z);
end
Notice, I added the length of v to the matrix of ones, such that you are sure that the predefined numbers in the matrix are larger than any index, hence the min() will not freak out.

Related

Fastest way of generating a logical matrix by given row indices of true values?

What is the most efficient way of generating
>> A
A =
0 1 1
1 1 0
1 0 1
0 0 0
with
>> B = [2 3; 1 2; 1 3]
B =
2 3
1 2
1 3
in MATLAB?
E.g., B(1, :), which is [2 3], means that A(2, 1) and A(3, 1) are true.
My attempt still requires one for loop, iterating through B's row. Is there a loop-free or more efficient way of doing this?
This is one way of many, though sub2ind is the dedicated function for that:
%// given row indices
B = [2 3; 1 2; 1 3]
%// size of row index matrix
[n,m] = size(B)
%// size of output matrix
[N,M] = deal( max(B(:)), n)
%// preallocation of output matrix
A = zeros(N,M)
%// get col indices to given row indices
cols = bsxfun(#times, ones(n,m),(1:n).')
%// set values
A( sub2ind([N,M],B,cols) ) = 1
A =
0 1 1
1 1 0
1 0 1
If you want a logical matrix, change the following to lines
A = false(N,M)
A( sub2ind([N,M],B,cols) ) = true
Alternative solution
%// given row indices
B = [2 3; 1 2; 1 3];
%// number if rows
r = 4; %// e.g. = max(B(:))
%// number if cols
c = 3; %// size(B,1)
%// preallocation of output matrix
A = zeros(r,c);
%// set values
A( bsxfun(#plus, B.', 0:r:(r*(c-1))) ) = 1;
Here's a way, using the sparse function:
A = full(sparse(cumsum(ones(size(B))), B, 1));
This gives
A =
0 1 1
1 1 0
1 0 1
If you need a predefined number of rows in the output, say r (in your example r = 4):
A = full(sparse(cumsum(ones(size(B))), B, 1, 4, size(B,1)));
which gives
A =
0 1 1
1 1 0
1 0 1
0 0 0
You can equivalently use the accumarrray function:
A = accumarray([repmat((1:size(B,1)).',size(B,2),1), B(:)], 1);
gives
A =
0 1 1
1 1 0
1 0 1
Or with a predefined number of rows, r = 4,
A = accumarray([repmat((1:size(B,1)).',size(B,2),1), B(:)], 1, [r size(B,1)]);
gives
A =
0 1 1
1 1 0
1 0 1
0 0 0

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.

Inserting variable number of zeros between non-zero elements in a vector in MATLAB

I have a vector like:
a = [1,2,3,4,5,6...,n]
and I would like to obtain a new vector like this:
a_new = [1,0,0,2,0,0,3,0,0,4,0,0,5,0,0,6,...,0,0,n]
where a fixed number of zeros (2 in the above example) are inserted between the non-zero elements. If I choose zero_p=3, the new vector would be:
a_new = [1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,5,0,0,0,6,...,0,0,0,n]
etc.
How can I do this?
Try this:
zero_p=3;
a_new=zeros(1, (zero_p+1)*length(a)-zero_p);
a_new(1:(zero_p+1):end)=a;
(Untested, but should hopefully work.)
There's a few ways I can think of:
Kronecker product
The kronecker product is excellently suited for this.
In Matlab, kron is what you're looking for:
a = 1:4;
a = kron(a, [1 0 0])
ans =
1 0 0 2 0 0 3 0 0 4 0 0
or, generalized,
a = 1:4;
zero_p = 3;
b = [1 zeros(1,zero_p-1)];
a = kron(a, b)
ans =
1 0 0 2 0 0 3 0 0 4 0 0
If you want to have it end with a non-zero element, you have to do one additional step:
a = a(1:end-zero_p);
Or, if you like one-liners, the whole thing can be done like this:
a = 1:4;
zero_p = 3;
a = [kron(a(1:end-1), [1 zeros(1,zero_p-1)]), a(end)]
ans =
1 0 0 2 0 0 3 0 0 4
Zero padding
Probably the simplest method and best performance:
a = 1:4;
zero_p = 3;
a = [a; zeros(zero_p, size(a, 2))];
a = a(1:end-zero_p);
Matrix multiplication
Also simple, readable and great performance, although it might be overkill for many situations other than this particular scenario:
a = 1:4;
b = [1; zeros(zero_p, 1)];
a = b*a;
a = a(1:end-zero_p);
x = [1 2 3 4 5];
upsample(x,3)
o/p: 1 0 0 2 0 0 3 0 0 4 0 0 5 0 0
Cheers!!

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

How can I generate the following matrix in MATLAB?

I want to generate a matrix that is "stairsteppy" from a vector.
Example input vector: [8 12 17]
Example output matrix:
[1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1]
Is there an easier (or built-in) way to do this than the following?:
function M = stairstep(v)
M = zeros(length(v),max(v));
v2 = [0 v];
for i = 1:length(v)
M(i,(v2(i)+1):v2(i+1)) = 1;
end
You can do this via indexing.
A = eye(3);
B = A(:,[zeros(1,8)+1, zeros(1,4)+2, zeros(1,5)+3])
Here's a solution without explicit loops:
function M = stairstep(v)
L = length(v); % M will be
V = max(v); % an L x V matrix
M = zeros(L, V);
% create indices to set to one
idx = zeros(1, V);
idx(v + 1) = 1;
idx = cumsum(idx) + 1;
idx = sub2ind(size(M), idx(1:V), 1:V);
% update the output matrix
M(idx) = 1;
EDIT: fixed bug :p
There's no built-in function I know of to do this, but here's one vectorized solution:
v = [8 12 17];
N = numel(v);
M = zeros(N,max(v));
M([0 v(1:N-1)]*N+(1:N)) = 1;
M(v(1:N-1)*N+(1:N-1)) = -1;
M = cumsum(M,2);
EDIT: I like the idea that Jonas had to use BLKDIAG. I couldn't help playing with the idea a bit until I shortened it further (using MAT2CELL instead of ARRAYFUN):
C = mat2cell(ones(1,max(v)),1,diff([0 v]));
M = blkdiag(C{:});
A very short version of a vectorized solution
function out = stairstep(v)
% create lists of ones
oneCell = arrayfun(#(x)ones(1,x),diff([0,v]),'UniformOutput',false);
% create output
out = blkdiag(oneCell{:});
You can use ones to define the places where you have 1's:
http://www.mathworks.com/help/techdoc/ref/ones.html