# Making Python faster¶

The Julia website has a set of benchmarks to show how fast it is. These are for toy functions, but serve as a nice set of examples for the basics of using cython and numba in Python.

These examples are adapted from here

In [2]:

benchmarks = pd.read_pickle('julia_benchmarks.pic')
benchmarks.ix[:, :6]

Out[2]:

Fortran Julia Python R Matlab
1 fib 0.70 2.11 77.76 533.52 26.89
2 parse_int 5.05 1.45 17.02 45.73 802.52
3 quicksort 1.31 1.15 32.89 264.54 4.92
4 mandel 0.81 0.79 15.32 53.16 7.58
5 pi_sum 1.00 1.00 21.99 9.56 1.00
6 rand_mat_stat 1.45 1.66 17.93 14.56 14.52
7 rand_mat_mul 3.48 1.02 1.14 1.57 1.12
In [145]:

import time
import random
import numpy as np

In [119]:

from numba import njit, jit

In [120]:

%load_ext cython

The cython extension is already loaded. To reload it, use:


Timing and reproting functions

In [121]:

def timer(f, *args, **kwargs):
start = time.clock()
ans = f(*args, **kwargs)
return ans, time.clock() - start

In [130]:

def report(fs, *args, **kwargs):
ans, t = timer(fs[0], *args, **kwargs)
print('%s: %.1f' % (fs[0].__name__, 1.0))
for f in fs[1:]:
ans_, t_ = timer(f, *args, **kwargs)
print('%s: %.1f' % (f.__name__, t/t_))


## Fib¶

In [63]:

def fib(n):
if n<2:
return n
return fib(n-1)+fib(n-2)

In [64]:

fib(20)

Out[64]:

6765

In [113]:

%timeit fib(20)

100 loops, best of 3: 5.84 ms per loop

In [68]:

from functools import lru_cache

@lru_cache()
def fib_lru(n):
if n<2:
return n
return fib(n-1)+fib(n-2)

In [114]:

%timeit fib_lru(20)

The slowest run took 92.76 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 213 ns per loop

In [115]:

%%cython -a

cpdef long fib_cython(int n):
if n<2:
return n
return fib_cython(n-1) + fib_cython(n-2)

Out[115]:

Cython: _cython_magic_a7383439b4d9daca4b8a6d569c53a027.pyx

