Выставляйте версии подпрограммы in, out и inplace с помощью f2py.

Я использую f2py для интеграции некоторых подпрограмм Fortran77 в мой модуль python, но не могу найти хороший способ решить следующую проблему. Мои подпрограммы на Фортране уничтожают все входные массивы в ходе вычислений. Я хотел бы предложить пользователю как возможность использовать эффективное с памятью поведение «на месте» этих подпрограмм, так и возможность выполнить подпрограмму, не уничтожая свои данные на стороне Python.

Я могу придумать два способа сделать это:

  1. Если пользователь не хочет, чтобы входные данные были уничтожены, создайте резервную копию всех входных массивов в Python перед вызовом моей процедуры Fortran. Скомпилируйте подпрограммы Fortran, используя объявление «intent (inplace)» в моей подписи. При выходе я могу восстановить входы с помощью резервной копии.
  2. Скомпилируйте одну и ту же процедуру Fortran с двумя разными файлами сигнатур, один с «намерением (на месте)», а другой с «намерением (в, вне)» (или просто «намерение (в)», в зависимости от ситуации). Затем в python я могу импортировать обе разновидности подпрограмм в свой модуль.

Мне не очень нравится ни один из подходов, потому что они оба кажутся непитоновскими. Есть ли лучший способ подойти к этой проблеме? Есть ли более простой способ реализовать подход 2, например. Могу ли я скомпилировать одну и ту же процедуру с двумя разными подписями в один общий объектный модуль?

Вот пример (на основе этой документации).

Подпрограмма Fortran fib.f:

C FILE: FIB.F
      SUBROUTINE FIB(A,N)
C
C     CALCULATE FIRST N FIBONACCI NUMBERS
C
      INTEGER N
      REAL*8 A(N)
      DO I=1,N
         IF (I.EQ.1) THEN
            A(I) = 0.0D0
         ELSEIF (I.EQ.2) THEN
            A(I) = 1.0D0
         ELSE 
            A(I) = A(I-1) + A(I-2)
         ENDIF
      ENDDO
      END
C END FILE FIB.F

Я создаю свой файл подписи, используя f2py fib.f -m fib.pyf, затем добавляю несколько объявлений о намерениях:

!    -*- f90 -*-
! Note: the context of this file is case sensitive.

python module fib ! in
    interface  ! in :fib
        subroutine fib(a,n) ! in :fib:fib.f
            real*8 dimension(n), intent(inout) :: a
            integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
        end subroutine fib
    end interface
end python module fib

! This file was auto-generated with f2py (version:2).
! See http://cens.ioc.ee/projects/f2py2e/

Я компилирую с помощью f2py -c fib.pyf fib.f, а затем могу запустить свою процедуру на месте:

>>> import numpy as np
>>> from fib import fib
>>> A = np.zeros(10, dtype=float)
>>> fib(A)
>>> print(A)
[  0.   1.   1.   2.   3.   5.   8.  13.  21.  34.]

Чтобы изменить этот пример на режим ввода/вывода, я просто изменяю объявление намерения в «fib.pyf» на intent(in,out).


person Ryan Walker    schedule 07.02.2015    source источник


Ответы (1)


В итоге я использовал объявление fortranname в файлах сигнатур для создания как inplace, так и in, out разновидностей одной и той же подпрограммы. Вот файл подписи:

    !    -*- f90 -*-
    ! Note: the context of this file is case sensitive.

    python module fib ! in
            interface  ! in :fib
                subroutine fib_inplace(a,n) ! in :fib:fib.f
                    fortranname fib
                    real*8 dimension(n), intent(inout) :: a
                    integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
                end subroutine fib
                subroutine fib(a,n) ! in :fib:fib.f
                    fortranname fib
                    real*8 dimension(n), intent(copy, in,out) :: a
                    integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
                end subroutine fib
            end interface
    end python module fib

Примечание: чтобы на самом деле запретить второй подпрограмме изменять входные данные Python, мне также пришлось добавить copy в директиву намерения.

person Ryan Walker    schedule 19.02.2015