Czy istnieje sposób na niejawne zdefiniowanie funkcji midprogram w Fortran '[duplikat]

Nov 19 2020

Próbuję rozwiązać kilka problemów z wartością własną. Używam gfortran. Napisałem moduł zawierający bisection_methodpodprogram. W moim programie zdefiniowałem secular(m,x)funkcję, która przyjmuje tablicę 2D mi zmiennoprzecinkową xi generuje charakterystyczny wielomian mat x; tj. det (m - x Id). Jednym z argumentów bisection_methodpodprogramu jest funkcja f, która miała być funkcją jednego rzeczywistego wejścia i rzeczywistego wyjścia. Chciałbym jednak wprowadzić funkcję „częściowo zastosowaną” secular(m,_)do tego podprogramu. Czy można to zrobić bez jawnego definiowania tej funkcji w module?

Nie mogę jednoznacznie zdefiniować tej funkcji, ponieważ mam wykonać tę procedurę dla kilku macierzy m. Nie mogę też modyfikować treści bisection_methodargumentu, ponieważ używam go również do funkcji jednego prawdziwego argumentu. Czy jest sposób na obejście tego w Fortranie?

Odpowiedzi

2 mcocdawc Nov 22 2020 at 12:38

Jak zauważył @francescalus, chcesz mieć zamknięcie swojego problemu.

Zamknięcia są częściowo obsługiwane w Fortranie przy użyciu procedur wewnętrznych, ponieważ procedura wewnętrzna ma dostęp do wszystkich zmiennych w otaczającym zakresie¹.

Zakładając, że chcesz znaleźć wartości własne w Mswoim kodzie, może on mieć taką strukturę.²

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


¹ Jedynym zastrzeżeniem jest to, że wewnętrzne procedury istnieją tylko tak długo, jak długo istnieje otaczający zakres. Dlatego niestety nie jest możliwe napisanie funkcji ogólnej, która pobiera funkcję i zwraca wskaźnik funkcji do jej częściowo zastosowanej wersji przy użyciu procedur wewnętrznych. Ale to nie dotyczy twojego problemu.

² Być może lepiej byłoby zwrócić rzeczywisty charakterystyczny wielomian. Wtedy mógłbyś go wyprowadzić, używając np. Newtona-Raphsona zamiast bisekcji.