Generated by Cython 0.23.4

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 1:
+2: cpdef long fib_cython(int n):
static PyObject *__pyx_pw_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_1fib_cython(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/
static long __pyx_f_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython(int __pyx_v_n, CYTHON_UNUSED int __pyx_skip_dispatch) {
long __pyx_r;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("fib_cython", 0);
/* … */
/* function exit code */
__pyx_L0:;
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_1fib_cython(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/
static PyObject *__pyx_pw_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_1fib_cython(PyObject *__pyx_self, PyObject *__pyx_arg_n) {
int __pyx_v_n;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("fib_cython (wrapper)", 0);
assert(__pyx_arg_n); {
__pyx_v_n = __Pyx_PyInt_As_int(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L3_error:;
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
__pyx_r = __pyx_pf_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython(__pyx_self, ((int)__pyx_v_n));
int __pyx_lineno = 0;
const char *__pyx_filename = NULL;
int __pyx_clineno = 0;

/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) {
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("fib_cython", 0);
__Pyx_XDECREF(__pyx_r);
__pyx_t_1 = __Pyx_PyInt_From_long(__pyx_f_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython(__pyx_v_n, 0)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;

/* function exit code */
__pyx_L1_error:;
__Pyx_XDECREF(__pyx_t_1);
__pyx_r = NULL;
__pyx_L0:;
__Pyx_XGIVEREF(__pyx_r);
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

+3:     if n<2:
  __pyx_t_1 = ((__pyx_v_n < 2) != 0);
if (__pyx_t_1) {
/* … */
}

+4:         return n
    __pyx_r = __pyx_v_n;
goto __pyx_L0;

+5:     return fib_cython(n-1) + fib_cython(n-2)
  __pyx_r = (__pyx_f_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython((__pyx_v_n - 1), 0) + __pyx_f_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython((__pyx_v_n - 2), 0));
goto __pyx_L0;

In [116]:

%timeit fib_cython(20)

10000 loops, best of 3: 129 µs per loop

In [82]:

@njit
def fib_numba(n):
a, b = 0, 1
for i in range(n-1):
a, b = b, a + b
return b

In [83]:

%timeit -r3 -n3 fib_numba(20)

The slowest run took 49263.70 times longer than the fastest. This could mean that an intermediate result is being cached
3 loops, best of 3: 501 ns per loop

In [84]:

%load_ext cython

In [123]:

%%cython -a

def fib_cython_seq(int n):
cdef int i
cdef long a, b, tmp
a = 0
b = 1
for i in range(n-1):
tmp = a
a = b
b += tmp
return b

Out[123]:

Cython: _cython_magic_106e06d591bbaf06dba1a9e2a3411245.pyx

Generated by Cython 0.23.4

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 01:
+02: def fib_cython_seq(int n):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq = {"fib_cython_seq", (PyCFunction)__pyx_pw_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq, METH_O, 0};
static PyObject *__pyx_pw_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq(PyObject *__pyx_self, PyObject *__pyx_arg_n) {
int __pyx_v_n;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("fib_cython_seq (wrapper)", 0);
assert(__pyx_arg_n); {
__pyx_v_n = __Pyx_PyInt_As_int(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L3_error:;
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
__pyx_r = __pyx_pf_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_fib_cython_seq(__pyx_self, ((int)__pyx_v_n));
int __pyx_lineno = 0;
const char *__pyx_filename = NULL;
int __pyx_clineno = 0;

/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_fib_cython_seq(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) {
CYTHON_UNUSED int __pyx_v_i;
long __pyx_v_a;
long __pyx_v_b;
long __pyx_v_tmp;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("fib_cython_seq", 0);
/* … */
/* function exit code */
__pyx_L1_error:;
__Pyx_XDECREF(__pyx_t_3);
__pyx_r = NULL;
__pyx_L0:;
__Pyx_XGIVEREF(__pyx_r);
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
/* … */
__pyx_tuple_ = PyTuple_Pack(6, __pyx_n_s_n, __pyx_n_s_n, __pyx_n_s_i, __pyx_n_s_a, __pyx_n_s_b, __pyx_n_s_tmp); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple_);
__Pyx_GIVEREF(__pyx_tuple_);
/* … */
__pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq, NULL, __pyx_n_s_cython_magic_106e06d591bbaf06db); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_fib_cython_seq, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

 03:     cdef int i
 04:     cdef long a, b, tmp
+05:     a = 0
  __pyx_v_a = 0;

+06:     b = 1
  __pyx_v_b = 1;

+07:     for i in range(n-1):
  __pyx_t_1 = (__pyx_v_n - 1);
for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
__pyx_v_i = __pyx_t_2;

+08:         tmp = a
    __pyx_v_tmp = __pyx_v_a;

+09:         a = b
    __pyx_v_a = __pyx_v_b;

+10:         b += tmp
    __pyx_v_b = (__pyx_v_b + __pyx_v_tmp);
}

+11:     return b
  __Pyx_XDECREF(__pyx_r);
__pyx_t_3 = __Pyx_PyInt_From_long(__pyx_v_b); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_r = __pyx_t_3;
__pyx_t_3 = 0;
goto __pyx_L0;

In [124]:

%timeit fib_cython_seq(20)

The slowest run took 15.42 times longer than the fastest. This could mean that an intermediate result is being cached
10000000 loops, best of 3: 122 ns per loop

In [131]:

report([fib, fib_lru, fib_cython, fib_numba, fib_cython_seq], 20)

fib: 1.0
fib_lru: 1151.4
fib_cython: 26.0
fib_numba: 639.7
fib_cython_seq: 1919.0

In [442]:

fs = fib, fib_lru, fib_cython, fib_numba, fib_cython_seq
for f in fs:
print(f(20))

6765
6765
6765
6765
6765


## Parse_int¶

In [158]:

def parse_int():
for i in range(1,1000):
n = random.randint(0,2**31-1)
s = hex(n)
#         if s[-1]=='L':
#             s = s[0:-1]
m = int(s,16)
assert m == n

In [142]:

%timeit parse_int()

100 loops, best of 3: 4.56 ms per loop

In [159]:

def parse_int_numpy():
for i in range(1,1000):
n = np.random.randint(0,2**31-1)
s = hex(n)
m = int(s,16)
assert m == n

In [160]:

%timeit parse_int_numpy()

1000 loops, best of 3: 1.51 ms per loop

In [169]:

%%cython -a

import cython
import numpy as np
cimport numpy as np

def parse_int_cython():
cdef int i, n, m
for i in range(1,1000):
n = np.random.randint(0,2**31-1)
m = int(hex(n),16)
assert m == n

Out[169]:

Cython: _cython_magic_2d3f37e15c7a44b97af38354a036490d.pyx

Generated by Cython 0.23.4

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 01:
+02: import cython
  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

+03: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

 04: cimport numpy as np
 05:
+06: def parse_int_cython():
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython = {"parse_int_cython", (PyCFunction)__pyx_pw_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython, METH_NOARGS, 0};
static PyObject *__pyx_pw_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("parse_int_cython (wrapper)", 0);
__pyx_r = __pyx_pf_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_parse_int_cython(__pyx_self);

/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_parse_int_cython(CYTHON_UNUSED PyObject *__pyx_self) {
CYTHON_UNUSED int __pyx_v_i;
int __pyx_v_n;
int __pyx_v_m;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("parse_int_cython", 0);
/* … */
/* function exit code */
__pyx_r = Py_None; __Pyx_INCREF(Py_None);
goto __pyx_L0;
__pyx_L1_error:;
__Pyx_XDECREF(__pyx_t_2);
__Pyx_XDECREF(__pyx_t_3);
__pyx_r = NULL;
__pyx_L0:;
__Pyx_XGIVEREF(__pyx_r);
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
/* … */
__pyx_tuple__8 = PyTuple_Pack(3, __pyx_n_s_i, __pyx_n_s_n, __pyx_n_s_m); if (unlikely(!__pyx_tuple__8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__8);
__Pyx_GIVEREF(__pyx_tuple__8);
/* … */
__pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython, NULL, __pyx_n_s_cython_magic_2d3f37e15c7a44b97a); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_parse_int_cython, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

 07:     cdef int i, n, m
+08:     for i in range(1,1000):
  for (__pyx_t_1 = 1; __pyx_t_1 < 0x3E8; __pyx_t_1+=1) {
__pyx_v_i = __pyx_t_1;

+09:         n = np.random.randint(0,2**31-1)
    __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_random); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_randint); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_4 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_v_n = __pyx_t_4;
/* … */
__pyx_tuple_ = PyTuple_Pack(2, __pyx_int_0, __pyx_int_2147483647); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple_);
__Pyx_GIVEREF(__pyx_tuple_);

+10:         m = int(hex(n),16)
    __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_n); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3);
__pyx_t_3 = 0;
__pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_hex, __pyx_t_2, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3);
__Pyx_INCREF(__pyx_int_16);
__Pyx_GIVEREF(__pyx_int_16);
PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_int_16);
__pyx_t_3 = 0;
__pyx_t_3 = __Pyx_PyObject_Call(((PyObject *)(&PyInt_Type)), __pyx_t_2, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_4 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_v_m = __pyx_t_4;

+11:         assert m == n
    #ifndef CYTHON_WITHOUT_ASSERTIONS
if (unlikely(!Py_OptimizeFlag)) {
if (unlikely(!((__pyx_v_m == __pyx_v_n) != 0))) {
PyErr_SetNone(PyExc_AssertionError);
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
}
#endif
}

In [170]:

%timeit parse_int_cython()

1000 loops, best of 3: 1.13 ms per loop

In [175]:

report([parse_int, parse_int_numpy, parse_int_cython])

parse_int: 1.0
parse_int_numpy: 2.7
parse_int_cython: 3.2


## Quicksort¶

In [171]:

def qsort_kernel(a, lo, hi):
i = lo
j = hi
while i < hi:
pivot = a[(lo+hi) // 2]
while i <= j:
while a[i] < pivot:
i += 1
while a[j] > pivot:
j -= 1
if i <= j:
a[i], a[j] = a[j], a[i]
i += 1
j -= 1
if lo < j:
qsort_kernel(a, lo, j)
lo = i
j = hi
return a

In [190]:

def benchmark_qsort():
lst = [ random.random() for i in range(1,5000) ]
qsort_kernel(lst, 0, len(lst)-1)

In [191]:

%timeit benchmark_qsort()

10 loops, best of 3: 23.8 ms per loop

In [214]:

%%cython -a

import cython
import numpy as np

@cython.boundscheck(False)
@cython.wraparound(False)
cdef double[:] qsort_kernel_cython(double[:] a, int lo, int hi):
cdef int i, j
cdef double pivot

i = lo
j = hi
while i < hi:
pivot = a[(lo+hi) // 2]
while i <= j:
while a[i] < pivot:
i += 1
while a[j] > pivot:
j -= 1
if i <= j:
a[i], a[j] = a[j], a[i]
i += 1
j -= 1
if lo < j:
qsort_kernel_cython(a, lo, j)
lo = i
j = hi
return a

def benchmark_qsort_cython():
lst = np.random.random(5000)
qsort_kernel_cython(lst, 0, len(lst)-1)

Out[214]:

Cython: _cython_magic_2e0923d1649b2de5c2ff7f8deca79258.pyx

Generated by Cython 0.23.4

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 01:
+02: import cython
  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

+03: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

 04:
 05: @cython.boundscheck(False)
 06: @cython.wraparound(False)
+07: cdef double[:] qsort_kernel_cython(double[:] a, int lo, int hi):
static __Pyx_memviewslice __pyx_f_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_qsort_kernel_cython(__Pyx_memviewslice __pyx_v_a, int __pyx_v_lo, int __pyx_v_hi) {
int __pyx_v_i;
int __pyx_v_j;
double __pyx_v_pivot;
__Pyx_memviewslice __pyx_r = { 0, 0, { 0 }, { 0 }, { 0 } };
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("qsort_kernel_cython", 0);
/* … */
/* function exit code */
__pyx_L1_error:;
__PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
__pyx_r.data = NULL;
__pyx_r.memview = NULL;

goto __pyx_L2;
__pyx_L0:;
if (unlikely(!__pyx_r.memview)) {
PyErr_SetString(PyExc_TypeError,"Memoryview return value is not initialized");
}
__pyx_L2:;
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

 08:     cdef int i, j
 09:     cdef double pivot
 10:
+11:     i = lo
  __pyx_v_i = __pyx_v_lo;

+12:     j = hi
  __pyx_v_j = __pyx_v_hi;

+13:     while i < hi:
  while (1) {
__pyx_t_1 = ((__pyx_v_i < __pyx_v_hi) != 0);
if (!__pyx_t_1) break;

+14:         pivot = a[(lo+hi) // 2]
    __pyx_t_2 = __Pyx_div_long((__pyx_v_lo + __pyx_v_hi), 2);
__pyx_v_pivot = (*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_2 * __pyx_v_a.strides[0]) )));

+15:         while i <= j:
    while (1) {
__pyx_t_1 = ((__pyx_v_i <= __pyx_v_j) != 0);
if (!__pyx_t_1) break;

+16:             while a[i] < pivot:
      while (1) {
__pyx_t_3 = __pyx_v_i;
__pyx_t_1 = (((*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_3 * __pyx_v_a.strides[0]) ))) < __pyx_v_pivot) != 0);
if (!__pyx_t_1) break;

+17:                 i += 1
        __pyx_v_i = (__pyx_v_i + 1);
}

+18:             while a[j] > pivot:
      while (1) {
__pyx_t_4 = __pyx_v_j;
__pyx_t_1 = (((*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_4 * __pyx_v_a.strides[0]) ))) > __pyx_v_pivot) != 0);
if (!__pyx_t_1) break;

+19:                 j -= 1
        __pyx_v_j = (__pyx_v_j - 1);
}

+20:             if i <= j:
      __pyx_t_1 = ((__pyx_v_i <= __pyx_v_j) != 0);
if (__pyx_t_1) {
/* … */
}
}

