用意图防止更改变量(in) [英] Prevent changing variables with intent(in)

查看:132
本文介绍了用意图防止更改变量(in)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读以下问题(正确使用FORTRAN INTENT()对于大型数组)我学会了用intent(in)定义一个变量是不够的,因为当变量传递给另一个子程序/函数时,它可以再次改变。那么我该如何避免这种情况呢?在他们提到的将子程序放入模块的原始线程中,但这对我没有帮助。例如,我想计算具有LU分解的矩阵的行列式。因此我使用Lapack函数zgetrf,但是这个函数改变了我的输入矩阵,编译器不显示任何警告。

 模块matHelper 
隐式无
包含

子程序initMat(AA)
real * 8 :: u
双复数,维(:, :),intent(inout):: AA
integer :: row,col,counter

计数器= 1
行数= 1,大小(AA,1)
做col = 1,大小(AA,2)
AA(行,列) = cmplx(counter,0)
counter = counter + 1
end do
end do

end subroutine initMat

!subroutine to写一个矩阵文件
!输入:AA - 双复数矩阵
! fid - 整数文件ID
! fname - 文件名
! stat - integer status = replace [0]或old [1]
子程序writeMat(AA,fid,fname,stat)
integer :: fid,stat
字符(len = *): :fname
double complex,dimension(:, :),intent(in):: AA
integer :: row,col
字符(len = 64):: fmtString

!用给定选项打开文件
if(fid / = 0)then
if(stat == 0)then
open(unit = fid,file = fname,status = 'replace',&
action ='write')
else if(stat == 1)then
open(unit = fid,file = fname,status ='old',& amp ;
action ='write')
else
print *,'试图用Id打开文件时出错',fid
返回
如果
结束结束如果

!初始化mat rix打印格式
write(fmtString,'(I0)')size(aa,2)
fmtString ='('// trim(fmtString)//'(\"{\",ES10.3, ,,1X,ES10.3,},:,1X))'
!write(*,*)fmtString

!通过迭代遍历每行
do row = 1,size(aa,1)
write(fid,fmt = fmtString)AA(row,:)
enddo
write(fid,*)''
结束子程序writeMat



!函数计算输入的行列式
!输入:AA - 双复数矩阵
!输出determinantMat - 双复数,
! 0如果AA不是方阵
函数determinantMat(AA)
双复数,维(:, :),intent(in):: AA
双复数:: determinantMat
整数,维数(min(size(AA,1),size(AA,2)))&
:: ipiv
integer :: ii,info

!检查是否为方矩阵,然后将行列式设为0
if(size(AA,1)/ = size(AA,2))然后
determinantMat = 0
返回
结束如果

!使用LAPACK函数计算LU facotirzation
调用zgetrf(size (AA,1),大小(AA,2),AA,大小(AA,1),ipiv,info)

if(info / = 0)then
determinantMat = cmplx( 0.D0,0.D0)
返回
结束如果
determinantMat = cmplx(1.D0,0.D0)
!三角形矩阵的行列式是对角元素的乘积$如果(ipiv(ii)/ = ii)那么b $ b做ii = 1,大小(AA,1)
,那么
!排列完成了,所以因子-1
determinantMat = -determinantMat * AA(ii,ii)
else
!没有排列,所以没有-1
d eterminantMat = determinantMat * AA(ii,ii)
end if
end do

end function determinantMat

end module matHelper
!* ************************************************** ********************


!模块可存储矩阵元素,维度,轨迹,行列式

程序测试
使用matHelper
隐式无
double复数,dimension(:, :),allocatable :: AA,BB
integer :: n,fid

fid = 0;

分配(AA(3,3))
调用initMat(AA)
调用writeMat(AA,0,'',0)
print *,' Determinante:',determinantMat(AA)!更改AA
调用writeMat(AA,0,'',0)
结束程序测试

PS:我正在使用ifort编译器v15.0.3 20150407

解决方案

我在家里没有ifort,但是你可能想用'-check interfaces'和'-ipo'编译。你可能需要'zgetrf'作为'-check接口'的工作路径,如果这不是源,那么它可能没有帮助。
如果你将'function determinantMat'声明为'PURE FUNCTION determinantMat',那么我很确定它会抱怨,因为'zgetrf'不知道是PURE还是ELEMENTAL。尝试^这个东西^第一个。



