Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/email/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion Fortran95中的行列式_Recursion_Matrix_Fortran_Gfortran_Determinants - Fatal编程技术网

Recursion Fortran95中的行列式

Recursion Fortran95中的行列式,recursion,matrix,fortran,gfortran,determinants,Recursion,Matrix,Fortran,Gfortran,Determinants,fortran中的这段代码使用拉普拉斯公式(按次项展开)计算nxn矩阵的行列式。我完全理解这个过程是如何运作的 但是,有人能给我一个关于以下代码如何操作的见解吗?比如说,给定的迭代,代码的这一部分包含递归函数行列式(矩阵)——假设某个nxn矩阵被读入并传递,另一个函数调用辅因子。我理解代码的某些方面,但递归让我深感困惑。我试着用3x3矩阵一步一步地运行,但没有效果 ! Expansion of determinants using Laplace formula recursive functi

fortran中的这段代码使用拉普拉斯公式(按次项展开)计算nxn矩阵的行列式。我完全理解这个过程是如何运作的

但是,有人能给我一个关于以下代码如何操作的见解吗?比如说,给定的迭代,代码的这一部分包含递归函数行列式(矩阵)——假设某个nxn矩阵被读入并传递,另一个函数调用辅因子。我理解代码的某些方面,但递归让我深感困惑。我试着用3x3矩阵一步一步地运行,但没有效果

! Expansion of determinants using Laplace formula
recursive function determinant(matrix) result(laplace_det)
real, dimension(:,:) :: matrix
integer :: msize(2), i, n
real :: laplace_det, det
real, dimension(:,:), allocatable :: cf

msize = shape(matrix) 
n = msize(1)          

if (n .eq. 1) then  
  det = matrix(1,1)
else
  det = 0    
  do i=1, n  
    allocate(cf(n-1, n-1))     
    cf = cofactor(matrix, i, 1)
    det = det + ((-1)**(i+1))* matrix(i,1) * determinant(cf)
    deallocate(cf)
  end do        
end if
laplace_det = det
end function determinant       

 function cofactor(matrix, mI, mJ)
  real, dimension(:,:) :: matrix
  integer :: mI, mJ
  integer :: msize(2), i, j, k, l, n
  real, dimension(:,:), allocatable :: cofactor
  msize = shape(matrix)
  n = msize(1)

  allocate(cofactor(n-1, n-1))
  l=0
  k = 1
  do i=1, n
   if (i .ne. mI) then
     l = 1
     do j=1, n
       if (j .ne. mJ) then
         cofactor(k,l) = matrix(i,j)
         l = l+ 1
       end if
     end do
     k = k+ 1
   end if
  end do
return
end function cofactor
我正在努力解决的主要部分是这两个调用和相应辅因子计算的操作

cf = cofactor(matrix, i, 1)
det = det + ((-1)**(i+1))* matrix(i,1) * determinant(cf)
任何解释的输入都将不胜感激(就像我所说的一个迭代示例)。这是我在stack overflow中的第一篇文章,因为我的大部分问题都位于mathstack中(您可能可以从问题的数学性质看出这一点)。虽然我有编程经验,但递归的概念(尤其是在本例中)真的让我难以置信


如果需要任何编辑,请继续,我不熟悉堆栈溢出的礼节

假设我们将以下3x3矩阵传递给
行列式()

在例程中,对
i=1,2,3
迭代执行以下两行:

cf = cofactor(matrix, i, 1)
det = det + ((-1)**(i+1))* matrix(i,1) * determinant(cf)
对应于第一列的拉普拉斯展开式。更具体地说,将上述3x3
矩阵
传递给
cofactor()
,通过删除
i
矩阵的第1行和第1列,得到2x2子矩阵。然后将获得的2x2子矩阵(
cf
)传递到下一行的
行列式()
,以计算与该子矩阵对应的系数。所以,在第一次迭代中,我们试图计算

请注意,右侧的三个行列式尚未通过后续的行列式()调用进行计算。让我们考虑一个这样的后续调用,例如对于<代码> i=1 < /代码>。我们正在传递以下子矩阵(存储在
cf
中)

