Reputation: 75
I have a matrix u
, I want to go across all rows and all columns and do the following. If the element is non zero, I return the value of the row index. If the element is zero, find the row index the next non zero element after this element. I can do this easily using two for loops with a find function. But I need to do this many many times (not because of the size of the matrix but because this is called many times). How can I do it faster?
here is the for loop code:
for w=scenario_size:-1:1
for t=1:time_size
l = u(t,w) ;
if l~=0
tprime = t ;
else
tprime = t+ find(u(t:end,w),1,'first') -1 ;
end
i(t,w) = tprime ;
boo(t,w) = number(tprime,w)/u(tprime,w) ;
end
end
Example if one column is [0,0,5,1,0,3]
, the i
is [3,3,3,4,6,6]
. The last element of any column of u
is always non-zero (I forced this by artificially adding a row of ones at the end).
Then boo
is the corresponding entry to tprime
for some matrix number
divided by the corresponding u
(which is non zero by construction).
Upvotes: 1
Views: 225
Reputation: 125854
You can solve this using find
, cummin
, and some logical indexing. Starting with this example case:
>> u = randi([0 1], 10);
>> u(end, :) = 1
u =
0 0 0 0 1 0 1 0 1 1
1 0 1 1 1 0 0 0 0 1
0 0 0 0 0 1 0 1 1 0
1 1 1 0 1 1 0 0 0 0
0 0 1 0 0 0 0 0 1 0
1 1 1 0 0 0 0 0 0 0
0 1 0 1 0 0 1 1 0 1
1 1 0 1 0 1 1 1 1 1
1 0 0 1 0 0 1 1 1 1
1 1 1 1 1 1 1 1 1 1
The following will do what you want:
i = nan(size(u)); % Start with all nan values
[r, ~] = find(u); % Get row indices of non-zero values
i(u ~= 0) = r; % Place row indices in locations of non-zero values
i = cummin(i, 1, 'reverse'); % Column-wise cumulative minimum, starting from bottom
And the result:
i =
2 4 2 2 1 3 1 3 1 1
2 4 2 2 2 3 7 3 3 2
4 4 4 7 4 3 7 3 3 7
4 4 4 7 4 4 7 7 5 7
6 6 5 7 10 8 7 7 5 7
6 6 6 7 10 8 7 7 8 7
8 7 10 7 10 8 7 7 8 7
8 8 10 8 10 8 8 8 8 8
9 10 10 9 10 10 9 9 9 9
10 10 10 10 10 10 10 10 10 10
And you can then calculate your matrix boo
by converting i
to a linear index:
index = i+time_size.*repmat(0:(scenario_size-1), time_size, 1); % Create linear index
boo = number(index)./u(index);
Alternatively, you can compute i
as a linear index from the start:
i = nan(size(u)); % Start with all nan values
index = find(u); % Get linear indices of non-zero values
i(index) = index; % Place linear indices in locations of non-zero values
i = cummin(i, 1, 'reverse'); % Column-wise cumulative minimum, starting from bottom
boo = number(i)./u(i);
Upvotes: 5
Reputation: 2777
@gnovice answer is good, just to give an alternative to find
function
u
matrix >> u = randi([0 1], 10);
u(end, :) = 1;
>> u
u =
0 0 0 0 0 1 1 0 0 0
0 1 1 1 0 1 0 1 1 1
1 1 1 0 1 0 0 1 1 0
1 1 1 1 1 0 1 1 0 1
1 1 0 1 1 1 1 0 0 0
0 0 1 0 1 1 1 0 0 1
0 1 0 0 1 1 0 0 0 1
0 1 0 1 1 1 0 1 1 0
0 0 0 1 0 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
non-zeros
row indices can be computed as follow >> t = 1:10*10;% All elements indices
r = t(u ~= 0); % All non-zeros elements indices
>> r
r =
Columns 1 through 18
3 4 5 10 12 13 14 15 17 18 20 22 23 24 26 30 32 34
Columns 19 through 36
35 38 39 40 43 44 45 46 47 48 50 51 52 55 56 57 58 59
Columns 37 through 54
60 61 64 65 66 69 70 72 73 74 78 79 80 82 83 88 89 90
Columns 55 through 60
92 94 96 97 99 100
Upvotes: 1