如果LAPACK有一个模块,那么可以知道zgetrf是或不是PURE / ELEMENTAL。 https://software.intel.com/ en-us / articles / blas-and-lapack-fortran95-mod-files



我建议你加入你的编译行:

   - 检查接口-ipo 

在初始构建期间,我喜欢(一旦它工作,就将它取出来加速):

   - 全选全部检查 - 全部检查

制作临时数组是一种解决方法。 (我没有编译过,所以它只是一个概念范例。)

  PURE FUNCTION determinantMat(AA)
使用LAPACK95! - 新线 - !
IMPLICIT NONE! - 新行 - !
double complex,dimension(:, :),intent(IN):: AA
double complex :: determinantMat!< - 输出
! - 内部函数 -
整数,尺寸(min(size(AA,1),size(AA,2))):: ipiv
!! - 下一行是新的 -
双复合体,尺寸(尺寸(AA, 1),size(AA,2)):: AA_Temp !!< - 我不知道这是否可行,你可能需要一个可分配的?
integer :: ii,info

!检查是否为方阵,然后将行列式设为0
if(size(AA,1)/ = size(AA,2) )then
determinantMat = 0
return
end如果

!用LAPACK函数计算LU因子分解
!! - 下一行是new--
AA_Temp = AA! - 初始化AA_Temp与AA--相同!
如果(info / = 0)则调用zgetrf(size(AA_temp,1),size(AA_Temp,2),AA_Temp,size(AA_Temp,1),ipiv,info)

then
determinantMat = cmplx(0.D0,0.D0)
返回
结束如果

determinantMat = cmplx(1.D0,0.D0)$ b $三角矩阵的b行列式是对角元素的乘积
do ii = 1,size(AA_Temp,1)
if(ipiv(ii)/ = ii)然后
! ,所以因子为-1
determinantMat = -determinantMat * AA_Temp(ii,ii)
else
!没有排列,所以没有-1
determinantMat = determinantMat * AA_Temp(ii ,ii)如果
结束了

结束函数determinantMat


$ b,
结束$ b

使用'USE LAPACK95'你可能不需要PURE,但是如果你希望它是PURE,那么你想明确地说出来。


so reading the following question (Correct use of FORTRAN INTENT() for large arrays) I learned that defining a variable with intent(in) isn't enough, since when the variable is passed to another subroutine/function, it can be changed again. So how can I avoid this? In the original thread they talked about putting the subroutine into a module, but that doesn't help for me. For example I want to calculate the determinant of a matrix with a LU-factorization. Therefore I use the Lapack function zgetrf, but however this function alters my input matrix and the compiler don't displays any warnings. So what can I do?

module matHelper
    implicit none
    contains

    subroutine initMat(AA)
        real*8                      ::  u
        double complex, dimension(:,:), intent(inout)   ::  AA
        integer                     ::  row, col, counter

        counter = 1
        do row=1,size(AA,1)
            do col=1,size(AA,2)
                AA(row,col)=cmplx(counter ,0)
                counter=counter+1 
            end do
        end do

    end subroutine initMat

    !subroutine to write a Matrix to file
    !Input: AA      -   double complex matrix
    !       fid     -   integer file id
    !       fname   -   file name
    !       stat        -   integer status =replace[0] or old[1]
    subroutine writeMat(AA,fid, fname, stat)
        integer                     ::  fid, stat
        character(len=*)                ::  fname
        double complex, dimension(:,:), intent(in)  ::  AA
        integer                     ::  row, col
        character (len=64)                ::  fmtString

        !opening file with given options
        if(fid  /= 0) then
            if(stat == 0) then
                open(unit=fid, file=fname, status='replace', &
                    action='write')
            else if(stat ==1) then
                open(unit=fid, file=fname, status='old', &
                    action='write')
            else
                print*, 'Error while trying to open file with Id', fid
                return
            end if
        end if

        !initializing matrix print format
        write(fmtString,'(I0)') size(aa,2)
        fmtString = '('// trim(fmtString) //'("{",ES10.3, ",", 1X, ES10.3,"}",:,1X))'
        !write(*,*) fmtString

        !writing matrix to file by iterating through each row
        do row=1,size(aa,1)
            write(fid,fmt = fmtString) AA(row,:)
        enddo
        write(fid,*) ''
    end subroutine writeMat



    !function to calculate the determinant of the input
    !Input: AA              -   double complex matrix
    !Output determinantMat  -   double complex, 
    !                           0 if AA not a square matrix
    function determinantMat(AA)
        double complex, dimension(:,:), intent(in)  ::  AA
        double complex              ::  determinantMat
        integer, dimension(min(size(AA,1),size(AA,2)))&
                                    ::  ipiv
        integer                     ::  ii, info

        !check if not square matrix, then set determinant to 0
        if(size(AA,1)/= size(AA,2)) then
            determinantMat = 0
            return
        end if

        !compute LU facotirzation with LAPACK function
        call zgetrf(size(AA,1),size(AA,2), AA,size(AA,1), ipiv,info)

        if(info /= 0) then
            determinantMat = cmplx(0.D0, 0.D0)
            return
        end if
        determinantMat = cmplx(1.D0, 0.D0)
        !determinant of triangular matrix is product of diagonal elements
        do ii=1,size(AA,1)
            if(ipiv(ii) /= ii) then
                !a permutation was done, so a factor of -1 
                determinantMat = -determinantMat *AA(ii,ii)
            else
                !no permutation, so no -1 
                determinantMat = determinantMat*AA(ii,ii)
            end if      
        end do

    end function determinantMat

end module matHelper
!***********************************************************************


!module which stores matrix elements, dimension, trace, determinant

program test
    use matHelper
    implicit none
    double complex, dimension(:,:), allocatable ::  AA, BB
    integer                                 ::  n, fid

    fid  = 0;

    allocate(AA(3,3))
    call initMat(AA)
    call writeMat(AA,0,' ', 0)
    print*, 'Determinante: ',determinantMat(AA) !changes AA
    call writeMat(AA,0, ' ', 0)
end program test

PS: I am using the ifort compiler v15.0.3 20150407

解决方案

I do not have ifort at home, but you may want to try compiling with '-check interfaces' and maybe with '-ipo'. You may need the path to 'zgetrf' for the '-check interfaces' to work, and if that is not source then it may not help. If you declare 'function determinantMat' as 'PURE FUNCTION determinantMat' then I am pretty sure it would complain because 'zgetrf' is not known to be PURE nor ELEMENTAL. Try ^this stuff^ first.

If LAPACK has a module, then zgetrf could be known to be, or not be, PURE/ELEMENTAL. https://software.intel.com/en-us/articles/blas-and-lapack-fortran95-mod-files

I would suggest you add to your compile line:

-check interfaces -ipo

During initial build I like (Take it out for speed once it works):

-check all -warn all

Making a temporary array is one way around it. (I have not compiled this, so it is only a conceptual exemplar.)

PURE FUNCTION determinantMat(AA)
USE LAPACK95                       !--New Line--!
IMPLICIT NONE                      !--New Line--!
double complex, dimension(:,:)  , intent(IN   )  ::  AA
double complex                                   ::  determinantMat !<- output
!--internals--
integer, dimension(min(size(AA,1),size(AA,2)))   ::  ipiv
!!--Next line is new--
double complex, dimension(size(AA,1),size(AA,2)) ::  AA_Temp  !!<- I have no idea if this will work, you may need an allocatable??
integer                                          ::  ii, info

!check if not square matrix, then set determinant to 0
if(size(AA,1)/= size(AA,2)) then
    determinantMat = 0
    return
end if

!compute LU factorization with LAPACK function
!!--Next line is new--
AA_Temp = AA  !--Initialise AA_Temp to be the same as AA--!
call zgetrf(size(AA_temp,1),size(AA_Temp,2), AA_Temp,size(AA_Temp,1), ipiv,info)

if(info /= 0) then
    determinantMat = cmplx(0.D0, 0.D0)
    return
end if

determinantMat = cmplx(1.D0, 0.D0)
!determinant of triangular matrix is product of diagonal elements
do ii=1,size(AA_Temp,1)
    if(ipiv(ii) /= ii) then
        !a permutation was done, so a factor of -1 
        determinantMat = -determinantMat *AA_Temp(ii,ii)
    else
        !no permutation, so no -1 
        determinantMat = determinantMat*AA_Temp(ii,ii)
    end if      
end do

end function determinantMat

With the 'USE LAPACK95' you probably do not need PURE, but if you wanted it to be PURE then you want to explicitly say so.

这篇关于用意图防止更改变量(in)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