Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
309 changes: 309 additions & 0 deletions pythran/Pythran.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Pythran version of the Julia challenge\n",
"\n",
"Pythran compiles Numpy code into native code, with an emphasis on numerical kernels. In some way it does the same as Julia, but for Numerical Python: use a single language to catch'em all."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Requirements\n",
"\n",
" pip install numpy\n",
" pip install pythran colorlog"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[33mWARNING \u001b[0m \u001b[34mPythran support disabled for module: scipy.special\u001b[0m\n",
"\u001b[33mWARNING \u001b[0m \u001b[34mPythran support disabled for module: scipy\u001b[0m\n"
]
}
],
"source": [
"import pythran\n",
"%load_ext pythran.magic"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"a = np.random.random((1000,1000))\n",
"b = np.random.random(1000)\n",
"c = np.random.rand()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"ref = a + b + np.sin(c)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The magic below calls Pythran to provide an accelerated, vectorized version, loop-merged kernel. Pythran can support much more complex code than that, obvisouly :-)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"%%pythran -DUSE_BOOST_SIMD -march=native -O3\n",
"import numpy as np\n",
"#pythran export kernel(float64[:,:], float64[:], float64)\n",
"def kernel(a, b, c):\n",
" return a + b + np.sin(c)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Checking that the result is correct"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"out = kernel(a, b, c)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.all(ref == out)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And benchmarking with %timeit, compared to numpy."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.71 ms ± 21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
]
}
],
"source": [
"%timeit a + b + np.sin(c)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"914 µs ± 8.54 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
]
}
],
"source": [
"%timeit kernel(a, b, c)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bonus: alternatives\n",
"\n",
"Naively exploring other straight-forward alternatives.\n",
"\n",
"### requirements\n",
"\n",
" pip install numba numexpr cython"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"import numexpr as ne"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4.35 ms ± 23.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
]
}
],
"source": [
"%timeit ne.evaluate(\"a + b * sin(c)\")"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"import numba\n",
"@numba.jit(nopython=True)\n",
"def kernel(a, b, c):\n",
" return a + b + np.sin(c)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.12 ms ± 19.6 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit kernel(a,b,c)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"%load_ext cython"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"%%cython --compile-args=-O3 --compile-args=-march=native\n",
"\n",
"import numpy as np\n",
"cimport numpy as np\n",
"cimport cython\n",
"\n",
"cdef extern from \"math.h\":\n",
" double sin(double)\n",
"\n",
"\n",
"@cython.boundscheck(False)\n",
"def kernel(np.ndarray[np.float64_t, ndim=2] a,\n",
" np.ndarray[np.float64_t, ndim=1] b,\n",
" np.float64_t c):\n",
"\n",
" # Local variables\n",
" cdef Py_ssize_t i, j\n",
" cdef np.ndarray[np.float64_t, ndim=2] out\n",
"\n",
" out = np.empty_like(a)\n",
"\n",
" for i in range(a.shape[0]):\n",
" for j in range(a.shape[1]):\n",
" out[i,j] = a[i,j] + b[i] + sin(c)\n",
"\n",
" return out"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.21 ms ± 15.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
]
}
],
"source": [
"%timeit kernel(a,b,c)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}