在Matlab中有效地找到满足逻辑条件的向量的第一个元素

时间:2017-07-17 14:42:08

标签: matlab performance find vectorization

我需要找到满足条件A(i)< = b的向量A的第一个元素的索引。我事先知道A的至少一个元素符合条件。我尝试过这个,但效率非常低:

i = find(A <= b, 1)

似乎Matlab正在做与此相同的事情:

X = A <= b
find(X, 1)

计算X的所有元素都有浪费:一旦遇到i,你就应该停止A(i)&lt; = b。所以我尝试了这个:

for i = 1 : length(A)

    if A(i) <= b

        break

    end

end

但迭代代码甚至比矢量化代码慢。

有没有办法更有效地执行此查找?

1 个答案:

答案 0 :(得分:1)

我不确定你是如何得出循环代码比矢量化代码慢的结论,但这里是结果的基准和一些上下文!

我正在使用2015b,所以这可能会利用Matlab的new(ish) JIT compiler

function benchie()
    A = rand(1e9, 1);
    b = 0.01;
    f = @() original(A,b);
    g = @() usingloop(A,b);
    disp(['Original with logical A <= b:    ', num2str(timeit(f)), ' sec']);
    disp(['Looping until found, then break: ', num2str(timeit(g)), ' sec']);
end
% Both of these functions return the same value for idx
function idx = original(A,b)
    idx = find(A <= b, 1);
end    
function idx = usingloop(A,b)
    for idx = 1:length(A)
        if A(idx) <= b
            break
        end
    end
end

<强>输出

Original with logical A <= b:    0.83666 sec

Warning: The measured time for F [function g] may be inaccurate because it is running
too fast. Try measuring something that takes longer. 
> In timeit (line 158)
  In benchie (line 7) 
Looping until found, then break: 1.8043e-06 sec

<强>摘要

使A与我的RAM一样大(8GB),usingloop方法仍然太快,timeit认为自己准确无误!这两个函数都给出了相同的答案,我认为usingloop的速度要快几个数量级。

我希望包含一个显示不同大小数组时间比较的图表,但不能usingloop太快...

注意:我使用idx作为我的变量而不是i。这是因为默认情况下i是复数常量sqrt(-1),并且在写过时您将立即产生(小)性能影响!

修改

我运行了另一个测试,其中A = 1e8:-1:1;b的值为A的每十分之一,以确定向量化的开销是否超过了进一步循环所需的时间进入阵列。以下是输出:

benchmark

您可以看到逻辑比较的开销几乎都是所需的时间,并且无论位置如何,该向量的实际索引都非常小。相反,一旦所需元素进入数组的短路,循环方法就很糟糕。

鉴于MATLAB使用矢量化和逻辑索引进行快速计算的声誉,我将回应@beaker的评论,说自定义(编译)C函数可能是看到对原始方法有任何改进的唯一方法。