Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Python utilities.ipynb
{
"cells": [
{
"metadata": {
"toc": "true"
},
"cell_type": "markdown",
"source": "# Table of Contents\n <p><div class=\"lev1 toc-item\"><a href=\"#Jupyter-magics\" data-toc-modified-id=\"Jupyter-magics-1\"><span class=\"toc-item-num\">1&nbsp;&nbsp;</span>Jupyter magics</a></div><div class=\"lev2 toc-item\"><a href=\"#Available-magics\" data-toc-modified-id=\"Available-magics-11\"><span class=\"toc-item-num\">1.1&nbsp;&nbsp;</span>Available magics</a></div><div class=\"lev2 toc-item\"><a href=\"#Using-%timeit\" data-toc-modified-id=\"Using-%timeit-12\"><span class=\"toc-item-num\">1.2&nbsp;&nbsp;</span>Using <code>%timeit</code></a></div><div class=\"lev2 toc-item\"><a href=\"#Getting-help\" data-toc-modified-id=\"Getting-help-13\"><span class=\"toc-item-num\">1.3&nbsp;&nbsp;</span>Getting help</a></div><div class=\"lev1 toc-item\"><a href=\"#Shortcuts-and-conveniences\" data-toc-modified-id=\"Shortcuts-and-conveniences-2\"><span class=\"toc-item-num\">2&nbsp;&nbsp;</span>Shortcuts and conveniences</a></div><div class=\"lev2 toc-item\"><a href=\"#Using-shell-commands\" data-toc-modified-id=\"Using-shell-commands-21\"><span class=\"toc-item-num\">2.1&nbsp;&nbsp;</span>Using shell commands</a></div><div class=\"lev2 toc-item\"><a href=\"#Running-bash-in-a-sub-process\" data-toc-modified-id=\"Running-bash-in-a-sub-process-22\"><span class=\"toc-item-num\">2.2&nbsp;&nbsp;</span>Running bash in a sub-process</a></div><div class=\"lev2 toc-item\"><a href=\"#Running-R-as-a-sub-process\" data-toc-modified-id=\"Running-R-as-a-sub-process-23\"><span class=\"toc-item-num\">2.3&nbsp;&nbsp;</span>Running R as a sub-process</a></div><div class=\"lev2 toc-item\"><a href=\"#Interactive-dashboards\" data-toc-modified-id=\"Interactive-dashboards-24\"><span class=\"toc-item-num\">2.4&nbsp;&nbsp;</span>Interactive dashboards</a></div><div class=\"lev1 toc-item\"><a href=\"#Pythonic-programming\" data-toc-modified-id=\"Pythonic-programming-3\"><span class=\"toc-item-num\">3&nbsp;&nbsp;</span>Pythonic programming</a></div><div class=\"lev2 toc-item\"><a href=\"#Generators\" data-toc-modified-id=\"Generators-31\"><span class=\"toc-item-num\">3.1&nbsp;&nbsp;</span>Generators</a></div><div class=\"lev2 toc-item\"><a href=\"#map,-reduce,-filter,-zip\" data-toc-modified-id=\"map,-reduce,-filter,-zip-32\"><span class=\"toc-item-num\">3.2&nbsp;&nbsp;</span><code>map</code>, <code>reduce</code>, <code>filter</code>, <code>zip</code></a></div><div class=\"lev2 toc-item\"><a href=\"#Classes\" data-toc-modified-id=\"Classes-33\"><span class=\"toc-item-num\">3.3&nbsp;&nbsp;</span>Classes</a></div><div class=\"lev2 toc-item\"><a href=\"#The-imperative-approach\" data-toc-modified-id=\"The-imperative-approach-34\"><span class=\"toc-item-num\">3.4&nbsp;&nbsp;</span>The imperative approach</a></div><div class=\"lev2 toc-item\"><a href=\"#The-functional-approach\" data-toc-modified-id=\"The-functional-approach-35\"><span class=\"toc-item-num\">3.5&nbsp;&nbsp;</span>The functional approach</a></div><div class=\"lev1 toc-item\"><a href=\"#Fast-computations\" data-toc-modified-id=\"Fast-computations-4\"><span class=\"toc-item-num\">4&nbsp;&nbsp;</span>Fast computations</a></div><div class=\"lev2 toc-item\"><a href=\"#Memoization\" data-toc-modified-id=\"Memoization-41\"><span class=\"toc-item-num\">4.1&nbsp;&nbsp;</span>Memoization</a></div><div class=\"lev3 toc-item\"><a href=\"#First-Example:-factorial-computations\" data-toc-modified-id=\"First-Example:-factorial-computations-411\"><span class=\"toc-item-num\">4.1.1&nbsp;&nbsp;</span>First Example: factorial computations</a></div><div class=\"lev3 toc-item\"><a href=\"#Second-example:-Fibonacci-numbers\" data-toc-modified-id=\"Second-example:-Fibonacci-numbers-412\"><span class=\"toc-item-num\">4.1.2&nbsp;&nbsp;</span>Second example: Fibonacci numbers</a></div><div class=\"lev2 toc-item\"><a href=\"#Writing-good-code\" data-toc-modified-id=\"Writing-good-code-42\"><span class=\"toc-item-num\">4.2&nbsp;&nbsp;</span>Writing good code</a></div><div class=\"lev3 toc-item\"><a href=\"#Memory-allocation,-implicit-array-copying\" data-toc-modified-id=\"Memory-allocation,-implicit-array-copying-421\"><span class=\"toc-item-num\">4.2.1&nbsp;&nbsp;</span>Memory allocation, implicit array copying</a></div><div class=\"lev2 toc-item\"><a href=\"#Numba\" data-toc-modified-id=\"Numba-43\"><span class=\"toc-item-num\">4.3&nbsp;&nbsp;</span>Numba</a></div><div class=\"lev3 toc-item\"><a href=\"#Pure-python-version\" data-toc-modified-id=\"Pure-python-version-431\"><span class=\"toc-item-num\">4.3.1&nbsp;&nbsp;</span>Pure python version</a></div><div class=\"lev3 toc-item\"><a href=\"#Numba-version\" data-toc-modified-id=\"Numba-version-432\"><span class=\"toc-item-num\">4.3.2&nbsp;&nbsp;</span>Numba version</a></div><div class=\"lev2 toc-item\"><a href=\"#Numexpr\" data-toc-modified-id=\"Numexpr-44\"><span class=\"toc-item-num\">4.4&nbsp;&nbsp;</span>Numexpr</a></div><div class=\"lev2 toc-item\"><a href=\"#Cython\" data-toc-modified-id=\"Cython-45\"><span class=\"toc-item-num\">4.5&nbsp;&nbsp;</span>Cython</a></div><div class=\"lev2 toc-item\"><a href=\"#Ray-tracing-example\" data-toc-modified-id=\"Ray-tracing-example-46\"><span class=\"toc-item-num\">4.6&nbsp;&nbsp;</span>Ray tracing example</a></div><div class=\"lev3 toc-item\"><a href=\"#Pure-Python\" data-toc-modified-id=\"Pure-Python-461\"><span class=\"toc-item-num\">4.6.1&nbsp;&nbsp;</span>Pure Python</a></div><div class=\"lev3 toc-item\"><a href=\"#Naive-Cython\" data-toc-modified-id=\"Naive-Cython-462\"><span class=\"toc-item-num\">4.6.2&nbsp;&nbsp;</span>Naive Cython</a></div><div class=\"lev3 toc-item\"><a href=\"#Cython-array-buffers\" data-toc-modified-id=\"Cython-array-buffers-463\"><span class=\"toc-item-num\">4.6.3&nbsp;&nbsp;</span>Cython array buffers</a></div><div class=\"lev4 toc-item\"><a href=\"#Take-1\" data-toc-modified-id=\"Take-1-4631\"><span class=\"toc-item-num\">4.6.3.1&nbsp;&nbsp;</span>Take 1</a></div><div class=\"lev4 toc-item\"><a href=\"#Take-2\" data-toc-modified-id=\"Take-2-4632\"><span class=\"toc-item-num\">4.6.3.2&nbsp;&nbsp;</span>Take 2</a></div><div class=\"lev3 toc-item\"><a href=\"#Cython-with-structs\" data-toc-modified-id=\"Cython-with-structs-464\"><span class=\"toc-item-num\">4.6.4&nbsp;&nbsp;</span>Cython with structs</a></div>"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "# Jupyter magics\n\nJupyter has a collection of built-in magics that make certain python tasks much easier (and much cleaner looking). Use them like decorators."
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Available magics"
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%lsmagic",
"execution_count": 1,
"outputs": [
{
"execution_count": 1,
"data": {
"text/plain": "Available line magics:\n%alias %alias_magic %autocall %automagic %autosave %bookmark %cat %cd %clear %colors %config %connect_info %cp %debug %dhist %dirs %doctest_mode %ed %edit %env %gui %hist %history %install_default_config %install_ext %install_profiles %killbgscripts %ldir %less %lf %lk %ll %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %ls %lsmagic %lx %macro %magic %man %matplotlib %mkdir %more %mv %notebook %page %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %popd %pprint %precision %profile %prun %psearch %psource %pushd %pwd %pycat %pylab %qtconsole %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %rm %rmdir %run %save %sc %set_env %store %sx %system %tb %time %timeit %unalias %unload_ext %who %who_ls %whos %xdel %xmode\n\nAvailable cell magics:\n%%! %%HTML %%SVG %%bash %%capture %%debug %%file %%html %%javascript %%latex %%perl %%prun %%pypy %%python %%python2 %%python3 %%ruby %%script %%sh %%svg %%sx %%system %%time %%timeit %%writefile\n\nAutomagic is ON, % prefix IS NOT needed for line magics.",
"application/json": {
"cell": {
"capture": "ExecutionMagics",
"time": "ExecutionMagics",
"sh": "Other",
"script": "ScriptMagics",
"svg": "DisplayMagics",
"python": "Other",
"!": "OSMagics",
"system": "OSMagics",
"pypy": "Other",
"debug": "ExecutionMagics",
"latex": "DisplayMagics",
"ruby": "Other",
"javascript": "DisplayMagics",
"prun": "ExecutionMagics",
"writefile": "OSMagics",
"bash": "Other",
"timeit": "ExecutionMagics",
"file": "Other",
"perl": "Other",
"HTML": "Other",
"python2": "Other",
"python3": "Other",
"html": "DisplayMagics",
"SVG": "Other",
"sx": "OSMagics"
},
"line": {
"store": "StoreMagics",
"doctest_mode": "BasicMagics",
"recall": "HistoryMagics",
"gui": "BasicMagics",
"lk": "Other",
"unalias": "OSMagics",
"page": "BasicMagics",
"rerun": "HistoryMagics",
"lx": "Other",
"prun": "ExecutionMagics",
"matplotlib": "PylabMagics",
"notebook": "BasicMagics",
"pastebin": "CodeMagics",
"xmode": "BasicMagics",
"ls": "Other",
"set_env": "OSMagics",
"alias": "OSMagics",
"dirs": "OSMagics",
"pprint": "BasicMagics",
"time": "ExecutionMagics",
"man": "KernelMagics",
"install_ext": "ExtensionMagics",
"save": "CodeMagics",
"connect_info": "KernelMagics",
"mkdir": "Other",
"killbgscripts": "ScriptMagics",
"reset_selective": "NamespaceMagics",
"ldir": "Other",
"macro": "ExecutionMagics",
"who": "NamespaceMagics",
"rm": "Other",
"logstop": "LoggingMagics",
"pycat": "OSMagics",
"qtconsole": "KernelMagics",
"timeit": "ExecutionMagics",
"unload_ext": "ExtensionMagics",
"load": "CodeMagics",
"cd": "OSMagics",
"pwd": "OSMagics",
"rmdir": "Other",
"install_default_config": "DeprecatedMagics",
"pdoc": "NamespaceMagics",
"mv": "Other",
"rehashx": "OSMagics",
"pinfo": "NamespaceMagics",
"pylab": "PylabMagics",
"lf": "Other",
"profile": "BasicMagics",
"logstate": "LoggingMagics",
"rep": "Other",
"logstart": "LoggingMagics",
"ll": "Other",
"alias_magic": "BasicMagics",
"magic": "BasicMagics",
"more": "KernelMagics",
"reload_ext": "ExtensionMagics",
"pfile": "NamespaceMagics",
"precision": "BasicMagics",
"loadpy": "CodeMagics",
"run": "ExecutionMagics",
"install_profiles": "DeprecatedMagics",
"autocall": "AutoMagics",
"lsmagic": "BasicMagics",
"clear": "KernelMagics",
"history": "HistoryMagics",
"whos": "NamespaceMagics",
"sx": "OSMagics",
"psource": "NamespaceMagics",
"logon": "LoggingMagics",
"who_ls": "NamespaceMagics",
"pdef": "NamespaceMagics",
"quickref": "BasicMagics",
"colors": "BasicMagics",
"reset": "NamespaceMagics",
"automagic": "AutoMagics",
"system": "OSMagics",
"bookmark": "OSMagics",
"debug": "ExecutionMagics",
"ed": "Other",
"autosave": "KernelMagics",
"xdel": "NamespaceMagics",
"psearch": "NamespaceMagics",
"edit": "KernelMagics",
"less": "KernelMagics",
"dhist": "OSMagics",
"config": "ConfigMagics",
"env": "OSMagics",
"cat": "Other",
"pdb": "ExecutionMagics",
"cp": "Other",
"pinfo2": "NamespaceMagics",
"sc": "OSMagics",
"pushd": "OSMagics",
"logoff": "LoggingMagics",
"popd": "OSMagics",
"hist": "Other",
"load_ext": "ExtensionMagics",
"tb": "ExecutionMagics"
}
}
},
"output_type": "execute_result",
"metadata": {}
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "In this tutorial we'll be making use of the %timeit magic to measure algorithm run time. "
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Using `%timeit`"
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%timeit pass",
"execution_count": 2,
"outputs": [
{
"text": "100000000 loops, best of 3: 8.94 ns per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "timeitResult = %timeit -n100 -r5 -p5 -o x = 3",
"execution_count": 3,
"outputs": [
{
"text": "100 loops, best of 5: 15.15 ns per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "from functools import reduce\n%timeit reduce(lambda x,y: x+y, range(1000))",
"execution_count": 4,
"outputs": [
{
"text": "10000 loops, best of 3: 148 µs per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "",
"execution_count": 8,
"outputs": [
{
"text": "10000 loops, best of 3: 19.4 µs per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "import numpy as np\nN = int(1e5)\nw = np.random.randn(N, 1)",
"execution_count": 5,
"outputs": []
},
{
"metadata": {
"scrolled": true,
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "t_wdot = %timeit -r100 -n1000 -o np.dot(w.T, w)\nt_sumsq = %timeit -r100 -n1000 -o (w**2).sum()",
"execution_count": 6,
"outputs": [
{
"text": "The slowest run took 9.96 times longer than the fastest. This could mean that an intermediate result is being cached.\n1000 loops, best of 100: 8.78 µs per loop\n1000 loops, best of 100: 91 µs per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "import matplotlib.pyplot as plt\n%matplotlib inline\nplt.figure(figsize=(10,5))\nplt.hold(True)\nplt.plot(t_wdot.all_runs, 'b.', MarkerSize=10)\nplt.plot(t_sumsq.all_runs, 'r.', MarkerSize=10);",
"execution_count": 7,
"outputs": [
{
"data": {
"text/plain": "<matplotlib.figure.Figure at 0x10ba5e048>",
"image/png": "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\n/x+lN0VOdoayewAAAABJRU5ErkJggg==\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Getting help"
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%timeit?",
"execution_count": null,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Also, Shift + Tab while cursor is over text for which docs are desired. "
},
{
"metadata": {},
"cell_type": "markdown",
"source": "# Shortcuts and conveniences\n\n## Using shell commands"
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "!ls",
"execution_count": 9,
"outputs": [
{
"text": "Gradient Descent (master).ipynb UBCS3.4 (28 October 2016).ipynb\r\nGradient Descent (skeleton).ipynb UBCS3_2.1_20170120.ipynb\r\nPython utilities.ipynb UBCS3_2.2_20170127.ipynb\r\nREADME UBCS3_2.3_20170203.ipynb\r\nUBCS3.1 (7 October 2016).ipynb \u001b[1m\u001b[34mdata\u001b[m\u001b[m\r\nUBCS3.2 (14 October 2016).ipynb flaskapp.py\r\nUBCS3.3 (21 October 2016).ipynb test_file.py\r\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "dirlist = !ls\nprint(dirlist)",
"execution_count": 10,
"outputs": [
{
"text": "['Gradient Descent (master).ipynb', 'Gradient Descent (skeleton).ipynb', 'Python utilities.ipynb', 'README', 'UBCS3.1 (7 October 2016).ipynb', 'UBCS3.2 (14 October 2016).ipynb', 'UBCS3.3 (21 October 2016).ipynb', 'UBCS3.4 (28 October 2016).ipynb', 'UBCS3_2.1_20170120.ipynb', 'UBCS3_2.2_20170127.ipynb', 'UBCS3_2.3_20170203.ipynb', 'data', 'flaskapp.py', 'test_file.py']\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Loading files using Jupyter magics (note `test_file.py` in `!ls` output above)."
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%load test_file.py",
"execution_count": null,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Running bash in a sub-process"
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%bash\nfor i in a b c;\ndo\necho $i\ndone",
"execution_count": 13,
"outputs": [
{
"text": "a\nb\nc\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Running R as a sub-process"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Sadly, no code completion, though..."
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%load_ext rpy2.ipython",
"execution_count": 14,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%R\nx <- 1:10\ny <- x^2\nplot(x, y, pch=20, col=4)",
"execution_count": 15,
"outputs": [
{
"data": {
"image/png": "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\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "X = timeitResult.all_runs\n%Rpush X\n%R str(X)",
"execution_count": 16,
"outputs": [
{
"data": {
"text/plain": " num [1:5] 1.92e-06 1.58e-06 1.53e-06 1.52e-06 1.52e-06\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%Rpull y\nimport matplotlib.pyplot as plt\n%matplotlib inline\nplt.plot(range(10), y, 'b.', MarkerSize=15);",
"execution_count": 17,
"outputs": [
{
"data": {
"text/plain": "<matplotlib.figure.Figure at 0x10ef0af98>",
"image/png": "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\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Interactive dashboards\n\nThis blog has a few articles that talk about some intriguing ways of using Jupyter. Including an article about [building interactive dashboards in Jupyter](https://blog.dominodatalab.com/interactive-dashboards-in-jupyter/)"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "# Pythonic programming"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "From Wikipedia\n\n> A common neologism in the Python community is pythonic, which can have a wide range of meanings related to program style. To say that code is pythonic is to say that it uses Python idioms well, that it is natural or shows fluency in the language. Likewise, to say of an interface or language feature that it is pythonic is to say that it works well with Python idioms, that its use meshes well with the rest of the language.\n>\n> In contrast, a mark of unpythonic code is that it attempts to write C++ (or Lisp, Perl, or Java) code in Python—that is, provides a rough transcription rather than an idiomatic translation of forms from another language. The concept of pythonicity is tightly bound to Python's minimalist philosophy of readability and avoiding the \"there's more than one way to do it\" approach. Unreadable code or incomprehensible idioms are unpythonic."
},
{
"metadata": {},
"cell_type": "markdown",
"source": "As an example of idiomatic python, check out this 900 line [implementation of Minecraft](https://github.com/fogleman/Minecraft/blob/master/main.py) in python."
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Generators"
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "list_with_repeats = [1,2,4,7,4,6,5,4,3,2,2,2,1]\nfirst_4 = next(j for j, x in enumerate(list_with_repeats) if x == 4)\nprint(first_4)",
"execution_count": 18,
"outputs": [
{
"text": "2\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "`enumerate`, itself, returns a generator object. Note that this approach is *in line* with **functional programming** but is distinct from **lazy evaluation**/**lazy lists** in that generators are use-once objects. "
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "enumerate?",
"execution_count": null,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "range(10)",
"execution_count": 19,
"outputs": [
{
"execution_count": 19,
"data": {
"text/plain": "range(0, 10)"
},
"output_type": "execute_result",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "(x**2 for x in range(10))",
"execution_count": 20,
"outputs": [
{
"execution_count": 20,
"data": {
"text/plain": "<generator object <genexpr> at 0x117f3d6d0>"
},
"output_type": "execute_result",
"metadata": {}
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## `map`, `reduce`, `filter`, `zip`"
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "sqmap = list(map(lambda x: x**2, range(10)))\nprint(sqmap)",
"execution_count": 21,
"outputs": [
{
"text": "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "sumsq = reduce(lambda x,y: x + y, sqmap)\nprint(sumsq)",
"execution_count": 22,
"outputs": [
{
"text": "285\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "def filterfun(x, th):\n sqrt_x = x**.5\n return (x < th) and (x > 0) and ((x % sqrt_x) == 0)\n\nsqltsumsq = list(filter(lambda x: filterfun(x, sumsq), range(1000)))\nprint(sqltsumsq)",
"execution_count": 23,
"outputs": [
{
"text": "[1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256]\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "def unzip(tuples):\n return zip(*tuples)\n\nlist(unzip([(j,j,j) for j in range(10)]))",
"execution_count": 24,
"outputs": [
{
"execution_count": 24,
"data": {
"text/plain": "[(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),\n (0, 1, 2, 3, 4, 5, 6, 7, 8, 9),\n (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)]"
},
"output_type": "execute_result",
"metadata": {}
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Classes"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Python, like C, Java, *etc.* can make use of classes for the kind of modularity expected of object-oriented programming languages. Defining a class in Python is very easy. "
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "class myNewClass:\n def __init__(self):\n print('Hello')\n def clsmth(self):\n \"\"\"\n call a class method and instance method\n \"\"\"\n myNewClass.helper1()\n self.helper2()\n def helper1():\n print('World!')\n def helper2(self):\n print('World!')",
"execution_count": 25,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "And instantiating an instance of that class is just as easy. "
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "myNewInstance = myNewClass()",
"execution_count": 26,
"outputs": [
{
"text": "Hello\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "myNewInstance.clsmth()",
"execution_count": 27,
"outputs": [
{
"text": "World!\nWorld!\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "myNewClass.helper1()",
"execution_count": 28,
"outputs": [
{
"text": "World!\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "myNewClass.helper2(myNewInstance)",
"execution_count": 29,
"outputs": [
{
"text": "World!\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "myNewInstance.helper2()",
"execution_count": 30,
"outputs": [
{
"text": "World!\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## The imperative approach"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## The functional approach\n\n* [Functional Programming HOWTO from Python](https://docs.python.org/3/howto/functional.html)\n* [FP in Python from IBM](http://www.ibm.com/developerworks/library/l-prog/)\n* [FP in Python from Mary Rose Cook](https://maryrosecook.com/blog/post/a-practical-introduction-to-functional-programming)"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "# Fast computations"
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%reset",
"execution_count": 31,
"outputs": [
{
"text": "Once deleted, variables cannot be recovered. Proceed (y/[n])? y\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Memoization"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### First Example: factorial computations"
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "def factorial(k):\n if k == 1:\n return 1\n return k * factorial(k-1)",
"execution_count": 32,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "try:\n factorial(3000)\nexcept RecursionError as RE:\n print(RE)\n print('Whoops! We\\'re asking too much from Python right now!')",
"execution_count": 33,
"outputs": [
{
"text": "maximum recursion depth exceeded in comparison\nWhoops! We're asking too much from Python right now!\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "factorial_memo = {}\ndef factorial2(k):\n if k == 1:\n return 1\n if k not in factorial_memo:\n factorial_memo[k] = k*factorial2(k-1)\n return factorial_memo[k]",
"execution_count": 34,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "factorial2(750)\nfactorial2(1500)\nfactorial2(2250)\nprint('We can now get the answer we want:\\n{}'.format(factorial2(3000)))",
"execution_count": 35,
"outputs": [
{
"text": "We can now get the answer we want:\n41493596034378540855568670930866121709511191949318099176894676576975585651235319500860007652178003420075184635383617118495750871114045907794553402161068339611621037904199177522062663390179682805164719697495968842457728766097103003726111095340241127118833157738815328438929737613021106312930374401485378725446079610290429491049793888120762511625132917004641668962117590203575175488980653577868915285093782469994674699190832093511068363824287063522268544339213775150488588104036818809099292912497141900508938994404715351473154531587441509960174267875087460367974117072368747277143988920683691618503608198459718093784453523958505377611086511162363145920886108557450874513945305436213711898150847192094426374203275029996333784944014775671414680824207499914714878359669720638954670589960178569480263388767112871068004950827400717124819476386401369193544354120312786601434792549959143530120653103406625503231020738351502195103148673612338739395096551462159349015789949944072311004426924838140141455487872738045856023561583204317945953055830693351246890721246151468485308724031267967089113548982733475375756899365176396424781733462510879015743437398920492267098317033932107176343983352444576040476565400414414699479984354554597799386702839428513413188913165695310848513525094006147774047007331406541794428004436691903685469270857271701648011512057452448607968773784803660653009109815639091294110633715621540903800135058671624262333902434166628716521228590274568833504897926869369792878376894841436573866436955075473964882256222183380014600761196859217603234808467455216330411738004331144225926243690558782914907973885758784585739828695390302383837265882427654306437517757897215045071361801730051628424476294227485755627828763498767195281368913583918824499284741591683130334032199946752082914885764345863832313545205075955912062067273296951386122994658607527317884452449865348164169238844889061495850934373442889814884427321817131272533891534506581143823381205875379808605080889761753882896252933633750454549168600267229591225528854584482686655324313011353754812409561237686078007700707939541848907149467377854407528307872988103912945121929864793703451257436445581459757140822705986325165352906584571123585270211933452981105568398809884094980346185078025273038736784042169427237980464304250045030806637032760016341921442805708802430850567892108646977455139539119838636167190300278146380136932482332771595180596193069504237836082620570887209297929797429404576877338319877444685544294800321741056689423710545028870419611915072739000031642014474213323293871618029555614004602867400422885389854650328028428515122296028795741801621823236098320971441047012533067314896153236788734984553949604397050352347766211395914519270422122231426998692087463520980686224354813376194395131942868113486531562228173214976481705381846155326596187530296478601160872263640443922257601926494610916885151013143945574398303192557154162151442469122370519149097861849436150963109933639594561796593396851958605338631176324147066842257192394742531726479559749993283247279807896470753054014194090200609712674753186365525403212757757853930697530056595208207457499471898144453772248207888443335118545601568853708182892895218300139654376947286418776665762815389737340159410543681435437346134244692067070082782423645557450882556670157242752810317141640631410681384330924027281318960884813040665226169552825637183862464944295688859393846726723694199475571320546018263425731029115353532728808182773021596787088437293412117084511580629967697266601663635276959969021502122104954259567278593185516268447100374434620422003535391203738393095420695021486207390653190910821344334251497896284236198571674773848126097443055036250866354720730971298084697196537722779893160200560725058007512407494448163392214398118492748281978655178478547749198714138485042290383954090570842038137277135667703565041081780520695032136233521692740531015340921761834078817735674646749071616600653230438902639786065509005309872435445689315601329942407112295015453771521051942445512795364971214872222193729289159833001742397977592530501318837883494884232222507318816399438935627817102875432588794558857742780390717166381257903798149148445526885871629931014510733215554773264576035916184298708323237568837917135073006026738292294687081030751946020376438138677107333779312582257356435534577162804030480925785909747233413932904072239860005448269296110393640127539539899397420021925268928622564959279136369546983247314494094297494213208716963662812963846191378114609210701033012119934264941666449130310898493535366401831282683112506578386425906537197010907276429330534751297336716929415047870949241778121534979499449732358445130210029720359993576507730563696950539990891252004810120090569633144368179194247963563389102486250773367249399801723451627048850149438343735826440053481474957421328873648479589553843836378275601433377798816126854462406494134416119108952653326761627660221130879211665924379496534838030236064294981985541014311566601739518539426008673198564586684635442730180022292607589767192198367529528365158715521887698317999005853121518691037776676883654291247419826099434535671529412823837612115555686210454583810355154404953718470726363218532775486501811002621331228429860926112159573066023932077476742800909462674322138805290643067711276964013735906251051050623568241317651533030775358975134565147424167401517470720839101869989993279364910892687924739705814152855543965954222603919059265825637344676406359525838966981511983959886603683753042017990328185945569412550519066302854869533377682984600031808093822130038102214387057461181304251961916405970456035183121708151658647356556540532928411748628957082856792300053525846377061280591452035546389932127875906349627837975871352588618213252263577038396202737385324908353680497990085701522483303439525197344653342994652565236096742834550523739733902374261808871799283722285366293439240895762913154442106573609205481842139365893867715542842477275100166734357743093638948444564764377184073874379471007867151070449554657626281566137550730763768080600031844296233977808233311359787577136983012817571625671683287281511937336685789437109097748581222868126824122317272681184975207863453107495331708260153159440253645365524453587952034745213429248916644504804355352281977721981971869054884176896398782704782066126921472548618247859626434279190274503452994769367997217285165465591799471789067885687278574470084289723778234763080740919512966238346427839653865017324665850192144091694630371265581197700774682562035198318782913591013997817303635173764706714383992810291224460848320518983248348855131025539721583184931653670732273172995431750775475634748127320956655431851879586978172491721700865768098908327830838240437737974455342525688712898855513180967012497859454290609627370590659970784172738420721605576789060565167694565490120388165775861939230924362983389549857279874523398090499858467484850399509109398834210424693113617875978611803096108774362764990414655167545507613665725914993376114340243762910290384135888531312591132544849225896007184851169390193985434649415483782338302531368775990005443722332901462568184095998830522521585328599833990336595418932696680163265899358234663247080324020429791357425755498549372896192091650794671997121439832581553945835125648010889886887056882711222628734035772418424803231173027338442220604015609242079569493204943809402465562530303328824165302038006041288444384884189129393985971765670211501611340121169355535864984802941563238279447576315042685734269863116562800932164578165410411899078396210758605145091526528422433647230880469088426412525126584729134059195171754291152622002229756986927959124620964363057052133099216422258437651889193630329851223282950806126200573565554213183555838289318138795940962303792777230344423432341561603558590502324475274502630869831414125396371754413611897269158650716722308083435295578401087236027347001118786146233185439431057058483770474806035004556885020602730222256397630738939985024978155182679916994164145540329909813190506654358156657691529068908186204138444091456355291242064901717436430473455191375922914953282988151808740076733486997695322871450791584448703980405737673555777873593937891577147956023340708456392314170118392555234618119775915673385955919265270624063734277760215846511035368057963320714896942663358570375305829676608224208465464558556667889222627619990263961792637457851652540918756608543859661221944248720424960000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Second example: Fibonacci numbers"
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "def fibo(n):\n if n == 1 or n == 2:\n return 1\n return fibo(n-1) + fibo(n-2)",
"execution_count": 36,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%timeit\nfor k in range(1,5):\n fibo(7*k)",
"execution_count": 37,
"outputs": [
{
"text": "10 loops, best of 3: 121 ms per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "class Memoize:\n def __init__(self, f):\n self.f = f\n self.memo = {}\n def __call__(self, *args):\n if not args in self.memo:\n self.memo[args] = self.f(*args)\n return self.memo[args]",
"execution_count": 38,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "fibo = Memoize(fibo)",
"execution_count": 39,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%timeit\nfor k in range(1,5):\n fibo(7*k)",
"execution_count": 40,
"outputs": [
{
"text": "The slowest run took 18.04 times longer than the fastest. This could mean that an intermediate result is being cached.\n100000 loops, best of 3: 2.75 µs per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Writing good code"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Memory allocation, implicit array copying"
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "import numpy as np",
"execution_count": 43,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "def nmz1(x):\n return x / np.linalg.norm(x)\n\ndef nmz2(x):\n x /= np.linalg.norm(x)\n return x",
"execution_count": 44,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%timeit x = np.random.rand(3000,3000)\nnmz1(x)",
"execution_count": 45,
"outputs": [
{
"text": "10 loops, best of 3: 38.3 ms per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%timeit x = np.random.rand(3000,3000)\nnmz2(x)",
"execution_count": 46,
"outputs": [
{
"text": "100 loops, best of 3: 14.7 ms per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Numba"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "In this section we provide an example of how to use Numba's `@jit` decorator to make fast computations happen *via* so-called \"just in time\" compiling. This tutorial can be found in its original format on the [IPython Cookbook](http://nbviewer.jupyter.org/github/ipython-books/cookbook-code/blob/master/notebooks/chapter05_hpc/01_numba.ipynb) website."
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "import numpy as np",
"execution_count": 47,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "size = 200\niterations = 100",
"execution_count": 48,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Pure python version"
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "def mandelbrot_python(m, size, iterations):\n for i in range(size):\n for j in range(size):\n c = -2 + 3./size*j + 1j*(1.5-3./size*i)\n z = 0\n for n in range(iterations):\n if np.abs(z) <= 10:\n z = z*z + c\n m[i, j] = n\n else:\n break",
"execution_count": 49,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "m = np.zeros((size, size))\nmandelbrot_python(m, size, iterations)",
"execution_count": 50,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "import matplotlib.pyplot as plt\n%matplotlib inline\nplt.imshow(np.log(m), cmap=plt.cm.hot,);\nplt.xticks([]); plt.yticks([]);",
"execution_count": 51,
"outputs": [
{
"data": {
"text/plain": "<matplotlib.figure.Figure at 0x10e26ad68>",
"image/png": "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\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%timeit m = np.zeros((size, size))\nmandelbrot_python(m, size, iterations)",
"execution_count": 52,
"outputs": [
{
"text": "1 loop, best of 3: 2.47 s per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Numba version"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Import Numba"
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "import numba\nfrom numba import jit, complex128",
"execution_count": 53,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Add the @jit (just-in-time) decorator to the very same function"
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "@jit(locals=dict(c=complex128, z=complex128))\ndef mandelbrot_numba(m, size, iterations):\n for i in range(size):\n for j in range(size):\n c = -2 + 3./size*j + 1j*(1.5-3./size*i)\n z = 0\n for n in range(iterations):\n if np.abs(z) <= 10:\n z = z*z + c\n m[i, j] = n\n else:\n break",
"execution_count": 54,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "m = np.zeros((size, size))\nmandelbrot_numba(m, size, iterations)",
"execution_count": 55,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%timeit m = np.zeros((size, size))\nmandelbrot_numba(m, size, iterations)",
"execution_count": 56,
"outputs": [
{
"text": "100 loops, best of 3: 5.84 ms per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Numexpr"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Let's import NumPy and Numexpr."
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "import numpy as np\nimport numexpr as ne",
"execution_count": 57,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "We generate three large vectors."
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "x, y, z = np.random.rand(3, 1000000)",
"execution_count": 58,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Now, we evaluate the time taken by NumPy to calculate a complex algebraic expression involving our vectors."
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%timeit x + (y**2 + (z*x + 1)*3)",
"execution_count": 59,
"outputs": [
{
"text": "10 loops, best of 3: 20.3 ms per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "And now, the same calculation performed by Numexpr. We need to give the formula as a string as Numexpr will parse it and compile it."
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%timeit ne.evaluate('x + (y**2 + (z*x + 1)*3)')",
"execution_count": 60,
"outputs": [
{
"text": "100 loops, best of 3: 3.69 ms per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Numexpr also makes use of multicore processors. Here, we have 4 physical cores and 8 virtual threads with hyperthreading. We can specify how many cores we want numexpr to use."
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "ne.ncores",
"execution_count": 61,
"outputs": [
{
"execution_count": 61,
"data": {
"text/plain": "8"
},
"output_type": "execute_result",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "for i in range(1, 5):\n ne.set_num_threads(i)\n %timeit ne.evaluate('x + (y**2 + (z*x + 1)*3)')",
"execution_count": 62,
"outputs": [
{
"text": "100 loops, best of 3: 6.4 ms per loop\n100 loops, best of 3: 4.15 ms per loop\n100 loops, best of 3: 3.53 ms per loop\n100 loops, best of 3: 3.4 ms per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Cython"
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%load_ext Cython",
"execution_count": 63,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%cython -a\nimport numpy as np\n\ndef mandelbrot_cython(int[:,::1] m, \n int size, \n int iterations):\n cdef int i, j, n\n cdef complex z, c\n for i in range(size):\n for j in range(size):\n c = -2 + 3./size*j + 1j*(1.5-3./size*i)\n z = 0\n for n in range(iterations):\n if z.real**2 + z.imag**2 <= 100:\n z = z*z + c\n m[i, j] = n\n else:\n break",
"execution_count": 64,
"outputs": [
{
"execution_count": 64,
"data": {
"text/plain": "<IPython.core.display.HTML object>",
"text/html": "<!DOCTYPE html>\n<!-- Generated by Cython 0.23.4 -->\n<html>\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n <title>Cython: _cython_magic_cc0c3c710e01dec074c1bcec46022dd6.pyx</title>\n <style type=\"text/css\">\n \nbody.cython { font-family: courier; font-size: 12; }\n\n.cython.tag { }\n.cython.line { margin: 0em }\n.cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; }\n\n.cython.line .run { background-color: #B0FFB0; }\n.cython.line .mis { background-color: #FFB0B0; }\n.cython.code.run { border-left: 8px solid #B0FFB0; }\n.cython.code.mis { border-left: 8px solid #FFB0B0; }\n\n.cython.code .py_c_api { color: red; }\n.cython.code .py_macro_api { color: #FF7000; }\n.cython.code .pyx_c_api { color: #FF3000; }\n.cython.code .pyx_macro_api { color: #FF7000; }\n.cython.code .refnanny { color: #FFA000; }\n.cython.code .trace { color: #FFA000; }\n.cython.code .error_goto { color: #FFA000; }\n\n.cython.code .coerce { color: #008000; border: 1px dotted #008000 }\n.cython.code .py_attr { color: #FF0000; font-weight: bold; }\n.cython.code .c_attr { color: #0000FF; }\n.cython.code .py_call { color: #FF0000; font-weight: bold; }\n.cython.code .c_call { color: #0000FF; }\n\n.cython.score-0 {background-color: #FFFFff;}\n.cython.score-1 {background-color: #FFFFe7;}\n.cython.score-2 {background-color: #FFFFd4;}\n.cython.score-3 {background-color: #FFFFc4;}\n.cython.score-4 {background-color: #FFFFb6;}\n.cython.score-5 {background-color: #FFFFaa;}\n.cython.score-6 {background-color: #FFFF9f;}\n.cython.score-7 {background-color: #FFFF96;}\n.cython.score-8 {background-color: #FFFF8d;}\n.cython.score-9 {background-color: #FFFF86;}\n.cython.score-10 {background-color: #FFFF7f;}\n.cython.score-11 {background-color: #FFFF79;}\n.cython.score-12 {background-color: #FFFF73;}\n.cython.score-13 {background-color: #FFFF6e;}\n.cython.score-14 {background-color: #FFFF6a;}\n.cython.score-15 {background-color: #FFFF66;}\n.cython.score-16 {background-color: #FFFF62;}\n.cython.score-17 {background-color: #FFFF5e;}\n.cython.score-18 {background-color: #FFFF5b;}\n.cython.score-19 {background-color: #FFFF57;}\n.cython.score-20 {background-color: #FFFF55;}\n.cython.score-21 {background-color: #FFFF52;}\n.cython.score-22 {background-color: #FFFF4f;}\n.cython.score-23 {background-color: #FFFF4d;}\n.cython.score-24 {background-color: #FFFF4b;}\n.cython.score-25 {background-color: #FFFF48;}\n.cython.score-26 {background-color: #FFFF46;}\n.cython.score-27 {background-color: #FFFF44;}\n.cython.score-28 {background-color: #FFFF43;}\n.cython.score-29 {background-color: #FFFF41;}\n.cython.score-30 {background-color: #FFFF3f;}\n.cython.score-31 {background-color: #FFFF3e;}\n.cython.score-32 {background-color: #FFFF3c;}\n.cython.score-33 {background-color: #FFFF3b;}\n.cython.score-34 {background-color: #FFFF39;}\n.cython.score-35 {background-color: #FFFF38;}\n.cython.score-36 {background-color: #FFFF37;}\n.cython.score-37 {background-color: #FFFF36;}\n.cython.score-38 {background-color: #FFFF35;}\n.cython.score-39 {background-color: #FFFF34;}\n.cython.score-40 {background-color: #FFFF33;}\n.cython.score-41 {background-color: #FFFF32;}\n.cython.score-42 {background-color: #FFFF31;}\n.cython.score-43 {background-color: #FFFF30;}\n.cython.score-44 {background-color: #FFFF2f;}\n.cython.score-45 {background-color: #FFFF2e;}\n.cython.score-46 {background-color: #FFFF2d;}\n.cython.score-47 {background-color: #FFFF2c;}\n.cython.score-48 {background-color: #FFFF2b;}\n.cython.score-49 {background-color: #FFFF2b;}\n.cython.score-50 {background-color: #FFFF2a;}\n.cython.score-51 {background-color: #FFFF29;}\n.cython.score-52 {background-color: #FFFF29;}\n.cython.score-53 {background-color: #FFFF28;}\n.cython.score-54 {background-color: #FFFF27;}\n.cython.score-55 {background-color: #FFFF27;}\n.cython.score-56 {background-color: #FFFF26;}\n.cython.score-57 {background-color: #FFFF26;}\n.cython.score-58 {background-color: #FFFF25;}\n.cython.score-59 {background-color: #FFFF24;}\n.cython.score-60 {background-color: #FFFF24;}\n.cython.score-61 {background-color: #FFFF23;}\n.cython.score-62 {background-color: #FFFF23;}\n.cython.score-63 {background-color: #FFFF22;}\n.cython.score-64 {background-color: #FFFF22;}\n.cython.score-65 {background-color: #FFFF22;}\n.cython.score-66 {background-color: #FFFF21;}\n.cython.score-67 {background-color: #FFFF21;}\n.cython.score-68 {background-color: #FFFF20;}\n.cython.score-69 {background-color: #FFFF20;}\n.cython.score-70 {background-color: #FFFF1f;}\n.cython.score-71 {background-color: #FFFF1f;}\n.cython.score-72 {background-color: #FFFF1f;}\n.cython.score-73 {background-color: #FFFF1e;}\n.cython.score-74 {background-color: #FFFF1e;}\n.cython.score-75 {background-color: #FFFF1e;}\n.cython.score-76 {background-color: #FFFF1d;}\n.cython.score-77 {background-color: #FFFF1d;}\n.cython.score-78 {background-color: #FFFF1c;}\n.cython.score-79 {background-color: #FFFF1c;}\n.cython.score-80 {background-color: #FFFF1c;}\n.cython.score-81 {background-color: #FFFF1c;}\n.cython.score-82 {background-color: #FFFF1b;}\n.cython.score-83 {background-color: #FFFF1b;}\n.cython.score-84 {background-color: #FFFF1b;}\n.cython.score-85 {background-color: #FFFF1a;}\n.cython.score-86 {background-color: #FFFF1a;}\n.cython.score-87 {background-color: #FFFF1a;}\n.cython.score-88 {background-color: #FFFF1a;}\n.cython.score-89 {background-color: #FFFF19;}\n.cython.score-90 {background-color: #FFFF19;}\n.cython.score-91 {background-color: #FFFF19;}\n.cython.score-92 {background-color: #FFFF19;}\n.cython.score-93 {background-color: #FFFF18;}\n.cython.score-94 {background-color: #FFFF18;}\n.cython.score-95 {background-color: #FFFF18;}\n.cython.score-96 {background-color: #FFFF18;}\n.cython.score-97 {background-color: #FFFF17;}\n.cython.score-98 {background-color: #FFFF17;}\n.cython.score-99 {background-color: #FFFF17;}\n.cython.score-100 {background-color: #FFFF17;}\n.cython.score-101 {background-color: #FFFF16;}\n.cython.score-102 {background-color: #FFFF16;}\n.cython.score-103 {background-color: #FFFF16;}\n.cython.score-104 {background-color: #FFFF16;}\n.cython.score-105 {background-color: #FFFF16;}\n.cython.score-106 {background-color: #FFFF15;}\n.cython.score-107 {background-color: #FFFF15;}\n.cython.score-108 {background-color: #FFFF15;}\n.cython.score-109 {background-color: #FFFF15;}\n.cython.score-110 {background-color: #FFFF15;}\n.cython.score-111 {background-color: #FFFF15;}\n.cython.score-112 {background-color: #FFFF14;}\n.cython.score-113 {background-color: #FFFF14;}\n.cython.score-114 {background-color: #FFFF14;}\n.cython.score-115 {background-color: #FFFF14;}\n.cython.score-116 {background-color: #FFFF14;}\n.cython.score-117 {background-color: #FFFF14;}\n.cython.score-118 {background-color: #FFFF13;}\n.cython.score-119 {background-color: #FFFF13;}\n.cython.score-120 {background-color: #FFFF13;}\n.cython.score-121 {background-color: #FFFF13;}\n.cython.score-122 {background-color: #FFFF13;}\n.cython.score-123 {background-color: #FFFF13;}\n.cython.score-124 {background-color: #FFFF13;}\n.cython.score-125 {background-color: #FFFF12;}\n.cython.score-126 {background-color: #FFFF12;}\n.cython.score-127 {background-color: #FFFF12;}\n.cython.score-128 {background-color: #FFFF12;}\n.cython.score-129 {background-color: #FFFF12;}\n.cython.score-130 {background-color: #FFFF12;}\n.cython.score-131 {background-color: #FFFF12;}\n.cython.score-132 {background-color: #FFFF11;}\n.cython.score-133 {background-color: #FFFF11;}\n.cython.score-134 {background-color: #FFFF11;}\n.cython.score-135 {background-color: #FFFF11;}\n.cython.score-136 {background-color: #FFFF11;}\n.cython.score-137 {background-color: #FFFF11;}\n.cython.score-138 {background-color: #FFFF11;}\n.cython.score-139 {background-color: #FFFF11;}\n.cython.score-140 {background-color: #FFFF11;}\n.cython.score-141 {background-color: #FFFF10;}\n.cython.score-142 {background-color: #FFFF10;}\n.cython.score-143 {background-color: #FFFF10;}\n.cython.score-144 {background-color: #FFFF10;}\n.cython.score-145 {background-color: #FFFF10;}\n.cython.score-146 {background-color: #FFFF10;}\n.cython.score-147 {background-color: #FFFF10;}\n.cython.score-148 {background-color: #FFFF10;}\n.cython.score-149 {background-color: #FFFF10;}\n.cython.score-150 {background-color: #FFFF0f;}\n.cython.score-151 {background-color: #FFFF0f;}\n.cython.score-152 {background-color: #FFFF0f;}\n.cython.score-153 {background-color: #FFFF0f;}\n.cython.score-154 {background-color: #FFFF0f;}\n.cython.score-155 {background-color: #FFFF0f;}\n.cython.score-156 {background-color: #FFFF0f;}\n.cython.score-157 {background-color: #FFFF0f;}\n.cython.score-158 {background-color: #FFFF0f;}\n.cython.score-159 {background-color: #FFFF0f;}\n.cython.score-160 {background-color: #FFFF0f;}\n.cython.score-161 {background-color: #FFFF0e;}\n.cython.score-162 {background-color: #FFFF0e;}\n.cython.score-163 {background-color: #FFFF0e;}\n.cython.score-164 {background-color: #FFFF0e;}\n.cython.score-165 {background-color: #FFFF0e;}\n.cython.score-166 {background-color: #FFFF0e;}\n.cython.score-167 {background-color: #FFFF0e;}\n.cython.score-168 {background-color: #FFFF0e;}\n.cython.score-169 {background-color: #FFFF0e;}\n.cython.score-170 {background-color: #FFFF0e;}\n.cython.score-171 {background-color: #FFFF0e;}\n.cython.score-172 {background-color: #FFFF0e;}\n.cython.score-173 {background-color: #FFFF0d;}\n.cython.score-174 {background-color: #FFFF0d;}\n.cython.score-175 {background-color: #FFFF0d;}\n.cython.score-176 {background-color: #FFFF0d;}\n.cython.score-177 {background-color: #FFFF0d;}\n.cython.score-178 {background-color: #FFFF0d;}\n.cython.score-179 {background-color: #FFFF0d;}\n.cython.score-180 {background-color: #FFFF0d;}\n.cython.score-181 {background-color: #FFFF0d;}\n.cython.score-182 {background-color: #FFFF0d;}\n.cython.score-183 {background-color: #FFFF0d;}\n.cython.score-184 {background-color: #FFFF0d;}\n.cython.score-185 {background-color: #FFFF0d;}\n.cython.score-186 {background-color: #FFFF0d;}\n.cython.score-187 {background-color: #FFFF0c;}\n.cython.score-188 {background-color: #FFFF0c;}\n.cython.score-189 {background-color: #FFFF0c;}\n.cython.score-190 {background-color: #FFFF0c;}\n.cython.score-191 {background-color: #FFFF0c;}\n.cython.score-192 {background-color: #FFFF0c;}\n.cython.score-193 {background-color: #FFFF0c;}\n.cython.score-194 {background-color: #FFFF0c;}\n.cython.score-195 {background-color: #FFFF0c;}\n.cython.score-196 {background-color: #FFFF0c;}\n.cython.score-197 {background-color: #FFFF0c;}\n.cython.score-198 {background-color: #FFFF0c;}\n.cython.score-199 {background-color: #FFFF0c;}\n.cython.score-200 {background-color: #FFFF0c;}\n.cython.score-201 {background-color: #FFFF0c;}\n.cython.score-202 {background-color: #FFFF0c;}\n.cython.score-203 {background-color: #FFFF0b;}\n.cython.score-204 {background-color: #FFFF0b;}\n.cython.score-205 {background-color: #FFFF0b;}\n.cython.score-206 {background-color: #FFFF0b;}\n.cython.score-207 {background-color: #FFFF0b;}\n.cython.score-208 {background-color: #FFFF0b;}\n.cython.score-209 {background-color: #FFFF0b;}\n.cython.score-210 {background-color: #FFFF0b;}\n.cython.score-211 {background-color: #FFFF0b;}\n.cython.score-212 {background-color: #FFFF0b;}\n.cython.score-213 {background-color: #FFFF0b;}\n.cython.score-214 {background-color: #FFFF0b;}\n.cython.score-215 {background-color: #FFFF0b;}\n.cython.score-216 {background-color: #FFFF0b;}\n.cython.score-217 {background-color: #FFFF0b;}\n.cython.score-218 {background-color: #FFFF0b;}\n.cython.score-219 {background-color: #FFFF0b;}\n.cython.score-220 {background-color: #FFFF0b;}\n.cython.score-221 {background-color: #FFFF0b;}\n.cython.score-222 {background-color: #FFFF0a;}\n.cython.score-223 {background-color: #FFFF0a;}\n.cython.score-224 {background-color: #FFFF0a;}\n.cython.score-225 {background-color: #FFFF0a;}\n.cython.score-226 {background-color: #FFFF0a;}\n.cython.score-227 {background-color: #FFFF0a;}\n.cython.score-228 {background-color: #FFFF0a;}\n.cython.score-229 {background-color: #FFFF0a;}\n.cython.score-230 {background-color: #FFFF0a;}\n.cython.score-231 {background-color: #FFFF0a;}\n.cython.score-232 {background-color: #FFFF0a;}\n.cython.score-233 {background-color: #FFFF0a;}\n.cython.score-234 {background-color: #FFFF0a;}\n.cython.score-235 {background-color: #FFFF0a;}\n.cython.score-236 {background-color: #FFFF0a;}\n.cython.score-237 {background-color: #FFFF0a;}\n.cython.score-238 {background-color: #FFFF0a;}\n.cython.score-239 {background-color: #FFFF0a;}\n.cython.score-240 {background-color: #FFFF0a;}\n.cython.score-241 {background-color: #FFFF0a;}\n.cython.score-242 {background-color: #FFFF0a;}\n.cython.score-243 {background-color: #FFFF0a;}\n.cython.score-244 {background-color: #FFFF0a;}\n.cython.score-245 {background-color: #FFFF0a;}\n.cython.score-246 {background-color: #FFFF09;}\n.cython.score-247 {background-color: #FFFF09;}\n.cython.score-248 {background-color: #FFFF09;}\n.cython.score-249 {background-color: #FFFF09;}\n.cython.score-250 {background-color: #FFFF09;}\n.cython.score-251 {background-color: #FFFF09;}\n.cython.score-252 {background-color: #FFFF09;}\n.cython.score-253 {background-color: #FFFF09;}\n.cython.score-254 {background-color: #FFFF09;}\n.cython .hll { background-color: #ffffcc }\n.cython { background: #f8f8f8; }\n.cython .c { color: #408080; font-style: italic } /* Comment */\n.cython .err { border: 1px solid #FF0000 } /* Error */\n.cython .k { color: #008000; font-weight: bold } /* Keyword */\n.cython .o { color: #666666 } /* Operator */\n.cython .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n.cython .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n.cython .cp { color: #BC7A00 } /* Comment.Preproc */\n.cython .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n.cython .c1 { color: #408080; font-style: italic } /* Comment.Single */\n.cython .cs { color: #408080; font-style: italic } /* Comment.Special */\n.cython .gd { color: #A00000 } /* Generic.Deleted */\n.cython .ge { font-style: italic } /* Generic.Emph */\n.cython .gr { color: #FF0000 } /* Generic.Error */\n.cython .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.cython .gi { color: #00A000 } /* Generic.Inserted */\n.cython .go { color: #888888 } /* Generic.Output */\n.cython .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.cython .gs { font-weight: bold } /* Generic.Strong */\n.cython .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.cython .gt { color: #0044DD } /* Generic.Traceback */\n.cython .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.cython .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.cython .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.cython .kp { color: #008000 } /* Keyword.Pseudo */\n.cython .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.cython .kt { color: #B00040 } /* Keyword.Type */\n.cython .m { color: #666666 } /* Literal.Number */\n.cython .s { color: #BA2121 } /* Literal.String */\n.cython .na { color: #7D9029 } /* Name.Attribute */\n.cython .nb { color: #008000 } /* Name.Builtin */\n.cython .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n.cython .no { color: #880000 } /* Name.Constant */\n.cython .nd { color: #AA22FF } /* Name.Decorator */\n.cython .ni { color: #999999; font-weight: bold } /* Name.Entity */\n.cython .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n.cython .nf { color: #0000FF } /* Name.Function */\n.cython .nl { color: #A0A000 } /* Name.Label */\n.cython .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n.cython .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.cython .nv { color: #19177C } /* Name.Variable */\n.cython .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n.cython .w { color: #bbbbbb } /* Text.Whitespace */\n.cython .mb { color: #666666 } /* Literal.Number.Bin */\n.cython .mf { color: #666666 } /* Literal.Number.Float */\n.cython .mh { color: #666666 } /* Literal.Number.Hex */\n.cython .mi { color: #666666 } /* Literal.Number.Integer */\n.cython .mo { color: #666666 } /* Literal.Number.Oct */\n.cython .sb { color: #BA2121 } /* Literal.String.Backtick */\n.cython .sc { color: #BA2121 } /* Literal.String.Char */\n.cython .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.cython .s2 { color: #BA2121 } /* Literal.String.Double */\n.cython .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n.cython .sh { color: #BA2121 } /* Literal.String.Heredoc */\n.cython .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n.cython .sx { color: #008000 } /* Literal.String.Other */\n.cython .sr { color: #BB6688 } /* Literal.String.Regex */\n.cython .s1 { color: #BA2121 } /* Literal.String.Single */\n.cython .ss { color: #19177C } /* Literal.String.Symbol */\n.cython .bp { color: #008000 } /* Name.Builtin.Pseudo */\n.cython .vc { color: #19177C } /* Name.Variable.Class */\n.cython .vg { color: #19177C } /* Name.Variable.Global */\n.cython .vi { color: #19177C } /* Name.Variable.Instance */\n.cython .il { color: #666666 } /* Literal.Number.Integer.Long */\n </style>\n <script>\n function toggleDiv(id) {\n theDiv = id.nextElementSibling\n if (theDiv.style.display != 'block') theDiv.style.display = 'block';\n else theDiv.style.display = 'none';\n }\n </script>\n</head>\n<body class=\"cython\">\n<p><span style=\"border-bottom: solid 1px grey;\">Generated by Cython 0.23.4</span></p>\n<p>\n <span style=\"background-color: #FFFF00\">Yellow lines</span> hint at Python interaction.<br />\n Click on a line that starts with a \"<code>+</code>\" to see the C code that Cython generated for it.\n</p>\n<div class=\"cython\"><pre class=\"cython line score-19\" onclick='toggleDiv(this)'>+<span class=\"\">01</span>: <span class=\"k\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"nn\">np</span></pre>\n<pre class='cython code score-19 '> __pyx_t_1 = <span class='pyx_c_api'>__Pyx_Import</span>(__pyx_n_s_numpy, 0, -1);<span class='error_goto'> if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_np, __pyx_t_1) &lt; 0) <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n/* … */\n __pyx_t_1 = <span class='py_c_api'>PyDict_New</span>();<span class='error_goto'> if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_test, __pyx_t_1) &lt; 0) <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n</pre><pre class=\"cython line score-0\">&#xA0;<span class=\"\">02</span>: </pre>\n<pre class=\"cython line score-61\" onclick='toggleDiv(this)'>+<span class=\"\">03</span>: <span class=\"k\">def</span> <span class=\"nf\">mandelbrot_cython</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">[:,::</span><span class=\"mf\">1</span><span class=\"p\">]</span> <span class=\"n\">m</span><span class=\"p\">,</span></pre>\n<pre class='cython code score-61 '>/* Python wrapper */\nstatic PyObject *__pyx_pw_46_cython_magic_cc0c3c710e01dec074c1bcec46022dd6_1mandelbrot_cython(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/\nstatic PyMethodDef __pyx_mdef_46_cython_magic_cc0c3c710e01dec074c1bcec46022dd6_1mandelbrot_cython = {\"mandelbrot_cython\", (PyCFunction)__pyx_pw_46_cython_magic_cc0c3c710e01dec074c1bcec46022dd6_1mandelbrot_cython, METH_VARARGS|METH_KEYWORDS, 0};\nstatic PyObject *__pyx_pw_46_cython_magic_cc0c3c710e01dec074c1bcec46022dd6_1mandelbrot_cython(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {\n __Pyx_memviewslice __pyx_v_m = { 0, 0, { 0 }, { 0 }, { 0 } };\n int __pyx_v_size;\n int __pyx_v_iterations;\n PyObject *__pyx_r = 0;\n <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"mandelbrot_cython (wrapper)\", 0);\n {\n static PyObject **__pyx_pyargnames[] = {&amp;__pyx_n_s_m,&amp;__pyx_n_s_size,&amp;__pyx_n_s_iterations,0};\n PyObject* values[3] = {0,0,0};\n if (unlikely(__pyx_kwds)) {\n Py_ssize_t kw_args;\n const Py_ssize_t pos_args = <span class='py_macro_api'>PyTuple_GET_SIZE</span>(__pyx_args);\n switch (pos_args) {\n case 3: values[2] = <span class='py_macro_api'>PyTuple_GET_ITEM</span>(__pyx_args, 2);\n case 2: values[1] = <span class='py_macro_api'>PyTuple_GET_ITEM</span>(__pyx_args, 1);\n case 1: values[0] = <span class='py_macro_api'>PyTuple_GET_ITEM</span>(__pyx_args, 0);\n case 0: break;\n default: goto __pyx_L5_argtuple_error;\n }\n kw_args = <span class='py_c_api'>PyDict_Size</span>(__pyx_kwds);\n switch (pos_args) {\n case 0:\n if (likely((values[0] = <span class='py_c_api'>PyDict_GetItem</span>(__pyx_kwds, __pyx_n_s_m)) != 0)) kw_args--;\n else goto __pyx_L5_argtuple_error;\n case 1:\n if (likely((values[1] = <span class='py_c_api'>PyDict_GetItem</span>(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--;\n else {\n <span class='pyx_c_api'>__Pyx_RaiseArgtupleInvalid</span>(\"mandelbrot_cython\", 1, 3, 3, 1); <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L3_error;}</span>\n }\n case 2:\n if (likely((values[2] = <span class='py_c_api'>PyDict_GetItem</span>(__pyx_kwds, __pyx_n_s_iterations)) != 0)) kw_args--;\n else {\n <span class='pyx_c_api'>__Pyx_RaiseArgtupleInvalid</span>(\"mandelbrot_cython\", 1, 3, 3, 2); <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L3_error;}</span>\n }\n }\n if (unlikely(kw_args &gt; 0)) {\n if (unlikely(<span class='pyx_c_api'>__Pyx_ParseOptionalKeywords</span>(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, \"mandelbrot_cython\") &lt; 0)) <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L3_error;}</span>\n }\n } else if (<span class='py_macro_api'>PyTuple_GET_SIZE</span>(__pyx_args) != 3) {\n goto __pyx_L5_argtuple_error;\n } else {\n values[0] = <span class='py_macro_api'>PyTuple_GET_ITEM</span>(__pyx_args, 0);\n values[1] = <span class='py_macro_api'>PyTuple_GET_ITEM</span>(__pyx_args, 1);\n values[2] = <span class='py_macro_api'>PyTuple_GET_ITEM</span>(__pyx_args, 2);\n }\n __pyx_v_m = <span class='pyx_c_api'>__Pyx_PyObject_to_MemoryviewSlice_d_dc_int</span>(values[0]);<span class='error_goto'> if (unlikely(!__pyx_v_m.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L3_error;}</span>\n __pyx_v_size = <span class='pyx_c_api'>__Pyx_PyInt_As_int</span>(values[1]);<span class='error_goto'> if (unlikely((__pyx_v_size == (int)-1) &amp;&amp; PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L3_error;}</span>\n __pyx_v_iterations = <span class='pyx_c_api'>__Pyx_PyInt_As_int</span>(values[2]);<span class='error_goto'> if (unlikely((__pyx_v_iterations == (int)-1) &amp;&amp; PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L3_error;}</span>\n }\n goto __pyx_L4_argument_unpacking_done;\n __pyx_L5_argtuple_error:;\n <span class='pyx_c_api'>__Pyx_RaiseArgtupleInvalid</span>(\"mandelbrot_cython\", 1, 3, 3, <span class='py_macro_api'>PyTuple_GET_SIZE</span>(__pyx_args)); <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L3_error;}</span>\n __pyx_L3_error:;\n <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_cc0c3c710e01dec074c1bcec46022dd6.mandelbrot_cython\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n return NULL;\n __pyx_L4_argument_unpacking_done:;\n __pyx_r = __pyx_pf_46_cython_magic_cc0c3c710e01dec074c1bcec46022dd6_mandelbrot_cython(__pyx_self, __pyx_v_m, __pyx_v_size, __pyx_v_iterations);\n int __pyx_lineno = 0;\n const char *__pyx_filename = NULL;\n int __pyx_clineno = 0;\n\n /* function exit code */\n <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n return __pyx_r;\n}\n\nstatic PyObject *__pyx_pf_46_cython_magic_cc0c3c710e01dec074c1bcec46022dd6_mandelbrot_cython(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_m, int __pyx_v_size, int __pyx_v_iterations) {\n int __pyx_v_i;\n int __pyx_v_j;\n int __pyx_v_n;\n __pyx_t_double_complex __pyx_v_z;\n __pyx_t_double_complex __pyx_v_c;\n PyObject *__pyx_r = NULL;\n <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"mandelbrot_cython\", 0);\n/* … */\n /* function exit code */\n __pyx_r = Py_None; <span class='pyx_macro_api'>__Pyx_INCREF</span>(Py_None);\n goto __pyx_L0;\n __pyx_L1_error:;\n <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_cc0c3c710e01dec074c1bcec46022dd6.mandelbrot_cython\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n __pyx_r = NULL;\n __pyx_L0:;\n __PYX_XDEC_MEMVIEW(&amp;__pyx_v_m, 1);\n <span class='refnanny'>__Pyx_XGIVEREF</span>(__pyx_r);\n <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n return __pyx_r;\n}\n/* … */\n __pyx_tuple__14 = <span class='py_c_api'>PyTuple_Pack</span>(8, __pyx_n_s_m, __pyx_n_s_size, __pyx_n_s_iterations, __pyx_n_s_i, __pyx_n_s_j, __pyx_n_s_n, __pyx_n_s_z, __pyx_n_s_c);<span class='error_goto'> if (unlikely(!__pyx_tuple__14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_tuple__14);\n <span class='refnanny'>__Pyx_GIVEREF</span>(__pyx_tuple__14);\n/* … */\n __pyx_t_1 = PyCFunction_NewEx(&amp;__pyx_mdef_46_cython_magic_cc0c3c710e01dec074c1bcec46022dd6_1mandelbrot_cython, NULL, __pyx_n_s_cython_magic_cc0c3c710e01dec074);<span class='error_goto'> if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_mandelbrot_cython, __pyx_t_1) &lt; 0) <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n __pyx_codeobj__15 = (PyObject*)<span class='pyx_c_api'>__Pyx_PyCode_New</span>(3, 0, 8, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_berkas_ipython_cython__cy, __pyx_n_s_mandelbrot_cython, 3, __pyx_empty_bytes);<span class='error_goto'> if (unlikely(!__pyx_codeobj__15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n</pre><pre class=\"cython line score-0\">&#xA0;<span class=\"\">04</span>: <span class=\"nb\">int</span> <span class=\"n\">size</span><span class=\"p\">,</span></pre>\n<pre class=\"cython line score-0\">&#xA0;<span class=\"\">05</span>: <span class=\"nb\">int</span> <span class=\"n\">iterations</span><span class=\"p\">):</span></pre>\n<pre class=\"cython line score-0\">&#xA0;<span class=\"\">06</span>: <span class=\"k\">cdef</span> <span class=\"kt\">int</span> <span class=\"nf\">i</span><span class=\"p\">,</span> <span class=\"nf\">j</span><span class=\"p\">,</span> <span class=\"nf\">n</span></pre>\n<pre class=\"cython line score-0\">&#xA0;<span class=\"\">07</span>: <span class=\"k\">cdef</span> <span class=\"kt\">complex</span> <span class=\"nf\">z</span><span class=\"p\">,</span> <span class=\"nf\">c</span></pre>\n<pre class=\"cython line score-0\" onclick='toggleDiv(this)'>+<span class=\"\">08</span>: <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">size</span><span class=\"p\">):</span></pre>\n<pre class='cython code score-0 '> __pyx_t_1 = __pyx_v_size;\n for (__pyx_t_2 = 0; __pyx_t_2 &lt; __pyx_t_1; __pyx_t_2+=1) {\n __pyx_v_i = __pyx_t_2;\n</pre><pre class=\"cython line score-0\" onclick='toggleDiv(this)'>+<span class=\"\">09</span>: <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">size</span><span class=\"p\">):</span></pre>\n<pre class='cython code score-0 '> __pyx_t_3 = __pyx_v_size;\n for (__pyx_t_4 = 0; __pyx_t_4 &lt; __pyx_t_3; __pyx_t_4+=1) {\n __pyx_v_j = __pyx_t_4;\n</pre><pre class=\"cython line score-10\" onclick='toggleDiv(this)'>+<span class=\"\">10</span>: <span class=\"n\">c</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mf\">2</span> <span class=\"o\">+</span> <span class=\"mf\">3.</span><span class=\"o\">/</span><span class=\"n\">size</span><span class=\"o\">*</span><span class=\"n\">j</span> <span class=\"o\">+</span> <span class=\"mf\">1</span><span class=\"n\">j</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"mf\">1.5</span><span class=\"o\">-</span><span class=\"mf\">3.</span><span class=\"o\">/</span><span class=\"n\">size</span><span class=\"o\">*</span><span class=\"n\">i</span><span class=\"p\">)</span></pre>\n<pre class='cython code score-10 '> if (unlikely(__pyx_v_size == 0)) {\n <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n }\n if (unlikely(__pyx_v_size == 0)) {\n <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n }\n __pyx_v_c = __Pyx_c_sum(__pyx_t_double_complex_from_parts((-2.0 + ((3. / __pyx_v_size) * __pyx_v_j)), 0), __Pyx_c_prod(__pyx_t_double_complex_from_parts(0, 1.0), __pyx_t_double_complex_from_parts((1.5 - ((3. / __pyx_v_size) * __pyx_v_i)), 0)));\n</pre><pre class=\"cython line score-0\" onclick='toggleDiv(this)'>+<span class=\"\">11</span>: <span class=\"n\">z</span> <span class=\"o\">=</span> <span class=\"mf\">0</span></pre>\n<pre class='cython code score-0 '> __pyx_v_z = __pyx_t_double_complex_from_parts(0, 0);\n</pre><pre class=\"cython line score-0\" onclick='toggleDiv(this)'>+<span class=\"\">12</span>: <span class=\"k\">for</span> <span class=\"n\">n</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">iterations</span><span class=\"p\">):</span></pre>\n<pre class='cython code score-0 '> __pyx_t_5 = __pyx_v_iterations;\n for (__pyx_t_6 = 0; __pyx_t_6 &lt; __pyx_t_5; __pyx_t_6+=1) {\n __pyx_v_n = __pyx_t_6;\n</pre><pre class=\"cython line score-2\" onclick='toggleDiv(this)'>+<span class=\"\">13</span>: <span class=\"k\">if</span> <span class=\"n\">z</span><span class=\"o\">.</span><span class=\"n\">real</span><span class=\"o\">**</span><span class=\"mf\">2</span> <span class=\"o\">+</span> <span class=\"n\">z</span><span class=\"o\">.</span><span class=\"n\">imag</span><span class=\"o\">**</span><span class=\"mf\">2</span> <span class=\"o\">&lt;=</span> <span class=\"mf\">100</span><span class=\"p\">:</span></pre>\n<pre class='cython code score-2 '> __pyx_t_7 = (((pow(<span class='pyx_macro_api'>__Pyx_CREAL</span>(__pyx_v_z), 2.0) + pow(<span class='pyx_macro_api'>__Pyx_CIMAG</span>(__pyx_v_z), 2.0)) &lt;= 100.0) != 0);\n if (__pyx_t_7) {\n/* … */\n goto __pyx_L9;\n }\n</pre><pre class=\"cython line score-0\" onclick='toggleDiv(this)'>+<span class=\"\">14</span>: <span class=\"n\">z</span> <span class=\"o\">=</span> <span class=\"n\">z</span><span class=\"o\">*</span><span class=\"n\">z</span> <span class=\"o\">+</span> <span class=\"n\">c</span></pre>\n<pre class='cython code score-0 '> __pyx_v_z = __Pyx_c_sum(__Pyx_c_prod(__pyx_v_z, __pyx_v_z), __pyx_v_c);\n</pre><pre class=\"cython line score-2\" onclick='toggleDiv(this)'>+<span class=\"\">15</span>: <span class=\"n\">m</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">n</span></pre>\n<pre class='cython code score-2 '> __pyx_t_8 = __pyx_v_i;\n __pyx_t_9 = __pyx_v_j;\n __pyx_t_10 = -1;\n if (__pyx_t_8 &lt; 0) {\n __pyx_t_8 += __pyx_v_m.shape[0];\n if (unlikely(__pyx_t_8 &lt; 0)) __pyx_t_10 = 0;\n } else if (unlikely(__pyx_t_8 &gt;= __pyx_v_m.shape[0])) __pyx_t_10 = 0;\n if (__pyx_t_9 &lt; 0) {\n __pyx_t_9 += __pyx_v_m.shape[1];\n if (unlikely(__pyx_t_9 &lt; 0)) __pyx_t_10 = 1;\n } else if (unlikely(__pyx_t_9 &gt;= __pyx_v_m.shape[1])) __pyx_t_10 = 1;\n if (unlikely(__pyx_t_10 != -1)) {\n <span class='pyx_c_api'>__Pyx_RaiseBufferIndexError</span>(__pyx_t_10);\n <span class='error_goto'>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}</span>\n }\n *((int *) ( /* dim=1 */ ((char *) (((int *) ( /* dim=0 */ (__pyx_v_m.data + __pyx_t_8 * __pyx_v_m.strides[0]) )) + __pyx_t_9)) )) = __pyx_v_n;\n</pre><pre class=\"cython line score-0\">&#xA0;<span class=\"\">16</span>: <span class=\"k\">else</span><span class=\"p\">:</span></pre>\n<pre class=\"cython line score-0\" onclick='toggleDiv(this)'>+<span class=\"\">17</span>: <span class=\"k\">break</span></pre>\n<pre class='cython code score-0 '> /*else*/ {\n goto __pyx_L8_break;\n }\n __pyx_L9:;\n }\n __pyx_L8_break:;\n }\n }\n</pre></div></body></html>"
},
"output_type": "execute_result",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%%timeit -n1 -r1 m = np.zeros((size, size), dtype=np.int32)\nmandelbrot_cython(m, size, iterations)",
"execution_count": 65,
"outputs": [
{
"text": "1 loop, best of 1: 8.56 ms per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Ray tracing example"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Pure Python"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "In this example, we will render a sphere with a diffuse and specular material. The principle is to model a scene with a light source and a camera, and use the physical properties of light propagation to calculate the light intensity and color of every pixel of the screen."
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "import numpy as np\nimport matplotlib.pyplot as plt",
"execution_count": 66,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%matplotlib inline",
"execution_count": 67,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "w, h = 200, 200 # Size of the screen in pixels.\n\ndef normalize(x):\n # This function normalizes a vector.\n x /= np.linalg.norm(x)\n return x\n\ndef intersect_sphere(O, D, S, R):\n # Return the distance from O to the intersection \n # of the ray (O, D) with the sphere (S, R), or \n # +inf if there is no intersection.\n # O and S are 3D points, D (direction) is a \n # normalized vector, R is a scalar.\n a = np.dot(D, D)\n OS = O - S\n b = 2 * np.dot(D, OS)\n c = np.dot(OS, OS) - R*R\n disc = b*b - 4*a*c\n if disc > 0:\n distSqrt = np.sqrt(disc)\n q = (-b - distSqrt) / 2.0 if b < 0 \\\n else (-b + distSqrt) / 2.0\n t0 = q / a\n t1 = c / q\n t0, t1 = min(t0, t1), max(t0, t1)\n if t1 >= 0:\n return t1 if t0 < 0 else t0\n return np.inf\n\ndef trace_ray(O, D):\n # Find first point of intersection with the scene.\n t = intersect_sphere(O, D, position, radius)\n # No intersection?\n if t == np.inf:\n return\n # Find the point of intersection on the object.\n M = O + D * t\n N = normalize(M - position)\n toL = normalize(L - M)\n toO = normalize(O - M)\n # Ambient light.\n col = ambient\n # Lambert shading (diffuse).\n col += diffuse * max(np.dot(N, toL), 0) * color\n # Blinn-Phong shading (specular).\n col += specular_c * color_light * \\\n max(np.dot(N, normalize(toL + toO)), 0) \\\n ** specular_k\n return col\n\ndef run():\n img = np.zeros((h, w, 3))\n # Loop through all pixels.\n for i, x in enumerate(np.linspace(-1., 1., w)):\n for j, y in enumerate(np.linspace(-1., 1., h)):\n # Position of the pixel.\n Q[0], Q[1] = x, y\n # Direction of the ray going through the optical center.\n D = normalize(Q - O)\n # Launch the ray and get the color of the pixel.\n col = trace_ray(O, D)\n if col is None:\n continue\n img[h - j - 1, i, :] = np.clip(col, 0, 1)\n return img\n\n# Sphere properties.\nposition = np.array([0., 0., 1.])\nradius = 1.\ncolor = np.array([0., 0., 1.])\ndiffuse = 1.\nspecular_c = 1.\nspecular_k = 50\n\n# Light position and color.\nL = np.array([5., 5., -10.])\ncolor_light = np.ones(3)\nambient = .05\n\n# Camera.\nO = np.array([0., 0., -1.]) # Position.\nQ = np.array([0., 0., 0.]) # Pointing to.\n\nimg = run()\nplt.imshow(img);\nplt.xticks([]); plt.yticks([]);",
"execution_count": 68,
"outputs": [
{
"data": {
"text/plain": "<matplotlib.figure.Figure at 0x117f2f2b0>",
"image/png": "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\nAABJRU5ErkJggg==\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%timeit run()",
"execution_count": 69,
"outputs": [
{
"text": "1 loop, best of 3: 1.5 s per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Naive Cython"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "In this example, we will render a sphere with a diffuse and specular material. The principle is to model a scene with a light source and a camera, and use the physical properties of light propagation to calculate the light intensity and color of every pixel of the screen."
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "import numpy as np\nimport matplotlib.pyplot as plt",
"execution_count": 70,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%matplotlib inline",
"execution_count": 71,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "#%load_ext cythonmagic\n%load_ext Cython",
"execution_count": 72,
"outputs": [
{
"text": "The Cython extension is already loaded. To reload it, use:\n %reload_ext Cython\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%%cython\nimport numpy as np\ncimport numpy as np\n\nw, h = 200, 200 # Size of the screen in pixels.\n\ndef normalize(x):\n # This function normalizes a vector.\n x /= np.linalg.norm(x)\n return x\n\ndef intersect_sphere(O, D, S, R):\n # Return the distance from O to the intersection \n # of the ray (O, D) with the sphere (S, R), or \n # +inf if there is no intersection.\n # O and S are 3D points, D (direction) is a \n # normalized vector, R is a scalar.\n a = np.dot(D, D)\n OS = O - S\n b = 2 * np.dot(D, OS)\n c = np.dot(OS, OS) - R*R\n disc = b*b - 4*a*c\n if disc > 0:\n distSqrt = np.sqrt(disc)\n q = (-b - distSqrt) / 2.0 if b < 0 \\\n else (-b + distSqrt) / 2.0\n t0 = q / a\n t1 = c / q\n t0, t1 = min(t0, t1), max(t0, t1)\n if t1 >= 0:\n return t1 if t0 < 0 else t0\n return np.inf\n\ndef trace_ray(O, D):\n # Find first point of intersection with the scene.\n t = intersect_sphere(O, D, position, radius)\n # No intersection?\n if t == np.inf:\n return\n # Find the point of intersection on the object.\n M = O + D * t\n N = normalize(M - position)\n toL = normalize(L - M)\n toO = normalize(O - M)\n # Ambient light.\n col = ambient\n # Lambert shading (diffuse).\n col += diffuse * max(np.dot(N, toL), 0) * color\n # Blinn-Phong shading (specular).\n col += specular_c * color_light * \\\n max(np.dot(N, normalize(toL + toO)), 0) \\\n ** specular_k\n return col\n\ndef run():\n img = np.zeros((h, w, 3))\n # Loop through all pixels.\n for i, x in enumerate(np.linspace(-1., 1., w)):\n for j, y in enumerate(np.linspace(-1., 1., h)):\n # Position of the pixel.\n Q[0], Q[1] = x, y\n # Direction of the ray going through the optical center.\n D = normalize(Q - O)\n depth = 0\n # Launch the ray and get the color of the pixel.\n col = trace_ray(O, D)\n if col is None:\n continue\n img[h - j - 1, i, :] = np.clip(col, 0, 1)\n return img\n\n# Sphere properties.\nposition = np.array([0., 0., 1.])\nradius = 1.\ncolor = np.array([0., 0., 1.])\ndiffuse = 1.\nspecular_c = 1.\nspecular_k = 50\n\n# Light position and color.\nL = np.array([5., 5., -10.])\ncolor_light = np.ones(3)\nambient = .05\n\n# Camera.\nO = np.array([0., 0., -1.]) # Position.\nQ = np.array([0., 0., 0.]) # Pointing to.",
"execution_count": 73,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "img = run()\nplt.imshow(img);\nplt.xticks([]); plt.yticks([]);",
"execution_count": 74,
"outputs": [
{
"data": {
"text/plain": "<matplotlib.figure.Figure at 0x120470898>",
"image/png": "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\nAABJRU5ErkJggg==\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%timeit -n1 -r1 run()",
"execution_count": 75,
"outputs": [
{
"text": "1 loop, best of 1: 1.41 s per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Cython array buffers"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "In this example, we will render a sphere with a diffuse and specular material. The principle is to model a scene with a light source and a camera, and use the physical properties of light propagation to calculate the light intensity and color of every pixel of the screen."
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "import numpy as np\nimport matplotlib.pyplot as plt",
"execution_count": 76,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%matplotlib inline",
"execution_count": 77,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "#%load_ext cythonmagic\n%load_ext Cython",
"execution_count": 78,
"outputs": [
{
"text": "The Cython extension is already loaded. To reload it, use:\n %reload_ext Cython\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "#### Take 1"
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%%cython\nimport numpy as np\ncimport numpy as np\nfrom numpy import dot\nfrom libc.math cimport sqrt\n\nDBL = np.double\nctypedef np.double_t DBL_C\nINT = np.int\nctypedef np.int_t INT_C\ncdef INT_C w, h\n\nw, h = 200, 200 # Size of the screen in pixels.\n\ndef normalize(np.ndarray[DBL_C, ndim=1] x):\n # This function normalizes a vector.\n x /= np.linalg.norm(x)\n return x\n\ndef intersect_sphere(np.ndarray[DBL_C, ndim=1] O, np.ndarray[DBL_C, ndim=1] D, \n np.ndarray[DBL_C, ndim=1] S, DBL_C R):\n # Return the distance from O to the intersection \n # of the ray (O, D) with the sphere (S, R), or \n # +inf if there is no intersection.\n # O and S are 3D points, D (direction) is a \n # normalized vector, R is a scalar.\n \n cdef DBL_C a, b, c, disc, distSqrt, q, t0, t1\n cdef np.ndarray[DBL_C, ndim=1] OS\n \n a = dot(D, D)\n OS = O - S\n b = 2 * dot(D, OS)\n c = dot(OS, OS) - R*R\n disc = b*b - 4*a*c\n if disc > 0:\n distSqrt = np.sqrt(disc)\n q = (-b - distSqrt) / 2.0 if b < 0 \\\n else (-b + distSqrt) / 2.0\n t0 = q / a\n t1 = c / q\n t0, t1 = min(t0, t1), max(t0, t1)\n if t1 >= 0:\n return t1 if t0 < 0 else t0\n return np.inf\n\ndef trace_ray(np.ndarray[DBL_C, ndim=1] O, np.ndarray[DBL_C, ndim=1] D,\n np.ndarray[DBL_C, ndim=1] position,\n np.ndarray[DBL_C, ndim=1] color,\n np.ndarray[DBL_C, ndim=1] L,\n np.ndarray[DBL_C, ndim=1] color_light):\n \n cdef DBL_C t\n cdef np.ndarray[DBL_C, ndim=1] M, N, toL, toO, col\n \n # Find first point of intersection with the scene.\n t = intersect_sphere(O, D, position, radius)\n # No intersection?\n if t == np.inf:\n return\n # Find the point of intersection on the object.\n M = O + D * t\n N = normalize(M - position)\n toL = normalize(L - M)\n toO = normalize(O - M)\n # Ambient light.\n col = ambient * np.ones(3)\n # Lambert shading (diffuse).\n col += diffuse * max(dot(N, toL), 0) * color\n # Blinn-Phong shading (specular).\n col += specular_c * color_light * \\\n max(dot(N, normalize(toL + toO)), 0) \\\n ** specular_k\n return col\n\ndef run():\n cdef np.ndarray[DBL_C, ndim=3] img\n img = np.zeros((h, w, 3))\n cdef INT_C i, j\n cdef DBL_C x, y\n cdef np.ndarray[DBL_C, ndim=1] O, Q, D, col, position, color, L, color_light\n\n # Sphere properties.\n position = np.array([0., 0., 1.])\n color = np.array([0., 0., 1.])\n L = np.array([5., 5., -10.])\n color_light = np.ones(3)\n \n # Camera.\n O = np.array([0., 0., -1.]) # Position.\n Q = np.array([0., 0., 0.]) # Pointing to.\n \n # Loop through all pixels.\n for i, x in enumerate(np.linspace(-1., 1., w)):\n for j, y in enumerate(np.linspace(-1., 1., h)):\n # Position of the pixel.\n Q[0], Q[1] = x, y\n # Direction of the ray going through the optical center.\n D = normalize(Q - O)\n # Launch the ray and get the color of the pixel.\n col = trace_ray(O, D, position, color, L, color_light)\n if col is None:\n continue\n img[h - j - 1, i, :] = np.clip(col, 0, 1)\n return img\n\ncdef DBL_C radius, ambient, diffuse, specular_k, specular_c\n\n# Sphere and light properties.\nradius = 1.\ndiffuse = 1.\nspecular_c = 1.\nspecular_k = 50.\nambient = .05",
"execution_count": 79,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "img = run()\nplt.imshow(img);\nplt.xticks([]); plt.yticks([]);",
"execution_count": 80,
"outputs": [
{
"data": {
"text/plain": "<matplotlib.figure.Figure at 0x12054da90>",
"image/png": "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\nAABJRU5ErkJggg==\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%timeit run()",
"execution_count": 81,
"outputs": [
{
"text": "1 loop, best of 3: 1.97 s per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "#### Take 2"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "In this version, we rewrite normalize in pure C."
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%%cython\nimport numpy as np\ncimport numpy as np\nfrom numpy import dot\nfrom libc.math cimport sqrt\n\nDBL = np.double\nctypedef np.double_t DBL_C\nINT = np.int\nctypedef np.int_t INT_C\ncdef INT_C w, h\n\nw, h = 200, 200 # Size of the screen in pixels.\n\n# normalize is now a pure C function that does not make\n# use NumPy for the computations\ncdef normalize(np.ndarray[DBL_C, ndim=1] x):\n cdef DBL_C n\n n = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2])\n x[0] /= n\n x[1] /= n\n x[2] /= n\n return x\n\ndef intersect_sphere(np.ndarray[DBL_C, ndim=1] O, np.ndarray[DBL_C, ndim=1] D, \n np.ndarray[DBL_C, ndim=1] S, DBL_C R):\n # Return the distance from O to the intersection \n # of the ray (O, D) with the sphere (S, R), or \n # +inf if there is no intersection.\n # O and S are 3D points, D (direction) is a \n # normalized vector, R is a scalar.\n \n cdef DBL_C a, b, c, disc, distSqrt, q, t0, t1\n cdef np.ndarray[DBL_C, ndim=1] OS\n \n a = dot(D, D)\n OS = O - S\n b = 2 * dot(D, OS)\n c = dot(OS, OS) - R*R\n disc = b*b - 4*a*c\n if disc > 0:\n distSqrt = np.sqrt(disc)\n q = (-b - distSqrt) / 2.0 if b < 0 \\\n else (-b + distSqrt) / 2.0\n t0 = q / a\n t1 = c / q\n t0, t1 = min(t0, t1), max(t0, t1)\n if t1 >= 0:\n return t1 if t0 < 0 else t0\n return np.inf\n\ndef trace_ray(np.ndarray[DBL_C, ndim=1] O, np.ndarray[DBL_C, ndim=1] D,\n np.ndarray[DBL_C, ndim=1] position,\n np.ndarray[DBL_C, ndim=1] color,\n np.ndarray[DBL_C, ndim=1] L,\n np.ndarray[DBL_C, ndim=1] color_light):\n \n cdef DBL_C t\n cdef np.ndarray[DBL_C, ndim=1] M, N, toL, toO, col\n \n # Find first point of intersection with the scene.\n t = intersect_sphere(O, D, position, radius)\n # No intersection?\n if t == np.inf:\n return\n # Find the point of intersection on the object.\n M = O + D * t\n N = normalize(M - position)\n toL = normalize(L - M)\n toO = normalize(O - M)\n # Ambient light.\n col = ambient * np.ones(3)\n # Lambert shading (diffuse).\n col += diffuse * max(dot(N, toL), 0) * color\n # Blinn-Phong shading (specular).\n col += specular_c * color_light * \\\n max(dot(N, normalize(toL + toO)), 0) \\\n ** specular_k\n return col\n\ndef run():\n cdef np.ndarray[DBL_C, ndim=3] img\n img = np.zeros((h, w, 3))\n cdef INT_C i, j\n cdef DBL_C x, y\n cdef np.ndarray[DBL_C, ndim=1] O, Q, D, col, position, color, L, color_light\n\n # Sphere properties.\n position = np.array([0., 0., 1.])\n color = np.array([0., 0., 1.])\n L = np.array([5., 5., -10.])\n color_light = np.ones(3)\n \n # Camera.\n O = np.array([0., 0., -1.]) # Position.\n Q = np.array([0., 0., 0.]) # Pointing to.\n \n # Loop through all pixels.\n for i, x in enumerate(np.linspace(-1., 1., w)):\n for j, y in enumerate(np.linspace(-1., 1., h)):\n # Position of the pixel.\n Q[0], Q[1] = x, y\n # Direction of the ray going through the optical center.\n D = normalize(Q - O)\n # Launch the ray and get the color of the pixel.\n col = trace_ray(O, D, position, color, L, color_light)\n if col is None:\n continue\n img[h - j - 1, i, :] = np.clip(col, 0, 1)\n return img\n\ncdef DBL_C radius, ambient, diffuse, specular_k, specular_c\n\n# Sphere and light properties.\nradius = 1.\ndiffuse = 1.\nspecular_c = 1.\nspecular_k = 50.\nambient = .05",
"execution_count": 82,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "img = run()\nplt.imshow(img);\nplt.xticks([]); plt.yticks([]);",
"execution_count": 83,
"outputs": [
{
"data": {
"text/plain": "<matplotlib.figure.Figure at 0x1206e8748>",
"image/png": "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\nAABJRU5ErkJggg==\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%timeit run()",
"execution_count": 84,
"outputs": [
{
"text": "1 loop, best of 3: 1.07 s per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Cython with structs"
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "import numpy as np\nimport matplotlib.pyplot as plt",
"execution_count": 85,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%matplotlib inline",
"execution_count": 86,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "import cython",
"execution_count": 87,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "#%load_ext cythonmagic\n%load_ext Cython",
"execution_count": 88,
"outputs": [
{
"text": "The Cython extension is already loaded. To reload it, use:\n %reload_ext Cython\n",
"output_type": "stream",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "We now use a pure C structure to represent a 3D vector. We also implement all operations we need by hand in pure C."
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "%%cython\ncimport cython\nimport numpy as np\ncimport numpy as np\nDBL = np.double\nctypedef np.double_t DBL_C\nfrom libc.math cimport sqrt\n\ncdef int w, h\n\ncdef struct Vec3:\n double x, y, z\n \ncdef Vec3 vec3(double x, double y, double z):\n cdef Vec3 v\n v.x = x\n v.y = y\n v.z = z\n return v\n\ncdef double dot(Vec3 x, Vec3 y):\n return x.x * y.x + x.y * y.y + x.z * y.z\n\ncdef Vec3 normalize(Vec3 x):\n cdef double n\n n = sqrt(x.x * x.x + x.y * x.y + x.z * x.z)\n return vec3(x.x / n, x.y / n, x.z / n)\n\ncdef double max(double x, double y):\n return x if x > y else y\n\ncdef double min(double x, double y):\n return x if x < y else y\n\ncdef double clip_(double x, double m, double M):\n return min(max(x, m), M)\n\ncdef Vec3 clip(Vec3 x, double m, double M):\n return vec3(clip_(x.x, m, M), clip_(x.y, m, M), clip_(x.z, m, M),)\n\ncdef Vec3 add(Vec3 x, Vec3 y):\n return vec3(x.x + y.x, x.y + y.y, x.z + y.z)\n\ncdef Vec3 subtract(Vec3 x, Vec3 y):\n return vec3(x.x - y.x, x.y - y.y, x.z - y.z)\n\ncdef Vec3 minus(Vec3 x):\n return vec3(-x.x, -x.y, -x.z)\n\ncdef Vec3 multiply(Vec3 x, Vec3 y):\n return vec3(x.x * y.x, x.y * y.y, x.z * y.z)\n \ncdef Vec3 multiply_s(Vec3 x, double c):\n return vec3(x.x * c, x.y * c, x.z * c)\n \ncdef double intersect_sphere(Vec3 O, \n Vec3 D, \n Vec3 S, \n double R):\n # Return the distance from O to the intersection of the ray (O, D) with the \n # sphere (S, R), or +inf if there is no intersection.\n # O and S are 3D points, D (direction) is a normalized vector, R is a scalar.\n cdef double a, b, c, disc, distSqrt, q, t0, t1\n cdef Vec3 OS\n \n a = dot(D, D)\n OS = subtract(O, S)\n b = 2 * dot(D, OS)\n c = dot(OS, OS) - R * R\n disc = b * b - 4 * a * c\n if disc > 0:\n distSqrt = sqrt(disc)\n q = (-b - distSqrt) / 2.0 if b < 0 else (-b + distSqrt) / 2.0\n t0 = q / a\n t1 = c / q\n t0, t1 = min(t0, t1), max(t0, t1)\n if t1 >= 0:\n return t1 if t0 < 0 else t0\n return 1000000\n\ncdef Vec3 trace_ray(Vec3 O, Vec3 D,):\n \n cdef double t, radius, diffuse, specular_k, specular_c, DF, SP\n cdef Vec3 M, N, L, toL, toO, col_ray, \\\n position, color, color_light, ambient\n\n # Sphere properties.\n position = vec3(0., 0., 1.)\n radius = 1.\n color = vec3(0., 0., 1.)\n diffuse = 1.\n specular_c = 1.\n specular_k = 50.\n \n # Light position and color.\n L = vec3(5., 5., -10.)\n color_light = vec3(1., 1., 1.)\n ambient = vec3(.05, .05, .05)\n \n # Find first point of intersection with the scene.\n t = intersect_sphere(O, D, position, radius)\n # Return None if the ray does not intersect any object.\n if t == 1000000:\n col_ray.x = 1000000\n return col_ray\n # Find the point of intersection on the object.\n M = vec3(O.x + D.x * t, O.y + D.y * t, O.z + D.z * t)\n N = normalize(subtract(M, position))\n toL = normalize(subtract(L, M))\n toO = normalize(subtract(O, M))\n DF = diffuse * max(dot(N, toL), 0)\n SP = specular_c * max(dot(N, normalize(add(toL, toO))), 0) ** specular_k\n \n return add(ambient, add(multiply_s(color, DF), multiply_s(color_light, SP)))\n\ndef run(int w, int h):\n cdef DBL_C[:,:,:] img = np.zeros((h, w, 3))\n cdef Vec3 img_\n cdef int i, j\n cdef double x, y\n cdef Vec3 O, Q, D, col_ray\n cdef double w_ = float(w)\n cdef double h_ = float(h)\n \n col_ray = vec3(0., 0., 0.)\n \n # Camera.\n O = vec3(0., 0., -1.) # Position.\n \n # Loop through all pixels.\n for i in range(w):\n Q = vec3(0., 0., 0.)\n for j in range(h):\n x = -1. + 2*(i)/w_\n y = -1. + 2*(j)/h_\n Q.x = x\n Q.y = y\n col_ray = trace_ray(O, normalize(subtract(Q, O)))\n if col_ray.x == 1000000:\n continue\n img_ = clip(col_ray, 0., 1.)\n img[h - j - 1, i, 0] = img_.x\n img[h - j - 1, i, 1] = img_.y\n img[h - j - 1, i, 2] = img_.z\n return img",
"execution_count": 89,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": true
},
"cell_type": "code",
"source": "w, h = 200, 200",
"execution_count": 90,
"outputs": []
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "img = run(w, h)\nplt.imshow(img);\nplt.xticks([]); plt.yticks([]);",
"execution_count": 91,
"outputs": [
{
"data": {
"text/plain": "<matplotlib.figure.Figure at 0x12094a550>",
"image/png": "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\n"
},
"output_type": "display_data",
"metadata": {}
}
]
},
{
"metadata": {
"trusted": true,
"collapsed": false
},
"cell_type": "code",
"source": "%timeit run(w, h)",
"execution_count": 92,
"outputs": [
{
"text": "100 loops, best of 3: 2.26 ms per loop\n",
"output_type": "stream",
"name": "stdout"
}
]
}
],
"metadata": {
"kernelspec": {
"name": "python3",
"display_name": "Python 3",
"language": "python"
},
"toc": {
"threshold": 4,
"number_sections": true,
"toc_cell": true,
"toc_window_display": false,
"toc_section_display": "block",
"sideBar": true,
"navigate_menu": true,
"nav_menu": {
"width": "252px",
"height": "264px"
}
},
"language_info": {
"nbconvert_exporter": "python",
"version": "3.5.2",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"mimetype": "text/x-python",
"name": "python",
"pygments_lexer": "ipython3",
"file_extension": ".py"
},
"gist": {
"id": "9a3744df66983045a9899d2298fd979b",
"data": {
"description": "Python utilities.ipynb",
"public": true
}
},
"_draft": {
"nbviewer_url": "https://gist.github.com/9a3744df66983045a9899d2298fd979b"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment