performance - Matlab代码的向量化

标签 performance matlab optimization vectorization

我对矢量化有点陌生我已经试过了,但是不行。能不能有人帮我把这段代码矢量化,并简单解释一下你是怎么做到的,这样我也能适应思考的过程谢谢。

function [result] = newHitTest (point,Polygon,r,tol,stepSize)
%This function calculates whether a point is allowed.

%First is a quick test is done by calculating the distance from point to 
%each point of the polygon. If that distance is smaller than range "r", 
%the point is not allowed. This will slow down the algorithm at some 
%points, but will greatly speed it up in others because less calls to the 
%circleTest routine are needed.
polySize=size(Polygon,1);
testCounter=0;

for i=1:polySize
d = sqrt(sum((Polygon(i,:)-point).^2));

if d < tol*r
    testCounter=1;
    break
end
end

if testCounter == 0
circleTestResult = circleTest (point,Polygon,r,tol,stepSize);
testCounter = circleTestResult;
end

result = testCounter;

最佳答案

考虑到Polygon是二维的,point是行向量,其他变量是标量,下面是新函数的第一个版本(向下滚动查看有很多方法可以对这只猫进行蒙皮):

function [result] = newHitTest (point,Polygon,r,tol,stepSize)
result = 0;
linDiff = Polygon-repmat(point,size(Polygon,1),1);
testLogicals = sqrt( sum( ( linDiff ).^2 ,2 )) < tol*r;    
if any(testLogicals); result = circleTest (point,Polygon,r,tol,stepSize); end

在Matlab中,矢量化的思想过程包括尝试使用一个命令操作尽可能多的数据大多数内置的Matlab函数在多维数据上运行非常高效使用for循环与此相反,因为您要将数据分解成更小的段进行处理,每个段都必须单独解释通过使用for循环进行数据分解,您可能会失去一些与Matlab内置函数背后的高度优化代码相关的巨大性能优势。
在您的示例中,首先要考虑的是主循环中的条件中断不能从矢量化进程中断相反,计算所有可能的结果,为数据的每一行创建一个结果数组,然后使用any关键字查看是否有任何行发出了应该调用circleTest函数的信号。
注:在Matlab中,不容易有效地有条件地中断计算然而,由于您只是在循环中计算欧几里德距离的一种形式,您可能会看到通过使用矢量化版本和计算所有可能的性能提升如果您的循环中的计算更昂贵,输入数据很大,并且您希望在遇到某个条件时立即中断,那么使用编译语言进行的matlab扩展可能比执行不必要计算的矢量化版本快得多不过,这是假设您知道如何用编译为本机代码的语言编写与Matlab内置代码性能匹配的代码。
回到话题。。。
首先要做的是取linDiff和行向量Polygon之间的线性差(point,在代码示例中)要以矢量化的方式执行此操作,两个变量的维度必须相同实现这一点的一种方法是使用repmat复制point的每一行,使其大小与Polygon相同然而,bsxfun通常是repmat(as described in this recent SO question)的一个更好的替代品,使得代码。。。
function [result] = newHitTest (point,Polygon,r,tol,stepSize)
result = 0;
linDiff = bsxfun(@minus, Polygon, point);
testLogicals = sqrt( sum( ( linDiff ).^2 ,2 )) < tol*r;    
if any(testLogicals); result = circleTest (point,Polygon,r,tol,stepSize); end

通过将第二个轴相加,将你的d值滚动到一个d列中(注意从Polygon中删除数组索引,并在,2命令中添加sum)。然后我进一步计算了逻辑数组testLogicals与距离度量的计算您很快就会发现,重矢量化的一个缺点是,它会使那些不熟悉Matlab的人对代码的可读性降低,但是性能的提高是值得的评论是非常必要的。
现在,如果你想彻底疯掉,你可以争辩说测试函数是如此简单,以至于它需要使用“匿名函数”或“lambda”,而不是一个完整的函数定义测试是否值得执行circleTest也不需要stepSize参数,这可能是使用匿名函数的另一个原因您可以将测试滚动到一个匿名函数中,然后在调用脚本中使用circleTest,从而在某种程度上使代码自文档化…
doCircleTest = @(point,Polygon,r,tol) any(sqrt( sum( bsxfun(@minus, Polygon, point).^2, 2 )) < tol*r);

if doCircleTest(point,Polygon,r,tol)
    result = circleTest (point,Polygon,r,tol,stepSize); 
else
    result = 0;
end

现在一切都矢量化了,函数句柄的使用给了我另一个想法…
如果计划在代码中的多个点执行此操作,则if语句的重复将变得有点难看为了保持dry,将带有条件函数的测试放在单个函数中似乎是明智的,就像您在原始文章中所做的那样但是,该函数的实用性将非常有限-它只测试是否应该执行circleTest函数,然后在需要时执行它。
现在想象一下,过一段时间,你有一些其他的条件函数,就像circleTest,它们自己等价于doCircleTest也许可以重用条件转换代码为此,创建一个与原始函数类似的函数,该函数接受默认值、计算成本较低的测试函数的布尔结果以及成本较高的条件函数的函数句柄及其相关参数。。。
function result = conditionalFun( default, cheapFunResult, expensiveFun, varargin )
if cheapFunResult
    result = expensiveFun(varargin{:});
else
    result = default;
end
end %//of function

您可以使用以下命令从主脚本调用此函数…
result = conditionalFun(0, doCircleTest(point,Polygon,r,tol), @circleTest, point,Polygon,r,tol,stepSize);

…它的优点是可以使用任何测试、默认值和昂贵的函数对于这个简单的例子来说,可能有点过分了,但是当我提出使用函数句柄的想法时,我的思想就在这里徘徊。

关于performance - Matlab代码的向量化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12949936/

相关文章:

python - 如果你不分配它,列表理解的效率如何?

matlab - 如何在 MATLAB 中获取矩阵的值,其中索引在 nx2 数组中给出

r - 在自定义 R 函数中预分配内存以提高性能(使用 dplyr)

javascript - 如何衡量单页应用程序中的客户端性能

c# - 对于非常长的字符串列表,什么是合适的搜索/检索方法?

matlab - 某些频率下功率谱的时间变化[MATLAB]

Matlab:在没有循环的情况下对对象进行乘法赋值

java - 打印所有 JVM 标志

ios - 优化 iOS 应用程序的迭代循环

performance - 我需要解决NP难题。有希望吗?