行列式()
。然后,再次重复如上所述的相同步骤,并且独立于父3x3矩阵的拉普拉斯展开。也就是说,行列式()现在迭代
i=1,2
,并尝试计算

请注意,此后续调用中的
i
与上一次调用中的
i
不同;它们都是生活在例程的特定调用中的局部变量,彼此完全独立。还请注意,在Fortran中,伪数组参数(如
矩阵(:,:)
)的索引始终从
1
开始(除非另有规定)。重复此类操作,直到子矩阵的大小变为
1

但在实践中,我相信理解此类代码的最简单方法是编写中间数据并跟踪数据/例程的实际流。例如,我们可以插入许多
print
语句作为

module mymod
    implicit none
contains

recursive function determinant(matrix) result(laplace_det)
    real :: matrix(:,:)
    integer :: i, n, p, q
    real :: laplace_det, det
    real, allocatable :: cf(:,:)

    n = size(matrix, 1) 

    !***** output *****   
    print "(a)", "Entering determinant() with matrix = "
    do p = 1, n
        print "(4x,100(f3.1,x))", ( matrix( p, q ), q=1,n )
    enddo

    if (n == 1) then  
        det = matrix(1,1)
    else
        det = 0
        do i = 1, n  
            allocate( cf(n-1, n-1) )
            cf = cofactor( matrix, i, 1 )

            !***** output *****
            print "(4x,a,i0,a,i0,a)", "Getting a ", &
                    n-1, "-by-", n-1, " sub-matrix from cofactor():"
            do p = 1, n-1
                print "(8x, 100(f3.1,x))", ( cf( p, q ), q=1,n-1 )
            enddo

            print "(4x,a)", "and passing it to determinant()."

            det = det + ((-1)**(i+1))* matrix( i, 1 ) * determinant( cf )
            deallocate(cf)
        end do
    end if

    laplace_det = det

    !***** output *****
    print *, "  ---> Returning det = ", det
end function

function cofactor(matrix, mI, mJ)
    .... (same as the original code)
end function

end module

program main
    use mymod
    implicit none
    real :: a(3,3), det

    a( 1, : ) = [ 2.0, 9.0, 4.0 ]
    a( 2, : ) = [ 7.0, 5.0, 3.0 ]
    a( 3, : ) = [ 6.0, 1.0, 8.0 ]

    det = determinant( a )
    print "(a, es30.20)", "Final det = ", det
end program
然后,输出清楚地显示了数据的处理方式:

Entering determinant() with matrix = 
    2.0 9.0 4.0
    7.0 5.0 3.0
    6.0 1.0 8.0
    Getting a 2-by-2 sub-matrix from cofactor():
        5.0 3.0
        1.0 8.0
    and passing it to determinant().
Entering determinant() with matrix = 
    5.0 3.0
    1.0 8.0
    Getting a 1-by-1 sub-matrix from cofactor():
        8.0
    and passing it to determinant().
Entering determinant() with matrix = 
    8.0
   ---> Returning det =    8.0000000    
    Getting a 1-by-1 sub-matrix from cofactor():
        3.0
    and passing it to determinant().
Entering determinant() with matrix = 
    3.0
   ---> Returning det =    3.0000000    
   ---> Returning det =    37.000000    
    Getting a 2-by-2 sub-matrix from cofactor():
        9.0 4.0
        1.0 8.0
    and passing it to determinant().
Entering determinant() with matrix = 
    9.0 4.0
    1.0 8.0
    Getting a 1-by-1 sub-matrix from cofactor():
        8.0
    and passing it to determinant().
Entering determinant() with matrix = 
    8.0
   ---> Returning det =    8.0000000    
    Getting a 1-by-1 sub-matrix from cofactor():
        4.0
    and passing it to determinant().
Entering determinant() with matrix = 
    4.0
   ---> Returning det =    4.0000000    
   ---> Returning det =    68.000000    
    Getting a 2-by-2 sub-matrix from cofactor():
        9.0 4.0
        5.0 3.0
    and passing it to determinant().
Entering determinant() with matrix = 
    9.0 4.0
    5.0 3.0
    Getting a 1-by-1 sub-matrix from cofactor():
        3.0
    and passing it to determinant().
