在向量中搜索的计算量太大

时间:2012-02-23 00:15:36

标签: database matlab search optimization

我需要执行以下代码块:

x = some_number;
y = some_other_number;

u = a_vector_of_numbers;
v = another_vector_of_numbers;
% u and v are of equal size

r1 = ((x == u) | (x == v));   % Expensive!
r2 = ((y == u) | (y == v));   % Expensive!

q = any(r1 & r2);

您可以将其视为:xy是图表上的两个节点,除非我弄错了,否则会检查xy是否已连接邻接列表[r1, r2]。换句话说,我试图回答这个问题:“是否有这样的索引i可以在x或{{1}找到yr1(i) }?“

我需要反复这样做。 r2(i)r1都可能包含多达数千个唯一值(图表上的节点数量为10 4 ),其长度为数十万(边数为10 6

我的分析器告诉我,我用注释表示的两行消耗了99%的运行时间,而我的程序运行需要很长时间,所以我想知道:这可以进行多少优化?最小计算时间的基本限制是什么,我的接近程度是多少?

此外,将此特定代码外包给另一种语言会非常容易。能做到这一点会带来显着的性能提升吗?

2 个答案:

答案 0 :(得分:4)

如果您的第一次检查(r1)可能会删除大部分结果,则可以预先过滤第二次检查以仅检查可能的匹配项。代码看起来像这样:

mask_r1 = ((x == u) | (x == v));   % Expensive!
r2 = ((y == u(mask_r1)) | (y == v(mask_r1)));   % Less expensive!
q = any(r2);

我甚至看过案例(通常在旧版本的Matlab中),在第一行添加find可以提高性能。但我认为这不再是真的(他们已经将这种优化引入解析器。)这三种方法的一些时序结果(原始,使用逻辑掩码,使用显式索引列表)如下:

x = 2;
y = 3;
v = randi(200,1e5,1);
u = randi(200,1e5,1);

tic;
for ix = 1:1000
    r1 = ((x == u) | (x == v));   % Expensive!
    r2 = ((y == u) | (y == v));   % Expensive!
    q = any(r1 & r2);
end
toc;  %1.175234


tic;
for ix = 1:1000
    mask_r1 = ((x == u) | (x == v));   % Expensive!
    r2 = ((y == u(mask_r1)) | (y == v(mask_r1)));   % Less expensive!
    q = any(r2);
end
toc;  %0.878857

tic;
for ix = 1:1000
    ixs_r1 = find(((x == u) | (x == v)));   % Expensive!
    r2 = ((y == u(r1)) | (y == v(r1)));   % Less expensive!
    q = any(r2);
end
toc;  %1.118103

答案 1 :(得分:3)

我没有测试过这个建议,过多地努力设置一些真实的测试数据,但是......

您是否尝试为图表创建邻接矩阵并将其用于查询?虽然创建矩阵(一次)将是一个相对昂贵的操作,检查边缘的存在会比读取两个邻接列表便宜得多(我认为)。

如果你坚持使用当前的算法(或者更重要的是,使用当前的数据结构),如果只是通过将工作卸载到另一种语言的实现来获得更多的速度,我会感到惊讶。使用另一种语言并不会改变您正在阅读寻找值的长数据向量的事实。