Julia中如何高效复用稀疏矩阵的稀疏模式?
在Julia中高效复用稀疏矩阵的稀疏模式
复用已创建稀疏矩阵的稀疏模式,核心是跳过重新构建矩阵索引结构(colptr、rowval等内部数组)的开销,直接操作存储非零值的nzval数组。以下是两种高效实现方式:
方法1:预排序后直接赋值(性能最优)
如果可以在首次创建矩阵时对(I,J)排序,后续更新值时无需任何索引查找,直接将排序后的新值覆盖nzval即可:
using SparseArrays N = 10 I = vec([1, 1, 2, 2]' .+ (0:N)) J = vec([1, 2, 1, 2]' .+ (0:N)) V = vec([1,-1,-1, 1]' .* ones(N+1)) # 首次创建时,按(I,J)排序并记录排序索引 perm = sortperm(collect(zip(I, J))) I_sorted = I[perm] J_sorted = J[perm] V_sorted = V[perm] A = sparse(I_sorted, J_sorted, V_sorted) # 准备新值W W = vec([1,-1, 1,-1]' .* ones(N+1)) # 对W应用相同排序,直接赋值给nzval W_sorted = W[perm] A.nzval .= W_sorted
这种方式仅在首次创建时多一次排序开销,后续更新的时间复杂度为O(n),远快于重新调用sparse。
方法2:建立(I,J)到nzval索引的映射(灵活通用)
如果无法提前排序,或原始(I,J)存在重复项(已被sparse合并),可以通过字典建立非零位置与nzval索引的映射:
using SparseArrays N = 10 I = vec([1, 1, 2, 2]' .+ (0:N)) J = vec([1, 2, 1, 2]' .+ (0:N)) V = vec([1,-1,-1, 1]' .* ones(N+1)) A = sparse(I, J, V) # 生成唯一(I,J)对到nzval索引的映射 i_sparse, j_sparse, _ = findnz(A) pos_map = Dict(zip(zip(i_sparse, j_sparse), eachindex(A.nzval))) # 准备新值W W = vec([1,-1, 1,-1]' .* ones(N+1)) # 查找每个原始位置对应的索引并赋值 indices = [pos_map[(I[k], J[k])] for k in eachindex(I, J, W)] A.nzval[indices] .= W
注意:若原始(I,J)存在重复项,sparse会默认合并这些位置的值(求和),此时映射中每个唯一(I,J)仅对应一个索引,需确保新值W也按相同规则合并后再赋值。
关于你原始方法的效率问题
你之前使用的A[I + size(A,2)*(J-1)] += W,本质是逐个查找每个(I[k],J[k])在稀疏矩阵中的位置,每次查找的时间复杂度为O(log n),当非零元素数量较大时,总开销会远超重新创建矩阵或上述两种方法。
内容的提问来源于stack exchange,提问作者acc963475
相关产品推荐
相关产品推荐

