我需要执行以下代码块:
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);
您可以将其视为:x
和y
是图表上的两个节点,除非我弄错了,否则会检查x
和y
是否已连接邻接列表[r1, r2]
。换句话说,我试图回答这个问题:“是否有这样的索引i
可以在x
或{{1}找到y
和r1(i)
}?“
我需要反复这样做。 r2(i)
和r1
都可能包含多达数千个唯一值(图表上的节点数量为10 4 ),其长度为数十万(边数为10 6 。
我的分析器告诉我,我用注释表示的两行消耗了99%的运行时间,而我的程序运行需要很长时间,所以我想知道:这可以进行多少优化?最小计算时间的基本限制是什么,我的接近程度是多少?
此外,将此特定代码外包给另一种语言会非常容易。能做到这一点会带来显着的性能提升吗?
答案 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)
我没有测试过这个建议,过多地努力设置一些真实的测试数据,但是......
您是否尝试为图表创建邻接矩阵并将其用于查询?虽然创建矩阵(一次)将是一个相对昂贵的操作,检查边缘的存在会比读取两个邻接列表便宜得多(我认为)。
如果你坚持使用当前的算法(或者更重要的是,使用当前的数据结构),如果只是通过将工作卸载到另一种语言的实现来获得更多的速度,我会感到惊讶。使用另一种语言并不会改变您正在阅读寻找值的长数据向量的事实。