【问题标题】:A method to vectorise a call to prod() for lots of arrays of varying length?一种对大量不同长度数组的 prod() 调用进行矢量化的方法?
【发布时间】:2016-08-25 14:12:30
【问题描述】:

所以我的问题是,我想在没有 for 循环的情况下执行此操作。获取多个向量但长度不同的 prod()。

我正在处理与体素相交的光线。我通常有 1e6 个射线和 1e5 个体素,但这可能会有所不同。

intxRays 是与体素相交的光线列表。

gainList 是一个一维向量,每个元素都有一个值,对应于之前计算的特定射线体素交点(实际上是在你可爱的很多 here 的帮助下)。

rayIntxStartrayIntxEnd 是索引的向量,在 gainlist 数组中,每条射线的对应值开始和结束(它们都是按顺序排列的)。

这是代码和一些示例以及预期的输出。

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

五条射线和九个体素的示例数据。假设体素增益数组对于九个体素(在上一步中使用)看起来像这样(为简单起见)。

voxelGains = 10:10:90;

现在假设光线 1 和 3 不击中任何物体,光线 2 击中体素 1 和 2,光线 4 击中体素 2:7 并且射线 5 击中体素 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];

对于这些数字,上面的代码会给出结果:

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

我希望这一切都有意义。

当我开发它时,我使用的光线和体素数要小得多,而且效果很好。不过,当我向上移动时,我的代码中的主要瓶颈是这个循环。实际上,仅 gainValsgainProd 分配就占了我运行时间的 80% 和 15%。

这是我能找到的唯一可行的方法,填充等由于涉及的尺寸而不起作用。

有没有办法在没有这个循环的情况下获得我想要的值?

非常感谢!

【问题讨论】:

  • 您的代码没有给出显示的输出,也没有实际工作。是否正确: SegCtr 可能是 intxSegCtr ; length(intxRays) 应该是 max(intxRays) 并且 intxSegCtr = intxSegCtr + 1;应该在循环的末尾?我觉得它应该可以正常工作
  • 很抱歉离开了。这是实际代码的一个非常简化的版本,所以很有可能我翻译错了。我会再看一遍并更新。谢谢。
  • @Finn 已更新,感谢您发现!
  • wb!有几种方法可以简化该循环,甚至更多。此示例中的给定向量是否通过循环在其他地方计算?
  • 谢谢! intxRays 和 gainList 都是在其他函数中根据从外部光线追踪器(本例中为 Zemax)提取的数据计算得出的。

标签: matlab for-loop optimization vectorization


【解决方案1】:

好的,这是一个非常小的性能提升,但它可能会有所帮助。为了在没有循环的情况下测试矩阵方式,需要更大的数据样本。

这些是 3 个灵魂,您的原创,优化和优化的方式作为 oneliner。如果这已经为你做了什么,你能试试吗?

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

【讨论】:

  • 这肯定更快。我曾经玩过类似的东西,但最终为了便于理解和隔离瓶颈而将其全部拆分。我会在接受之前再放几天,以防万一。
  • 因此使用此处提出的最终解决方案来实现它会更快,但我希望有一个不需要 for 循环的解决方案。
  • 我尝试了一些没有循环的东西,但它需要 logner 作为计算,对于 3 条射线来说,矩阵不值得。还有其他可用的数据变体吗?我觉得如果你只知道哪条射线击中哪个体素和体素的增益而不是增益列表和每条射线的 inidzes 信息会更容易
  • 我有这些数据,但由于数据量大,我发现这种方式更容易开发。我会再看看这个,看看我是否可以用另一种方式更好地提出这个问题。
猜你喜欢
  • 2021-10-13
  • 2011-04-13
  • 2013-01-07
  • 1970-01-01
  • 2019-01-23
  • 2020-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多