6

I am trying to learn f2py and I have the following Fortran code

      subroutine fibonacci(a, n)
      implicit none
      integer :: i, n
      double precision :: a(n)
      do i = 1, n
          if (i .eq. 1) then
              a(i) = 0d0
          elseif (i .eq. 2) then
              a(i) = 1d0
          else 
              a(i) = a(i - 1) + a(i - 2)
          endif
      enddo
      end subroutine fibonacci

which is compiled with f2py -c fibonacci.f -m fibonacci and later called in Python

import numpy
import fibonacci

a = numpy.zeros(13)
fibonacci.fibonacci(a)
print a

The subroutine fibonacci called in Python did not get enough number of arguments, but the code mysteriously worked. By the way, calling the subroutine fibonacci with fibonacci.fibonacci(a, len(a)) also worked!

Could someone please explain this? Thanks!

zyy
  • 1,271
  • 15
  • 25

1 Answers1

6

f2py knows that a and n are function parameters, and from the declaration

double precision :: a(n)

it is able to infer that n is the length of a. NumPy arrays have a length, so there is no need for the parameter n in the Python wrapper, and f2py makes it optional.

Note that the code generated by f2py checks that you don't give a value of n that is too big:

In [19]: a = np.zeros(10)

In [20]: fibonacci.fibonacci(a, 99)
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-20-e9497469fd10> in <module>()
----> 1 fibonacci.fibonacci(a, 99)

error: (len(a)>=n) failed for 1st keyword n: fibonacci:n=99

You can give a smaller value:

In [21]: a = np.zeros(10)

In [22]: fibonacci.fibonacci(a, 6)

In [23]: a
Out[23]: array([0., 1., 1., 2., 3., 5., 0., 0., 0., 0.])

You might find it useful to generate and look at the interface file that f2py produces for this function. The command

f2py -h fibonacci.pyf fibonacci.f

displays

Reading fortran codes...
    Reading file 'fibonacci.f' (format:fix,strict)
Post-processing...
    Block: fibonacci
Post-processing (stage 2)...
Saving signatures to file "./fibonacci.pyf"

and generates the file fibonacci.pyf, which contains

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

subroutine fibonacci(a,n) ! in fibonacci.f
    double precision dimension(n) :: a
    integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
end subroutine fibonacci

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

You can see from the generated declaration

    integer, optional,check(len(a)>=n),depend(a) :: n=len(a)

that f2py has inferred that n should be an optional parameter whose value must not exceed the length of a and whose default value is len(a).

Warren Weckesser
  • 110,654
  • 19
  • 194
  • 214