+21:                 a[i], a[j] = a[j], a[i]
        __pyx_t_5 = __pyx_v_j;
__pyx_t_6 = (*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_5 * __pyx_v_a.strides[0]) )));
__pyx_t_7 = __pyx_v_i;
__pyx_t_8 = (*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_7 * __pyx_v_a.strides[0]) )));
__pyx_t_9 = __pyx_v_i;
*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_9 * __pyx_v_a.strides[0]) )) = __pyx_t_6;
__pyx_t_10 = __pyx_v_j;
*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_10 * __pyx_v_a.strides[0]) )) = __pyx_t_8;

+22:                 i += 1
        __pyx_v_i = (__pyx_v_i + 1);

+23:                 j -= 1
        __pyx_v_j = (__pyx_v_j - 1);

+24:         if lo < j:
    __pyx_t_1 = ((__pyx_v_lo < __pyx_v_j) != 0);
if (__pyx_t_1) {
/* … */
}

+25:             qsort_kernel_cython(a, lo, j)
      __pyx_t_11 = __pyx_f_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_qsort_kernel_cython(__pyx_v_a, __pyx_v_lo, __pyx_v_j); if (unlikely(!__pyx_t_11.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);

+26:         lo = i
    __pyx_v_lo = __pyx_v_i;

+27:         j = hi
    __pyx_v_j = __pyx_v_hi;
}

+28:     return a
  __PYX_INC_MEMVIEW(&__pyx_v_a, 0);
__pyx_r = __pyx_v_a;
goto __pyx_L0;

 29:
