1

I'm trying to speed up steps 1-4 in the following code (the rest is setup that will be predetermined for my actual problem.)

% Given sizes:
m = 200;
n = 1e8;

% Given vectors:
value_vector = rand(m, 1);
index_vector = randi([0 200], n, 1);

% Objective: Determine the values for the values_grid based on indices provided by index_grid, which
%            correspond to the indices of the value in value_vector

% 0. Preallocate
values = zeros(n, 1);

% 1. Remove "0" indices since these won't have values assigned
nonzero_inds = (index_vector ~= 0);

% 2. Examine only nonzero indices
value_inds = index_vector(nonzero_inds);

% 3. Get the values for these indices
nonzero_values = value_vector(value_inds);

% 4. Assign values  to output (0 for those with 0 index)
values(nonzero_inds) = nonzero_values;

Here's my analysis of these portions of the code:

  1. Necessary since the index_vector will contain zeros which need to be ferreted out. O(n) since it's just a matter of going through the vector one element at a time and checking (value ∨ 0)
  2. Should be O(n) to go through index_vector and retain those that are nonzero from the previous step
  3. Should be O(n) since we have to check each nonzero index_vector element, and for each element we access the value_vector which is O(1).
  4. Should be O(n) to go through each element of nonzero_inds, access corresponding values index, access the corresponding nonzero_values element, and assign it to the values vector.

The code above takes about 5 seconds to run through steps 1-4 on 4 cores, 3.8GHz. Do you all have any ideas on how this could be sped up? Thanks.

sw_buddy
  • 125
  • 1
  • 9
  • 2
    Are the extra (and possibly unused) elements from the 0s necessary? If not, wouldn't `randi([1 m], n, 1)` with none of the filtering code suffice? – TroyHaskin Oct 13 '20 at 23:38
  • why are you pre-allocating a vector with zeros (step 0) and assign non-zero values only to certain indices (step 4)? In the end, you obtain a again a vector that contains zeros... – max Oct 14 '20 at 06:46
  • @TroyHaskin Sorry, I should have specified and have updated the description to clarify that the "given" data is just simulating what I will actually have to work with, and I just used random values to show this example. So I will actually have 0 values and I can't be rid of them, and I'm trying to speed up steps 1-4. @ max the values vector contains more than just zeros. The code is self-sufficient if you have matlab and want to run it. The nonzero inds are assigned nonzero values – sw_buddy Oct 14 '20 at 13:47
  • 1
    There is a more efficient solution if you could create `index_vector` as `randi([1 201], n, 1);` – rahnema1 Oct 14 '20 at 15:21
  • I was just thinking that as well - we could change `value_vector = [0; value_vector]` so and `index_vector = index_vector + 1` so that index 1 now assigns a value of 0, which is happening anyways, and the rest are still assigned correctly. It seems like this could be faster. – sw_buddy Oct 14 '20 at 16:40

2 Answers2

1

Wow, I found something really interesting. I saw this link in the "related" section about indexing vectors being inefficient in Matlab sometimes, so I decided to try a for loop. This code ended up being an order of magnitude faster!

for i = 1:n
    if index_vector(i) > 0
        values(i) = value_vector(index_vector(i));
    end
end

EDIT: Another interesting thing, unfortunately detrimental to my problem though. The speed of this solution depends on the amount of zeros in the index_vector. With index_vector = randi([0 200]);, a small proportion of the values are zeros, but if I try index_vector = randi([0 1]), approximately half of the values will be zero and then the above for loop is actually an order of magnitude slower. However, using ~= instead of > speeds the loop back up so that it's on a similar order of magnitude. Very interesting and odd behavior.

sw_buddy
  • 125
  • 1
  • 9
0

if you stick to matlab and the flow of the algorithm you want , and not doing this in fortran or c, here's a small start:

change the randi to rand, and round by casting to uint8 and use the > logical operation that for some reason is faster at my end

to sum up:

value_vector = rand(m, 1 );
index_vector = uint8(-0.5+201*rand(n,1) );
values = zeros(n, 1);
values=value_vector(index_vector(index_vector>0));

this improved at my end by a factor 1.6

dpdp
  • 322
  • 1
  • 6
  • Thanks, I should have clarified on my post that I was only trying to speed up steps 1-4; the given values/vectors will be predetermined. I tried `>` but unfortunately didn't see any speed up. Thanks for the comment though! – sw_buddy Oct 14 '20 at 13:42