fortran에서 프로그램 중간에 함수를 암시 적으로 정의하는 방법이 있습니까?

Nov 19 2020

일부 고유 값 문제를 해결하려고합니다. gfortran을 사용하고 있습니다. bisection_method서브 루틴 을 포함하는 모듈을 작성했습니다 . 내 프로그램에서 secular(m,x)2D 배열 m과 부동 소수점 을 취하고 at x의 특성 다항식을 출력하는 함수를 정의 m했습니다 x. 즉, det (m-x Id). bisection_method서브 루틴 의 인수 f중 하나는 하나의 실제 입력과 실제 출력의 함수로 의도 된 function입니다. 그러나이 secular(m,_)서브 루틴에 '부분 적용'기능 을 입력하고 싶습니다 . 모듈에서이 함수를 명시 적으로 정의하지 않고이를 수행하는 방법이 있습니까?

여러 행렬에 대해이 절차를 수행하기 때문에이 함수를 명시 적으로 정의 할 수 없습니다 m. 또한 bisection_method하나의 실제 인수의 기능에도 사용하기 때문에 본문을 수정할 수 없습니다 . Fortran에이 문제를 해결할 방법이 있습니까?

답변

2 mcocdawc Nov 22 2020 at 12:38

@francescalus가 지적했듯이 문제에 대한 종결을 원합니다.

내부 프로시 저는 주변 범위의 모든 변수에 액세스 할 수 있기 때문에 내부 프로 시저를 사용하여 Fortran에서 클로저를 부분적으로 지원합니다 .¹

M코드로 고유 값을 찾고 싶다면 다음 과 같이 구성 할 수 있습니다 .²

module bisection_and_linalg
    use iso_fortran_env, only: real64
    integer, parameter :: wp = real64
    implicit none(type, external)

    abstract interface
        real(wp) pure function real_function(x)
            real(wp), intent(in) :: x
        end function
    end interface

contains

    !> Find the root of f in the interval I
    real(wp) pure function bisect(f, I)
        procedure(real_function) :: f
        real(wp) :: I(2)
        ...
    end function

    !> Evaluate the characteristic polynomial of m at x
    real(wp) pure function secular(M, x)
        real(wp), intent(in) :: M(:, :), x

        ...
    end function

    !> Get eigenvalues
    real(wp) pure function eigenvalues(M)
        real(wp), intent(in) :: M(:, :)

        ...

        ! n.b. here you can use the bisection method to
        !   find your eigenvalues.
        bisect(f, ...)

    contains

        real(wp) pure function f(x)
            ! n.b. here you have your closure.
            !   M is captured from surrounding scope.
            f = secular(M, x)
        end function
    end function

end module


¹ 유일한주의 사항은 내부 절차는 주변 범위가 존재하는 동안 만 존재한다는 것입니다. 따라서 안타깝게도 내부 프로 시저를 사용하여 함수를 가져 와서 부분적으로 적용된 버전에 대한 함수 포인터를 반환하는 일반 함수를 작성하는 것은 불가능합니다. 그러나 이것은 당신의 문제에 대한 관심사가 아닙니다.

² 아마도 실제 특성 다항식을 반환하는 것이 더 나을 것입니다. 그런 다음 이분법 대신 Newton-Raphson을 사용하여 파생시킬 수 있습니다.