043. Comparing Fortran and NumPy syntax#

topic: Arrays

Used to NumPy? Many of the Fortran intrinsics to deal with arrays will already be familiar to you.

A bit of Fortran vs NumPy#

Fortran

NumPy equivalent1

Value

integer :: a(2, 3)
np.empty(
  (2, 3),
  dtype=np.int32
)

Empty 2x3 array of int32 2 3

a = 1
a[:] = 1

All array elements set to 1 4 5

size(a)
a.size

6

shape(a)
a.shape

(2, 3) 7

a(1,1) = 100
a[0,0] = 100

Element in first row and first column set to 100

maxval(a)
a.max()

100

minval(a)
a.min()

1

sum(a)
a.sum()

105

sum(a, dim=1)
a.sum(axis=0)

(101, 2, 2)


cf-numpy.f90 | | Godbolt Compiler Explorer logo | Fortran logo#
program cf_numpy
   implicit none

   integer, parameter :: m = 2, n = 3
   integer :: a(m, n)
   character(len=*), parameter :: fmt = "(x, a, ':', x, *(g0, x))"

   print *, "Before setting:"
   call print11(a)

   a = 1  ! Set all elements

   print *, "After setting:"
   call print11(a)

   print fmt, "size", size(a)
   print fmt, "shape", shape(a)

   a(1,1) = 100
   
   print fmt, "maxval", maxval(a)
   print fmt, "minval", minval(a)

   print fmt, "sum", sum(a)
   print fmt, "sum, dim=1", sum(a, dim=1)
   print fmt, "sum, dim=2", sum(a, dim=2)

contains

   subroutine print11(mat)
      integer, intent(in) :: mat(:,:)

      print "(3x, 'row 1:', x, *(i0, x))", mat(1, :)
      print "(3x, 'col 1:', x, *(i0, x))", mat(:, 1)

   end subroutine print11

end program cf_numpy
Output8#
 Before setting:
   row 1: 0 2103326976 0
   col 1: 0 0
 After setting:
   row 1: 1 1 1
   col 1: 1 1
 size: 6
 shape: 2 3
 maxval: 100
 minval: 1
 sum: 105
 sum, dim=1: 101 2 2
 sum, dim=2: 102 3

Note

NumPy also provides a functional API that makes it look more like Fortran. See such comparisons and more here: https://www.fortran90.org/src/rosetta.html



1

The NumPy examples assume

import numpy as np
2

In Fortran, the “empty” array may get values set to zero, but this is not guaranteed (compiler and hardware(?) dependence). With NumPy, the uninitialized array elements will not (all) be zero.

3

In Fortran, remember that the array elements are stored in column-major order. In NumPy, row-major order is the default, though you can specify on creation or transform to column-major order.

4

With NumPy,

a = np.full((m, n), value, dtype=np.int32)

could be used to achieve the result of the first two steps.

5

Notes

  • Fortran supports the shorthand for setting all elements (a = 1 above), but if you do that in Python, a becomes a single Python integer (int).

  • Fortran also supports setting all elements with colon syntax, but you must specify a : for each dimension.

  • In NumPy, a[:] and a[...] both work as shorthand for the entire array regardless of the number of dimensions, whereas in Fortran we need to give a colon for each dimension: a(:,:).

  • For Fortran allocatable arrays, a = ... might6 re-allocate the array, whereas explicit a(:,:) = ... would not.

6

If it has already been allocated and the RHS is an array with a different shape from the LHS. a = 1 like in our example still just sets all elements to 1.

7

shape(a) (Fortran) returns an integer array, whereas a.shape (NumPy) returns a tuple of Python ints (i.e., not NumPy integers).

8

Compiled using GNU Fortran (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0 with no flags