0

So my problem is, I'd like to do this without the for loop. Geting the prod() of multiple vectors but of different lengths.

I am dealing with rays intersecting voxels. I typically have 1e6 rays and 1e5 voxels, but this can vary.

intxRays is a list of rays that have intersected voxels.

gainList is a one dimensional vector, each element has a value that corresponds to a specific ray voxel intersection calculated previously (actually with the help of you lovely lot here).

rayIntxStart and rayIntxEnd are vectors of indices for, where in the gainlist array, each ray's corresponding values start and end (they're all in order).

Here is the code and some examples and expected outputs.

gainSum = zeros(1, 5);

% only interested in the intx uniques
intxSegCtr = 1;

% loop through all of the unique segments
for rayCtr = 1:max(intxRays)

    if rayCtr == intxRays(intxSegCtr)

        startInd = rayIntxStart(intxSegCtr);
        endInd = rayIntxEnd(intxSegCtr);

        % find which rows correspoond to those segements
        gainVals = gainList(startInd:endInd);
        gainProd = prod(gainVals);

        % get the product of the gains for those voxels
        gainSumIdx = intxRays(intxSegCtr);
        gainSum(gainSumIdx) = gainProd;

        % increment counter
        intxSegCtr = intxSegCtr + 1;

    end
end

Example data for five rays and nine voxels. Assume the voxel gain array looked like this (for simplicity) for nine voxels (used in previous step).

voxelGains = 10:10:90;

Now say rays 1 and 3 don't hit anything, ray 2 hits voxels 1 and 2, ray 4 hits voxels 2:7 and ray 5 hits voxels 6:9

intxRays = [2, 4, 5];

gainList = [10, 20, 20, 30, 40, 50, 60, 70, 60 70, 80, 90];

rayIntxStart = [1, 3, 9];

rayIntxEnd = [2, 8, 12];

For these numbers the above code would give as a result:

gainSum = [0, 200, 0, 5.0400e+09, 3.024e+07];

I hope this all makes sense.

When I developed it I was using far smaller ray and voxel numbers and it worked fine. As I'm moving up though, the major bottleneck in my code is this loop. Actually just the gainVals and gainProd assignment is like 80% and 15% of my runtime on their own.

This is the only method I can find that works, padding and the like won't work due to the sizes involved.

Is there a way to get the value I want, without this loop?

Many thanks!

Community
  • 1
  • 1
Adam Sroka
  • 100
  • 7
  • your code does not give the shown output nor does it actually work. is it correct that: SegCtr is probably intxSegCtr ; length(intxRays) should be max(intxRays) and intxSegCtr = intxSegCtr + 1; should be at the end of the loop? i feel like then it works as it should – Finn Aug 25 '16 at 14:43
  • Sorry had been away. This is a very simplified version of the actual code so there's a good chance I've translated it wrong. I'll go through it again and update. Thank you. – Adam Sroka Aug 30 '16 at 10:30
  • @Finn It has been updated, thanks for spotting that! – Adam Sroka Aug 30 '16 at 10:56
  • wb! there are a few ways to simplfy that loop and maybe more. Do the given vectors in this example get calculated somewhere else by a loop? – Finn Aug 30 '16 at 11:55
  • Thanks! Both intxRays and gainList are calculated in other functions from data extracted from an external ray-tracer (Zemax in this case). – Adam Sroka Aug 30 '16 at 11:59
  • do you happen to have a bigger data set? with 3 rays it is hard to compare the calculation time – Finn Aug 30 '16 at 13:37
  • All of the real data sets are GBs, I can try and produce something smaller maybe? – Adam Sroka Aug 31 '16 at 10:23
  • yeah that could work like enough to calculate more than a second. it just had to be enough so the random background part of the calculatoin time can be neglected – Finn Aug 31 '16 at 12:25

1 Answers1

1

ok this is a very small performance boost, but it might help. for testing the matrix way without the loop a bigger data sample is needed.

These are 3 soultions, your original, an optimized and the optimized way as a oneliner. could you please try if this is already doing something for you?

clear all
% orignial loop through all Rays
intxRays = [2, 4, 5];
gainList = [10, 20, 20, 30, 40, 50, 60, 70, 60 70, 80, 90];
rayIntxStart = [1, 3, 9];
rayIntxEnd = [2, 8, 12];
gainSum = zeros(1, 5);
tic
% only interested in the intx uniques
intxSegCtr = 1;

% loop through all of the unique segments
for rayCtr = 1:max(intxRays)

    if rayCtr == intxRays(intxSegCtr)

        startInd = rayIntxStart(intxSegCtr);
        endInd = rayIntxEnd(intxSegCtr);

        % find which rows correspoond to those segements
        gainVals = gainList(startInd:endInd);
        gainProd = prod(gainVals);

        % get the product of the gains for those voxels
        gainSumIdx = intxRays(intxSegCtr);
        gainSum(gainSumIdx) = gainProd;

        % increment counter
        intxSegCtr = intxSegCtr + 1;

    end
end
toc

clear all
%loop insted of every single one to max just through the intxRays
intxRays = [2, 4, 5];
gainList = [10, 20, 20, 30, 40, 50, 60, 70, 60 70, 80, 90];
rayIntxStart = [1, 3, 9];
rayIntxEnd = [2, 8, 12];
gainSum = zeros(1, 5);
tic
for rayCtr=1:length(intxRays)
    %no if as you just go through them
    %intxRays(rayCtr) is the corresponding element

     startInd = rayIntxStart(rayCtr);
     endInd = rayIntxEnd(rayCtr);
     % find which rows correspoond to those segements
     gainVals = gainList(startInd:endInd);
     gainProd = prod(gainVals);     

    % get the product of the gains for those voxels and set them to the ray
    gainSum(intxRays(rayCtr)) = gainProd;
end
%disp(gainSum);
toc

clear all
%same as above, but down to 1 line so no additional values are generated
intxRays = [2, 4, 5];
gainList = [10, 20, 20, 30, 40, 50, 60, 70, 60 70, 80, 90];
rayIntxStart = [1, 3, 9];
rayIntxEnd = [2, 8, 12];
gainSum = zeros(1, 5);
tic
for rayCtr=1:length(intxRays)
gainSum(intxRays(rayCtr))=prod(gainList(rayIntxStart(rayCtr):rayIntxEnd(rayCtr)));
end
toc
Finn
  • 2,333
  • 1
  • 10
  • 21
  • This is definitely faster. I had played around with something similar but eventually split it all up for ease of understanding and to isolate the bottleneck. I'll leave it a few days longer before accepting, this just in case. – Adam Sroka Aug 31 '16 at 10:25
  • So implementing it with the final solution proposed here is quicker, I'd love a solution that didn't need the for loop though. – Adam Sroka Aug 31 '16 at 12:05
  • i tried something without a loop but it takes logner as calculationg the matrizes isn't worth it for 3 rays. also are there other data variants available? i feel like it would be easier if you just had the information which ray hit which voxel and the gain of a voxel instead of the gain list and the inidzes per ray – Finn Aug 31 '16 at 12:28
  • I have that data but due to data sizes I found it easier to develop this way. I'll have another look at this and see if I can present the question better another way. – Adam Sroka Aug 31 '16 at 13:50