如何推导出其元素是函数的矩阵?

时间:2016-11-18 01:23:40

标签: function matrix fortran subroutine derivative

我正在使用fortran而我正在尝试使用矩阵的导数,其元素是函数。

    program derivada_matrix

    integer, parameter :: matrix_size = 5
    integer :: i,j
    real(8) :: time = 1.0
    real(8),dimension (matrix_size, matrix_size) :: W
    real(8),dimension (matrix_size, matrix_size) :: dW

   call potent(time,W)
   do i = 1, matrix_size
      do j=1, matrix_size
         call Derivada(time,W(i,j),dW(i,j))
       end do
   end do

   print*, 'matrix'
   print*, W
   print*, 'derivada', dW


   end program


  Subroutine Derivada (x1,F,D)
  implicit none
  Real*8 :: x1
  Real*8 :: h= 1.0E-6
  integer, parameter :: matrix_size = 5
  real*8 :: D,F
  external F
  D = (1.0*F(x1-2*h) - 8.0*F(x1-h) + 8.0*F(x1+h) -   1.0*F(x1+2*h))/(12.0*h)

 return
 End subroutine Derivada

 subroutine potent(T,W)
 implicit none
 integer, parameter :: matrix_size = 5
 real(8),dimension(matrix_size,matrix_size) :: W
 Real(8):: T
 integer :: i,j
 do i = 1, matrix_size
    do j=i,matrix_size
        W(i,j) = 0.0
        W(j,i) = W(i,j)
    end do
    W(i,i) = cos(T)
end do
RETURN
END subroutine potent

基本上,第一个子程序在主对角线上创建一个带有函数(余弦)的测试矩阵,在其他地方创建零,并且它应该推导出第二个子程序。 这是我收到的错误/警告信息

      call Derivada(time,W(i,j),dW(i,j))
                      1
    Warning: Expected a procedure for argument ‘f’ at (1)

我收到的错误/警告信息是在第二个电话中。我想因为当我创建W矩阵时,它将其属性作为函数丢失,然后我不能在第二次调用中用作派生每个元素的参数。 怎么能改善呢? 如何创建一个程序/函数子程序,它的输入是这样的矩阵,它的输出将是它的衍生物???

由于

1 个答案:

答案 0 :(得分:0)

代码没有按照您的想法行事。 W只是一系列实物。您只需填写T点评估的cos条目。它不是一系列函数。

这是一种更现代化的方法,可以满足您的需求。它不使用extern函数,而是使用过程指针并将它们包装在派生类型中,以便您可以创建它们的数组。然后你指向你想要它的衍生物的函数。

这种方法的局限性在于您必须遵守接口,在这种情况下,它只适用于接受一个双参数的函数。您可以通过多种方式扩展它,例如使用可选参数,将它们包装在派生类型中,或使用多个接口,但这取决于您。

module deriv
  use, intrinsic :: iso_fortran_env, only: dp => real64
  implicit none

  ! Wrapper for a procedure pointer so we can make an array of them
  type ptr_wrapper
     procedure(f), nopass, pointer :: func
  end type ptr_wrapper


  ! Use an interface for the function rather than "extern" functions
  ! Change the interface to whatever you want. You could take multiple reals, integers, etc
  abstract interface
    pure function f(x1)
       import
       real(dp), intent(in) :: x1
       real(dp) :: f
     end function f
  end interface


contains

  function derivada(x1, fx) result(d)
    implicit none
    real(dp), intent(in) :: x1
    procedure(f), pointer :: fx
    real(dp) :: d

    real(dp) :: h = 1.0E-6

    d = (1.0*fx(x1-2*h) - 8.0*fx(x1-h) + 8.0*fx(x1+h) -   1.0*fx(x1+2*h))/(12.0*h)

  end function derivada


  pure function test_func(x1)
    real(dp), intent(in) :: x1
    real(dp) test_func

    test_func = 2d0 * x1
  end function test_func

  pure function test_func2(x1)
    real(dp), intent(in) :: x1
    real(dp) test_func2

    test_func2 = x1**2
  end function test_func2


end module deriv

program derivada_matrix
  use, intrinsic :: iso_fortran_env, only: dp => real64
  use deriv
  implicit none

  integer i, j
  real(dp) :: dx


  type(ptr_wrapper) :: w(2,2)

  !Point to the function that you want each index to point to
  w(1,1)%func => test_func
  w(1,2)%func => test_func2
  ! Pointing to the generic function wasn't working so I had to point to the specific double value trig functions
  w(2,1)%func => dcos 
  w(2,2)%func => dsin  

  do i = 1, 2
     do j = 1, 2
        dx = derivada(1d0, w(i,j)%func)
        print *, dx
     end do
  end do


end program derivada_matrix

它在x = 1.0

时打印出这些函数的导数
  2.00000000000000     
  2.00000000011102     
 -0.841470984776962     
  0.540302305853706