这段代码可以进一步矢量化以消除循环吗?

时间:2015-11-09 13:06:43

标签: matlab optimization vectorization

我正在研究MATLAB中的光线跟踪几何问题,并且在我的程序中遇到了瓶颈。

该函数接收光线的起点和终点( lStart lEnd ),一组平面点和法线( pPoint 规范)。然后,该函数计算沿着与每个平面相交的光线的距离。

以下是对原始等式的引用:https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection#Algebraic_form

我到目前为止的代码如下:

dists = (diag(bsxfun(@minus, pPoint, lStart) * norms')) ./ ((lEnd - lStart) * norms')';

在循环中调用了它,例如:

nRays   = size(lStart, 1);
nPlanes = size(pPoint, 1);
dists   = zeros(nPlanes, nRays);

for rayCtr = 1:nRays

    dists(:, rayCtr) = (diag(bsxfun(@minus, pPoint, lStart(rayCtr, :)) * norms')) ./...
         ((lEnd(rayCtr, :) - lStart(rayCtr, :)) * norms')';

end

这对于单个光线非常有效。

鉴于一条光线 [1 x 3] 和300架 [300 x 3] ,我得到一个 [300 x 1] 矩阵与每个平面交叉点的距离。

我正在努力的是,将其矢量化为光线列表。

典型数据集中的大小为:

lStart, lEnd  = [14e6, 3];
pPoint, norms = [300,  3];

光线处理通常分为数万个 - 以适应内存。对于每个批次,我想消除rayCtr循环。使用这种方法,整个程序只需要8个小时(32位,Windows,2GB RAM)。

以下是六个平面(形成一个长方体)和两个光线作为MWE的一些坐标:

pPoint = [-0.5000   -0.5000   -0.5000;
          -0.5000   -0.5000    0.5000;
          -0.5000   -0.5000   -0.5000;
          -0.5000    0.5000   -0.5000;
          -0.5000   -0.5000   -0.5000;
           0.5000   -0.5000   -0.5000]

norms = [0  0   1;
         0  0   1;
         0  1   0;
         0  1   0;
         1  0   0;
         1  0   0]

lStart = [-1 0 0;
          -1 0.25 0]

lEnd   = [1 0 0;
          1 0.25 0]

示例的预期输出是:

dists = [-Inf -Inf;
          Inf  Inf; 
         -Inf -Inf; 
          Inf  Inf; 
          0.25 0.25; 
          0.75 0.75]

非常感谢。

更新:根据已接受答案中提出的解决方案,运行时间缩短到大约30分钟 - 现在受到读写操作和体素查找的限制。

1 个答案:

答案 0 :(得分:11)

我认为你需要的是

dists=sum(bsxfun(@times,bsxfun(@minus,...
                               permute(pPoint,[1 3 2]),permute(lStart,[3 1 2])),...
                 permute(norms,[1 3 2])),3)...
        ./(sum(bsxfun(@times,...
                      permute(lEnd-lStart,[3 1 2]),permute(norms,[1 3 2])),3))

这假定pPointnorms的尺寸为[nlay 3],而lStartlEnd的尺寸为[nray 3]。结果大小为[nlay nray],每个对应一个(图层,光线)对。

这为您的示例提供了正确的结果:

dists =

      -Inf      -Inf
       Inf       Inf
      -Inf      -Inf
       Inf       Inf
    0.2500    0.2500
    0.7500    0.7500

这是为分母部分计算引入一些fast matrix-multiplication的另一种方法 -

p1 = sum(bsxfun(@times,bsxfun(@minus,pPoint,permute(lStart,[3 2 1])),norms),2)
p2 = norms*(lEnd - lStart).'
dists = squeeze(p1)./p2

由于lStart被列为数据集,因此最好保持原样并置换周围的事物。因此,获得squeeze(p1)的另一种方法是 -

squeeze(sum(bsxfun(@times,bsxfun(@minus,permute(pPoint,[3 2 1]),lStart),permute(norms,[3 2 1])),2)).'