在已分配的向量fortran中插入值更改形状

时间:2013-01-30 15:02:14

标签: arrays performance memory-management fortran

我想问一下我在使用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 =压缩稀疏列格式,此处有更多信息:

MKL定义: http://software.intel.com/sites/products/documentation/hpc/mkl/mklman/GUID-9FCEB1C4-670D-4738-81D2-F378013412B0.htm

2 个答案:

答案 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格式化矩阵,不遗余力地重新调整数据。