In [1]:
import hope
hope.config.optimize = True
hope.config.verbose = True
hope.config.keeptemp = True
import numba
import numpy as np
from util import perf_comp_data
from native_util import load
%load_ext cythonmagic
%load_ext version_information
%version_information numpy, Cython, numba, hope


Out[1]:
SoftwareVersion
Python2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]
IPython1.1.0
OSposix [darwin]
numpy1.8.1
Cython0.20.2
numba0.13.3
hope0.3.0
Thu Sep 04 15:18:18 2014 CEST

In [2]:
# Pure python version

def pairwise_python(X, D):
    M = X.shape[0]
    N = X.shape[1]
    for i in range(M):
        for j in range(M):
            d = 0.0
            for k in range(N):
                tmp = X[i, k] - X[j, k]
                d += tmp * tmp
            D[i, j] = np.sqrt(d)

In [3]:
# Numpy python version

def pairwise_numpy(X, D):
    M = X.shape[0]
    for i in range(M):
        D[i, :] = np.sqrt(np.sum((X[i, :] - X[:]) ** 2, axis=1))

In [4]:
# numba version
@numba.jit(nopython=True)
def pairwise_numba(X, D):
    M = X.shape[0]
    N = X.shape[1]
    for i in range(M):
        for j in range(M):
            d = 0.0
            for k in range(N):
                tmp = X[i, k] - X[j, k]
                d += tmp * tmp
            D[i, j] = np.sqrt(d)

In [5]:
%%cython

cimport cython
from libc.math cimport sqrt

@cython.boundscheck(False)
@cython.wraparound(False)
def pairwise_cython(double[:, ::1] X, double[:, ::1] D):
    cdef int M = X.shape[0]
    cdef int N = X.shape[1]
    cdef double tmp, d
    for i in range(M):
        for j in range(M):
            d = 0.0
            for k in range(N):
                tmp = X[i, k] - X[j, k]
                d += tmp * tmp
            D[i, j] = sqrt(d)

In [6]:
# hope version
@hope.jit
def pairwise_hope(X, D, M, N):
    for i in range(M):
        for j in range(M):
            d = 0.0
            for k in range(N):
                tmp = X[i, k] - X[j, k]
                d += tmp * tmp
            D[i, j] = np.sqrt(d)

In [7]:
from native_util import load

native_pairwise_mod = load("pairwise")
pairwise_native = native_pairwise_mod.run


running build_ext
building 'pairwise' extension
C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes

compile options: '-I/Users/jakeret/Library/Python/2.7/lib/python/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'
extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'
clang: ././src/pairwise.cpp
/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 ./src/pairwise.o -o ./pairwise.so


In [8]:
X = np.random.random((1000, 3))
D = np.empty((1000, 1000))

In [10]:
D1 = np.empty((1000, 1000))
D2 = np.empty((1000, 1000))
D3 = np.empty((1000, 1000))
D4 = np.empty((1000, 1000))
D5 = np.empty((1000, 1000))
D6 = np.empty((1000, 1000))

pairwise_python(X, D1)
pairwise_numpy(X, D2)
pairwise_numba(X, D3)
pairwise_cython(X, D4)
pairwise_hope(X, D5, X.shape[0], X.shape[1])
pairwise_native(X, D6, X.shape[0], X.shape[1])

assert np.allclose(D1, D2)
assert np.allclose(D1, D3)
assert np.allclose(D1, D4)
assert np.allclose(D1, D5)
assert np.allclose(D1, D6)

In [11]:
print "naive python"
%timeit pairwise_python(X, D)
print "numpy"
%timeit pairwise_numpy(X, D)
print "numba"
%timeit pairwise_numba(X, D)
print "cython"
%timeit pairwise_cython(X, D)
print "hope"
%timeit pairwise_hope(X, D, X.shape[0], X.shape[1])
print "native"
%timeit pairwise_native(X, D, X.shape[0], X.shape[1])


naive python
1 loops, best of 3: 5.75 s per loop
numpy
10 loops, best of 3: 36.6 ms per loop
numba
100 loops, best of 3: 6.88 ms per loop
cython
100 loops, best of 3: 4.22 ms per loop
hope
100 loops, best of 3: 6.36 ms per loop
native
100 loops, best of 3: 4.23 ms per loop

In [ ]:
from util import perf_comp_data

In [13]:
M, N = X.shape
data_list = 4*["X, D"]+ 2*["X, D, M, N"]
#print data_list
perf_comp_data(["pairwise_python", 
                "pairwise_numpy", 
                "pairwise_numba", 
                "pairwise_cython", 
                "pairwise_hope",
                "pairwise_native"],
               data_list, rep=100)


function: pairwise_native     , av. time sec:   0.00420749, min. time sec:   0.00414991, relative:       1.0
function: pairwise_cython     , av. time sec:   0.00421405, min. time sec:   0.00415277, relative:       1.0
function: pairwise_hope       , av. time sec:   0.00635457, min. time sec:   0.00626707, relative:       1.5
function: pairwise_numba      , av. time sec:   0.00690150, min. time sec:   0.00681400, relative:       1.6
function: pairwise_numpy      , av. time sec:   0.03677249, min. time sec:   0.03618908, relative:       8.7
function: pairwise_python     , av. time sec:   5.90122139, min. time sec:   5.63599896, relative:    1402.6

In [ ]: