{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "> This is one of the 100 recipes of the [IPython Cookbook](http://ipython-books.github.io/), the definitive guide to high-performance scientific computing and data science in Python." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 5.12. Trying the Julia language in the notebook" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For this recipe, you need to install Julia and IJulia. You'll find the installation instructions in the book." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. We can't avoid the customary *Hello World* example. The `println()` function displays a string and adds a line break at the end." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "println(\"Hello world!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2. We create a polymorphic function `f` that computes the expression $z*z+c$. We will notably evaluate this function on arrays, so we use elementwise operators with a dot (`.`) prefix." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "f(z, c) = z.*z .+ c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "3. Let's evaluate `f` on scalar complex numbers (the imaginary number $i$ is `1im`)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "f(2.0 + 1.0im, 1.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "4. Now, we create a `(2, 2)` matrix. Components are separated by a space, rows are separated by a semicolon (`;`). The type of this `Array` is automatically inferred from its components. The `Array` type is a built-in data type in Julia, similar, but not identical, to NumPy's `ndarray` type." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "z = [-1.0 - 1.0im 1.0 - 1.0im;\n", " -1.0 + 1.0im 1.0 + 1.0im]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "5. We can index arrays with brackets `[]`. A notable difference with Python is that indexing starts from 1 instead of 0. MATLAB has the same convention. Besides, the keyword `end` refers to the last item in that dimension." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "z[1,end]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "6. We can evaluate `f` on the matrix `z` and a scalar `c` (polymorphism)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "f(z, 0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "7. Now, we create a function `julia` that computes a Julia set. Optional named arguments are separated from positional arguments by a semicolon (`;`). Julia's syntax for flow control is close from Python's, except that colons are dropped, indentation doesn't count, and block `end` keywords are mandatory." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "function julia(z, c; maxiter=200)\n", " for n = 1:maxiter\n", " if abs2(z) > 4.0\n", " return n-1\n", " end\n", " z = f(z, c)\n", " end\n", " return maxiter\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "8. We can use Python packages from Julia. First, we have to install the `PyCall` package by using Julia's built-in package manager (`Pkg`). Once the package is installed, we can use it in the interactive session with `using PyCall`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "Pkg.add(\"PyCall\")\n", "using PyCall" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "9. We can import Python packages with the `@pyimport` **macro** (a metaprogramming feature in Julia). This macro is the equivalent of Python's `import` command." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "@pyimport numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "10. The `np` namespace is now available in the Julia interactive session. NumPy arrays are automatically converted to Julia `Array`s." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "z = np.linspace(-1., 1., 100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "11. We can use list comprehensions to evaluate the function `julia` on many arguments." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "m = [julia(z[i], 0.5) for i=1:100]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "12. Let's try the Gadfly plotting package. This library offers a high-level plotting interface inspired by Grammar of Graphics. In the notebook, plots are interactive thanks to the **d3.js** library." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "Pkg.add(\"Gadfly\")\n", "using Gadfly" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "plot(x=1:100, y=m, Geom.point, Geom.line)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "13. Now, we compute a Julia set by using two nested loops. In general, and unlike Python, there is no significant performance penalty using `for` loops instead of vectorized operations in Julia. High-performance code can be written either with vectorized operations or `for` loops." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "@time m = [julia(complex(r, i), complex(-0.06, 0.67)) \n", " for i = 1:-.001:-1,\n", " r = -1.5:.001:1.5];" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "14. Finally, we use the `PyPlot` package to draw matplotlib figures in Julia." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "Pkg.add(\"PyPlot\")\n", "using PyPlot" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "imshow(m, cmap=\"RdGy\", \n", " extent=[-1.5, 1.5, -1, 1]);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> You'll find all the explanations, figures, references, and much more in the book (to be released later this summer).\n", "\n", "> [IPython Cookbook](http://ipython-books.github.io/), by [Cyrille Rossant](http://cyrille.rossant.net), Packt Publishing, 2014 (500 pages)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.2" } }, "nbformat": 4, "nbformat_minor": 0 }