Entering determinant() with matrix = 
    3.0
   ---> Returning det =    3.0000000    
    Getting a 1-by-1 sub-matrix from cofactor():
        4.0
    and passing it to determinant().
Entering determinant() with matrix = 
    4.0
   ---> Returning det =    4.0000000    
   ---> Returning det =    7.0000000    
   ---> Returning det =   -360.00000    
Final det =    -3.60000000000000000000E+02
您可以插入更多打印行,直到整个机制变得清晰


顺便说一句,中的代码似乎比OP的代码简单得多,它直接创建一个子矩阵作为本地数组。代码的简化版本如下:

recursive function det_rosetta( mat, n ) result( accum )
    integer :: n
    real    :: mat(n, n)
    real    :: submat(n-1, n-1), accum
    integer :: i, sgn

    if ( n == 1 ) then
        accum = mat(1,1)
    else
        accum = 0.0
        sgn = 1
        do i = 1, n
            submat( 1:n-1, 1:i-1 ) = mat( 2:n, 1:i-1 )
            submat( 1:n-1, i:n-1 ) = mat( 2:n, i+1:n )

            accum = accum + sgn * mat(1, i) * det_rosetta( submat, n-1 )
            sgn = - sgn
        enddo
    endif
end function
请注意,拉普拉斯展开是沿着第一行进行的,并且
子集
是使用数组部分指定的。作业也可以简单地写为

submat( :, :i-1 ) = mat( 2:, :i-1 )
submat( :, i: )   = mat( 2:, i+1: )

其中省略了数组部分的上限和下限(然后,默认情况下使用声明的上限和下限值)。后一种形式用于Rosetta页面。

添加通用标记“fortran”可能有用。此外,我想知道以下哪两项是困难/困惑的根源:(1)Fortran中可分配数组的处理,(2)Fortran中递归函数的基本行为(如所示)。我理解Fortran中可分配数组的使用,据我所知,它们本质上允许数组大小的动态分配。尽管我看不到(尽管它很清楚地起作用)
行列式(cf)
的递归是如何在每次递归迭代中为我们提供正确的值的。我试着在纸上和笔上跟随代码只进行了一次迭代,比如在递归函数行列式(矩阵)中的
I=1
,但我只是在余因子函数中迷失了方向。我认为
余因子()
函数通过移除传递矩阵的第mI行和第mJ列,从给定数组中构建子数组,例如,如果
matrix
是6x6数组,那么
cf
就是5x5数组。然后将获得的
cf
作为
行列式(cf)
传递给
行列式()
,该行列式将“新”进行评估(即,独立于行列式()的当前调用)。因此,这有点像用相同的名称调用越来越多的独立函数。(对不起,如果我的解释不好…)嗯,我会在周一和教授谈谈这件事,你说的很有道理,我一直跟进到这一点,但工作不符合要求(我会仔细检查)。我也想知道为什么我被否决了(从1到0)。我希望得到建设性的批评,以免重蹈覆辙。我在我的第一篇博文中说,这是我关于堆栈溢出的第一个条目。不管怎样,谢谢你的帮助,roygvib它在某种程度上增强了我对这个问题的理解。我使用小矩阵做了一些测试,代码似乎运行正常(尽管为了获得更高的精度,双精度可能会更好…)。此外,你可以通过谷歌搜索“行列式递归”(例如,和一个非常棒的解释)找到更多信息
recursive function det_rosetta( mat, n ) result( accum )
    integer :: n
    real    :: mat(n, n)
    real    :: submat(n-1, n-1), accum
    integer :: i, sgn

    if ( n == 1 ) then
        accum = mat(1,1)
    else
        accum = 0.0
        sgn = 1
        do i = 1, n
            submat( 1:n-1, 1:i-1 ) = mat( 2:n, 1:i-1 )
            submat( 1:n-1, i:n-1 ) = mat( 2:n, i+1:n )

            accum = accum + sgn * mat(1, i) * det_rosetta( submat, n-1 )
            sgn = - sgn
        enddo
    endif
end function
submat( :, :i-1 ) = mat( 2:, :i-1 )
submat( :, i: )   = mat( 2:, i+1: )