+30: def benchmark_qsort_cython():
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython = {"benchmark_qsort_cython", (PyCFunction)__pyx_pw_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython, METH_NOARGS, 0};
static PyObject *__pyx_pw_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("benchmark_qsort_cython (wrapper)", 0);
__pyx_r = __pyx_pf_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_benchmark_qsort_cython(__pyx_self);

/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_benchmark_qsort_cython(CYTHON_UNUSED PyObject *__pyx_self) {
PyObject *__pyx_v_lst = NULL;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("benchmark_qsort_cython", 0);
/* … */
/* function exit code */
__pyx_r = Py_None; __Pyx_INCREF(Py_None);
goto __pyx_L0;
__pyx_L1_error:;
__Pyx_XDECREF(__pyx_t_1);
__Pyx_XDECREF(__pyx_t_2);
__PYX_XDEC_MEMVIEW(&__pyx_t_3, 1);
__PYX_XDEC_MEMVIEW(&__pyx_t_5, 1);
__pyx_r = NULL;
__pyx_L0:;
__Pyx_XDECREF(__pyx_v_lst);
__Pyx_XGIVEREF(__pyx_r);
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
/* … */
__pyx_tuple__15 = PyTuple_Pack(1, __pyx_n_s_lst); if (unlikely(!__pyx_tuple__15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__15);
__Pyx_GIVEREF(__pyx_tuple__15);
/* … */
__pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython, NULL, __pyx_n_s_cython_magic_2e0923d1649b2de5c2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_benchmark_qsort_cython, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_codeobj__16 = (PyObject*)__Pyx_PyCode_New(0, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__15, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_cliburn_ipython_cython__c, __pyx_n_s_benchmark_qsort_cython, 30, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}

+31:     lst = np.random.random(5000)
  __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_random); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_random); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_lst = __pyx_t_2;
__pyx_t_2 = 0;
/* … */
__pyx_tuple_ = PyTuple_Pack(1, __pyx_int_5000); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple_);
__Pyx_GIVEREF(__pyx_tuple_);

+32:     qsort_kernel_cython(lst, 0, len(lst)-1)
  __pyx_t_3 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_lst);
if (unlikely(!__pyx_t_3.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_t_4 = PyObject_Length(__pyx_v_lst); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_t_5 = __pyx_f_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_qsort_kernel_cython(__pyx_t_3, 0, (__pyx_t_4 - 1)); if (unlikely(!__pyx_t_5.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__PYX_XDEC_MEMVIEW(&__pyx_t_3, 1);
__PYX_XDEC_MEMVIEW(&__pyx_t_5, 1);

In [215]:

%timeit benchmark_qsort_cython()

The slowest run took 4.02 times longer than the fastest. This could mean that an intermediate result is being cached
1000 loops, best of 3: 735 µs per loop

In [216]:

report([benchmark_qsort, benchmark_qsort_cython])

benchmark_qsort: 1.0
benchmark_qsort_cython: 25.6


## Mandel¶

In [217]:

def mandel(z):
maxiter = 80
c = z
for n in range(maxiter):
if abs(z) > 2:
return n
z = z*z + c
return maxiter

def mandelperf():
r1 = np.linspace(-2.0, 0.5, 26)
r2 = np.linspace(-1.0, 1.0, 21)
return [mandel(complex(r, i)) for r in r1 for i in r2]

In [219]:

%timeit mandelperf()

100 loops, best of 3: 6.9 ms per loop

In [259]:

@jit
def mandel_numba(z):
maxiter = 80
c = z
for n in range(maxiter):
if abs(z) > 2:
return n
z = z*z + c
return maxiter

@jit
def mandelperf_numba():
r1 = np.linspace(-2.0, 0.5, 26)
r2 = np.linspace(-1.0, 1.0, 21)
res = np.empty((26, 21), dtype='int')
for i in range(26):
for j in range(21):
res[i, j] = mandel_numba(complex(r1[i], r2[j]))
return res

In [260]:

%timeit mandelperf_numba()

The slowest run took 2568.37 times longer than the fastest. This could mean that an intermediate result is being cached
1 loops, best of 3: 156 µs per loop

In [268]:

%%cython -a

cimport cython
import numpy as np
cimport numpy as np

cdef extern from "complex.h":
double cabs(double complex)

cdef int mandel_cython(double complex z):
cdef int n
cdef int max_iter
cdef double complex c
maxiter = 80
c = z
for n in range(maxiter):
if cabs(z) > 2:
return n
z = z*z + c
return maxiter

@cython.boundscheck(False)
@cython.wraparound(False)
def mandelperf_cython():
cdef int i, j

cdef double[:] r1 = np.linspace(-2.0, 0.5, 26)
cdef double[:] r2 = np.linspace(-1.0, 1.0, 21)
cdef int[:,:] res = np.empty((26,21), dtype=np.int32)

for i in range(26):
for j in range(21):
res[i,j] = mandel_cython(r1[i] + r2[j]*1j)
return res

Out[268]:

Cython: _cython_magic_49b54927ec0b1cfc50dc062249bda68a.pyx

Generated by Cython 0.23.4

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 01:
+02: cimport cython
  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

+03: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

 04: cimport numpy as np
 05:
 06: cdef extern from "complex.h":
 07:     double cabs(double complex)
 08:
+09: cdef int mandel_cython(double complex z):
static int __pyx_f_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_mandel_cython(__pyx_t_double_complex __pyx_v_z) {
int __pyx_v_n;
__pyx_t_double_complex __pyx_v_c;
long __pyx_v_maxiter;
int __pyx_r;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("mandel_cython", 0);
/* … */
/* function exit code */
__pyx_L0:;
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

 10:     cdef int n
 11:     cdef int max_iter
 12:     cdef double complex c
+13:     maxiter = 80
  __pyx_v_maxiter = 80;

+14:     c = z
  __pyx_v_c = __pyx_v_z;

+15:     for n in range(maxiter):
  __pyx_t_1 = __pyx_v_maxiter;
for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
__pyx_v_n = __pyx_t_2;

+16:         if cabs(z) > 2:
    __pyx_t_3 = ((cabs(__pyx_v_z) > 2.0) != 0);
if (__pyx_t_3) {
/* … */
}

+17:             return n
      __pyx_r = __pyx_v_n;
goto __pyx_L0;

+18:         z = z*z + c
    __pyx_v_z = __Pyx_c_sum(__Pyx_c_prod(__pyx_v_z, __pyx_v_z), __pyx_v_c);
}

+19:     return maxiter
  __pyx_r = __pyx_v_maxiter;
goto __pyx_L0;

 20:
 21: @cython.boundscheck(False)
 22: @cython.wraparound(False)
+23: def mandelperf_cython():
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython = {"mandelperf_cython", (PyCFunction)__pyx_pw_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython, METH_NOARGS, 0};
static PyObject *__pyx_pw_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("mandelperf_cython (wrapper)", 0);
__pyx_r = __pyx_pf_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_mandelperf_cython(__pyx_self);

/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_mandelperf_cython(CYTHON_UNUSED PyObject *__pyx_self) {
int __pyx_v_i;
int __pyx_v_j;
__Pyx_memviewslice __pyx_v_r1 = { 0, 0, { 0 }, { 0 }, { 0 } };
__Pyx_memviewslice __pyx_v_r2 = { 0, 0, { 0 }, { 0 }, { 0 } };
__Pyx_memviewslice __pyx_v_res = { 0, 0, { 0 }, { 0 }, { 0 } };
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("mandelperf_cython", 0);
/* … */
/* function exit code */
__pyx_L1_error:;
__Pyx_XDECREF(__pyx_t_1);
__Pyx_XDECREF(__pyx_t_2);
__PYX_XDEC_MEMVIEW(&__pyx_t_3, 1);
__Pyx_XDECREF(__pyx_t_4);
__Pyx_XDECREF(__pyx_t_5);
__PYX_XDEC_MEMVIEW(&__pyx_t_6, 1);
__pyx_r = NULL;
__pyx_L0:;
__PYX_XDEC_MEMVIEW(&__pyx_v_r1, 1);
__PYX_XDEC_MEMVIEW(&__pyx_v_r2, 1);
__PYX_XDEC_MEMVIEW(&__pyx_v_res, 1);
__Pyx_XGIVEREF(__pyx_r);
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
/* … */
__pyx_tuple__24 = PyTuple_Pack(5, __pyx_n_s_i, __pyx_n_s_j, __pyx_n_s_r1, __pyx_n_s_r2, __pyx_n_s_res); if (unlikely(!__pyx_tuple__24)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__24);
__Pyx_GIVEREF(__pyx_tuple__24);
/* … */
__pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython, NULL, __pyx_n_s_cython_magic_49b54927ec0b1cfc50); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_mandelperf_cython, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_codeobj__25 = (PyObject*)__Pyx_PyCode_New(0, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__24, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_cliburn_ipython_cython__c, __pyx_n_s_mandelperf_cython, 23, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__25)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;}

 24:     cdef int i, j
 25:
+26:     cdef double[:] r1 = np.linspace(-2.0, 0.5, 26)
  __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_linspace); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_3 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_1);
if (unlikely(!__pyx_t_3.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_r1 = __pyx_t_3;
__pyx_t_3.memview = NULL;
__pyx_t_3.data = NULL;
/* … */
__pyx_tuple_ = PyTuple_Pack(3, __pyx_float_neg_2_0, __pyx_float_0_5, __pyx_int_26); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple_);
__Pyx_GIVEREF(__pyx_tuple_);

+27:     cdef double[:] r2 = np.linspace(-1.0, 1.0, 21)
  __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_linspace); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_3 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_1);
