我想问一下我在使用Fortran管理CSR / CSC *矩阵时经常遇到的问题。 假设我们有一个具有N个实数值的向量V.先前已经以一定大小分配了向量。现在我们必须在索引P的中间添加一个值。 蛮力代码将是:
allocate(tempV(N))
tempV=V
deallocate(V)
allocate(V(N+1))
V=(/tempV(1:P-1), newValue, tempV(P:N)/)
deallocate(tempV)
显然,如果一旦这不成问题就完成了,但重复数千次就不会那么有效。内存将填充并清空我想要插入的每个值4次。
我想知道哪种方法可以解决这个问题。你可以提出简单的Fortran(首选),也可以提供像MKL / Lapack / Blas这样的库的一些解决方案。
附录:我可以用RESHAPE吗?通过this definition(与我的Fortran-book定义相同),我可以做类似
的事情REAL, DIMENSION(1:1) :: newPad = (/ newValue /)
V=RESHAPE(V, (/ N+1 /), PAD=newPad)
现在已在V的末尾添加了值,因此我使用
进行排列V =(/ V(1:P-1),V(N + 1:N + 1),V(P:N)/)
通过这种方式,可以避免明确创建临时向量并丢失分配。
它是否有效且可扩展,因为RESHAPE可以在库中已经并行化了吗?
* PS :为了清楚起见CSR =压缩稀疏行格式,CSC =压缩稀疏列格式,此处有更多信息:
答案 0 :(得分:3)
为此目的引入了Fortran 2003子例程move_alloc
。它将分配状态,数组边界,动态类型,类型参数和值从源移动到目标,而不实际复制数据。源变量将被取消分配。
使用move_alloc
的简短示例修改代码,只需要一次复制操作:
allocate(tempV(N+1))
tempV(:P-1) = V(:P-1)
tempV(P) = newValue
tempV(P+1:) = V(P:)
call move_alloc(tempV, V)
当然,一次为多个项目执行此操作会减少分配开销,但这对您来说可能是不可能的。
修改强>
至于指针的建议,如果你不能使用任何F2003功能,你可能会使用一个像这样的子程序:
pure subroutine insert(arr, val, pos)
real, pointer, intent(inout) :: arr(:)
real, intent(in) :: val
integer, intent(in) :: pos
real, pointer :: temp(:)
if(associated(arr)) then
allocate(temp(lbound(arr,1):ubound(arr,1) + 1))
! ...or perhaps check/do something if pos is not within these bounds
temp(:pos-1) = arr(:pos-1)
temp(pos) = val
temp(pos+1:) = arr(pos:)
deallocate(arr)
arr => temp
endif
end subroutine insert
当然,您可以轻松地将其与您的目的相适应或使其更通用。您可以将它与分配的指针变量一起使用:
real, pointer :: V(:)
! :
allocate(V(10))
V = 1.
! :
call insert(V, 3.141592, 5)
答案 1 :(得分:1)
问题是,您是否需要在插入后立即使用CSR格式,或者您可以首先以更加插入的格式插入更多插入,然后转换为CSR。
您可以查看sparskit及其链接列表存储格式,或者您可以为自己创建一些新元素的链接列表,一旦完成插入,您就可以构建一个新的CSR格式化矩阵,不遗余力地重新调整数据。