我一直在FORTRAN中编写代码但是我在使用lapack dsyevr时遇到了问题:
http://netlib.sandia.gov/lapack/double/dsyevr.f
我遇到的问题似乎与内存分配问题有关,特别是我相信dsyevr生成的输出数组(包括A是输入和输出)。
我试图编写一个简化的代码来演示我所看到的问题。如果有任何需要澄清,请告诉我。代码名为prof1.f90并调用dsyevr函数:
PROGRAM prog1
implicit none
real(kind=8), allocatable :: W(:)
real(kind=8), allocatable :: Z(:,:)
real(kind=8), allocatable :: A(:,:)
integer(kind=8) :: n, info, il, iu, m, lwork, liwork
integer(kind=8) :: i, k, p, q, nu
real(kind=8) :: abstol, vl, vu
real(kind=8), allocatable :: work(:)
integer, allocatable :: isuppz(:), iwork(:)
n = 3
allocate(W(3),Z(3,3),A(n,n),stat=info)
if (info .ne. 0) stop "error allocating arrays"
A(1,1)=3.78136524999999994E-003
A(1,2)=0.0000000000000000
A(1,3)=-7.92918150000000038E-004
A(2,1)=0.0000000000000000
A(2,2)=5.20293929999999984E-003
A(2,3)=0.0000000000000000
A(3,1)=-7.92918150000000038E-004
A(3,2)=0.0000000000000000
A(3,3)=3.78136524999999994E-003
vl = 1.06451084056294826E-313
vu = 0.0
il = 4294967297
iu = 8839891
m = 140733655445712
W(1) = 2.98844710000000001E-003
W(2) = 4.57428340000000030E-003
W(3) = 5.20293929999999984E-003
Z(1,1) = 8.65587596665713699E-317
Z(1,2) = 8.65587596665713699E-317
Z(1,3) = 1.58101006669198894E-322
Z(2,1) = 1.58101006669198894E-322
Z(2,2) = 0.0000000000000000
Z(2,3) = 8.65569415049946741E-317
Z(3,1) = 4.24400777097956191E-314
Z(3,2) = 4.79243676466009148E-322
Z(3,3) = 3.51391740150311405E-316
lwork = -1
liwork = -1
abstol = 1d-5
allocate(work(1),iwork(1),isuppz(6))
call dsyevr('V','A','U',n,A,n,vl,vu,il,iu,abstol,m,W,Z,n,isuppz,work,lwork,iwork,liwork,info)
if (info .ne. 0) stop "error obtaining work array dimensions"
lwork = work(1)
liwork = iwork(1)
deallocate(work,iwork)
allocate(work(lwork),iwork(liwork),stat=info)
if (info .ne. 0) stop "error allocating work arrays"
call dsyevr('V','A','U',n,A,n,vl,vu,il,iu,abstol,m,W,Z,n,isuppz,work,lwork,iwork,liwork,info)
if (info .ne. 0) stop "error diagonalizing the hamiltonian"
deallocate(A,work,iwork,isuppz)
END PROGRAM prog1
在上面的代码中,dsyevr函数被调用两次,第一次只是为了获得工作的维度等...矩阵运行正确然而第二次调用时它返回以下错误
*** glibc detected *** ./PROGRAM: munmap_chunk(): invalid pointer: 0x000000000134cc20 ***
我还可以提供Backtrace和MemoryMap。
如果它有用,我一直在使用的makefile如下所示。该程序使用以下行创建:
make PROGRAM
生成文件:
FC = gfortran
FCFLAGS = -g -fbounds-check
FCFLAGS = -O2
FCFLAGS += -I/usr/include
%: %.o
$(FC) $(FCFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.f90
$(FC) $(FCFLAGS) -c $< -fno-range-check
%.o: %.F90
$(FC) $(FCFLAGS) -c $<
.PHONY: clean veryclean
PROGRAM: prog1.f90 prog1.o
$(FC) $(FCFLAGS) -o $@ prog1.o $(LIBS) -Wl,--start-group -L$(MKLROOT)/lib/intel64 -lmkl_gf_ilp64 -lmkl_core -lmkl_sequential -Wl,--end-group -lpthread
clean:
rm -f *.o *.mod *.MOD
veryclean: clean
rm -f *~ $(PROGRAM)
其中$ MKLROOT是/opt/intel/composer_xe_2011_sp1.8.273/mkl
如果有用,我使用了valgrind:
valgrind --tool=memcheck --db-attach=yes ./PROGRAM
我发现了以下错误:
==31069==
==31069== Invalid write of size 8
==31069== at 0x57B9F92: mkl_lapack_dsyevr (in /opt/intel/composer_xe_2011_sp1.8.273 /mkl/lib/intel64/libmkl_core.so)
==31069== by 0x4D9A580: DSYEVR (in /opt/intel/composer_xe_2011_sp1.8.273/mkl/lib /intel64/libmkl_gf_ilp64.so)
==31069== by 0x401163: MAIN__ (in /home/j/workbook/Test4/PROGRAM)
==31069== by 0x401F09: main (in /home/j/workbook/Test4/PROGRAM)
==31069== Address 0x6afe0b0 is 0 bytes inside a block of size 4 alloc'd
==31069== at 0x4A069EE: malloc (vg_replace_malloc.c:270)
==31069== by 0x400FE4: MAIN__ (in /home/j/workbook/Test4/PROGRAM)
==31069== by 0x401F09: main (in /home/j/workbook/Test4/PROGRAM)
==31069==
我不确定该行&#34;无效写入大小为8&#34;指的是一些整数或实数的大小(如Jonathan Dursi所述)或指的是传递给dsyevr的数组的大小。
答案 0 :(得分:3)
文档中并不明显,但必须分配isuppz
,即使是lwork = -1
的初始调用也是如此。如果将isuppz分配移动到第一次调用之前,代码就会成功完成。
之后,因为您正在使用MKL的ILP(8字节整数)版本,例如带有8字节整数索引的LAPACK,所有的LAPACK例程的整数参数必须是相同的长类型,因此您需要
integer(kind=8), allocatable :: isuppz(:), iwork(:)
我注意到,对于none和integer,kind = 8实际上是标准的一部分,你应该使用selected_int / real_kind或iso_fortran_env
模块和int64
等