Tutorial to convert python code to cython

This tutorial has 3 sections:

Simple example

We run a python code that can integrate a function, the original integration Python code is pyintegrate.py; it looks like this:

from math import sin

def f(x):
    return sin(x**2)

def integrate_f(a, b, N):
    s = 0
    dx = (b-a)/N
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

We use this test driver program testintegrate.py to show our comparison of the python code versus the cython code, here the code

from __future__ import print_function

import integrate
import pyintegrate
import time

start = time.time()
t = pyintegrate.integrate_f(0.,5.,1000000) # python integration
end = time.time()
pe = end - start
print("Python elapsed", pe)
start = time.time()
t = integrate.integrate_f(0.,5.,1000000) # cython integration
end = time.time()
ce = end - start
print("Cython elapsed", ce)
print("Speedup:",pe / ce)

Take the python example pyintegrate.py and convert it to integrate.pyx. Then instrument the file with cython instructions, this is simple because we only tell the compiler about the types of variables using keywords int, double, … in function argument lists and cdef which is used to declare variables and return values. The cdef extern command point to external definitions to be used. For example, we use the sin function from the C-library (and not the python library.) Here is the finished integrate.pyx

cdef extern from "math.h":
     double sin(double)

cdef double f(double x):
    return sin(x**2)

def integrate_f(double a, double b, int N):
    cdef int i
    cdef double s, dx
    s = 0.0
    dx = (b-a)/N
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

Now we are almost set, but still need to convert our .pyx file, for that we use a setup.py template.

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy

ext_modules=[ 
    Extension("integrate", ["integrate.pyx"]),
]

setup(
  cmdclass = {'build_ext': build_ext},
  ext_modules = ext_modules,
)

we call this setup file to translate integrage.pyx to a .c file and then to compile that to a .so file that we can import into our python testintegrate.py. We call the setup.py file like this:

python setup.py build_ext --inplace

This will print out something like this

running build_ext
building 'integrate' extension
clang -fno-strict-aliasing -fno-common -dynamic -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/usr/local/include -I/usr/local/opt/openssl/include -I/usr/local/opt/sqlite/include -I/usr/local/Cellar/python@2/2.7.14_3/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c integrate.c -o build/temp.macosx-10.13-x86_64-2.7/integrate.o
clang -bundle -undefined dynamic_lookup build/temp.macosx-10.13-x86_64-2.7/integrate.o -L/usr/local/lib -L/usr/local/opt/openssl/lib -L/usr/local/opt/sqlite/lib -o /Users/beerli/Documents/Work/talks/CLASSES/ISC-4304/lectures/L21/scipy-cyBinding a NUMPY progrthon/integrate/integrate.so

We now can run our testintegrate.py file to get the result.

python testintegrate.py

showing this output:

python elapsed 0.0827810764313 value= 0.666159147475
cython elapsed 0.0135059356689 value= 0.666159147475
speedup 6.12923668973

Binding a NUMPY program

< to come >