{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Just-in-time compilation (JIT)\n", "====\n", "\n", "For programmer productivity, it often makes sense to code the majority of your application in a high-level language such as Python and only optimize code bottlenecks identified by profiling. One way to speed up these bottlenecks is to compile the code to machine executables, often via an intermediate C or C-like stage. There are two common approaches to compiling Python code - using a Just-In-Time (JIT) compiler and using Cython for Ahead of Time (AOT) compilation.\n", "\n", "This notebook mostly illustrates the JIT approach." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**References**\n", "\n", "- [Numba](http://numba.pydata.org)\n", "- [The need for speed without bothering too much: An introduction to numba](http://nbviewer.jupyter.org/github/akittas/presentations/blob/master/pythess/numba/numba.ipynb?utm_source=newsletter_mailer&utm_medium=email&utm_campaign=weekly)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Utility function for timing functions**" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import time\n", "from numpy.testing import assert_almost_equal" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def timer(f, *args, **kwargs):\n", " start = time.clock()\n", " ans = f(*args, **kwargs)\n", " return ans, time.clock() - start" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def report(fs, *args, **kwargs):\n", " ans, t = timer(fs[0], *args, **kwargs)\n", " print('%s: %.1f' % (fs[0].__name__, 1.0)) \n", " for f in fs[1:]:\n", " ans_, t_ = timer(f, *args, **kwargs)\n", " print('%s: %.1f' % (f.__name__, t/t_))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `numexpr`\n", "----\n", "\n", "One of the simplest approaches is to use [`numexpr`](https://github.com/pydata/numexpr) which takes a `numpy` expression and compiles a more efficient version of the `numpy` expression written as a string. If there is a simple expression that is taking too long, this is a good choice due to its simplicity. However, it is quite limited." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "a = np.random.random(int(1e6))\n", "b = np.random.random(int(1e6))\n", "c = np.random.random(int(1e6))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9.44 ms ± 1.36 ms per loop (mean ± std. dev. of 3 runs, 3 loops each)\n" ] } ], "source": [ "%timeit -r3 -n3 b**2 - 4*a*c" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "import numexpr as ne" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2.52 ms ± 779 µs per loop (mean ± std. dev. of 3 runs, 3 loops each)\n" ] } ], "source": [ "%timeit -r3 -n3 ne.evaluate('b**2 - 4*a*c')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `numba`\n", "----\n", "\n", "When it works, the JIT `numba` can speed up Python code tremendously with minimal effort. \n", "\n", "[Documentation for `numba`](http://numba.pydata.org/numba-doc/0.12.2/index.html)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Plain Python version" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def matrix_multiply(A, B):\n", " m, n = A.shape\n", " n, p = B.shape\n", " C = np.zeros((m, p))\n", " for i in range(m):\n", " for j in range(p):\n", " for k in range(n):\n", " C[i,j] += A[i,k] * B[k, j]\n", " return C" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "A = np.random.random((30, 50))\n", "B = np.random.random((50, 40))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Numba jit version" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "import numba\n", "from numba import jit" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "@jit\n", "def matrix_multiply_numba(A, B):\n", " m, n = A.shape\n", " n, p = B.shape\n", " C = np.zeros((m, p))\n", " for i in range(m):\n", " for j in range(p):\n", " for k in range(n):\n", " C[i,j] += A[i,k] * B[k, j]\n", " return C" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "43.1 ms ± 198 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", "59 µs ± 3.57 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] } ], "source": [ "%timeit matrix_multiply(A, B)\n", "%timeit matrix_multiply_numba(A, B)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Numpy version" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "def matrix_multiply_numpy(A, B):\n", " return A.dot(B)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Check that outputs are the same" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "assert_almost_equal(matrix_multiply(A, B), matrix_multiply_numba(A, B))\n", "assert_almost_equal(matrix_multiply(A, B), matrix_multiply_numpy(A, B))" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "60.6 µs ± 1.85 µs per loop (mean ± std. dev. of 3 runs, 3 loops each)\n" ] } ], "source": [ "%timeit -r3 -n3 matrix_multiply_numba(A, B)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "matrix_multiply: 1.0\n", "matrix_multiply_numba: 591.2\n", "matrix_multiply_numpy: 550.0\n" ] } ], "source": [ "report([matrix_multiply, matrix_multiply_numba, matrix_multiply_numpy], A, B)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "### Pre-compilation by giving specific signature " ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "@jit('double[:,:](double[:,:], double[:,:])')\n", "def matrix_multiply_numba_1(A, B):\n", " m, n = A.shape\n", " n, p = B.shape\n", " C = np.zeros((m, p))\n", " for i in range(m):\n", " for j in range(p):\n", " for k in range(n):\n", " C[i,j] += A[i,k] * B[k, j]\n", " return C" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "57.4 µs ± 303 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", "53.7 µs ± 263 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n" ] } ], "source": [ "%timeit matrix_multiply_numba(A, B)\n", "%timeit matrix_multiply_numba_1(A, B)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 2: Using nopython" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Vectorized Python version" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "def mc_pi(n):\n", " x = np.random.uniform(-1, 1, (n,2))\n", " return 4*np.sum((x**2).sum(1) < 1)/n" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "n = int(1e6)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "57.4 ms ± 157 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] } ], "source": [ "%timeit mc_pi(n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Numba on vectorized version" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "@jit\n", "def mc_pi_numba(n):\n", " x = np.random.uniform(-1, 1, (n,2))\n", " return 4*np.sum((x**2).sum(1) < 1)/n" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "38.2 ms ± 618 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] } ], "source": [ "%timeit mc_pi_numba(n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Using nopython" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "@jit(nopython=True)\n", "def mc_pi_numba_njit(n):\n", " x = np.random.uniform(-1, 1, (n,2))\n", " return 4*np.sum((x**2).sum(1) < 1)/n" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "from numba.errors import TypingError" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "try:\n", " mc_pi_numba_njit(n)\n", "except TypingError:\n", " print(\"Unable to convert to pure C code.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Numba on unrolled version" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "@jit(nopython=True)\n", "def mc_pi_numba_unrolled(n):\n", " s = 0\n", " for i in range(n):\n", " x = np.random.uniform(-1, 1)\n", " y = np.random.uniform(-1, 1)\n", " if (x*x + y*y) < 1:\n", " s += 1\n", " return 4*s/n" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "21.9 ms ± 54.1 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] } ], "source": [ "%timeit mc_pi_numba_unrolled(n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Usig cache=True\n", "\n", "This stores the compiled function in a file and avoids re-compilation on re-running a Python program." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "@jit(nopython=True, cache=True)\n", "def mc_pi_numba_unrolled_cache(n):\n", " s = 0\n", " for i in range(n):\n", " x = np.random.uniform(-1, 1)\n", " y = np.random.uniform(-1, 1)\n", " if (x*x + y*y) < 1:\n", " s += 1\n", " return 4*s/n" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "21.9 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] } ], "source": [ "%timeit mc_pi_numba_unrolled_cache(n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using numba vectorize and guvectoize\n", "----\n", "\n", "Sometimes it is convenient to use `numba` to convert functions to vectorized functions for use in `numpy`. See [documentation](http://numba.pydata.org/numba-doc/dev/user/vectorize.html) for details." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "from numba import int32, int64, float32, float64" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using `vectorize`" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "@numba.vectorize()\n", "def f(x, y):\n", " return np.sqrt(x**2 + y**2)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "xs = np.random.random(10)\n", "ys = np.random.random(10)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.52017797, 0.60036725, 0.98036295, 0.73798956, 1.23158168,\n", " 0.75068551, 0.79861068, 0.80421275, 1.25123047, 0.50919095])" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.array([np.sqrt(x**2 + y**2) for (x, y) in zip(xs, ys)])" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.52017797, 0.60036725, 0.98036295, 0.73798956, 1.23158168,\n", " 0.75068551, 0.79861068, 0.80421275, 1.25123047, 0.50919095])" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f(xs, ys)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding function signatures" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "@numba.vectorize([float64(float64, float64),\n", " float32(float32, float32),\n", " float64(int64, int64),\n", " float32(int32, int32)])\n", "def f_sig(x, y):\n", " return np.sqrt(x**2 + y**2)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.52017797, 0.60036725, 0.98036295, 0.73798956, 1.23158168,\n", " 0.75068551, 0.79861068, 0.80421275, 1.25123047, 0.50919095])" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f_sig(xs, ys)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using `guvectorize` " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Create our own version of inner1d**" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "@numba.guvectorize([(float64[:], float64[:], float64[:])], '(n),(n)->()')\n", "def nb_inner1d(u, v, res):\n", " res[0] = 0\n", " for i in range(len(u)):\n", " res[0] += u[i]*v[i]" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "xs = np.random.random((3,4))" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1.68593054, 1.91540631, 2.1076339 ])" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nb_inner1d(xs, xs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Check**" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "from numpy.core.umath_tests import inner1d" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1.68593054, 1.91540631, 2.1076339 ])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "inner1d(xs,xs)" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The slowest run took 4.94 times longer than the fastest. This could mean that an intermediate result is being cached.\n", "4.86 µs ± 3.82 µs per loop (mean ± std. dev. of 3 runs, 3 loops each)\n" ] } ], "source": [ "%timeit -r3 -n3 nb_inner1d(xs, xs)" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The slowest run took 4.83 times longer than the fastest. This could mean that an intermediate result is being cached.\n", "4.95 µs ± 3.85 µs per loop (mean ± std. dev. of 3 runs, 3 loops each)\n" ] } ], "source": [ "%timeit -r3 -n3 inner1d(xs, xs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Create our own version of matrix_multiply**" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [], "source": [ "@numba.guvectorize([(int64[:,:], int64[:,:], int64[:,:])], \n", " '(m,n),(n,p)->(m,p)')\n", "def nb_matrix_multiply(u, v, res):\n", " m, n = u.shape\n", " n, p = v.shape\n", " for i in range(m):\n", " for j in range(p):\n", " res[i,j] = 0\n", " for k in range(n):\n", " res[i,j] += u[i,k] * v[k,j]" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [], "source": [ "xs = np.random.randint(0, 10, (5, 2, 3))\n", "ys = np.random.randint(0, 10, (5, 3, 2))" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[[ 47, 42],\n", " [ 87, 60]],\n", "\n", " [[ 49, 54],\n", " [ 35, 101]],\n", "\n", " [[ 58, 70],\n", " [ 24, 45]],\n", "\n", " [[117, 96],\n", " [ 85, 70]],\n", "\n", " [[ 79, 81],\n", " [ 86, 90]]])" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nb_matrix_multiply(xs, ys)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Check**" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "from numpy.core.umath_tests import matrix_multiply" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[[ 47, 42],\n", " [ 87, 60]],\n", "\n", " [[ 49, 54],\n", " [ 35, 101]],\n", "\n", " [[ 58, 70],\n", " [ 24, 45]],\n", "\n", " [[117, 96],\n", " [ 85, 70]],\n", "\n", " [[ 79, 81],\n", " [ 86, 90]]])" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "matrix_multiply(xs, ys)" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The slowest run took 6.21 times longer than the fastest. This could mean that an intermediate result is being cached.\n", "6.95 µs ± 6.14 µs per loop (mean ± std. dev. of 3 runs, 3 loops each)\n" ] } ], "source": [ "%timeit -r3 -n3 nb_matrix_multiply(xs, ys)" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The slowest run took 4.36 times longer than the fastest. This could mean that an intermediate result is being cached.\n", "5.69 µs ± 4.22 µs per loop (mean ± std. dev. of 3 runs, 3 loops each)\n" ] } ], "source": [ "%timeit -r3 -n3 matrix_multiply(xs, ys)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Parallelization with vectorize and guvectorize\n", "----" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [], "source": [ "@numba.vectorize([float64(float64, float64),\n", " float32(float32, float32),\n", " float64(int64, int64),\n", " float32(int32, int32)],\n", " target='parallel')\n", "def f_parallel(x, y):\n", " return np.sqrt(x**2 + y**2)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "xs = np.random.random(int(1e8))\n", "ys = np.random.random(int(1e8))" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.4 s ± 3.36 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] } ], "source": [ "%timeit f(xs, ys)" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "320 ms ± 6.86 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] } ], "source": [ "%timeit f_parallel(xs, ys)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "### Mandelbrot example with `numba`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Pure Python**" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [], "source": [ "# color function for point at (x, y)\n", "def mandel(x, y, max_iters):\n", " c = complex(x, y)\n", " z = 0.0j\n", " for i in range(max_iters):\n", " z = z*z + c\n", " if z.real*z.real + z.imag*z.imag >= 4:\n", " return i\n", " return max_iters" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [], "source": [ "def create_fractal(xmin, xmax, ymin, ymax, image, iters):\n", " height, width = image.shape\n", " \n", " pixel_size_x = (xmax - xmin)/width\n", " pixel_size_y = (ymax - ymin)/height\n", " \n", " for x in range(width):\n", " real = xmin + x*pixel_size_x\n", " for y in range(height):\n", " imag = ymin + y*pixel_size_y\n", " color = mandel(real, imag, iters)\n", " image[y, x] = color " ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mandelbrot created on CPU in 22.444073 s\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "gimage = np.zeros((1024, 1536), dtype=np.uint8)\n", "xmin, xmax, ymin, ymax = np.array([-2.0, 1.0, -1.0, 1.0]).astype('float32')\n", "iters = 50\n", "\n", "start = time.clock()\n", "create_fractal(xmin, xmax, ymin, ymax, gimage, iters)\n", "dt = time.clock() - start\n", "\n", "print(\"Mandelbrot created on CPU in %f s\" % dt)\n", "plt.grid(False)\n", "plt.imshow(gimage, cmap='jet')\n", "pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Numba**" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [], "source": [ "from numba import uint32, float32" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**The jit decorator can also be called as a regular function**" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [], "source": [ "mandel_numba = jit(uint32(float32, float32, uint32))(mandel)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [], "source": [ "@jit\n", "def create_fractal_numba(xmin, xmax, ymin, ymax, image, iters):\n", " height, width = image.shape\n", " \n", " pixel_size_x = (xmax - xmin)/width\n", " pixel_size_y = (ymax - ymin)/height\n", " \n", " for x in range(width):\n", " real = xmin + x*pixel_size_x\n", " for y in range(height):\n", " imag = ymin + y*pixel_size_y\n", " color = mandel_numba(real, imag, iters)\n", " image[y, x] = color " ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mandelbrot created wiht Numba in 0.249863 s\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "gimage = np.zeros((1024, 1536), dtype=np.uint8)\n", "xmin, xmax, ymin, ymax = np.array([-2.0, 1.0, -1.0, 1.0]).astype('float32')\n", "iters = 50\n", "\n", "start = time.clock()\n", "create_fractal_numba(xmin, xmax, ymin, ymax, gimage, iters)\n", "dt = time.clock() - start\n", "\n", "print(\"Mandelbrot created wiht Numba in %f s\" % dt)\n", "plt.grid(False)\n", "plt.imshow(gimage, cmap='jet')\n", "pass" ] } ], "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.5" }, "latex_envs": { "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 0 } }, "nbformat": 4, "nbformat_minor": 1 }