Existe-t-il un moyen de définir implicitement une fonction midprogram dans fortran '[duplicate]

Nov 19 2020

J'essaye de résoudre certains problèmes de valeurs propres. J'utilise gfortran. J'ai écrit un module qui contient le bisection_methodsous - programme. Dans mon programme, j'ai défini la secular(m,x)fonction qui prend un tableau 2D met un flottant xet produit le polynôme caractéristique de mat x; ie det (m - x Id). L'un des arguments du bisection_methodsous-programme est une fonction f, qui a été conçue comme une fonction d'une entrée réelle et d'une sortie réelle. Je voudrais cependant saisir la fonction «partiellement appliquée» secular(m,_)à ce sous-programme. Existe-t-il un moyen de le faire, sans définir explicitement cette fonction dans un module?

Je ne peux pas définir ces fonctions explicitement, car je dois faire cette procédure pour plusieurs matrices m. De plus, je ne peux pas modifier le corps du bisection_methodcar je l'utilise également pour la fonction d'un argument réel. Y a-t-il un moyen de contourner cela à Fortran?

Réponses

2 mcocdawc Nov 22 2020 at 12:38

Comme l'a souligné @francescalus, vous voulez que votre problème soit clos.

Les fermetures sont partiellement prises en charge dans Fortran en utilisant des procédures internes, car la procédure interne a accès à toutes les variables du périmètre environnant.

En supposant que vous vouliez trouver les valeurs propres de Mavec votre code, il pourrait être structuré comme ceci.²

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


¹ La seule mise en garde est que les procédures internes n'existent que tant que la portée environnante existe. Il n'est donc malheureusement pas possible d'écrire une fonction générique qui prend une fonction et renvoie un pointeur de fonction vers une version partiellement appliquée de celle-ci en utilisant des procédures internes. Mais ce n'est pas une préoccupation pour votre problème.

² Il serait peut-être préférable de renvoyer un polynôme caractéristique réel. Ensuite, vous pouvez le dériver, pour utiliser par exemple Newton-Raphson au lieu de la bissection.