我是英特尔MKL的新手。这是我遇到的一个问题 - 显然是一个与MKL本身无关的问题,但问题是如何声明并将一个迄今未知大小的数组作为子程序的输出传递给另一个子程序。
我正在尝试使用mkl_ddnscsr将矩阵转换为适合Pardiso调用的CSR格式:
CALL mkl_ddnscsr(job,Nt,Nt,Adns,Nt,Acsr,ja,ia,info)
CALL PARDISO(pt,1,1,11,13,Nt,Acsr,ia,ja,perm,1,iparm,0,b,x,errr)
问题是,在调用mkl_ddnscsr子例程之前,我不知道CSR的形式是什么,形成了Acsr和索引向量ja。如何在主程序中声明Acsr和ja,或者这两行所在的子程序?
我试过像
这样的东西INTERFACE
SUBROUTINE mkl_ddnscsr(job, m, n, Adns, lda, Acsr, ja, ia, info)
IMPLICIT NONE
INTEGER :: job(8)
INTEGER :: m, n, lda, info
INTEGER, ALLOCATABLE :: ja(:)
INTEGER :: ia(m+1)
REAL(KIND=8), ALLOCATABLE :: Acsr(:)
REAL(KIND=8) :: Adns(:)
END SUBROUTINE
END INTERFACE
接着是
INTEGER, ALLOCATABLE :: ja(:)
REAL(KIND=8), ALLOCATABLE :: Acsr(:)
在INTERFACE之外,在主程序中。但是这种配置在运行时给我分段错误。
另一方面,如果我尝试类似
的话INTERFACE
SUBROUTINE mkl_ddnscsr(job, m, n, Adns, lda, Acsr, ja, ia, info)
IMPLICIT NONE
INTEGER :: job(8)
INTEGER :: m, n, lda, info
INTEGER :: ja(:), ia(m+1)
REAL(KIND=8) :: Acsr(:), Adns(:)
END SUBROUTINE
END INTERFACE
然后
INTEGER, DIMENSION(:) :: ja
REAL(KIND=8), DIMENSION(:) :: Acsr
然后ifort会给我以下信息:
error #6596: If a deferred-shape array is intended, then the ALLOCATABLE or POINTER attribute is missing; if an assumed-shape array is intended, the array must be a dummy argument.
任何人都知道如何解决这个问题?在主程序(或主子程序)中声明ja和Acsr并传递它们的正确方法是什么?
请注意,子程序是英特尔MKL程序包的一部分,而不是我自己编写的程序,因此看起来module
是不可能的。
答案 0 :(得分:1)
您可以从manual page或MKL安装目录中的包含文件mkl_ddnscsr
找到mkl_spblas.fi
的界面(例如,/ path / to / mkl / include /)
INTERFACE
subroutine mkl_ddnscsr ( job, m, n, Adns, lda, Acsr, AJ, AI, info )
integer job(8)
integer m, n, lda, info
integer AJ(*), AI(m+1)
double precision Adns(*), Acsr(*)
end
END INTERFACE
因为此例程只有Fortran77样式的伪参数(即显式形状数组AI(m+1)
或假定大小的数组,如Adns(*)
),所以可以传递任何本地或可分配的数组(在分配之后)调用方)作为实际参数。此外,并不是必须明确地编写接口块,但是include
它(在调用方面)检测潜在的接口不匹配应该是有用的。
根据手册,看起来mkl_ddnscsr
(将密集转换为稀疏矩阵的例程)看起来像这样:
program main
implicit none
! include 'mkl_spblas.fi' !! or mkl.fi (not mandatory but recommended)
integer :: nzmax, nnz, job( 8 ), m, n, lda, info, irow, k
double precision :: A( 10, 20 )
double precision, allocatable :: Asparse(:)
integer, allocatable :: ia(:), ja(:)
A( :, : ) = 0.0d0
A( 2, 3 ) = 23.0d0
A( 2, 7 ) = 27.0d0
A( 5, 4 ) = 54.0d0
A( 9, 9 ) = 99.0d0
!! Give an estimate of the number of non-zeros.
nzmax = 10
!! Or assume that non-zeros occupy at most 2% of A(:,:), for example.
! nzmax = size( A ) / 50
!! Or count the number of non-zeros directly.
! nzmax = count( abs( A ) > 0.0d0 )
print *, "nzmax = ", nzmax
m = size( A, 1 ) !! number of rows
n = size( A, 2 ) !! number of columns
lda = m !! leading dimension of A
allocate( Asparse( nzmax ) )
allocate( ja( nzmax ) ) !! <-> columns(:)
allocate( ia( m + 1 ) ) !! <-> rowIndex(:)
job( 1 ) = 0 !! convert dense to sparse A
job( 2:3 ) = 1 !! use 1-based indices
job( 4 ) = 2 !! use the whole A as input
job( 5 ) = nzmax !! maximum allowed number of non-zeros
job( 6 ) = 1 !! generate Asparse, ia, and ja as output
call mkl_ddnscsr( job, m, n, A, lda, Asparse, ja, ia, info )
if ( info /= 0 ) then
print *, "insufficient nzmax (stopped at ", info, "row)"; stop
endif
nnz = ia( m+1 ) - 1
print *, "number of non-zero elements = ", nnz
do irow = 1, m
!! This loop runs only for rows having nonzero elements.
do k = ia( irow ), ia( irow + 1 ) - 1
print "(2i5, f15.8)", irow, ja( k ), Asparse( k )
enddo
enddo
end program
使用ifort -mkl test.f90
(使用ifort14.0)进行编译,得出预期结果
nzmax = 10
number of non-zero elements = 4
2 3 23.00000000
2 7 27.00000000
5 4 54.00000000
9 9 99.00000000
关于nzmax
的确定,我认为至少有三种方法:(1)只使用猜测值(如上所述); (2)假设整个数组中非零元素的分数;或(3)直接计算密集阵列中的非零数。在任何情况下,因为我们将非零的确切数量作为输出(nnz
),我们可以重新分配Asparse
和ja
以获得确切的大小(如果需要)。