if (unlikely(!__pyx_t_3.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_r2 = __pyx_t_3;
__pyx_t_3.memview = NULL;
__pyx_t_3.data = NULL;
/* … */
__pyx_tuple__2 = PyTuple_Pack(3, __pyx_float_neg_1_0, __pyx_float_1_0, __pyx_int_21); if (unlikely(!__pyx_tuple__2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__2);
__Pyx_GIVEREF(__pyx_tuple__2);

+28:     cdef int[:,:] res = np.empty((26,21), dtype=np.int32)
  __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_empty); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* … */
__pyx_tuple__3 = PyTuple_Pack(2, __pyx_int_26, __pyx_int_21); if (unlikely(!__pyx_tuple__3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__3);
__Pyx_GIVEREF(__pyx_tuple__3);
__pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_int32); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_dtype, __pyx_t_5) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__4, __pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_dsds_int(__pyx_t_5);
if (unlikely(!__pyx_t_6.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__pyx_v_res = __pyx_t_6;
__pyx_t_6.memview = NULL;
__pyx_t_6.data = NULL;
__pyx_tuple__4 = PyTuple_Pack(1, __pyx_tuple__3); if (unlikely(!__pyx_tuple__4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__4);
__Pyx_GIVEREF(__pyx_tuple__4);

 29:
+30:     for i in range(26):
  for (__pyx_t_7 = 0; __pyx_t_7 < 26; __pyx_t_7+=1) {
__pyx_v_i = __pyx_t_7;

+31:         for j in range(21):
    for (__pyx_t_8 = 0; __pyx_t_8 < 21; __pyx_t_8+=1) {
__pyx_v_j = __pyx_t_8;

+32:             res[i,j] = mandel_cython(r1[i] + r2[j]*1j)
      __pyx_t_9 = __pyx_v_i;
__pyx_t_10 = __pyx_v_j;
__pyx_t_11 = __pyx_v_i;
__pyx_t_12 = __pyx_v_j;
*((int *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_res.data + __pyx_t_11 * __pyx_v_res.strides[0]) ) + __pyx_t_12 * __pyx_v_res.strides[1]) )) = __pyx_f_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_mandel_cython(__Pyx_c_sum(__pyx_t_double_complex_from_parts((*((double *) ( /* dim=0 */ (__pyx_v_r1.data + __pyx_t_9 * __pyx_v_r1.strides[0]) ))), 0), __Pyx_c_prod(__pyx_t_double_complex_from_parts((*((double *) ( /* dim=0 */ (__pyx_v_r2.data + __pyx_t_10 * __pyx_v_r2.strides[0]) ))), 0), __pyx_t_double_complex_from_parts(0, 1.0))));
}
}

+33:     return res
  __Pyx_XDECREF(__pyx_r);
__pyx_t_5 = __pyx_memoryview_fromslice(__pyx_v_res, 2, (PyObject *(*)(char *)) __pyx_memview_get_int, (int (*)(char *, PyObject *)) __pyx_memview_set_int, 0);; if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_r = __pyx_t_5;
__pyx_t_5 = 0;
goto __pyx_L0;

In [269]:

%timeit mandelperf_cython()

1000 loops, best of 3: 222 µs per loop

In [271]:

report([mandelperf, mandelperf_numba, mandelperf_cython])

mandelperf: 1.0
mandelperf_numba: 19.7
mandelperf_cython: 15.4

In [454]:

for f in mandelperf, mandelperf_numba, mandelperf_cython:
print(np.reshape(f(), (26,21)), "\n")

[[ 0  0  0  0  0  0  0  0  0  0 80  0  0  0  0  0  0  0  0  0  0]
[ 0  0  0  0  1  1  2  2  3  3 80  3  3  2  2  1  1  0  0  0  0]
[ 0  0  1  1  2  2  2  3  3  3 80  3  3  3  2  2  2  1  1  0  0]
[ 1  1  2  2  2  2  2  3  3  5 80  5  3  3  2  2  2  2  2  1  1]
[ 1  2  2  2  2  2  2  3  4  5 80  5  4  3  2  2  2  2  2  2  1]
[ 1  2  2  2  2  2  3  4  4  6 80  6  4  4  3  2  2  2  2  2  1]
[ 2  2  2  2  2  2  4  4  5 11 80 11  5  4  4  2  2  2  2  2  2]
[ 2  2  2  2  2  3  6  6  7 13 80 13  7  6  6  3  2  2  2  2  2]
[ 2  2  2  2  2  4  6 15 17 80 80 80 17 15  6  4  2  2  2  2  2]
[ 2  2  2  2  3  4  6 11 80 80 80 80 80 11  6  4  3  2  2  2  2]
[ 2  2  2  3  3  4  6 34 80 80 80 80 80 34  6  4  3  3  2  2  2]
[ 2  2  3  3  4  4  6 10 80 80 80 80 80 10  6  4  4  3  3  2  2]
[ 2  3  3  3  4  5  6  8 14 80 80 80 14  8  6  5  4  3  3  3  2]
[ 2  3  3  4  5  7 10 23 80 80 80 80 80 23 10  7  5  4  3  3  2]
[ 3  3  3  6 11 11 80 80 80 80 80 80 80 80 80 11 11  6  3  3  3]
[ 3  3  4  7 80 80 80 80 80 80 80 80 80 80 80 80 80  7  4  3  3]
[ 3  4  5  7 25 80 80 80 80 80 80 80 80 80 80 80 25  7  5  4  3]
[ 4  5  7  9 80 80 80 80 80 80 80 80 80 80 80 80 80  9  7  5  4]
[ 6  8 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80  8  6]
[ 8 23 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 23  8]
[80  7 17 12 80 80 80 80 80 80 80 80 80 80 80 80 80 12 17  7 80]
[ 3  4  5  8 80 80 80 80 80 80 80 80 80 80 80 80 80  8  5  4  3]
[ 3  3  4  5 11 80 80 80 80 80 80 80 80 80 80 80 11  5  4  3  3]
[ 2  3  4  5 14 80 80 80 80 80 11 80 80 80 80 80 14  5  4  3  2]
[ 2  2  3  4 14  6  8 14 30  7  6  7 30 14  8  6 14  4  3  2  2]
[ 1  2  2  3  3  4  4  5  4  4  4  4  4  5  4  4  3  3  2  2  1]]

[[ 0  0  0  0  0  0  0  0  0  0 80  0  0  0  0  0  0  0  0  0  0]
[ 0  0  0  0  1  1  2  2  3  3 80  3  3  2  2  1  1  0  0  0  0]
[ 0  0  1  1  2  2  2  3  3  3 80  3  3  3  2  2  2  1  1  0  0]
[ 1  1  2  2  2  2  2  3  3  5 80  5  3  3  2  2  2  2  2  1  1]
[ 1  2  2  2  2  2  2  3  4  5 80  5  4  3  2  2  2  2  2  2  1]
[ 1  2  2  2  2  2  3  4  4  6 80  6  4  4  3  2  2  2  2  2  1]
[ 2  2  2  2  2  2  4  4  5 11 80 11  5  4  4  2  2  2  2  2  2]
[ 2  2  2  2  2  3  6  6  7 13 80 13  7  6  6  3  2  2  2  2  2]
[ 2  2  2  2  2  4  6 15 17 80 80 80 17 15  6  4  2  2  2  2  2]
[ 2  2  2  2  3  4  6 11 80 80 80 80 80 11  6  4  3  2  2  2  2]
[ 2  2  2  3  3  4  6 34 80 80 80 80 80 34  6  4  3  3  2  2  2]
[ 2  2  3  3  4  4  6 10 80 80 80 80 80 10  6  4  4  3  3  2  2]
[ 2  3  3  3  4  5  6  8 14 80 80 80 14  8  6  5  4  3  3  3  2]
[ 2  3  3  4  5  7 10 23 80 80 80 80 80 23 10  7  5  4  3  3  2]
[ 3  3  3  6 11 11 80 80 80 80 80 80 80 80 80 11 11  6  3  3  3]
[ 3  3  4  7 80 80 80 80 80 80 80 80 80 80 80 80 80  7  4  3  3]
[ 3  4  5  7 25 80 80 80 80 80 80 80 80 80 80 80 25  7  5  4  3]
[ 4  5  7  9 80 80 80 80 80 80 80 80 80 80 80 80 80  9  7  5  4]
[ 6  8 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80  8  6]
[ 8 23 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 23  8]
[80  7 17 12 80 80 80 80 80 80 80 80 80 80 80 80 80 12 17  7 80]
[ 3  4  5  8 80 80 80 80 80 80 80 80 80 80 80 80 80  8  5  4  3]
[ 3  3  4  5 11 80 80 80 80 80 80 80 80 80 80 80 11  5  4  3  3]
[ 2  3  4  5 14 80 80 80 80 80 11 80 80 80 80 80 14  5  4  3  2]
[ 2  2  3  4 14  6  8 14 30  7  6  7 30 14  8  6 14  4  3  2  2]
[ 1  2  2  3  3  4  4  5  4  4  4  4  4  5  4  4  3  3  2  2  1]]

[[ 0  0  0  0  0  0  0  0  0  0 80  0  0  0  0  0  0  0  0  0  0]
[ 0  0  0  0  1  1  2  2  3  3 80  3  3  2  2  1  1  0  0  0  0]
[ 0  0  1  1  2  2  2  3  3  3 80  3  3  3  2  2  2  1  1  0  0]
[ 1  1  2  2  2  2  2  3  3  5 80  5  3  3  2  2  2  2  2  1  1]
[ 1  2  2  2  2  2  2  3  4  5 80  5  4  3  2  2  2  2  2  2  1]
[ 1  2  2  2  2  2  3  4  4  6 80  6  4  4  3  2  2  2  2  2  1]
[ 2  2  2  2  2  2  4  4  5 11 80 11  5  4  4  2  2  2  2  2  2]
[ 2  2  2  2  2  3  6  6  7 13 80 13  7  6  6  3  2  2  2  2  2]
[ 2  2  2  2  2  4  6 15 17 80 80 80 17 15  6  4  2  2  2  2  2]
[ 2  2  2  2  3  4  6 11 80 80 80 80 80 11  6  4  3  2  2  2  2]
[ 2  2  2  3  3  4  6 34 80 80 80 80 80 34  6  4  3  3  2  2  2]
[ 2  2  3  3  4  4  6 10 80 80 80 80 80 10  6  4  4  3  3  2  2]
[ 2  3  3  3  4  5  6  8 14 80 80 80 14  8  6  5  4  3  3  3  2]
[ 2  3  3  4  5  7 10 23 80 80 80 80 80 23 10  7  5  4  3  3  2]
[ 3  3  3  6 11 11 80 80 80 80 80 80 80 80 80 11 11  6  3  3  3]
[ 3  3  4  7 80 80 80 80 80 80 80 80 80 80 80 80 80  7  4  3  3]
[ 3  4  5  7 25 80 80 80 80 80 80 80 80 80 80 80 25  7  5  4  3]
[ 4  5  7  9 80 80 80 80 80 80 80 80 80 80 80 80 80  9  7  5  4]
[ 6  8 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80  8  6]
[ 8 23 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 23  8]
[80  7 17 12 80 80 80 80 80 80 80 80 80 80 80 80 80 12 17  7 80]
[ 3  4  5  8 80 80 80 80 80 80 80 80 80 80 80 80 80  8  5  4  3]
[ 3  3  4  5 11 80 80 80 80 80 80 80 80 80 80 80 11  5  4  3  3]
[ 2  3  4  5 14 80 80 80 80 80 11 80 80 80 80 80 14  5  4  3  2]
[ 2  2  3  4 14  6  8 14 30  7  6  7 30 14  8  6 14  4  3  2  2]
[ 1  2  2  3  3  4  4  5  4  4  4  4  4  5  4  4  3  3  2  2  1]]



## Pi_sum¶

In [272]:

def pisum(t):
sum = 0.0
for j in range(1, 501):
sum = 0.0
for k in range(1, t+1):
sum += 1.0/(k*k)
return sum

In [273]:

%timeit pisum(10000)

1 loops, best of 3: 1.33 s per loop

In [282]:

@jit
def pisum_numba(t):
sum = 0.0
for j in range(1, 501):
sum = 0.0
for k in range(1, t+1):
sum += 1.0/(k*k)
return sum

In [283]:

%timeit pisum_numba(10000)

10 loops, best of 3: 35.8 ms per loop

In [298]:

%%cython -a

cimport cython

@cython.cdivision(True)
def pisum_cython(int t):
cdef double sum
cdef int j, k

for j in range(1, 501):
sum = 0.0
for k in range(1, t+1):
sum += 1.0/(k*k)
return sum

Out[298]:

Cython: _cython_magic_39bd6be55fc470028b8a8a158c919aa6.pyx

Generated by Cython 0.23.4

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 01:
 02: cimport cython
 03:
 04: @cython.cdivision(True)
+05: def pisum_cython(int t):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython(PyObject *__pyx_self, PyObject *__pyx_arg_t); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython = {"pisum_cython", (PyCFunction)__pyx_pw_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython, METH_O, 0};
static PyObject *__pyx_pw_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython(PyObject *__pyx_self, PyObject *__pyx_arg_t) {
int __pyx_v_t;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("pisum_cython (wrapper)", 0);
assert(__pyx_arg_t); {
__pyx_v_t = __Pyx_PyInt_As_int(__pyx_arg_t); if (unlikely((__pyx_v_t == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L3_error:;
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
__pyx_r = __pyx_pf_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_pisum_cython(__pyx_self, ((int)__pyx_v_t));
int __pyx_lineno = 0;
const char *__pyx_filename = NULL;
int __pyx_clineno = 0;

/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_pisum_cython(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_t) {
double __pyx_v_sum;
CYTHON_UNUSED int __pyx_v_j;
int __pyx_v_k;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("pisum_cython", 0);
/* … */
/* function exit code */
__pyx_L1_error:;
__Pyx_XDECREF(__pyx_t_4);
__pyx_r = NULL;
__pyx_L0:;
__Pyx_XGIVEREF(__pyx_r);
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
/* … */
__pyx_tuple_ = PyTuple_Pack(5, __pyx_n_s_t, __pyx_n_s_t, __pyx_n_s_sum, __pyx_n_s_j, __pyx_n_s_k); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple_);
__Pyx_GIVEREF(__pyx_tuple_);
/* … */
__pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython, NULL, __pyx_n_s_cython_magic_39bd6be55fc470028b); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_pisum_cython, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

 06:     cdef double sum
 07:     cdef int j, k
 08:
+09:     for j in range(1, 501):
  for (__pyx_t_1 = 1; __pyx_t_1 < 0x1F5; __pyx_t_1+=1) {
__pyx_v_j = __pyx_t_1;

+10:         sum = 0.0
    __pyx_v_sum = 0.0;

+11:         for k in range(1, t+1):
    __pyx_t_2 = (__pyx_v_t + 1);
for (__pyx_t_3 = 1; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
__pyx_v_k = __pyx_t_3;

+12:             sum += 1.0/(k*k)
      __pyx_v_sum = (__pyx_v_sum + (1.0 / (__pyx_v_k * __pyx_v_k)));
}
}

+13:     return sum
  __Pyx_XDECREF(__pyx_r);
__pyx_t_4 = PyFloat_FromDouble(__pyx_v_sum); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__pyx_r = __pyx_t_4;
__pyx_t_4 = 0;
goto __pyx_L0;

In [299]:

%timeit pisum_cython(10000)

10 loops, best of 3: 35.8 ms per loop

In [286]:

report([pisum, pisum_numba, pisum_cython], 10000)

pisum: 1.0
pisum_numba: 35.6
pisum_cython: 35.6

In [455]:

for f in pisum, pisum_numba, pisum_cython:
print(f(10000))

1.6448340718480652
1.6448340718480652
1.6448340718480652


## Rand_mat_stat¶

In [287]:

def randmatstat(t):
n = 5
v = np.zeros(t)
w = np.zeros(t)
for i in range(1,t):
a = np.random.randn(n, n)
b = np.random.randn(n, n)
c = np.random.randn(n, n)
d = np.random.randn(n, n)
P = np.matrix(np.hstack((a, b, c, d)))
Q = np.matrix(np.vstack((np.hstack((a, b)), np.hstack((c, d)))))
v[i] = np.trace(np.linalg.matrix_power(np.transpose(P)*P, 4))
w[i] = np.trace(np.linalg.matrix_power(np.transpose(Q)*Q, 4))
return (np.std(v)/np.mean(v), np.std(w)/np.mean(w))

In [288]:

%timeit randmatstat(1000)

1 loops, best of 3: 260 ms per loop

In [391]:

def randmatstat_numba(t):
n = 5
v = np.zeros(t)
w = np.zeros(t)
for i in range(1,t):
a, b, c, d = np.random.randn(4, n, n)
P = np.hstack((a, b, c, d))
Q = np.vstack((np.hstack((a, b)), np.hstack((c, d))))

PTP = P.T.dot(P)
QTQ = Q.T.dot(Q)

v[i] = np.trace(PTP @ PTP @ PTP @ PTP)
w[i] = np.trace(QTQ @ QTQ @ QTQ @ QTQ)
return (np.std(v)/np.mean(v), np.std(w)/np.mean(w))

In [393]:

def randmatstat_alt(t):
n = 5
v = np.zeros(t)
w = np.zeros(t)

for i in range(1,t):
a, b, c, d = np.random.randn(4, n, n)
P = np.hstack((a, b, c, d))
Q = np.vstack((np.hstack((a, b)), np.hstack((c, d))))

P1 = P.T @ P
P2 = P1 @ P1
P4 = P2 @ P2

Q1 = Q.T @ Q
Q2 = Q1 @ Q1
Q4 = Q2 @ Q2

v[i] = np.trace(P4)
w[i] = np.trace(Q4)

return (np.std(v)/np.mean(v), np.std(w)/np.mean(w))

In [394]:

%timeit randmatstat_alt(1000)

10 loops, best of 3: 131 ms per loop

In [396]:

report([randmatstat, randmatstat_alt], 1000)

randmatstat: 1.0
randmatstat_alt: 2.1

In [458]:

for f in randmatstat, randmatstat_alt:
np.random.seed(123)
print(f(1000))

(0.72398346943567571, 0.7713214961017032)
(0.72398346943567571, 0.7713214961017032)


## Rand_mat_mul¶

In [289]:

def randmatmul(n):
A = np.random.rand(n,n)
B = np.random.rand(n,n)
return np.dot(A,B)

In [290]:

%timeit randmatmul(1000)

10 loops, best of 3: 81 ms per loop


## Comparison¶

These benchmarks don’t mean very much - they were constructed by the Julia team presumably to show off Julia’s strengths, and are used here just to illustrate basic Python optimization techniques. In some case (quicksort, mandel, pi_sum), this gives dramatic performance improvements but in other cases (parse_int, rand_mat_stat) there is less improvement. For fib, the speed depends on the algorithm used for calculation, and whether caching is enabled in the recursive case. The final test rand_mat_mul basically depends on the linear algebra library installed (blas, mkl, atlas) and is not really a comparison across languages.

Julia certainly does look promising, and we might include mix in some Julia code in future courses.

In [459]:

benchmarks['P2J'] = benchmarks.Python / benchmarks.Julia
benchmarks['SU'] = [1919.0, 3.2, 25.6, 19.7, 35.6, 2.1, 1.0]
pd.options.display.float_format = '{:.2f}'.format
benchmarks.ix[:, [0,2,3,-2,-1]]

Out[459]:

Julia Python P2J SU
1 fib 2.11 77.76 36.85 1919.00
2 parse_int 1.45 17.02 11.74 3.20
3 quicksort 1.15 32.89 28.60 25.60
4 mandel 0.79 15.32 19.39 19.70
5 pi_sum 1.00 21.99 21.99 35.60
6 rand_mat_stat 1.66 17.93 10.80 2.10
7 rand_mat_mul 1.02 1.14 1.12 1.00
In [ ]: