Cython Magic Functions

Loading the extension

IPython has a cythonmagic extension that contains a number of magic functions for working with Cython code. This extension can be loaded using the %load_ext magic as follows:

In [1]:
%load_ext cythonmagic

The %cython_inline magic

The %%cython_inline magic uses Cython.inline to compile a Cython expression. This allows you to enter and run a function body with Cython code. Use a bare return statement to return values.

In [2]:
a = 10
b = 20
In [3]:
%%cython_inline
return a+b
Out[3]:
30

The %cython_pyximport magic

The %%cython_pyximport magic allows you to enter arbitrary Cython code into a cell. That Cython code is written as a .pyx file in the current working directory and then imported using pyximport. You have to specify the name of the module that the Code will appear in. All symbols from the module are imported automatically by the magic function.

In [4]:
%%cython_pyximport foo
def f(x):
    return 4.0*x
In [5]:
f(10)
Out[5]:
40.0

The %cython magic

Probably the most important magic is the %cython magic. This is similar to the %%cython_pyximport magic, but doesn't require you to specify a module name. Instead, the %%cython magic manages everything using temporary files in the ~/.cython/magic directory. All of the symbols in the Cython module are imported automatically by the magic.

Here is a simple example of a Black-Scholes options pricing algorithm written in Cython. Please note that this example might not compile on non-POSIX systems (e.g., Windows) because of a missing erf symbol.

In [6]:
%%cython
cimport cython
from libc.math cimport exp, sqrt, pow, log, erf

@cython.cdivision(True)
cdef double std_norm_cdf_cy(double x) nogil:
    return 0.5*(1+erf(x/sqrt(2.0)))

@cython.cdivision(True)
def black_scholes_cy(double s, double k, double t, double v,
                     double rf, double div, double cp):
    """Price an option using the Black-Scholes model.
    
    s : initial stock price
    k : strike price
    t : expiration time
    v : volatility
    rf : risk-free rate
    div : dividend
    cp : +1/-1 for call/put
    """
    cdef double d1, d2, optprice
    with nogil:
        d1 = (log(s/k)+(rf-div+0.5*pow(v,2))*t)/(v*sqrt(t))
        d2 = d1 - v*sqrt(t)
        optprice = cp*s*exp(-div*t)*std_norm_cdf_cy(cp*d1) - \
            cp*k*exp(-rf*t)*std_norm_cdf_cy(cp*d2)
    return optprice
In [7]:
black_scholes_cy(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)
Out[7]:
10.327861752731728

For comparison, the same code is implemented here in pure python.

In [8]:
from math import exp, sqrt, pow, log, erf

def std_norm_cdf_py(x):
    return 0.5*(1+erf(x/sqrt(2.0)))

def black_scholes_py(s, k, t, v, rf, div, cp):
    """Price an option using the Black-Scholes model.
    
    s : initial stock price
    k : strike price
    t : expiration time
    v : volatility
    rf : risk-free rate
    div : dividend
    cp : +1/-1 for call/put
    """
    d1 = (log(s/k)+(rf-div+0.5*pow(v,2))*t)/(v*sqrt(t))
    d2 = d1 - v*sqrt(t)
    optprice = cp*s*exp(-div*t)*std_norm_cdf_py(cp*d1) - \
        cp*k*exp(-rf*t)*std_norm_cdf_py(cp*d2)
    return optprice
In [9]:
black_scholes_py(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)
Out[9]:
10.327861752731728

Below we see the runtime of the two functions: the Cython version is nearly a factor of 10 faster.

In [10]:
%timeit black_scholes_cy(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)
1000000 loops, best of 3: 319 ns per loop
In [11]:
%timeit black_scholes_py(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)
100000 loops, best of 3: 2.28 ┬Ás per loop

External libraries

Cython allows you to specify additional libraries to be linked with your extension, you can do so with the -l flag (also spelled --lib). Note that this flag can be passed more than once to specify multiple libraries, such as -lm -llib2 --lib lib3. Here's a simple example of how to access the system math library:

In [12]:
%%cython -lm
from libc.math cimport sin
print 'sin(1)=', sin(1)
sin(1)= 0.841470984808

You can similarly use the -I/--include flag to add include directories to the search path, and -c/--compile-args to add extra flags that are passed to Cython via the extra_compile_args of the distutils Extension class. Please see the Cython docs on C library usage for more details on the use of these flags.