Overview

Fython is Fortran with a Python syntax. If performance requirements periodically forces you out of Python, with Fython you won’t feel it

hello.fy

real offset = 0

def fast_sum:
  real in v(1e9)
  real res r

  r = 0
  for i in [1, 1e9]:
    r += v[i] + offset

  print 'The sum is {:sum(v)}'

The loop above is automatically parallelized by the Fortran compiler that powers Fython.

Usage in Python is as simple as

hello.py

import fython
import numpy as np

hello = fython.load('.hello')

offset = hello.offset()
v = fython.Real(shape=[1e9])

offset = 10
v[:] = np.random.uniform(0, 1, 1e9)

hello.fast_sum(v)

Features

Performance

The Fython language is a syntaxtic binding for the Fortran language. Any instruction you write in Fython is translated to Fortran, with the exact same meaning. The translated Fortran code is then compiled to machine instructions. There is no boiler plate code generation or LLVM in between. What you code is what you run (WYCIWYR).

Python Syntax

Fython allows to write Fortran code with Python syntax. No messy end xyz everywhere. No more % for object attributes, enjoy the car.color notation. No more concatenation puzzle, use multiline string """xyz""". No more & for multiline instruction, simply use parenthesis

many(
  arguments,
  and,
  more,
)

Write class with class, enjoying attribute getter and setter.

class Nucleon(Atom):
  real position = 1
  int weight = 10

  def pget fission:
    self inout
    self.weight /= 2

  Nucleon n
  n.fission
  print 'weight {:n.weight}'

Python Comfort

Fython import system is modeled after Python. You can define Fython modules accross several folders. They will all correctly compile and link.

import .variance = var
import stat.mean(*)
import .svm(vapnik, least_square_svm=lsq_svm)

Fython has a stack trace for fast error spotting. Say goodbye to those uninformative runtime errors.

fython sigsegv: segmentation fault

module stat.buggy
function subboom
line 7

stack trace (lineno function module) (most recent first)

7 subboom   stat.buggy
3 boom      stat.buggy

Fython print and read function are intuitive. The format mini-language is that of Fortran plus several improvements. Interpolating variables can be specified directly in the string like Perl.

print './out' 'x is {:x}'

print .file 'column 2 is {v:x[:,2]}

read .data: x y z

Pycessor

Use Python to easily do your preprocessing magic

import numpy

real pi = |numpy.pi|

# lazy initialization of exotic random variate
real v(1e3)

|
  for i in range(1000):
    write('v[i] = {:f}'.format(numpy.random.uniform()))

|

Any expression enclosed in bars is evaluated against the imported Python module. The return value of a pycession can be any valid Fython code.

Template

Overload of a function or a class can be created with template interpolation

def temp f:
  T in x
  T res r
  r = x + 10

def g = f(T=real)

When this is not sufficient, a whole package can be templatized

quicksort.fy

import type_provider(target_class=T)

def quicksort(x):
  T x(:)
  int i
  int res r

  r = 0
  for i in [1, size(x)]:
    r += x[i].less_than(x[i+1])

consumer.fy

import quicksort(*)
||type_provider = maxwell, target_class = Atom ||

int r
Atom a(10)
r = quicksort(a)

FyTypes

You can send Python object by reference to Fython using the intuitive fytypes

from fython import *

m = load('stat.mean')

nb_element = Int(value=3)
x = Real(value=[1, 2, 3])
result = Real()

m.mean(nb_element, x, result)

print(result[:])

When using a fytype, you always access or modify its value with a slice. Wheter the value is a scalar or an array.

x[:2] += 10

result[:] *= 10

Changes made by Fython are propagated back to Python

m.moving_average_in_place(x)

print('moving average is:', x[:])

You can also access and modify global Fython variables

n = m.roundoff_tolerance()
n[:] = 1e-5

All the above works for real, integer and string variables of any dimension

cities = Char(size=30, value=['montreal', 'tokyo', 'santiago'])
result = Char(size=30)

m.word_mean(nb_element, cities, result)

Wrap Fortran code and shared library

All intrinsic Fortran module are avalaible in Fython. Other Fortran modules are avalaible once they are in your Python path

import iso_c_binding(*)
import fftw.discrete_cosine_transform(*)

real x(10)
fftw_dct(x)

Putting a Fortran module in the Python path is usually done with

import sys
sys.path.append('~/fftw')

A Shared library can be imported once you have a Fortran or a Fython interface for it

import mkl.include.mkl_vsl(*)
import mkl.lib.intel64.libmkl_intel_lp64(*)

The first import is the fortran interface mkl_vsl.f90. The second import is for the shared object library libmkl_intel_lp64.so.

The requirement for these imports to work is that the mkl root directory must be in your Python path. This is usually achieve with

import sys
sys.path.append('/opt/intel')

Installation

git clone https://github.com/nicolasessisbreton/fython
cd fython
python3 setup.py install

Dependencies:

Platform:

Linux

Contribute

Any contribution is welcomed. The source is avalaible on github.

Support

Questions, suggestions, improvements or bug fixes? Join the discussion here.

License

Fython is released under an Apache License 2.0.