user2489252
user2489252

Reputation:

Using fortranmagic in IPython notebook for sorting an array: no return value

I have to say that I am not a Fortran-programmer at all. I usually only use Python and C++, but sometimes colleagues have written great Fortran functions that would be great to implement in my Python code for efficiency. I was just about to try the f2py module via IPython's magic function.

For a trivial test, I have the following bubblesort implementation where I want to sort a Python list in place (which I convert to an numpy array laid out in memory the Fortran-style; I assume this would be more efficient than using Python lists right?)

However, the function has no return value here (None), and I am wondering where my mistake would be!?

The commands to install and load the fortranmagic which uses f2py

%install_ext https://raw.github.com/mgaitan/fortran_magic/master/fortranmagic.py
%load_ext fortranmagic

The Fortran bubblesort code:

%%fortran
SUBROUTINE fortran_bubblesort(a)
  REAL, INTENT(in out), DIMENSION(:) :: a
  REAL :: temp
  INTEGER :: i, j
  LOGICAL :: swapped = .TRUE.

  DO j = SIZE(a)-1, 1, -1
    swapped = .FALSE.
    DO i = 1, j
      IF (a(i) > a(i+1)) THEN
        temp = a(i)
        a(i) = a(i+1)
        a(i+1) = temp
        swapped = .TRUE.
      END IF
    END DO
    IF (.NOT. swapped) EXIT
  END DO
END SUBROUTINE fortran_bubblesort

The execution:

x = np.asfortranarray([3,2,1])
y = fortran_bubblesort(x)
print(x, y)

The result:

[3 2 1] None

========

To test that a value can be returned in general, I ran the following code, which works just fine:

%%fortran
SUBROUTINE fortran_sum(x, y, z)
    REAL, INTENT(in) :: x,y
    REAL, INTENT(out) :: z

    z = x + y

END SUBROUTINE fortran_sum

Execute:

fortran_sum(3, 4)

Returns:

7.0

Upvotes: 1

Views: 857

Answers (2)

I made the original Fortran code of the question working by just replacing both "REAL" statements by "REAL(kind=8)" statements. That way, Fortran's variables match Python's ones.
Also, to get the execution working and to avoid the "None" output, I propose the following lines (note that I've changed the integer inputs by float data to have a correct match):

import numpy as np
x = np.asfortranarray([3.,0., 2.,1.])
print(x)
fortran_bubblesort(x)
print(x)

Execution:

[ 3. 0. 2. 1.]
[ 0. 1. 2. 3.]

Note that I've also added number zero to be more Pythonic ;-)

Upvotes: 0

steabert
steabert

Reputation: 6898

The problem you are facing has to do with the array dimensions. It looks like that subroutine was yanked from a module, as it uses an assumed-shape dummy array a. This requires an explicit interface, and I don't know if and/or how f2py handles that. I've only ever used f2py using assumed size dummy arrays, which it handles well. This would be the code:

SUBROUTINE fortran_bubblesort(a,n)
  INTEGER, INTENT(in) :: n
  REAL, INTENT(in out), DIMENSION(n) :: a
  REAL :: temp
  INTEGER :: i, j
  LOGICAL :: swapped = .TRUE.

  DO j = SIZE(a)-1, 1, -1
    swapped = .FALSE.
    DO i = 1, j
      IF (a(i) > a(i+1)) THEN
        temp = a(i)
        a(i) = a(i+1)
        a(i+1) = temp
        swapped = .TRUE.
      END IF
    END DO
    IF (.NOT. swapped) EXIT
  END DO
END SUBROUTINE fortran_bubblesort

In this case, f2py will notice that n is just the array dimension, and it will make it an optional argument in the python function.

Upvotes: 0

Related Questions