Function 南·乔尔斯基';如果我没有';不要使用打印子程序
我编写了一个函数来获得实矩阵的Cholesky分解。问题是它在矩阵的某些点返回NaN值。代码如下:Function 南·乔尔斯基';如果我没有';不要使用打印子程序,function,fortran,nan,subroutine,Function,Fortran,Nan,Subroutine,我编写了一个函数来获得实矩阵的Cholesky分解。问题是它在矩阵的某些点返回NaN值。代码如下: MODULE funciones2 IMPLICIT NONE CONTAINS FUNCTION cholesky(a) USE ::comprob !Module to test whether or not a matrix is square and symmetric IMPLICIT NONE REAL, ALLOCATABLE :: cholesky(:,:),u(:,:) REA
MODULE funciones2
IMPLICIT NONE
CONTAINS
FUNCTION cholesky(a)
USE ::comprob !Module to test whether or not a matrix is square and symmetric
IMPLICIT NONE
REAL, ALLOCATABLE :: cholesky(:,:),u(:,:)
REAL :: a(:,:),s
INTEGER :: i,j,k,n
LOGICAL :: comp
comp=symmat(a)
IF (comp) THEN
n=size(a,1)
ALLOCATE (u(n,n))
u=0.0
u(1,1)=sqrt(a(1,1))
DO j=2,n,1
u(1,j)=a(1,j)/u(1,1)
END DO
DO i=2,n,1
DO k=1,i-1,1
s=s+(u(k,i)**2)
END DO
u(i,i)=sqrt(a(i,i)-s)
s=0
DO j=i+1,n,1
DO k=1,i-1,1
s=s+u(k,i)*u(k,j)
END DO
u(i,j)=(1/u(i,i))*(a(i,j)-s)
s=0
END DO
END DO
cholesky=u
ELSE
print*,"CHOLESKY: The matrix is not symmetric."
ENDIF
ENDFUNCTION
ENDMODULE
程序代码为:
PROGRAM pchol
USE :: funciones2
USE :: dispmodule
IMPLICIT NONE
REAL, ALLOCATABLE :: a(:,:),af(:,:)
CHARACTER(LEN=20) :: na
na='B.txt'
a=loadm(na)
CALL DISP('A =',a,ADVANCE='DOUBLE')
a=matmul(transpose(a),a)
!CALL DISP('ATA =',a,ADVANCE='DOUBLE')
af=cholesky(a)
CALL DISP('Ach ',af,ADVANCE='DOUBLE')
af=transpose(af)
CALL DISP('AchT ',af,ADVANCE='DOUBLE')
ENDPROGRAM
“dispmodule”是一个用于漂亮打印矩阵的模块(Jonasson,2009)(您可以在这里查看:)。我发现如果我在这一部分中使用子程序DISP:
a=matmul(transpose(a),a)
CALL DISP('ATA =',a,ADVANCE='DOUBLE')
南的问题消失了!(请注意,在最后一部分中,“CALL DISP”之前没有“!”)
为什么会这样?我将对另一个函数使用Cholesky分解函数,我不能一直调用DISP来避免问题。我怎样才能解决这个问题
编辑:
以下是不使用DISP子程序编译程序的数值结果:
A =3.00000 2.00000 4.00000 5.00000
2.00000 -3.00000 1.00000 -2.00000
1.00000 1.00000 2.00000 0.00000
Ach 3.74166 0.26726 4.27618 2.93987
0.00000 NaN NaN NaN
0.00000 0.00000 NaN NaN
0.00000 0.00000 0.00000 NaN
AchT 3.74166 0.00000 0.00000 0.00000
0.26726 NaN 0.00000 0.00000
4.27618 NaN NaN 0.00000
2.93987 NaN NaN NaN
A =3.00000 2.00000 4.00000 5.00000
2.00000 -3.00000 1.00000 -2.00000
1.00000 1.00000 2.00000 0.00000
ATA =14.0000 1.0000 16.0000 11.0000
1.0000 14.0000 7.0000 16.0000
16.0000 7.0000 21.0000 18.0000
11.0000 16.0000 18.0000 29.0000
Ach 3.74166 0.26726 4.27618 2.93987
0.00000 3.73210 1.56940 4.07660
0.00000 0.00000 0.50128 -1.93350
0.00000 0.00000 0.00000 0.00648
AchT 3.74166 0.00000 0.00000 0.00000
0.26726 3.73210 0.00000 0.00000
4.27618 1.56940 0.50128 0.00000
2.93987 4.07660 -1.93350 0.00648
以下是编译DISP子程序时的数值结果:
A =3.00000 2.00000 4.00000 5.00000
2.00000 -3.00000 1.00000 -2.00000
1.00000 1.00000 2.00000 0.00000
Ach 3.74166 0.26726 4.27618 2.93987
0.00000 NaN NaN NaN
0.00000 0.00000 NaN NaN
0.00000 0.00000 0.00000 NaN
AchT 3.74166 0.00000 0.00000 0.00000
0.26726 NaN 0.00000 0.00000
4.27618 NaN NaN 0.00000
2.93987 NaN NaN NaN
A =3.00000 2.00000 4.00000 5.00000
2.00000 -3.00000 1.00000 -2.00000
1.00000 1.00000 2.00000 0.00000
ATA =14.0000 1.0000 16.0000 11.0000
1.0000 14.0000 7.0000 16.0000
16.0000 7.0000 21.0000 18.0000
11.0000 16.0000 18.0000 29.0000
Ach 3.74166 0.26726 4.27618 2.93987
0.00000 3.73210 1.56940 4.07660
0.00000 0.00000 0.50128 -1.93350
0.00000 0.00000 0.00000 0.00648
AchT 3.74166 0.00000 0.00000 0.00000
0.26726 3.73210 0.00000 0.00000
4.27618 1.56940 0.50128 0.00000
2.93987 4.07660 -1.93350 0.00648
编辑2:我为每个新的计算矩阵分配了新的变量,但问题仍然存在
PROGRAM pchol
USE :: funciones2
USE :: dispmodule
IMPLICIT NONE
REAL, ALLOCATABLE :: a(:,:),af(:,:),at(:,:),am(:,:),am1(:,:)
CHARACTER(LEN=20) :: na
INTEGER :: m,n
na='B.txt'
a=loadm(na)
!CALL DISP('A =',a,ADVANCE='DOUBLE')
m=size(a,1)
n=size(a,2)
ALLOCATE (at(n,m))
ALLOCATE (am(n,n))
ALLOCATE (af(n,n))
at=transpose(a)
am=matmul(at,a)
am1=am
!CALL DISP('ATA =',am1,ADVANCE='DOUBLE')
af=cholesky(am)
CALL DISP('Ach ',af,ADVANCE='DOUBLE')
af=transpose(af)
CALL DISP('AchT ',af,ADVANCE='DOUBLE')
ENDPROGRAM
更新:最小可编译示例。我取出了子程序DISP()及其相应的模块。我还取出了对矩阵对称性进行压缩的模和函数。此外,我取出了我编写的用于从文件中读取矩阵的函数(我直接在程序中编写了相同的矩阵)和用于打印矩阵的函数。问题变得更糟了,现在没有数字,甚至第一行也不像以前那样,在使用cholesky()之后,所有矩阵都变为NaN。gfortran版本是5.3.0
PROGRAM pcholstack
IMPLICIT NONE
REAL, ALLOCATABLE :: af(:,:),at(:,:),am(:,:),am1(:,:)
REAL :: a(3,4)
INTEGER :: m,n,i,j
a(1,1)=3
a(2,1)=2
a(3,1)=1
a(1,2)=2
a(2,2)=-3
a(3,2)=1
a(1,3)=4
a(2,3)=1
a(3,3)=2
a(1,4)=5
a(2,4)=-2
a(3,4)=1
m=size(a,1)
n=size(a,2)
do i=1,m,1
write(*,1017),(a(i,j),j=1,n)
end do
1017 format (10f15.2)
write(*,*)
ALLOCATE (at(n,m))
ALLOCATE (am(n,n))
ALLOCATE (af(n,n))
at=transpose(a)
am=matmul(at,a)
am1=am
write(*,*) am1(1,1)
write(*,*)
do i=1,n,1
write(*,1018),(at(i,j),j=1,m)
end do
1018 format (10f15.2)
write(*,*)
do i=1,n,1
write(*,1019),(am(i,j),j=1,n)
end do
1019 format (10f15.2)
write(*,*)
af=cholesky(am)
!af=transpose(af)
do i=1,n,1
write(*,1016),(af(i,j),j=1,n)
end do
1016 format (10f15.2)
CONTAINS
FUNCTION cholesky(a)
IMPLICIT NONE
REAL, ALLOCATABLE :: u(:,:),cholesky(:,:)
REAL :: a(:,:),s
INTEGER :: i,j,k,n
n=size(a,1)
ALLOCATE (u(n,n))
u=0.0
u(1,1)=sqrt(a(1,1))
DO j=2,n,1
u(1,j)=a(1,j)/u(1,1)
END DO
DO i=2,n,1
DO k=1,i-1,1
s=s+(u(k,i)**2)
END DO
u(i,i)=sqrt(a(i,i)-s)
s=0
DO j=i+1,n,1
DO k=1,i-1,1
s=s+u(k,i)*u(k,j)
END DO
u(i,j)=(1/u(i,i))*(a(i,j)-s)
s=0
END DO
END DO
cholesky=u
ENDFUNCTION
ENDPROGRAM
我相信你的问题在于这两方面:
a=loadm(na)
a=matmul(transpose(a),a)
我没有loadm
的代码,但您的a
矩阵是4x3。然后调用matmul
并将一个4x4放入其中(从而使用非为其保留的内存,其他东西可以写入该内存)。cholesky
功能将其视为4x3,而不是4x4
更新: 它实际上在
gfortran
中工作,自动分配变量。但是它在pgfortran中失败了
问题是:cholesky
的返回值没有正确定义。最简单的方法就是返回u
:
FUNCTION cholesky(a) result (u)
取出
cholesky
数组的定义,不要在函数结尾处为其赋值。英特尔Fortran发现您在cholesky中使用的s
不正确。首次使用时未定义s
的值
因此,结果可以是任何东西
可能您想将其设置为0
> ifort cholesky.f90 -g -check -traceback -standard-semantics
> ./a.out
3.00 2.00 4.00 5.00
2.00 -3.00 1.00 -2.00
1.00 1.00 2.00 1.00
14.00000
3.00 2.00 1.00
2.00 -3.00 1.00
4.00 1.00 2.00
5.00 -2.00 1.00
14.00 1.00 16.00 12.00
1.00 14.00 7.00 17.00
16.00 7.00 21.00 20.00
12.00 17.00 20.00 30.00
forrtl: severe (194): Run-Time Check Failure. The variable 'cholesky$S$_1' is being used in 'cholesky.f90(82,9)' without being defined
Image PC Routine Line Source
a.out 0000000000407DB7 pcholstack_IP_cho 82 cholesky.f90
a.out 0000000000405B47 MAIN__ 54 cholesky.f90
a.out 000000000040261E Unknown Unknown Unknown
libc.so.6 00007F41B73496E5 Unknown Unknown Unknown
a.out 0000000000402529 Unknown Unknown Unknown
报告的代码为:
s = 0 !you probably wanted
DO i=2,n,1
DO k=1,i-1,1
s=s+(u(k,i)**2) !<<<=====
s=0!你可能想要
i=2,n,1吗
DO k=1,i-1,1
s=s+(u(k,i)**2)!哪些地方?请阅读,我们需要一个确切的案例,看看完整的输入数据和完整的输出。我们需要能够复制您的计算。请注意,您依赖于Fortran 2003自动分配分配分配数组。默认情况下,某些编译器(尤其是较旧版本的英特尔Fortran)不会启用此功能。如何编译源代码?您还没有显示全部代码,所以我不能100%确定,但从我所看到的情况来看,这段代码是非法的-cholesky有一个假定的形状伪参数,但在调用点的作用域中没有接口。请显示完整的代码,以便进行检查。也请使用隐式无。同样,因为您没有显示整个程序,我无法确定,但程序中似乎没有cholesky声明,@VladimirF,我已经添加了输出计算。我使用gfortran作为编译器。您应该使用-fcheck=all-Wall-g-fbacktrace
进行编译,然后再次运行。每当你怀疑有错误时,就应该这样做。我认为这也可能是问题所在,所以我在第二次编辑中修复了它,为每个新的计算矩阵分配了新的变量,但问题仍然存在。现在,at
和am
没有分配。我现在分配了它们,它仍然无法找到,并且修复了另一个问题。我想主要有两种可能会造成麻烦。。一个是您的代码中仍然存在一些bug(从问题中的代码中看不到),另一个是您的gfortran版本存在一些编译器bug,例如,对于具有可分配返回数组的函数。(您可以通过gfortran-v
检查版本)无论如何,我相信如果您准备一个最小的可编译示例(不使用“dispmodule”),以便我们可以尝试代码,这将非常有用。此外,如上所述,附加选项,如-fcheck=all-Wall-g-fbacktrace
,可能会给出一些提示。