How to find the indices of nonzero rows in a matrix? - matlab

How to find the indices of nonzero rows in a matrix?
Example:
A = [
14 0 6 9 8 17
85 14 1 3 0 99
0 0 0 0 0 0
29 4 5 8 7 46
0 0 0 0 0 0
17 0 5 0 0 49
]
the desired result :
V =[1 2 4 6]

You can use
ix = any(x,2);
any check whether there is any element that is not a zero. The second argument stands for "per-row" computation.
If you want to get the numeric index, you can use find function:
numIx = find(ix);
Another method:
ix = sum(abs(x),2)~=0;

Use
[i,~] = ind2sub(size(A),find(A));
v = unique(i);
Result for the matrix given above:
v = unique(i')
v =
1 2 4 6

Here's one that ab(uses) the fast matrix multiplication in MATLAB -
idx = find(abs(A)*ones(size(A,2),1))

Related

finding indeces of similar group elements

I have a vector test2 that includes NaN 0 and 1 in random order (we cannot make any assumption).
test2 = [NaN 1 1 1 0 0 0 NaN NaN NaN 0 0 0 1 1 1 0 1 1 1 ];
I would like to group the elements containing consecutive 1 and to have in the separte vectors start and finish the first and last index of the groups.
In this case start and finish should be:
start = [2 14 18];
finish = [4 16 20];
I tried to adapt the code provided here coming up with this solution that is not working...could you help me with the right solution and tell me why the one I tried doesn't work?
a = (test2 ==1);
d = diff(a);
start = find([a(1) d]==1); % Start index of each group
finish = find([d - a(end)]==-1); % Last index of each group
start =
2 14 18
finish =
2 3 5 6 7 8 9 10 11 12 14 15 18 19
I am using MATLAB R2013b running on Windows.
I tried also using MATLAB R2013a running on ubuntu.
a = (test2 ==1)
d=diff([0 a 0])
start=find(d==1)
finish=find(d==-1)-1
Padding a zero at the beginning and end is the easiest possibility. Then the special cases where a group starts at index 1 or ends at last index don't cause problems.
Full output:
>> test2 = [NaN 1 1 1 0 0 0 NaN NaN NaN 0 0 0 1 1 1 0 1 1 1 ]
test2 =
Columns 1 through 16
NaN 1 1 1 0 0 0 NaN NaN NaN 0 0 0 1 1 1
Columns 17 through 20
0 1 1 1
>> a = (test2 ==1)
a =
Columns 1 through 16
0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1
Columns 17 through 20
0 1 1 1
>> d=diff([0 a 0])
d =
Columns 1 through 16
0 1 0 0 -1 0 0 0 0 0 0 0 0 1 0 0
Columns 17 through 21
-1 1 0 0 -1
>> start=find(d==1)
start =
2 14 18
>> finish=find(d==-1)-1
finish =
4 16 20
>>
The problem is the line finish = find([d - a(end)]==-1);, in particular that a(end) == 1. There are two steps to correcting this. First, change the problem line to finish = find(d==-1); This tells MATLAB, "Look for the elements where the difference between adjacent elements is -1". In other words, the vector shifts from 1 to 0 or NaN. If you run the code, you'll get
start = 2 14 18
finish = 4 16
Now, you'll notice the last element isn't detected (i.e. we should get finish(3) == 20. This is because the length of d is one less than the length of test2; the function diff cannot calculate the difference between the last element and the non-existant last+1 element!
To remedy this, we should modify a:
a = [(test2 == 1) 0];
And you will get the right output for start and finish.

Matlab:How to find the indices of rows without any zero in a matrix?

How to find the indices of rows without any zero in a matrix?
Example:
A = [
14 0 6 9 8 17
85 14 1 3 0 99
0 0 0 0 0 0
29 4 5 8 7 46
0 0 0 0 0 0
17 0 5 0 0 49
]
the desired result :
V =[4]
Since Adiel did not post an answer, I'll make their comment a CW: the command
V = find(all(A,2))
does the job, because all(A,2) processes every row, returning 1 if there are any nonzero entries. Then find returns the indices of nonzero entries, which are the desired row numbers.
Similarly, V = find(all(A,1)) works column-wise.

Reshape / Transform an upper triangular matrix in MATLAB

I have an upper triangular matrix (without the diagonal) given by:
M = [0 3 2 2 0 0; 0 0 8 6 3 2; 0 0 0 3 2 1; 0 0 0 0 2 1; 0 0 0 0 0 0]
The resulting matrix should look like this:
R = [0 0 0 0 0 0; 0 2 0 0 0 0; 2 3 1 0 0 0; 2 6 2 1 0 0; 3 8 3 2 0 0]
Since I couldn't find a simple explanation which describes my goal I tried to visualize it with an image:
I already tried lots of different combinations of rot90, transpose, flipud etc., but I could't find the right transformation that gives me the matrix R
EDIT:
The rows of the matrix M are not always sorted as in the example above. For another matrix M_2:
M_2 = [0 2 3 1 0 0; 0 0 3 6 3 9; 0 0 0 1 2 4; 0 0 0 0 2 6; 0 0 0 0 0 0]
the resulting matrix R_2 need to be the following:
R_2 = [0 0 0 0 0 0; 0 9 0 0 0 0; 1 3 4 0 0 0; 3 6 2 6 0 0; 2 3 1 2 0 0]
Again the visualization below:
EDIT:
Inspired by the tip from #Dan's comment, it can be further simplified to
R = reshape(rot90(M), size(M));
Original Answer:
This should be a simple way to do this
F = rot90(M);
R = F(reshape(1:numel(M), size(M)))
which returns
R =
0 0 0 0 0 0
0 2 0 0 0 0
2 3 1 0 0 0
2 6 2 1 0 0
3 8 3 2 0 0
The idea is that when you rotate the matrix you get
>> F = rot90(M)
F =
0 2 1 1 0
0 3 2 2 0
2 6 3 0 0
2 8 0 0 0
3 0 0 0 0
0 0 0 0 0
which is a 6 by 5 matrix. If you consider the linear indexing over F the corresponding indices are
>> reshape(1:30, size(F))
1 7 13 19 25
2 8 14 20 26
3 9 15 21 27
4 10 16 22 28
5 11 17 23 29
6 12 18 24 30
where elements 6, 11, 12, 16, 17, 18 , and ... are zero now if you reshape this to a 5 by 6 matrix you get
>> reshape(1:30, size(M))
1 6 11 16 21 26
2 7 12 17 22 27
3 8 13 18 23 28
4 9 14 19 24 29
5 10 15 20 25 30
Now those elements corresponding to zero values are on top, exactly what we wanted. So by passing this indexing array to F we get the desired R.
Without relying on order (just rotating the colored strips and pushing them to the bottom).
First solution: note that it doesn't work if there are zeros between the "data" values (for example, if M(1,3) is 0 in the example given). If there may be zeros please see second solution below:
[nRows nCols]= size(M);
R = [flipud(M(:,2:nCols).') zeros(nRows,1)];
[~, rowSubIndex] = sort(~~R);
index = sub2ind([nRows nCols],rowSubIndex,repmat(1:nCols,nRows,1));
R = R(index);
Second solution: works even if there are zeros within the data:
[nRows nCols]= size(M);
S = [flipud(M(:,2:nCols).') zeros(nRows,1)];
mask = 1 + fliplr(tril(NaN*ones(nRows, nCols)));
S = S .* mask;
[~, rowSubIndex] = sort(~isnan(S));
index = sub2ind([nRows nCols],rowSubIndex,repmat(1:nCols,nRows,1));
R = S(index);
R(isnan(R)) = 0;
Alternate option, using loops:
[nRows nCols]= size(M);
R = zeros(nRows,nCols);
for n = 1:nRows
R((n+1):nCols,n)=fliplr(M(n,(n+1):nCols));
end

Multiplication of Vectors with diagonal of a matrices from t to t+1 in Matlab

Still very new to programming...
I have 9x1 Vectors at time t, t+1, t+2 etc.
[10 10 10 10 10 10 10 10 10]'
and matrices. Each matrix is 9x9 and also at time 1, t+1, t+2 etc. =
1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 1
They are 3d matrices and I want to make them 4d in the future.
I want to multiply vector(:,:,t) with the diagonal of matrix at time t and output vector(:,:,t+1).
So in short...
vector t multiplied by diag matrix t = vector t+1
vector t+1 multiplied by diag matrix t+1 = vector t+2
vector t+2 multiplied by diag matrix t+2 = vector t+3 ... and so on.
the diagonal numbers change in each time step but for simplicity sake, let's keep them all at 1 for the moment.
I've tried using diag but it states I have to use a 2D input so only works when I ignore t.
Cheers for your help guys - it's helping me learn a lot. Any hints or solutions will be much appreciated. I know you guys know the simplest and most efficient solutions.
Since the result of each step depends on the previous iteration, it cannot be vectorized. So I would go with #JohnColby's solution.
For what it's worth, here is an example how you would extract the diagonals of a 3D matrix in a vectorized way:
M = reshape(1:3*4*3,[3 4 3]);
[r,c,p] = size(M);
ind = bsxfun(#plus, (1:r+1:r*c)', (0:p-1).*r*c);
M(ind)
Each column of the result corresponds to the diagonal elements from each slice (doesn't have to be square matrix):
>> M
M(:,:,1) =
1 4 7 10
2 5 8 11
3 6 9 12
M(:,:,2) =
13 16 19 22
14 17 20 23
15 18 21 24
M(:,:,3) =
25 28 31 34
26 29 32 35
27 30 33 36
>> M(ind)
ans =
1 13 25
5 17 29
9 21 33
Here you go:
n = 10;
% Make sample data
t = zeros(9,1,n);
t(:,1,1) = 1;
T = repmat(diag(ones(9,1)), [1 1 n]);
% Loop though to fill in t based on previous t and T
for i = 2:n
t(:,1,i) = t(:,1,i-1) .* diag(T(:,:,i-1));
end
Now all of t should be 1.

Split an array in MATLAB

I have an array of integer numbers, and I want to split this array where 0 comes and a function that give me points of split.
Example: Array : 0 0 0 1 2 4 5 6 6 0 0 0 0 0 22 4 5 6 6 0 0 0 4 4 0
The function must return these numbers:
[ 3 10 ;14 20 ;22 25 ]
These numbers are index of start and end of nonzero numbers.
Here's a simple vectorized solution using the functions DIFF and FIND:
>> array = [0 0 0 1 2 4 5 6 6 0 0 0 0 0 22 4 5 6 6 0 0 0 4 4 0]; %# Sample array
>> edgeArray = diff([0; (array(:) ~= 0); 0]);
>> indices = [find(edgeArray > 0)-1 find(edgeArray < 0)]
indices =
3 10
14 20
22 25
The above code works by first creating a column array with ones indicating non-zero elements, padding this array with zeroes (in case any of the non-zero spans extend to the array edges), and taking the element-wise differences. This gives a vector edgeArray with 1 indicating the start of a non-zero span and -1 indicating the end of a non-zero span. Then the function FIND is used to get the indices of the starts and ends.
One side note/nitpick: these aren't the indices of the starts and ends of the non-zero spans like you say. They are technically the indices just before the starts and just after the ends of the non-zero spans. You may actually want the following instead:
>> indices = [find(edgeArray > 0) find(edgeArray < 0)-1]
indices =
4 9
15 19
23 24
Try this
a = [0 0 0 1 2 4 5 6 6 0 0 0 0 0 22 4 5 6 6 0 0 0 4 4 0];
%#Places where value was zero and then became non-zero
logicalOn = a(1:end-1)==0 & a(2:end)~=0;
%#Places where value was non-zero and then became zero
logicalOff = a(1:end-1)~=0 & a(2:end)==0;
%#Build a matrix to store the results
M = zeros(sum(logicalOn),2);
%#Indices where value was zero and then became non-zero
[~,indOn] = find(logicalOn);
%#Indices where value was non-zero and then became zero
[~,indOff] = find(logicalOff);
%#We're looking for the zero AFTER the transition happened
indOff = indOff + 1;
%#Fill the matrix with results
M(:,1) = indOn(:);
M(:,2) = indOff(:);
%#Display result
disp(M);
On the theme, but with a slight variation:
>>> a= [0 0 0 1 2 4 5 6 6 0 0 0 0 0 22 4 5 6 6 0 0 0 4 4 0];
>>> adjust= [0 1]';
>>> tmp= reshape(find([0 diff(a== 0)])', 2, [])
tmp =
4 15 23
10 20 25
>>> indices= (tmp- repmat(adjust, 1, size(tmp, 2)))'
indices =
4 9
15 19
23 24
As gnovice already pointed out on the positional semantics related to indices, I'll just add that, with this solution, various schemes can be handled very straightforward manner, when calculating indices. Thus, for your request:
>>> adjust= [1 0]';
>>> tmp= reshape(find([0 diff(a== 0)])', 2, []);
>>> indices= (tmp- repmat(adjust, 1, size(tmp, 2)))'
indices =
3 10
14 20
22 25