问题
I would like to ask you about a problem that I have frequently in the management of CSR/CSC* matrices using Fortran. Suppose we have a vector V with N real values. The vector has been allocated previously with a certain size. Now we have to add a value in the middle of it at the index P. A brute force code would be:
allocate(tempV(N))
tempV=V
deallocate(V)
allocate(V(N+1))
V=(/tempV(1:P-1), newValue, tempV(P:N)/)
deallocate(tempV)
Clearly, if it is done once it is not a problem, but repeating it thousands times would not be so efficient. Memory would fill and empty 4 times every value I would like to insert.
I would like to know which would be a better procedure to tackle this problem. You can propose plain Fortran (preferred), but also some solution by libraries like MKL/Lapack/Blas.
Addendum: could I do it with RESHAPE? going through this definition (same of my Fortran-book definition), I could do something like
REAL, DIMENSION(1:1) :: newPad = (/ newValue /)
V=RESHAPE(V, (/ N+1 /), PAD=newPad)
Now the values has been added at the end of V, so I make a permutation with
V=(/ V(1:P-1), V(N+1:N+1), V(P:N) /)
In this way, it would avoid to create explicitly a temporary vector and to lose allocation.
Would it be efficient and scalable since RESHAPE could be parallelized already in the libraries?
*PS: To make things clear CSR = Compressed Sparse Row format, CSC = Compressed Sparse Column format, more infos here:
MKL definitions:http://software.intel.com/sites/products/documentation/hpc/mkl/mklman/GUID-9FCEB1C4-670D-4738-81D2-F378013412B0.htm
回答1:
The Fortran 2003 subroutine move_alloc was introduced for this purpose. It moves the allocation status, array bounds, dynamic type, type parameters and values from the source to the target, without actually copying the data. The source variable becomes deallocated.
A modification of your code with a short example of move_alloc that requires only one copy operation:
allocate(tempV(N+1))
tempV(:P-1) = V(:P-1)
tempV(P) = newValue
tempV(P+1:) = V(P:)
call move_alloc(tempV, V)
Of course, doing this for multiple items at a time would reduce allocation overhead, but that may not be possible for you.
Edit
As for the recommendation of pointers if you cannot use any F2003 features, you could probably use a subroutine somewhat like this:
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
Of course you can easily adapt this to your purposes or make it more generic. You can use this with allocated pointer variables:
real, pointer :: V(:)
! :
allocate(V(10))
V = 1.
! :
call insert(V, 3.141592, 5)
回答2:
The question is really, whether you need the CSR format immediately after the insertion, or you can rather have more insertions first in a more insertion friendly format and convert then to CSR.
You may have a look at sparskit and its linked list storage format, or you may create yourself some linked list for the new elements, and once you finished insertion, you could build up a new CSR formatted matrix, sparing a lot of reshuffling the data.
来源:https://stackoverflow.com/questions/14607020/insert-a-value-changing-shape-in-allocated-vector-fortran