Julia 将能够很好地优化该代码,但我们可以在一定程度上简化和提高性能。既然您提到了迭代器,让我们从使用迭代器理解的解决方案开始,我们使用sum 对值求和并分解出公因子list[i]:
list[i]*sum(list[j] for j in 1:length(list) if mat[i,j] == 1)
这或多或少被朱莉娅解释为:
-list[i]*sum(Iterators.map(j->list[j], Iterators.filter(j -> mat[i,j] == 1, 1:length(list))))
但理解更简洁,您可能看起来更熟悉。
这比原来的性能略高(节省 20%-30% 的时间),但是,迭代器通常不是最快的解决方案,除非内存是瓶颈。让我们尝试广播:
-list[i]*sum(list[mat[i,:] .== 1])
这进一步提高了性能(在我的测试中比原来节省了 40%)。
我们不需要mat[i,:] 的副本,所以让我们使用视图:
list[i]*sum(list[@view(mat[i,:]) .== 1])
现在我们已经削减了 50% 以上。当然,只使用一个产品可能更简单(因为我们有 0 和 1)并且性能相似:
-list[i]*sum(list .* mat[i,:])
如果您可以以不同的方式排列数据,则应该可以进一步提高性能,例如使用 BitMatrix 代替数字并使用转置矩阵,因此我们迭代列而不是行(因为 Julia 使用列优先顺序)。
基准测试:
using BenchmarkTools
function original(mat, list, i)
N = length(list)
e = 0
for j in (1:N)
if mat[i,j] == 1
e += -(list[i]*list[j])
end
end
e
end
function sol1(mat, list, i)
-list[i]*sum(list[j] for j in 1:length(list) if mat[i,j] == 1)
end
function sol2(mat, list, i)
-list[i]*sum(list[mat[i,:] .== 1])
end
function sol3(mat, list, i)
-list[i]*sum(list[@view(mat[i,:]) .== 1])
end
function sol4(mat, list, i)
-list[i]*sum(list .* mat[i,:])
end
mat = rand(0:1, 1000, 1000)
list = rand(1000)
i = rand(1:1000)
@btime original($mat, $list, $i)
@btime sol1($mat, $list, $i)
@btime sol2($mat, $list, $i)
@btime sol3($mat, $list, $i)
@btime sol4($mat, $list, $i)