├── installation ├── README.md ├── Install Julia Packages.md ├── Install IPython Notebook.md └── Install Julia.md ├── fractal_example ├── julia_set ├── julia_set.cpp └── Julia_sets_in_Python.ipynb ├── Index.ipynb ├── LICENSE.md ├── README.md ├── ∞. What's next.ipynb ├── 0. Why Julia.ipynb ├── 4. Performance in Julia.ipynb ├── 3. Example of defining a new type.ipynb ├── 6. Interoperability with Python and C.ipynb └── 5. Metaprogramming.ipynb /installation/README.md: -------------------------------------------------------------------------------- 1 | Note that **many of these installation instructions are now out of date**. 2 | -------------------------------------------------------------------------------- /fractal_example/julia_set: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/scipy_2014_julia/HEAD/fractal_example/julia_set -------------------------------------------------------------------------------- /fractal_example/julia_set.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int julia(complex z, complex c, int maxiter=200) { 6 | for (int n=1; n<=maxiter; n++) { 7 | //if ( (z.real()*z.real() + z.imag()*z.imag()) > 4.) { 8 | if (abs(z) > 2.) { 9 | return n-1; 10 | } 11 | 12 | z = z*z + c; 13 | } 14 | 15 | return maxiter; 16 | } 17 | 18 | int main() 19 | { 20 | for (double i=1; i >= -1; i -= 0.002) { 21 | for (double r=-1.5; r <= 1.5; r += 0.002) { 22 | julia(complex(r, i), complex(-.06, .67)); 23 | 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /installation/Install Julia Packages.md: -------------------------------------------------------------------------------- 1 | # Install Julia Packages 2 | 3 | Julia has a built-in package manager for installing add-on functionality written 4 | in Julia. There is already an impressive collection of packages. The list of 5 | registered Julia packages can be found at http://pkg.julialang.org. 6 | 7 | Run Julia from the command line by typing `julia` and install the following 8 | packages: 9 | 10 | ```Julia 11 | Pkg.update() 12 | Pkg.add("PyPlot") 13 | Pkg.add("Gadfly") 14 | Pkg.add("IJulia") 15 | ``` 16 | 17 | In Julia `Pkg.status()` prints a summary of the state of your local packages. 18 | The list of installed packages is provided by `Pkg.installed()`. `Pkg.update()` 19 | updates the installed packages and `Pkg.rm()` removes unwanted packages. 20 | 21 | 22 | # Test Julia and the installed packages 23 | 24 | Make the following shell script with the name `check-julia.sh`: 25 | 26 | ```Shell 27 | julia -e 'println("Hello, world!"); 28 | println("3 + 4 = ", 3 + 4); 29 | using PyPlot; 30 | plot(rand(10), rand(10), "-o"); 31 | savefig("test.pdf")' 32 | ``` 33 | 34 | Make it executable and execute it: 35 | ```Shell 36 | chmod +x check-julia.sh 37 | ./check-julia.sh 38 | ``` 39 | 40 | This should print the following and create a PDF called 'test.pdf' 41 | with a plot consisting of a few random points joined by lines. 42 | 43 | ```ShellSession 44 | Hello, world! 45 | 3 + 4 = 7 46 | INFO: Loading help data... 47 | ``` 48 | -------------------------------------------------------------------------------- /Index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Introduction to Julia\n", 8 | "\n", 9 | "This is an introdutory tutorial on the Julia programming language.\n", 10 | "\n", 11 | "Since it was first given at the SciPy 2014 conference, it has a slant towards people coming from Python, but it is designed to be accessible for anyone with a minimal amount of programming experience.\n", 12 | "\n", 13 | "We will cover the following topics:" 14 | ] 15 | }, 16 | { 17 | "cell_type": "markdown", 18 | "metadata": {}, 19 | "source": [ 20 | "- [0. Why Julia?](0. Why Julia.ipynb) (presentation)\n", 21 | "- Fractal examples \n", 22 | "- [1. Basic Julia syntax](1. Introduction to Julia.ipynb)\n", 23 | "- [2. Graphics and packages](2. Packages and graphics in Julia.ipynb)\n", 24 | "- [3. Defining a new type](3. Example of defining a new type.ipynb)\n", 25 | "- [4. Performance in Julia](4. Performance in Julia.ipynb)\n", 26 | "- [5. Metaprogramming](5. Metaprogramming.ipynb)\n", 27 | "- [6. Interoperability with Python and C](6. Interoperability with Python and C.ipynb)\n", 28 | "- [∞. Where to go next](∞. What's next.ipynb)" 29 | ] 30 | } 31 | ], 32 | "metadata": { 33 | "kernelspec": { 34 | "display_name": "Julia 0.4.6", 35 | "language": "julia", 36 | "name": "julia-0.4" 37 | }, 38 | "language_info": { 39 | "file_extension": ".jl", 40 | "mimetype": "application/julia", 41 | "name": "julia", 42 | "version": "0.4.6" 43 | }, 44 | "widgets": { 45 | "state": {}, 46 | "version": "1.1.2" 47 | } 48 | }, 49 | "nbformat": 4, 50 | "nbformat_minor": 0 51 | } 52 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The materials for the "Introduction to Julia" tutorial are licensed following licenses: 2 | 3 | - the **code** portions under the MIT "Expat" License; 4 | 5 | - **everything else** under the CC-by-SA 4.0 License: 6 | 7 | 8 | ## MIT "Expat" License for the code portions: 9 | 10 | > Copyright (c) 2014-2016: David Sanders. 11 | > 12 | > Permission is hereby granted, free of charge, to any person obtaining 13 | > a copy of this software and associated documentation files (the 14 | > "Software"), to deal in the Software without restriction, including 15 | > without limitation the rights to use, copy, modify, merge, publish, 16 | > distribute, sublicense, and/or sell copies of the Software, and to 17 | > permit persons to whom the Software is furnished to do so, subject to 18 | > the following conditions: 19 | > 20 | > The above copyright notice and this permission notice shall be 21 | > included in all copies or substantial portions of the Software. 22 | > 23 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 26 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 27 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 28 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 29 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ## CC by SA 4.0 for the non-code portions: 32 | 33 | Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. 34 | -------------------------------------------------------------------------------- /installation/Install IPython Notebook.md: -------------------------------------------------------------------------------- 1 | ## IPython Notebook 2 | The tutorial makes heavy use of the [IPython Notebook](http://ipython.org/notebook.html) using the 3 | [IJulia](https://github.com/JuliaLang/IJulia.jl) profile. IJulia requires IPython 1.0 or later. 4 | Thus, please make sure that the latest version of IPython is installed, including the IPython Notebook. 5 | 6 | [Installing IPython](http://ipython.org/install.html) and related scientific-Python packages 7 | differs by operating system and your want of control. On recent Linux distributions (e.g. ubuntu 14.04) 8 | a sufficiently recent `ipython-notebook` will be available through the package manager. On Mac and Windows the 9 | simplest way to install is by [downloading the Anaconda package](http://continuum.io/downloads) and 10 | running its installer. (Do *not* use Enthought Canopy/EPD.) 11 | 12 | **Important**: on Windows, the Anaconda installer window gives options *Add Anaconda to the System Path* and also *Register Anaconda as default Python version of the system*. Be sure to **check these boxes**. 13 | 14 | If you already have Python installed and are familiar with installing packages, you can get a brand-new 15 | IPython Notebook with pip: 16 | 17 | ```Shell 18 | pip install ipython[notebook] --upgrade 19 | ``` 20 | 21 | For more details and hints for troubleshooting have a look at [Julia at MIT](https://github.com/stevengj/julia-mit/blob/master/README.md#installing-julia-and-ijulia) 22 | 23 | 24 | ## Running Julia in the IJulia Notebook 25 | Assuming IPython Notebook (>= 1.0), Julia (>= 0.2) and the Julia Package IJulia are installed and working, 26 | open up the command line and type: 27 | 28 | ```Shell 29 | ipython notebook --profile julia 30 | ``` 31 | 32 | For less typing (on Mac and Linux) it's handy to create an alias in .bash_profile (Mac) or .bashrc (Linux): 33 | ```Shell 34 | alias ijulia="ipython notebook --profile julia" 35 | ``` 36 | 37 | More details regarding IJulia can be found at [Julia at MIT](https://github.com/stevengj/julia-mit/blob/master/README.md#running-julia-in-the-ijulia-notebook). 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction to Julia tutorial at SciPy 2014 2 | 3 | This tutorial was created by [David P. Sanders](http://sistemas.fciencias.unam.mx/~dsanders/), who gave it at the conference 4 | [SciPy 2014](https://conference.scipy.org/scipy2014/). Video recordings are 5 | available: [part 1](http://www.youtube.com/watch?v=vWkgEddb4-A) and 6 | [part 2](http://www.youtube.com/watch?v=I3JH5Bg46yU). 7 | 8 | The tutorial consists of a sequence of IJulia notebooks, i.e., IPython [now [Jupyter](http://jupyter.org/)] notebooks, using the IJulia profile. 9 | To follow the tutorial you need to have installed the [IPython Notebook](Install IPython Notebook.md) 10 | and the [Julia language](Install Julia.md), together with several 11 | [Julia packages](Install Julia Packages.md). It is best to install them in that order. 12 | 13 | **The version given at the Scipy 2014 conference (as recorded on the corresponding SciPy YouTube video) is v1.0; this can be obtained with `git checkout v1.0`. It has since been reformatted for ease of use.** 14 | 15 | **Note that some parts of this tutorial are out of date. See my Invitation to Julia and Intermediate Julia tutorials**. 16 | 17 | **Corrections should be sent as Pull Requests to this repository.** 18 | 19 | 20 | 21 | ## Getting started 22 | Invoke IJulia using the following command from a terminal; a window will open in your web browser: 23 | 24 | ```Shell 25 | ipython notebook --profile julia 26 | ``` 27 | 28 | Then start the tutorial in IPython Notebook from the [index](Index.ipynb). 29 | 30 | If you do not have IPython Notebook at hand you can view the tutorial online on 31 | [NbViewer](http://nbviewer.ipython.org/github/dpsanders/scipy_2014_julia/blob/master/Index.ipynb). 32 | 33 | Note that Julia can instead be started from the command line by typing `julia` or by double clicking on its icon. `quit()` or `Ctrl-D` ends the Julia session. 34 | 35 | --- 36 | Financial support is acknowledged from UNAM grants DGAPA-PAPIME PE-105911 and PE 37 | -107114 and DGAPA-PAPIIT IN-117214, as well as the SciPy 2014 conference. 38 | 39 | Thanks to Robert Nuske for help with installation instructions and this README. 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /installation/Install Julia.md: -------------------------------------------------------------------------------- 1 | # Installing Julia 2 | 3 | This tutorial is based on Julia version 0.3.0. The easiest 4 | way to install a recent version on Mac and Windows is to download 5 | the relevant installer from the respective section of [Julia Downloads](http://julialang.org/downloads/). 6 | Note that the version number is shown when you start up Julia. 7 | 8 | 9 | Packages for ubuntu are available from the PPA [staticfloat/julianightlies](https://launchpad.net/~staticfloat/+archive/ubuntu/julianightlies) 10 | which depends on the PPA [staticfloat/julia-deps](https://launchpad.net/~staticfloat/+archive/ubuntu/julia-deps). 11 | Add those two PPAs to your sources.list and install a brand-new Julia 12 | via the package manager. 13 | 14 | 15 | If you have previously installed an earlier version of Julia, 16 | the best idea is to remove the .julia directory from your home directory 17 | to have a clean install. 18 | 19 | 20 | ## Alternative: Installation from source 21 | An alternative is to compile Julia from the [source](https://github.com/JuliaLang/julia). 22 | This takes a while, and will need various development tools installed 23 | (git, gcc, g++, gfortran, m4). 24 | 25 | 26 | Download the source, change into the julia directory just created 27 | and build julia with make: 28 | 29 | ```Shell 30 | git clone https://github.com/JuliaLang/julia.git 31 | cd julia 32 | make -j 4 33 | ``` 34 | Here, `-j 4` builds with 4 threads in parallel (using 4 cores); this number should be changed to take account 35 | of the number of cores that your processor has. With 4 cores, building Julia from scratch takes around an hour. 36 | 37 | This may result in compilation errors that can be solved by using 38 | the normal `make` instead of the multicore version for the relevant section. 39 | 40 | If you have compilation errors related to LAPACK, read the instructions 41 | that will be shown during compilation for possible alternative compilation 42 | settings to try. 43 | 44 | 45 | ## Start and stop Julia 46 | To start a Julia type `julia` at the command line and `quit()` to end the session. 47 | 48 | ```ShellSession 49 | $ julia 50 | _ 51 | _ _ _(_)_ | A fresh approach to technical computing 52 | (_) | (_) (_) | Documentation: http://docs.julialang.org 53 | _ _ _| |_ __ _ | Type "help()" for help. 54 | | | | | | | |/ _` | | 55 | | | |_| | | | (_| | | Version 0.3.0-rc1+327 (2014-08-04 06:36 UTC) 56 | _/ |\__'_|_|_|\__'_| | Commit 03abf69 (4 days old master) 57 | |__/ | x86_64-linux-gnu 58 | 59 | julia> 1 + 1 60 | 2 61 | 62 | julia> quit() 63 | $ 64 | ``` 65 | 66 | -------------------------------------------------------------------------------- /fractal_example/Julia_sets_in_Python.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "", 4 | "signature": "sha256:c4dedeb2f8a9c86eca0c3ca85bf5b42d36a830fbcf7669c0ad8d7711f5b6bf3b" 5 | }, 6 | "nbformat": 3, 7 | "nbformat_minor": 0, 8 | "worksheets": [ 9 | { 10 | "cells": [ 11 | { 12 | "cell_type": "code", 13 | "collapsed": false, 14 | "input": [ 15 | "def julia(z, c, maxiter=200):\n", 16 | " for n in xrange(maxiter):\n", 17 | " if abs(z) > 4:\n", 18 | " return n-1\n", 19 | " \n", 20 | " z = z*z + c\n", 21 | " \n", 22 | " return maxiter\n" 23 | ], 24 | "language": "python", 25 | "metadata": {}, 26 | "outputs": [], 27 | "prompt_number": 1 28 | }, 29 | { 30 | "cell_type": "code", 31 | "collapsed": false, 32 | "input": [ 33 | "import numpy as np" 34 | ], 35 | "language": "python", 36 | "metadata": {}, 37 | "outputs": [], 38 | "prompt_number": 8 39 | }, 40 | { 41 | "cell_type": "code", 42 | "collapsed": false, 43 | "input": [ 44 | "#@time m = [ uint8(julia(complex(r,i), complex(-.06,.67))) for i=1:-.002:-1, r=-1.5:.002:1.5 ];" 45 | ], 46 | "language": "python", 47 | "metadata": {}, 48 | "outputs": [] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "collapsed": false, 53 | "input": [ 54 | "#X, Y = np.ogrid[1:-1:-.002, -1.5:1.5:.002]\n", 55 | "#m = [[ int(julia(complex(r,i), complex(-.06,.67))) for i in np.arange(1, 1,-.002)] \n", 56 | "# for r in np.arange(-1.5, 1.5, 0.002)];\n", 57 | "\n", 58 | "\n" 59 | ], 60 | "language": "python", 61 | "metadata": {}, 62 | "outputs": [], 63 | "prompt_number": 20 64 | }, 65 | { 66 | "cell_type": "code", 67 | "collapsed": false, 68 | "input": [ 69 | "%%time\n", 70 | "for i in np.r_[1:-1:-.002]:\n", 71 | " for r in np.r_[-1.5:1.5:0.002]:\n", 72 | " julia(complex(r,i), complex(-.06, .67))\n", 73 | " " 74 | ], 75 | "language": "python", 76 | "metadata": {}, 77 | "outputs": [ 78 | { 79 | "output_type": "stream", 80 | "stream": "stdout", 81 | "text": [ 82 | "CPU times: user 16.4 s, sys: 99.4 ms, total: 16.5 s\n", 83 | "Wall time: 16.5 s\n" 84 | ] 85 | } 86 | ], 87 | "prompt_number": 23 88 | }, 89 | { 90 | "cell_type": "code", 91 | "collapsed": false, 92 | "input": [], 93 | "language": "python", 94 | "metadata": {}, 95 | "outputs": [] 96 | } 97 | ], 98 | "metadata": {} 99 | } 100 | ] 101 | } -------------------------------------------------------------------------------- /∞. What's next.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language": "Julia", 4 | "name": "", 5 | "signature": "sha256:0ef6b1055ecdd54fa0e3f24b34bf32fc6b0b978eac7f191c120e8c248fb16f43" 6 | }, 7 | "nbformat": 3, 8 | "nbformat_minor": 0, 9 | "worksheets": [ 10 | { 11 | "cells": [ 12 | { 13 | "cell_type": "heading", 14 | "level": 1, 15 | "metadata": {}, 16 | "source": [ 17 | "What's next?" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "As Julia is a new language, there are relatively few resources for learning it.\n", 25 | "\n", 26 | "Useful learning resources are:\n", 27 | "\n", 28 | "- Leah Hanson's blog, with well-written explanations: \n", 29 | "\n", 30 | "- Learn Julia in a few minutes: \n", 31 | "\n", 32 | "There are a couple of books on Julia in preparation.\n", 33 | "\n", 34 | "\n", 35 | "The main reference manual is\n", 36 | "\n", 37 | "- The Julia Manual: \n", 38 | "\n", 39 | "\n", 40 | "\n", 41 | "The best place to get help with any problems is the julia-users Google group: \n", 42 | "\n", 43 | "The talks from the first JuliaCon conference should be online soon: " 44 | ] 45 | }, 46 | { 47 | "cell_type": "heading", 48 | "level": 2, 49 | "metadata": {}, 50 | "source": [ 51 | "Packages" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "Probably the easiest way to get started with Julia is to find a package which implements functionality of interest to you and start reading the source code.\n", 59 | "\n", 60 | "A rather random selection of interesting packages:" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "- `DataStructures.jl`: data structures\n", 68 | "- `Lazy.jl`: functional programming\n", 69 | "- `JuMP`: optimization library with domain-specific language for defining problems\n", 70 | "- `TaylorSeries`: $n$-dimensional Taylor series manipulation (I'm a minor co-author)\n" 71 | ] 72 | }, 73 | { 74 | "cell_type": "heading", 75 | "level": 2, 76 | "metadata": {}, 77 | "source": [ 78 | "Parallel processing" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "Julia was designed with various types of support for parallel processing. Launching Julia with `julia -p 4` will run Julia with 4 parallel threads. The `@parallel` macro does the necessary:" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "collapsed": false, 91 | "input": [ 92 | "nheads = @parallel (+) for i=1:200000000\n", 93 | " int(randbool())\n", 94 | "end" 95 | ], 96 | "language": "python", 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "metadata": {}, 101 | "output_type": "pyout", 102 | "prompt_number": 1, 103 | "text": [ 104 | "100001758" 105 | ] 106 | } 107 | ], 108 | "prompt_number": 1 109 | }, 110 | { 111 | "cell_type": "code", 112 | "collapsed": false, 113 | "input": [ 114 | "Pkg.update()" 115 | ], 116 | "language": "python", 117 | "metadata": {}, 118 | "outputs": [] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "collapsed": false, 123 | "input": [], 124 | "language": "python", 125 | "metadata": {}, 126 | "outputs": [] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "metadata": {}, 131 | "source": [ 132 | "For instance, the `ParallelSparseMatMul.jl` package uses this to do sparse matrix multiplication in parallel: " 133 | ] 134 | } 135 | ], 136 | "metadata": {} 137 | } 138 | ] 139 | } -------------------------------------------------------------------------------- /0. Why Julia.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "celltoolbar": "Slideshow", 4 | "language": "Julia", 5 | "name": "", 6 | "signature": "sha256:24cf265a84971ab62554f1c4918742e657f1c0600577f90e80e5fdabe9835a3b" 7 | }, 8 | "nbformat": 3, 9 | "nbformat_minor": 0, 10 | "worksheets": [ 11 | { 12 | "cells": [ 13 | { 14 | "cell_type": "heading", 15 | "level": 1, 16 | "metadata": { 17 | "slideshow": { 18 | "slide_type": "slide" 19 | } 20 | }, 21 | "source": [ 22 | "Why Julia?" 23 | ] 24 | }, 25 | { 26 | "cell_type": "heading", 27 | "level": 1, 28 | "metadata": { 29 | "slideshow": { 30 | "slide_type": "subslide" 31 | } 32 | }, 33 | "source": [ 34 | "Or: DIRHTLYAPL\n", 35 | "\n" 36 | ] 37 | }, 38 | { 39 | "cell_type": "heading", 40 | "level": 1, 41 | "metadata": { 42 | "slideshow": { 43 | "slide_type": "subslide" 44 | } 45 | }, 46 | "source": [ 47 | "\"Do I Really Have To Learn Yet Another Programming Language??\"" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": { 53 | "slideshow": { 54 | "slide_type": "fragment" 55 | } 56 | }, 57 | "source": [ 58 | "##David P. Sanders\n", 59 | "\n", 60 | "###Department of Physics, Faculty of Sciences\n", 61 | "###National University of Mexico (UNAM)\n", 62 | "\n", 63 | "###Twitter: @DavidPSanders\n", 64 | "###GitHub: dpsanders" 65 | ] 66 | }, 67 | { 68 | "cell_type": "heading", 69 | "level": 1, 70 | "metadata": { 71 | "slideshow": { 72 | "slide_type": "slide" 73 | } 74 | }, 75 | "source": [ 76 | "Advantages of Julia" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": { 82 | "slideshow": { 83 | "slide_type": "fragment" 84 | } 85 | }, 86 | "source": [ 87 | "Julia:\n", 88 | "\n", 89 | "- is interpreted, but (JIT-) compiled\n", 90 | "- is high-level and easy to learn\n", 91 | "\n", 92 | "\n", 93 | "- designed so easy to make fast from the start\n", 94 | "- is fast (~2--3x C speed)\n", 95 | "\n", 96 | "\n" 97 | ] 98 | }, 99 | { 100 | "cell_type": "markdown", 101 | "metadata": { 102 | "slideshow": { 103 | "slide_type": "subslide" 104 | } 105 | }, 106 | "source": [ 107 | "Julia:\n", 108 | "\n", 109 | "- has a sophisticated type system\n", 110 | "- but it is not *necessary* to talk about types\n", 111 | "\n", 112 | "- has *multiple dispatch*: functions specialised on the types of their arguments\n", 113 | "\n", 114 | "\n", 115 | "- has sophisticated *metaprogramming* (macros) for generating code programatically\n", 116 | "- allow the creation of domain-specific languages\n" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": { 122 | "slideshow": { 123 | "slide_type": "subslide" 124 | } 125 | }, 126 | "source": [ 127 | "Julia:\n", 128 | "\n", 129 | "- most of the standard library is implemented *in Julia itself* \n", 130 | "\n", 131 | "- avoids the infamous \"two-language problem\"\n", 132 | "\n", 133 | "- \"users are developers\"\n" 134 | ] 135 | }, 136 | { 137 | "cell_type": "heading", 138 | "level": 1, 139 | "metadata": { 140 | "slideshow": { 141 | "slide_type": "slide" 142 | } 143 | }, 144 | "source": [ 145 | "Using Julia" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "metadata": { 151 | "slideshow": { 152 | "slide_type": "subslide" 153 | } 154 | }, 155 | "source": [ 156 | "- From the REPL (Read--Eval--Print Loop):\n", 157 | "\n", 158 | " julia\n", 159 | " \n", 160 | " \n", 161 | "- Inside IJulia (IPython interface with Julia kernel):\n", 162 | "\n", 163 | " ipython notebook --profile julia\n", 164 | "\n", 165 | "\n", 166 | "- Inside an IDE, e.g. LightTable + Jewel + Juno/Jupiter; Julia Studio" 167 | ] 168 | }, 169 | { 170 | "cell_type": "heading", 171 | "level": 1, 172 | "metadata": { 173 | "slideshow": { 174 | "slide_type": "slide" 175 | } 176 | }, 177 | "source": [ 178 | "Getting help with Julia" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": { 184 | "slideshow": { 185 | "slide_type": "fragment" 186 | } 187 | }, 188 | "source": [ 189 | "- Julia manual: \n", 190 | "\n", 191 | "- julia-users mailing list: " 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "collapsed": false, 197 | "input": [ 198 | ";ipython nbconvert Why\\ Julia.ipynb --to slides --post serve" 199 | ], 200 | "language": "python", 201 | "metadata": { 202 | "slideshow": { 203 | "slide_type": "skip" 204 | } 205 | }, 206 | "outputs": [] 207 | } 208 | ], 209 | "metadata": {} 210 | } 211 | ] 212 | } -------------------------------------------------------------------------------- /4. Performance in Julia.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language": "Julia", 4 | "name": "", 5 | "signature": "sha256:d626340af21f8d147b9383b7356827d91ec39cb12d353836849107f24b740e24" 6 | }, 7 | "nbformat": 3, 8 | "nbformat_minor": 0, 9 | "worksheets": [ 10 | { 11 | "cells": [ 12 | { 13 | "cell_type": "heading", 14 | "level": 1, 15 | "metadata": {}, 16 | "source": [ 17 | "Design considerations" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "As a JIT (\"Just in Time\")-compiled language, Julia is designed for good performance. Currently, it is usually expected that it should usually be able to reach speeds within at most a factor of 2 of that of corresponding C code.\n", 25 | "\n", 26 | "However, to attain decent performance, there are certain principles that must be used in code; see the [Performance tips](http://julia.readthedocs.org/en/latest/manual/performance-tips/) section of the Julia manual for more details." 27 | ] 28 | }, 29 | { 30 | "cell_type": "heading", 31 | "level": 2, 32 | "metadata": {}, 33 | "source": [ 34 | "Profiling" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "When profiling, always run each function once with the correct argument types before timing it, since the first time it is run the compilation time will play a large role." 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "collapsed": false, 47 | "input": [ 48 | "Pkg.update()" 49 | ], 50 | "language": "python", 51 | "metadata": {}, 52 | "outputs": [ 53 | { 54 | "output_type": "stream", 55 | "stream": "stderr", 56 | "text": [ 57 | "INFO: Updating METADATA...\n" 58 | ] 59 | }, 60 | { 61 | "output_type": "stream", 62 | "stream": "stderr", 63 | "text": [ 64 | "INFO: Updating cache of Compose...\n" 65 | ] 66 | }, 67 | { 68 | "output_type": "stream", 69 | "stream": "stderr", 70 | "text": [ 71 | "INFO: Updating cache of Gadfly...\n" 72 | ] 73 | }, 74 | { 75 | "output_type": "stream", 76 | "stream": "stderr", 77 | "text": [ 78 | "INFO: Computing changes...\n" 79 | ] 80 | }, 81 | { 82 | "output_type": "stream", 83 | "stream": "stderr", 84 | "text": [ 85 | "INFO: Cloning cache of Contour from git://github.com/tlycken/Contour.jl.git\n" 86 | ] 87 | }, 88 | { 89 | "output_type": "stream", 90 | "stream": "stderr", 91 | "text": [ 92 | "INFO: Upgrading Compose: v0.3.0 => v0.3.1\n" 93 | ] 94 | }, 95 | { 96 | "output_type": "stream", 97 | "stream": "stderr", 98 | "text": [ 99 | "INFO: Installing Contour v0.0.1\n" 100 | ] 101 | }, 102 | { 103 | "output_type": "stream", 104 | "stream": "stderr", 105 | "text": [ 106 | "INFO: Upgrading Gadfly: v0.3.0 => v0.3.1\n" 107 | ] 108 | }, 109 | { 110 | "output_type": "stream", 111 | "stream": "stderr", 112 | "text": [ 113 | "INFO: Building Datetime\n" 114 | ] 115 | } 116 | ], 117 | "prompt_number": 1 118 | }, 119 | { 120 | "cell_type": "code", 121 | "collapsed": false, 122 | "input": [ 123 | "@time sin(10)" 124 | ], 125 | "language": "python", 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "output_type": "stream", 130 | "stream": "stdout", 131 | "text": [ 132 | "elapsed time: 6" 133 | ] 134 | }, 135 | { 136 | "output_type": "stream", 137 | "stream": "stdout", 138 | "text": [ 139 | ".941e-6 seconds (96 bytes allocated)\n" 140 | ] 141 | }, 142 | { 143 | "metadata": {}, 144 | "output_type": "pyout", 145 | "prompt_number": 2, 146 | "text": [ 147 | "-0.5440211108893698" 148 | ] 149 | } 150 | ], 151 | "prompt_number": 2 152 | }, 153 | { 154 | "cell_type": "code", 155 | "collapsed": false, 156 | "input": [ 157 | "a = 3" 158 | ], 159 | "language": "python", 160 | "metadata": {}, 161 | "outputs": [ 162 | { 163 | "metadata": {}, 164 | "output_type": "pyout", 165 | "prompt_number": 3, 166 | "text": [ 167 | "3" 168 | ] 169 | } 170 | ], 171 | "prompt_number": 3 172 | }, 173 | { 174 | "cell_type": "heading", 175 | "level": 2, 176 | "metadata": {}, 177 | "source": [ 178 | "No global variables please!" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": {}, 184 | "source": [ 185 | "Global variables are slow in Julia: **do not use global variables!**\n", 186 | "\n", 187 | "Your main program should be wrapped in a function.\n", 188 | "Any time you are tempted to use globals, just send them as arguments to functions, and return them if necessary.\n", 189 | "\n", 190 | "If you have many variables to pass around, wrap them in a type, e.g. called `State`" 191 | ] 192 | }, 193 | { 194 | "cell_type": "heading", 195 | "level": 2, 196 | "metadata": {}, 197 | "source": [ 198 | "Type stability" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "metadata": {}, 204 | "source": [ 205 | "The second important idea for gaining performance is that of *type stability*.\n", 206 | "\n", 207 | "Any calculation will be immediately slowed down by having variables which can change type during a calculation, simply due to the extra work that must be done at run-time to check the type of the variables. (This is one of the main reasons for the slowness of Python and the necessity for type declarations in Cython to gain speed.)" 208 | ] 209 | }, 210 | { 211 | "cell_type": "markdown", 212 | "metadata": {}, 213 | "source": [ 214 | "A simple example (due to Leah Hanson) is the following pair of almost-identical functions:" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "collapsed": false, 220 | "input": [ 221 | "function sum1(N::Int)\n", 222 | " total = 0\n", 223 | " \n", 224 | " for i in 1:N\n", 225 | " total += i/2\n", 226 | " end\n", 227 | " \n", 228 | " total\n", 229 | "end\n", 230 | "\n", 231 | "function sum2(N::Int)\n", 232 | " total = 0.0\n", 233 | " \n", 234 | " for i in 1:N\n", 235 | " total += i/2\n", 236 | " end\n", 237 | " \n", 238 | " total\n", 239 | "end" 240 | ], 241 | "language": "python", 242 | "metadata": {}, 243 | "outputs": [ 244 | { 245 | "metadata": {}, 246 | "output_type": "pyout", 247 | "prompt_number": 4, 248 | "text": [ 249 | "sum2 (generic function with 1 method)" 250 | ] 251 | } 252 | ], 253 | "prompt_number": 4 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "metadata": {}, 258 | "source": [ 259 | "We must first run the functions once each to compile them, before looking at any timings:" 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "collapsed": false, 265 | "input": [ 266 | "sum1(10), sum2(10)" 267 | ], 268 | "language": "python", 269 | "metadata": {}, 270 | "outputs": [ 271 | { 272 | "metadata": {}, 273 | "output_type": "pyout", 274 | "prompt_number": 5, 275 | "text": [ 276 | "(27.5,27.5)" 277 | ] 278 | } 279 | ], 280 | "prompt_number": 5 281 | }, 282 | { 283 | "cell_type": "markdown", 284 | "metadata": {}, 285 | "source": [ 286 | "[Happily, they produce the same result!]" 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "collapsed": false, 292 | "input": [ 293 | "N = 10000000\n", 294 | "\n", 295 | "@time sum1(N)\n", 296 | "@time sum2(N)" 297 | ], 298 | "language": "python", 299 | "metadata": {}, 300 | "outputs": [ 301 | { 302 | "output_type": "stream", 303 | "stream": "stdout", 304 | "text": [ 305 | "elapsed time: 0." 306 | ] 307 | }, 308 | { 309 | "output_type": "stream", 310 | "stream": "stdout", 311 | "text": [ 312 | "656544448 seconds (320108552 bytes allocated, 36.27% gc time)\n", 313 | "elapsed time: 0.039772714 seconds (96 bytes allocated)\n" 314 | ] 315 | }, 316 | { 317 | "metadata": {}, 318 | "output_type": "pyout", 319 | "prompt_number": 6, 320 | "text": [ 321 | "2.50000025e13" 322 | ] 323 | } 324 | ], 325 | "prompt_number": 6 326 | }, 327 | { 328 | "cell_type": "markdown", 329 | "metadata": {}, 330 | "source": [ 331 | "The second version is consistently over **10 times faster** than the first version, due simply to type stability. It also allocates almost no memory. The first version allocates an enormous amount of memory (in fact, it is allocating and deallocating all the time), and spends a large fraction of its time in garbage collection." 332 | ] 333 | }, 334 | { 335 | "cell_type": "markdown", 336 | "metadata": {}, 337 | "source": [ 338 | "To help with type stability, there are functions `zero(x)` and `one(x)` that return the correctly-typed zero and one with the same type as the variable `x`:" 339 | ] 340 | }, 341 | { 342 | "cell_type": "markdown", 343 | "metadata": {}, 344 | "source": [ 345 | "Packages: `Lint.jl`, `TypeCheck.jl`" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "collapsed": false, 351 | "input": [ 352 | "x = 1\n", 353 | "zero(x)" 354 | ], 355 | "language": "python", 356 | "metadata": {}, 357 | "outputs": [ 358 | { 359 | "metadata": {}, 360 | "output_type": "pyout", 361 | "prompt_number": 2, 362 | "text": [ 363 | "0" 364 | ] 365 | } 366 | ], 367 | "prompt_number": 2 368 | }, 369 | { 370 | "cell_type": "code", 371 | "collapsed": false, 372 | "input": [ 373 | "y = 0.5\n", 374 | "zero(y)" 375 | ], 376 | "language": "python", 377 | "metadata": {}, 378 | "outputs": [ 379 | { 380 | "metadata": {}, 381 | "output_type": "pyout", 382 | "prompt_number": 7, 383 | "text": [ 384 | "0.0" 385 | ] 386 | } 387 | ], 388 | "prompt_number": 7 389 | }, 390 | { 391 | "cell_type": "code", 392 | "collapsed": false, 393 | "input": [ 394 | "x = BigFloat(\"0.1\")\n", 395 | "one(x)" 396 | ], 397 | "language": "python", 398 | "metadata": {}, 399 | "outputs": [ 400 | { 401 | "metadata": {}, 402 | "output_type": "pyout", 403 | "prompt_number": 8, 404 | "text": [ 405 | "1e+00 with 256 bits of precision" 406 | ] 407 | } 408 | ], 409 | "prompt_number": 8 410 | }, 411 | { 412 | "cell_type": "heading", 413 | "level": 2, 414 | "metadata": {}, 415 | "source": [ 416 | "Exploring the guts" 417 | ] 418 | }, 419 | { 420 | "cell_type": "markdown", 421 | "metadata": {}, 422 | "source": [ 423 | "Julia gives us access to basically every step in the compilation process:" 424 | ] 425 | }, 426 | { 427 | "cell_type": "code", 428 | "collapsed": false, 429 | "input": [ 430 | "code_lowered(sum1, (Int,))" 431 | ], 432 | "language": "python", 433 | "metadata": {}, 434 | "outputs": [ 435 | { 436 | "metadata": {}, 437 | "output_type": "pyout", 438 | "prompt_number": 34, 439 | "text": [ 440 | "1-element Array{Any,1}:\n", 441 | " :($(Expr(:lambda, {:N}, {{:total,:#s246,:#s245,:#s244,:i},{{:N,:Any,0},{:total,:Any,2},{:#s246,:Any,18},{:#s245,:Any,2},{:#s244,:Any,18},{:i,:Any,18}},{}}, :(begin # In[23], line 2:\n", 442 | " total = 0 # line 4:\n", 443 | " #s246 = colon(1,N)\n", 444 | " #s245 = top(start)(#s246)\n", 445 | " unless top(!)(top(done)(#s246,#s245)) goto 1\n", 446 | " 2: \n", 447 | " #s244 = top(next)(#s246,#s245)\n", 448 | " i = top(tupleref)(#s244,1)\n", 449 | " #s245 = top(tupleref)(#s244,2) # line 5:\n", 450 | " total = total + i / 2\n", 451 | " 3: \n", 452 | " unless top(!)(top(!)(top(done)(#s246,#s245))) goto 2\n", 453 | " 1: \n", 454 | " 0: # line 8:\n", 455 | " return total\n", 456 | " end))))" 457 | ] 458 | } 459 | ], 460 | "prompt_number": 34 461 | }, 462 | { 463 | "cell_type": "code", 464 | "collapsed": false, 465 | "input": [ 466 | "code_lowered(sum2, (Int,))" 467 | ], 468 | "language": "python", 469 | "metadata": {}, 470 | "outputs": [ 471 | { 472 | "metadata": {}, 473 | "output_type": "pyout", 474 | "prompt_number": 35, 475 | "text": [ 476 | "1-element Array{Any,1}:\n", 477 | " :($(Expr(:lambda, {:N}, {{:total,:#s246,:#s245,:#s244,:i},{{:N,:Any,0},{:total,:Any,2},{:#s246,:Any,18},{:#s245,:Any,2},{:#s244,:Any,18},{:i,:Any,18}},{}}, :(begin # In[23], line 12:\n", 478 | " total = 0.0 # line 14:\n", 479 | " #s246 = colon(1,N)\n", 480 | " #s245 = top(start)(#s246)\n", 481 | " unless top(!)(top(done)(#s246,#s245)) goto 1\n", 482 | " 2: \n", 483 | " #s244 = top(next)(#s246,#s245)\n", 484 | " i = top(tupleref)(#s244,1)\n", 485 | " #s245 = top(tupleref)(#s244,2) # line 15:\n", 486 | " total = total + i / 2\n", 487 | " 3: \n", 488 | " unless top(!)(top(!)(top(done)(#s246,#s245))) goto 2\n", 489 | " 1: \n", 490 | " 0: # line 18:\n", 491 | " return total\n", 492 | " end))))" 493 | ] 494 | } 495 | ], 496 | "prompt_number": 35 497 | }, 498 | { 499 | "cell_type": "code", 500 | "collapsed": false, 501 | "input": [ 502 | "code_typed(sum1, (Int,))" 503 | ], 504 | "language": "python", 505 | "metadata": {}, 506 | "outputs": [ 507 | { 508 | "metadata": {}, 509 | "output_type": "pyout", 510 | "prompt_number": 36, 511 | "text": [ 512 | "1-element Array{Any,1}:\n", 513 | " :($(Expr(:lambda, {:N}, {{:total,:#s246,:#s245,:#s244,:i,:_var0,:_var1},{{:N,Int64,0},{:total,Any,2},{:#s246,UnitRange{Int64},18},{:#s245,Int64,2},{:#s244,(Int64,Int64),18},{:i,Int64,18},{:_var0,Int64,18},{:_var1,Int64,18}},{}}, :(begin # In[23], line 2:\n", 514 | " total = 0 # line 4:\n", 515 | " #s246 = $(Expr(:new, UnitRange{Int64}, 1, :(top(getfield)(Intrinsics,:select_value)(top(sle_int)(1,N::Int64)::Bool,N::Int64,top(box)(Int64,top(sub_int)(1,1))::Int64)::Int64)))::UnitRange{Int64}\n", 516 | " #s245 = top(getfield)(#s246::UnitRange{Int64},:start)::Int64\n", 517 | " unless top(box)(Bool,top(not_int)(#s245::Int64 === top(box)(Int64,top(add_int)(top(getfield)(#s246::UnitRange{Int64},:stop)::Int64,1))::Int64::Bool))::Bool goto 1\n", 518 | " 2: \n", 519 | " _var0 = #s245::Int64\n", 520 | " _var1 = top(box)(Int64,top(add_int)(#s245::Int64,1))::Int64\n", 521 | " i = _var0::Int64\n", 522 | " #s245 = _var1::Int64 # line 5:\n", 523 | " total = total::Union(Int64,Float64) + top(box)(Float64,top(div_float)(top(box)(Float64,top(sitofp)(Float64,i::Int64))::Float64,top(box)(Float64,top(sitofp)(Float64,2))::Float64))::Float64::Float64\n", 524 | " 3: \n", 525 | " unless top(box)(Bool,top(not_int)(top(box)(Bool,top(not_int)(#s245::Int64 === top(box)(Int64,top(add_int)(top(getfield)(#s246::UnitRange{Int64},:stop)::Int64,1))::Int64::Bool))::Bool))::Bool goto 2\n", 526 | " 1: \n", 527 | " 0: # line 8:\n", 528 | " return total::Union(Int64,Float64)\n", 529 | " end::Union(Int64,Float64)))))" 530 | ] 531 | } 532 | ], 533 | "prompt_number": 36 534 | }, 535 | { 536 | "cell_type": "code", 537 | "collapsed": false, 538 | "input": [ 539 | "code_typed(sum2, (Int,))" 540 | ], 541 | "language": "python", 542 | "metadata": {}, 543 | "outputs": [ 544 | { 545 | "metadata": {}, 546 | "output_type": "pyout", 547 | "prompt_number": 37, 548 | "text": [ 549 | "1-element Array{Any,1}:\n", 550 | " :($(Expr(:lambda, {:N}, {{:total,:#s246,:#s245,:#s244,:i,:_var0,:_var1},{{:N,Int64,0},{:total,Float64,2},{:#s246,UnitRange{Int64},18},{:#s245,Int64,2},{:#s244,(Int64,Int64),18},{:i,Int64,18},{:_var0,Int64,18},{:_var1,Int64,18}},{}}, :(begin # In[23], line 12:\n", 551 | " total = 0.0 # line 14:\n", 552 | " #s246 = $(Expr(:new, UnitRange{Int64}, 1, :(top(getfield)(Intrinsics,:select_value)(top(sle_int)(1,N::Int64)::Bool,N::Int64,top(box)(Int64,top(sub_int)(1,1))::Int64)::Int64)))::UnitRange{Int64}\n", 553 | " #s245 = top(getfield)(#s246::UnitRange{Int64},:start)::Int64\n", 554 | " unless top(box)(Bool,top(not_int)(#s245::Int64 === top(box)(Int64,top(add_int)(top(getfield)(#s246::UnitRange{Int64},:stop)::Int64,1))::Int64::Bool))::Bool goto 1\n", 555 | " 2: \n", 556 | " _var0 = #s245::Int64\n", 557 | " _var1 = top(box)(Int64,top(add_int)(#s245::Int64,1))::Int64\n", 558 | " i = _var0::Int64\n", 559 | " #s245 = _var1::Int64 # line 15:\n", 560 | " total = top(box)(Float64,top(add_float)(total::Float64,top(box)(Float64,top(div_float)(top(box)(Float64,top(sitofp)(Float64,i::Int64))::Float64,top(box)(Float64,top(sitofp)(Float64,2))::Float64))::Float64))::Float64\n", 561 | " 3: \n", 562 | " unless top(box)(Bool,top(not_int)(top(box)(Bool,top(not_int)(#s245::Int64 === top(box)(Int64,top(add_int)(top(getfield)(#s246::UnitRange{Int64},:stop)::Int64,1))::Int64::Bool))::Bool))::Bool goto 2\n", 563 | " 1: \n", 564 | " 0: # line 18:\n", 565 | " return total::Float64\n", 566 | " end::Float64))))" 567 | ] 568 | } 569 | ], 570 | "prompt_number": 37 571 | }, 572 | { 573 | "cell_type": "code", 574 | "collapsed": false, 575 | "input": [ 576 | "code_llvm(sum1, (Int, ))" 577 | ], 578 | "language": "python", 579 | "metadata": {}, 580 | "outputs": [ 581 | { 582 | "output_type": "stream", 583 | "stream": "stdout", 584 | "text": [ 585 | "\n", 586 | "define %jl_value_t* @\"julia_sum1;19538\"(i64) {\n", 587 | "top:\n", 588 | " %1 = alloca [5 x %jl_value_t*], align 8\n", 589 | " %.sub = getelementptr inbounds [5 x %jl_value_t*]* %1, i64 0, i64 0\n", 590 | " %2 = getelementptr [5 x %jl_value_t*]* %1, i64 0, i64 2, !dbg !2590\n", 591 | " store %jl_value_t* inttoptr (i64 6 to %jl_value_t*), %jl_value_t** %.sub, align 8\n", 592 | " %3 = load %jl_value_t*** @jl_pgcstack, align 8, !dbg !2590\n", 593 | " %4 = getelementptr [5 x %jl_value_t*]* %1, i64 0, i64 1, !dbg !2590\n", 594 | " %.c = bitcast %jl_value_t** %3 to %jl_value_t*, !dbg !2590\n", 595 | " store %jl_value_t* %.c, %jl_value_t** %4, align 8, !dbg !2590\n", 596 | " store %jl_value_t** %.sub, %jl_value_t*** @jl_pgcstack, align 8, !dbg !2590\n", 597 | " %5 = getelementptr [5 x %jl_value_t*]* %1, i64 0, i64 3\n", 598 | " store %jl_value_t* null, %jl_value_t** %5, align 8\n", 599 | " %6 = getelementptr [5 x %jl_value_t*]* %1, i64 0, i64 4\n", 600 | " store %jl_value_t* null, %jl_value_t** %6, align 8\n", 601 | " store %jl_value_t* inttoptr (i64 140474354759232 to %jl_value_t*), %jl_value_t** %2, align 8, !dbg !2591\n", 602 | " %7 = icmp sgt i64 %0, 0, !dbg !2592\n", 603 | " br i1 %7, label %L, label %L3, !dbg !2592\n", 604 | "\n", 605 | "L: ; preds = %top, %L\n", 606 | " %8 = phi %jl_value_t* [ %16, %L ], [ inttoptr (i64 140474354759232 to %jl_value_t*), %top ], !dbg !2592\n", 607 | " %\"#s245.0\" = phi i64 [ %9, %L ], [ 1, %top ]\n", 608 | " %9 = add i64 %\"#s245.0\", 1, !dbg !2592\n", 609 | " store %jl_value_t* %8, %jl_value_t** %5, align 8, !dbg !2593\n", 610 | " %10 = sitofp i64 %\"#s245.0\" to double, !dbg !2593\n", 611 | " %11 = fmul double %10, 5.000000e-01, !dbg !2593\n", 612 | " %12 = call %jl_value_t* @alloc_2w(), !dbg !2593\n", 613 | " %13 = getelementptr inbounds %jl_value_t* %12, i64 0, i32 0, !dbg !2593\n", 614 | " store %jl_value_t* inttoptr (i64 140474354684320 to %jl_value_t*), %jl_value_t** %13, align 8, !dbg !2593\n", 615 | " %14 = getelementptr inbounds %jl_value_t* %12, i64 1, i32 0, !dbg !2593\n", 616 | " %15 = bitcast %jl_value_t** %14 to double*, !dbg !2593\n", 617 | " store double %11, double* %15, align 8, !dbg !2593\n", 618 | " store %jl_value_t* %12, %jl_value_t** %6, align 8, !dbg !2593\n", 619 | " %16 = call %jl_value_t* @jl_apply_generic(%jl_value_t* inttoptr (i64 140474385387040 to %jl_value_t*), %jl_value_t** %5, i32 2), !dbg !2593\n", 620 | " store %jl_value_t* %16, %jl_value_t** %2, align 8, !dbg !2593\n", 621 | " %17 = icmp eq i64 %\"#s245.0\", %0, !dbg !2593\n", 622 | " br i1 %17, label %L3, label %L, !dbg !2593\n", 623 | "\n", 624 | "L3: ; preds = %L, %top\n", 625 | " %18 = phi %jl_value_t* [ inttoptr (i64 140474354759232 to %jl_value_t*), %top ], [ %16, %L ]\n", 626 | " %19 = load %jl_value_t** %4, align 8, !dbg !2594\n", 627 | " %20 = getelementptr inbounds %jl_value_t* %19, i64 0, i32 0, !dbg !2594\n", 628 | " store %jl_value_t** %20, %jl_value_t*** @jl_pgcstack, align 8, !dbg !2594\n", 629 | " ret %jl_value_t* %18, !dbg !2594\n", 630 | "}\n" 631 | ] 632 | } 633 | ], 634 | "prompt_number": 38 635 | }, 636 | { 637 | "cell_type": "code", 638 | "collapsed": false, 639 | "input": [ 640 | "code_native(sum1, (Int,))" 641 | ], 642 | "language": "python", 643 | "metadata": {}, 644 | "outputs": [ 645 | { 646 | "output_type": "stream", 647 | "stream": "stdout", 648 | "text": [ 649 | "\t.section\t__TEXT,__text,regular,pure_instructions\n", 650 | "Filename: In[23]\n", 651 | "Source line: 2\n", 652 | "\tpush\tRBP\n", 653 | "\tmov\tRBP, RSP\n", 654 | "\tpush\tR15\n", 655 | "\tpush\tR14\n", 656 | "\tpush\tR13\n", 657 | "\tpush\tR12\n", 658 | "\tpush\tRBX\n", 659 | "\tsub\tRSP, 56\n", 660 | "\tmov\tR12, RDI\n", 661 | "\tmov\tQWORD PTR [RBP - 80], 6\n", 662 | "Source line: 2\n", 663 | "\tmovabs\tRCX, 4463631920\n", 664 | "\tmov\tRAX, QWORD PTR [RCX]\n", 665 | "\tmov\tQWORD PTR [RBP - 72], RAX\n", 666 | "\tlea\tRAX, QWORD PTR [RBP - 80]\n", 667 | "\tmov\tQWORD PTR [RCX], RAX\n", 668 | "\tmov\tQWORD PTR [RBP - 56], 0\n", 669 | "\tmov\tQWORD PTR [RBP - 48], 0\n", 670 | "\tmovabs\tRAX, 140474354759232\n", 671 | "Source line: 2\n", 672 | "\tmov\tQWORD PTR [RBP - 64], RAX\n", 673 | "\ttest\tR12, R12\n", 674 | "\tjle\t121\n", 675 | "\tmov\tEBX, 1\n", 676 | "Source line: 5\n", 677 | "\tmovabs\tR13, 4451150720\n", 678 | "\tmovabs\tR15, 140474354684320\n", 679 | "\tmovabs\tRCX, 4605169152\n", 680 | "\tvmovsd\tXMM0, QWORD PTR [RCX]\n", 681 | "\tvmovsd\tQWORD PTR [RBP - 88], XMM0\n", 682 | "\tmovabs\tR14, 4450807376\n", 683 | "\tmov\tQWORD PTR [RBP - 56], RAX\n", 684 | "\tcall\tR13\n", 685 | "\tmov\tQWORD PTR [RAX], R15\n", 686 | "\tvcvtsi2sd\tXMM0, XMM0, RBX\n", 687 | "\tvmulsd\tXMM0, XMM0, QWORD PTR [RBP - 88]\n", 688 | "\tvmovsd\tQWORD PTR [RAX + 8], XMM0\n", 689 | "\tmov\tQWORD PTR [RBP - 48], RAX\n", 690 | "\tmovabs\tRDI, 140474385387040\n", 691 | "\tlea\tRSI, QWORD PTR [RBP - 56]\n", 692 | "\tmov\tEDX, 2\n", 693 | "\tcall\tR14\n", 694 | "Source line: 4\n", 695 | "\tinc\tRBX\n", 696 | "Source line: 5\n", 697 | "\tdec\tR12\n", 698 | "\tmov\tQWORD PTR [RBP - 64], RAX\n", 699 | "\tjne\t-67\n", 700 | "Source line: 8\n", 701 | "\tmov\tRCX, QWORD PTR [RBP - 72]\n", 702 | "Source line: 2\n", 703 | "\tmovabs\tRDX, 4463631920\n", 704 | "Source line: 8\n", 705 | "\tmov\tQWORD PTR [RDX], RCX\n", 706 | "\tadd\tRSP, 56\n", 707 | "\tpop\tRBX\n", 708 | "\tpop\tR12\n", 709 | "\tpop\tR13\n", 710 | "\tpop\tR14\n", 711 | "\tpop\tR15\n", 712 | "\tpop\tRBP\n", 713 | "\tret\n" 714 | ] 715 | } 716 | ], 717 | "prompt_number": 39 718 | }, 719 | { 720 | "cell_type": "heading", 721 | "level": 1, 722 | "metadata": {}, 723 | "source": [ 724 | "Profiling" 725 | ] 726 | }, 727 | { 728 | "cell_type": "markdown", 729 | "metadata": {}, 730 | "source": [ 731 | "Simple profiling of a function may be achieved using the `@time` macro\n", 732 | "\n", 733 | "A detailed profile may be obtained using `@profile`.\n", 734 | "\n", 735 | "A graphical view is available via the `ProfileView.jl` package." 736 | ] 737 | }, 738 | { 739 | "cell_type": "code", 740 | "collapsed": false, 741 | "input": [ 742 | "@profile sum1(10000000)" 743 | ], 744 | "language": "python", 745 | "metadata": {}, 746 | "outputs": [ 747 | { 748 | "metadata": {}, 749 | "output_type": "pyout", 750 | "prompt_number": 10, 751 | "text": [ 752 | "2.50000025e13" 753 | ] 754 | } 755 | ], 756 | "prompt_number": 10 757 | }, 758 | { 759 | "cell_type": "code", 760 | "collapsed": false, 761 | "input": [ 762 | "f(N) = sum1(N)" 763 | ], 764 | "language": "python", 765 | "metadata": {}, 766 | "outputs": [ 767 | { 768 | "metadata": {}, 769 | "output_type": "pyout", 770 | "prompt_number": 11, 771 | "text": [ 772 | "f (generic function with 1 method)" 773 | ] 774 | } 775 | ], 776 | "prompt_number": 11 777 | }, 778 | { 779 | "cell_type": "code", 780 | "collapsed": false, 781 | "input": [ 782 | "@profile f(10000000)" 783 | ], 784 | "language": "python", 785 | "metadata": {}, 786 | "outputs": [ 787 | { 788 | "metadata": {}, 789 | "output_type": "pyout", 790 | "prompt_number": 12, 791 | "text": [ 792 | "2.50000025e13" 793 | ] 794 | } 795 | ], 796 | "prompt_number": 12 797 | }, 798 | { 799 | "cell_type": "code", 800 | "collapsed": false, 801 | "input": [], 802 | "language": "python", 803 | "metadata": {}, 804 | "outputs": [] 805 | } 806 | ], 807 | "metadata": {} 808 | } 809 | ] 810 | } -------------------------------------------------------------------------------- /3. Example of defining a new type.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language": "Julia", 4 | "name": "", 5 | "signature": "sha256:4e92abd6972541e00a90b8f54ac8aeb68b9188cb61c4e9588769b9907b1eb623" 6 | }, 7 | "nbformat": 3, 8 | "nbformat_minor": 0, 9 | "worksheets": [ 10 | { 11 | "cells": [ 12 | { 13 | "cell_type": "heading", 14 | "level": 1, 15 | "metadata": {}, 16 | "source": [ 17 | "Example of defining a type: Arrays with arbitrary indexing" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "For scientific applications, it is often useful to have arrays whose indices may start anywhere. Let's try to define a 1D array with this property, as an example of implementing a new type.\n", 25 | "\n", 26 | "I want \n", 27 | "\n", 28 | "```\n", 29 | "a = IndexedArray([3,4,5], -7) # starting from -7\n", 30 | "\n", 31 | "a[-7]\n", 32 | "```\n" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "----\n", 40 | "**Exercise**: What structure should it have?\n", 41 | "\n", 42 | "----\n", 43 | "\n", 44 | "\n", 45 | "\n", 46 | "\n", 47 | "\n", 48 | "\n", 49 | "\n", 50 | "\n" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "collapsed": false, 56 | "input": [ 57 | "\n", 58 | "\n", 59 | "\n", 60 | "\n", 61 | "\n", 62 | "\n", 63 | "\n", 64 | "\n", 65 | "\n", 66 | "\n", 67 | "\n", 68 | "\n", 69 | "\n", 70 | "\n", 71 | "\n" 72 | ], 73 | "language": "python", 74 | "metadata": {}, 75 | "outputs": [], 76 | "prompt_number": 1 77 | }, 78 | { 79 | "cell_type": "code", 80 | "collapsed": false, 81 | "input": [ 82 | "type IndexedArray\n", 83 | " data::Vector{Float64}\n", 84 | " low_index::Integer\n", 85 | "end" 86 | ], 87 | "language": "python", 88 | "metadata": {}, 89 | "outputs": [], 90 | "prompt_number": 1 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "----\n", 97 | "**Exercise**: Write a function that calculates the correct index.\n", 98 | "\n", 99 | "----\n", 100 | " " 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "metadata": {}, 106 | "source": [ 107 | "We calculate the correct index once and for all:" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "collapsed": false, 113 | "input": [ 114 | "reindex(a::IndexedArray, i) = i - a.low_index + 1" 115 | ], 116 | "language": "python", 117 | "metadata": {}, 118 | "outputs": [ 119 | { 120 | "metadata": {}, 121 | "output_type": "pyout", 122 | "prompt_number": 2, 123 | "text": [ 124 | "reindex (generic function with 1 method)" 125 | ] 126 | } 127 | ], 128 | "prompt_number": 2 129 | }, 130 | { 131 | "cell_type": "code", 132 | "collapsed": false, 133 | "input": [ 134 | "getindex(a::IndexedArray, i) = a.data[reindex(a, i)] \n" 135 | ], 136 | "language": "python", 137 | "metadata": {}, 138 | "outputs": [ 139 | { 140 | "metadata": {}, 141 | "output_type": "pyout", 142 | "prompt_number": 3, 143 | "text": [ 144 | "getindex (generic function with 182 methods)" 145 | ] 146 | } 147 | ], 148 | "prompt_number": 3 149 | }, 150 | { 151 | "cell_type": "code", 152 | "collapsed": false, 153 | "input": [], 154 | "language": "python", 155 | "metadata": {}, 156 | "outputs": [] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "collapsed": false, 161 | "input": [ 162 | "v = IndexedArray([3, 4, 5], -3)" 163 | ], 164 | "language": "python", 165 | "metadata": {}, 166 | "outputs": [ 167 | { 168 | "metadata": {}, 169 | "output_type": "pyout", 170 | "prompt_number": 4, 171 | "text": [ 172 | "IndexedArray([3.0,4.0,5.0],-3)" 173 | ] 174 | } 175 | ], 176 | "prompt_number": 4 177 | }, 178 | { 179 | "cell_type": "code", 180 | "collapsed": false, 181 | "input": [ 182 | "v[-3]" 183 | ], 184 | "language": "python", 185 | "metadata": {}, 186 | "outputs": [ 187 | { 188 | "metadata": {}, 189 | "output_type": "pyout", 190 | "prompt_number": 5, 191 | "text": [ 192 | "3.0" 193 | ] 194 | } 195 | ], 196 | "prompt_number": 5 197 | }, 198 | { 199 | "cell_type": "code", 200 | "collapsed": false, 201 | "input": [ 202 | "v[-2]" 203 | ], 204 | "language": "python", 205 | "metadata": {}, 206 | "outputs": [ 207 | { 208 | "metadata": {}, 209 | "output_type": "pyout", 210 | "prompt_number": 12, 211 | "text": [ 212 | "4.0" 213 | ] 214 | } 215 | ], 216 | "prompt_number": 12 217 | }, 218 | { 219 | "cell_type": "code", 220 | "collapsed": false, 221 | "input": [ 222 | "v[-1]" 223 | ], 224 | "language": "python", 225 | "metadata": {}, 226 | "outputs": [ 227 | { 228 | "metadata": {}, 229 | "output_type": "pyout", 230 | "prompt_number": 6, 231 | "text": [ 232 | "5.0" 233 | ] 234 | } 235 | ], 236 | "prompt_number": 6 237 | }, 238 | { 239 | "cell_type": "code", 240 | "collapsed": false, 241 | "input": [ 242 | "v[0]" 243 | ], 244 | "language": "python", 245 | "metadata": {}, 246 | "outputs": [ 247 | { 248 | "ename": "LoadError", 249 | "evalue": "BoundsError()\nwhile loading In[7], in expression starting on line 1", 250 | "output_type": "pyerr", 251 | "traceback": [ 252 | "BoundsError()\nwhile loading In[7], in expression starting on line 1", 253 | " in getindex at array.jl:246", 254 | " in getindex at In[3]:1" 255 | ] 256 | } 257 | ], 258 | "prompt_number": 7 259 | }, 260 | { 261 | "cell_type": "code", 262 | "collapsed": false, 263 | "input": [ 264 | "v[-1] = 10" 265 | ], 266 | "language": "python", 267 | "metadata": {}, 268 | "outputs": [ 269 | { 270 | "ename": "LoadError", 271 | "evalue": "no method setindex!(IndexedArray, Int64, Int64)\nwhile loading In[8], in expression starting on line 1", 272 | "output_type": "pyerr", 273 | "traceback": [ 274 | "no method setindex!(IndexedArray, Int64, Int64)\nwhile loading In[8], in expression starting on line 1" 275 | ] 276 | } 277 | ], 278 | "prompt_number": 8 279 | }, 280 | { 281 | "cell_type": "markdown", 282 | "metadata": {}, 283 | "source": [ 284 | "Many operations already work:" 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "collapsed": false, 290 | "input": [ 291 | "v[-3:-2]" 292 | ], 293 | "language": "python", 294 | "metadata": {}, 295 | "outputs": [ 296 | { 297 | "metadata": {}, 298 | "output_type": "pyout", 299 | "prompt_number": 13, 300 | "text": [ 301 | "2-element Array{Float64,1}:\n", 302 | " 3.0\n", 303 | " 4.0" 304 | ] 305 | } 306 | ], 307 | "prompt_number": 13 308 | }, 309 | { 310 | "cell_type": "markdown", 311 | "metadata": {}, 312 | "source": [ 313 | "But others don't yet:" 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "collapsed": false, 319 | "input": [ 320 | "v[-3] = 10" 321 | ], 322 | "language": "python", 323 | "metadata": {}, 324 | "outputs": [ 325 | { 326 | "ename": "LoadError", 327 | "evalue": "no method setindex!(IndexedArray, Int64, Int64)\nwhile loading In[14], in expression starting on line 1", 328 | "output_type": "pyerr", 329 | "traceback": [ 330 | "no method setindex!(IndexedArray, Int64, Int64)\nwhile loading In[14], in expression starting on line 1" 331 | ] 332 | } 333 | ], 334 | "prompt_number": 14 335 | }, 336 | { 337 | "cell_type": "code", 338 | "collapsed": false, 339 | "input": [ 340 | "setindex!(a::IndexedArray, x, i) = a.data[reindex(a, i)] = x" 341 | ], 342 | "language": "python", 343 | "metadata": {}, 344 | "outputs": [ 345 | { 346 | "metadata": {}, 347 | "output_type": "pyout", 348 | "prompt_number": 9, 349 | "text": [ 350 | "setindex! (generic function with 115 methods)" 351 | ] 352 | } 353 | ], 354 | "prompt_number": 9 355 | }, 356 | { 357 | "cell_type": "code", 358 | "collapsed": false, 359 | "input": [ 360 | "v[-3] = 10" 361 | ], 362 | "language": "python", 363 | "metadata": {}, 364 | "outputs": [ 365 | { 366 | "metadata": {}, 367 | "output_type": "pyout", 368 | "prompt_number": 10, 369 | "text": [ 370 | "10" 371 | ] 372 | } 373 | ], 374 | "prompt_number": 10 375 | }, 376 | { 377 | "cell_type": "code", 378 | "collapsed": false, 379 | "input": [ 380 | "v" 381 | ], 382 | "language": "python", 383 | "metadata": {}, 384 | "outputs": [ 385 | { 386 | "metadata": {}, 387 | "output_type": "pyout", 388 | "prompt_number": 12, 389 | "text": [ 390 | "IndexedArray([10.0,4.0,5.0],-3)" 391 | ] 392 | } 393 | ], 394 | "prompt_number": 12 395 | }, 396 | { 397 | "cell_type": "code", 398 | "collapsed": false, 399 | "input": [ 400 | "v[-3] = 10" 401 | ], 402 | "language": "python", 403 | "metadata": {}, 404 | "outputs": [ 405 | { 406 | "metadata": {}, 407 | "output_type": "pyout", 408 | "prompt_number": 20, 409 | "text": [ 410 | "10" 411 | ] 412 | } 413 | ], 414 | "prompt_number": 20 415 | }, 416 | { 417 | "cell_type": "code", 418 | "collapsed": false, 419 | "input": [ 420 | "v" 421 | ], 422 | "language": "python", 423 | "metadata": {}, 424 | "outputs": [ 425 | { 426 | "metadata": {}, 427 | "output_type": "pyout", 428 | "prompt_number": 21, 429 | "text": [ 430 | "IndexedArray([10.0,4.0,5.0],-3)" 431 | ] 432 | } 433 | ], 434 | "prompt_number": 21 435 | }, 436 | { 437 | "cell_type": "code", 438 | "collapsed": false, 439 | "input": [ 440 | "for i in v\n", 441 | " println(i)\n", 442 | "end" 443 | ], 444 | "language": "python", 445 | "metadata": {}, 446 | "outputs": [ 447 | { 448 | "ename": "LoadError", 449 | "evalue": "no method start(IndexedArray)\nwhile loading In[13], in expression starting on line 1", 450 | "output_type": "pyerr", 451 | "traceback": [ 452 | "no method start(IndexedArray)\nwhile loading In[13], in expression starting on line 1", 453 | " in anonymous at no file" 454 | ] 455 | } 456 | ], 457 | "prompt_number": 13 458 | }, 459 | { 460 | "cell_type": "heading", 461 | "level": 2, 462 | "metadata": {}, 463 | "source": [ 464 | "Iteration" 465 | ] 466 | }, 467 | { 468 | "cell_type": "markdown", 469 | "metadata": {}, 470 | "source": [ 471 | "To define iteration for our new type, we need to define the `start`, `next` and `done` functions.\n", 472 | "To see how to do so, the easiest thing is to copy some pre-existing code!" 473 | ] 474 | }, 475 | { 476 | "cell_type": "code", 477 | "collapsed": false, 478 | "input": [ 479 | "methods(start)" 480 | ], 481 | "language": "python", 482 | "metadata": {}, 483 | "outputs": [ 484 | { 485 | "html": [ 486 | "43 methods for generic function start:" 487 | ], 488 | "metadata": {}, 489 | "output_type": "pyout", 490 | "prompt_number": 13, 491 | "text": [ 492 | "# 43 methods for generic function \"start\":\n", 493 | "start(mt::MethodTable) at reflection.jl:123\n", 494 | "start(t::(Any...,)) at tuple.jl:13\n", 495 | "start(r::FloatRange{T<:FloatingPoint}) at range.jl:219\n", 496 | "start(r::StepRange{T,S}) at range.jl:225\n", 497 | "start(r::UnitRange{T<:Real}) at range.jl:230\n", 498 | "start(x::Number) at number.jl:36\n", 499 | "start(B::BitArray{N}) at bitarray.jl:199\n", 500 | "start(a::AbstractArray{T,N}) at abstractarray.jl:245\n", 501 | "start(s::IntSet) at intset.jl:130\n", 502 | "start(v::Union(KeyIterator{T<:Associative{K,V}},ValueIterator{T<:Associative{K,V}})) at dict.jl:149\n", 503 | "start(t::ObjectIdDict) at dict.jl:293\n", 504 | "start(t::Dict{K,V}) at dict.jl:675\n", 505 | "start(t::WeakKeyDict{K,V}) at dict.jl:750\n", 506 | "start(s::Set{T}) at set.jl:32\n", 507 | "start(e::Enumerate{I}) at iterator.jl:11\n", 508 | "start(z::Zip{I<:(Any...,)}) at iterator.jl:31\n", 509 | "start(z::Zip2{I1,I2}) at iterator.jl:55\n", 510 | "start(f::Filter{I}) at iterator.jl:73\n", 511 | "start(i::Rest{I,S}) at iterator.jl:110\n", 512 | "start(s::String) at string.jl:55\n", 513 | "start(itr::RegexMatchIterator) at regex.jl:204\n", 514 | "start(itr::EachLine) at io.jl:259\n", 515 | "start(::EnvHash) at env.jl:117\n", 516 | "start(t::Task) at task.jl:165\n", 517 | "start(pq::PriorityQueue{K,V}) at collections.jl:270\n", 518 | "start(c::Combinations{T}) at combinatorics.jl:258\n", 519 | "start(p::Permutations{T}) at combinatorics.jl:292\n", 520 | "start(p::IntegerPartitions) at combinatorics.jl:325\n", 521 | "start(f::FixedPartitions) at combinatorics.jl:391\n", 522 | "start(p::SetPartitions{T<:AbstractArray{T,1}}) at combinatorics.jl:453\n", 523 | "start(p::FixedSetPartitions{T<:AbstractArray{T,1}}) at combinatorics.jl:521\n", 524 | "start(d::SpDiagIterator{Tv,Ti}) at sparse/sparsematrix.jl:1863\n", 525 | "start{T}(q::Deque{T}) at /Users/david/.julia/DataStructures/src/deque.jl:101\n", 526 | "start(ct::Accumulator{T,V<:Number}) at /Users/david/.julia/DataStructures/src/accumulator.jl:38\n", 527 | "start(cc::ClassifiedCollections{K,Collection}) at /Users/david/.julia/DataStructures/src/classifiedcollections.jl:37\n", 528 | "start(t::HashDict{K,V,O<:Union(Nothing,Int64)}) at /Users/david/.julia/DataStructures/src/hashdict.jl:486\n", 529 | "start(::OrderedDict{K,V},...) at /Users/david/.julia/DataStructures/src/delegate.jl:11\n", 530 | "start(s::OrderedSet{T}) at /Users/david/.julia/DataStructures/src/orderedset.jl:40\n", 531 | "start(::DefaultDictBase{K,V,F,D<:Associative{K,V}},...) at /Users/david/.julia/DataStructures/src/delegate.jl:11\n", 532 | "start(::DefaultDict{K,V,F},...) at /Users/david/.julia/DataStructures/src/delegate.jl:11\n", 533 | "start(::DefaultOrderedDict{K,V,F},...) at /Users/david/.julia/DataStructures/src/delegate.jl:11\n", 534 | "start{T}(l::Nil{T}) at /Users/david/.julia/DataStructures/src/list.jl:124\n", 535 | "start{T}(l::Cons{T}) at /Users/david/.julia/DataStructures/src/list.jl:125" 536 | ] 537 | } 538 | ], 539 | "prompt_number": 13 540 | }, 541 | { 542 | "cell_type": "markdown", 543 | "metadata": {}, 544 | "source": [ 545 | "Let's pick the one for an abstract array. This is what we need to implement:" 546 | ] 547 | }, 548 | { 549 | "cell_type": "code", 550 | "collapsed": false, 551 | "input": [ 552 | "# start(a::AbstractArray) = 1\n", 553 | "# next(a::AbstractArray,i) = (a[i],i+1)\n", 554 | "# done(a::AbstractArray,i) = (i > length(a))" 555 | ], 556 | "language": "python", 557 | "metadata": {}, 558 | "outputs": [], 559 | "prompt_number": 18 560 | }, 561 | { 562 | "cell_type": "markdown", 563 | "metadata": {}, 564 | "source": [ 565 | "First, we must, as the error message says, explicitly import the functions from `Base` in order to extend them:" 566 | ] 567 | }, 568 | { 569 | "cell_type": "code", 570 | "collapsed": false, 571 | "input": [ 572 | "import Base: start, next, done" 573 | ], 574 | "language": "python", 575 | "metadata": {}, 576 | "outputs": [ 577 | { 578 | "output_type": "stream", 579 | "stream": "stderr", 580 | "text": [ 581 | "Warning: import of Base.start into Main conflicts with an existing identifier; ignored.\n", 582 | "Warning: import of Base.next into Main conflicts with an existing identifier; ignored.\n", 583 | "Warning: import of Base.done into Main conflicts with an existing identifier; ignored.\n" 584 | ] 585 | } 586 | ], 587 | "prompt_number": 21 588 | }, 589 | { 590 | "cell_type": "code", 591 | "collapsed": false, 592 | "input": [ 593 | "start(a::IndexedArray) = a.low_index\n", 594 | "next(a::IndexedArray,i) = (a[i],i+1)\n", 595 | "done(a::IndexedArray,i) = (i > a.low_index + length(a) - 1)" 596 | ], 597 | "language": "python", 598 | "metadata": {}, 599 | "outputs": [ 600 | { 601 | "metadata": {}, 602 | "output_type": "pyout", 603 | "prompt_number": 22, 604 | "text": [ 605 | "done (generic function with 1 method)" 606 | ] 607 | } 608 | ], 609 | "prompt_number": 22 610 | }, 611 | { 612 | "cell_type": "code", 613 | "collapsed": false, 614 | "input": [ 615 | "v" 616 | ], 617 | "language": "python", 618 | "metadata": {}, 619 | "outputs": [ 620 | { 621 | "metadata": {}, 622 | "output_type": "pyout", 623 | "prompt_number": 23, 624 | "text": [ 625 | "IndexedArray([10.0,4.0,5.0],-3)" 626 | ] 627 | } 628 | ], 629 | "prompt_number": 23 630 | }, 631 | { 632 | "cell_type": "code", 633 | "collapsed": false, 634 | "input": [ 635 | "for i in v\n", 636 | " println(i)\n", 637 | "end" 638 | ], 639 | "language": "python", 640 | "metadata": {}, 641 | "outputs": [ 642 | { 643 | "ename": "LoadError", 644 | "evalue": "no method start(IndexedArray)\nwhile loading In[24], in expression starting on line 1", 645 | "output_type": "pyerr", 646 | "traceback": [ 647 | "no method start(IndexedArray)\nwhile loading In[24], in expression starting on line 1", 648 | " in anonymous at no file" 649 | ] 650 | } 651 | ], 652 | "prompt_number": 24 653 | }, 654 | { 655 | "cell_type": "code", 656 | "collapsed": false, 657 | "input": [ 658 | "length(a::IndexedArray) = length(a.data)" 659 | ], 660 | "language": "python", 661 | "metadata": {}, 662 | "outputs": [ 663 | { 664 | "metadata": {}, 665 | "output_type": "pyout", 666 | "prompt_number": 25, 667 | "text": [ 668 | "length (generic function with 1 method)" 669 | ] 670 | } 671 | ], 672 | "prompt_number": 25 673 | }, 674 | { 675 | "cell_type": "code", 676 | "collapsed": false, 677 | "input": [ 678 | "import Base.length" 679 | ], 680 | "language": "python", 681 | "metadata": {}, 682 | "outputs": [], 683 | "prompt_number": 24 684 | }, 685 | { 686 | "cell_type": "code", 687 | "collapsed": false, 688 | "input": [ 689 | "length(a::IndexedArray) = length(a.data)" 690 | ], 691 | "language": "python", 692 | "metadata": {}, 693 | "outputs": [ 694 | { 695 | "metadata": {}, 696 | "output_type": "pyout", 697 | "prompt_number": 25, 698 | "text": [ 699 | "length (generic function with 58 methods)" 700 | ] 701 | } 702 | ], 703 | "prompt_number": 25 704 | }, 705 | { 706 | "cell_type": "code", 707 | "collapsed": false, 708 | "input": [ 709 | "for i in v\n", 710 | " println(i)\n", 711 | "end" 712 | ], 713 | "language": "python", 714 | "metadata": {}, 715 | "outputs": [ 716 | { 717 | "output_type": "stream", 718 | "stream": "stdout", 719 | "text": [ 720 | "10" 721 | ] 722 | }, 723 | { 724 | "output_type": "stream", 725 | "stream": "stdout", 726 | "text": [ 727 | ".0\n", 728 | "4.0\n", 729 | "5.0\n" 730 | ] 731 | } 732 | ], 733 | "prompt_number": 32 734 | }, 735 | { 736 | "cell_type": "code", 737 | "collapsed": false, 738 | "input": [ 739 | "v" 740 | ], 741 | "language": "python", 742 | "metadata": {}, 743 | "outputs": [ 744 | { 745 | "metadata": {}, 746 | "output_type": "pyout", 747 | "prompt_number": 26, 748 | "text": [ 749 | "IndexedArray([10.0,4.0,5.0],-3)" 750 | ] 751 | } 752 | ], 753 | "prompt_number": 26 754 | }, 755 | { 756 | "cell_type": "code", 757 | "collapsed": false, 758 | "input": [ 759 | "v + v" 760 | ], 761 | "language": "python", 762 | "metadata": {}, 763 | "outputs": [ 764 | { 765 | "ename": "LoadError", 766 | "evalue": "no method +(IndexedArray, IndexedArray)\nwhile loading In[27], in expression starting on line 1", 767 | "output_type": "pyerr", 768 | "traceback": [ 769 | "no method +(IndexedArray, IndexedArray)\nwhile loading In[27], in expression starting on line 1" 770 | ] 771 | } 772 | ], 773 | "prompt_number": 27 774 | }, 775 | { 776 | "cell_type": "code", 777 | "collapsed": false, 778 | "input": [], 779 | "language": "python", 780 | "metadata": {}, 781 | "outputs": [] 782 | } 783 | ], 784 | "metadata": {} 785 | } 786 | ] 787 | } -------------------------------------------------------------------------------- /6. Interoperability with Python and C.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Interoperability with Python: the `PyCall` package" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Coming from the Python ecosystem, the range of packages available in Julia can seem somewhat limited.\n", 15 | "This is offset, however, by the ease of calling out to packages written in other languages from within Julia." 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "In particular, Python interoperability is very easy, thanks to the [`PyCall` package](https://github.com/stevengj/PyCall.jl). This is loaded with" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 1, 28 | "metadata": { 29 | "collapsed": false 30 | }, 31 | "outputs": [], 32 | "source": [ 33 | "using PyCall" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "`PyCall` has a high-level interface that is designed so that the \"transport\" between Julia and Python is transparent from the user's point of view. For example, to import the Python `math` module, we do" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 2, 46 | "metadata": { 47 | "collapsed": false 48 | }, 49 | "outputs": [], 50 | "source": [ 51 | "@pyimport math" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 3, 57 | "metadata": { 58 | "collapsed": false 59 | }, 60 | "outputs": [ 61 | { 62 | "data": { 63 | "text/plain": [ 64 | "quote # /Users/dsanders/.julia/v0.3/PyCall/src/PyCall.jl, line 362:\n", 65 | " if PyCall.!(PyCall.isdefined(:math)) # line 363:\n", 66 | " const math = PyCall.pywrap(PyCall.pyimport(\"math\"))\n", 67 | " else # line 364:\n", 68 | " if PyCall.!(PyCall.isa(math,PyCall.Module)) # line 365:\n", 69 | " PyCall.error(\"@pyimport: \",:math,\" already defined\")\n", 70 | " end\n", 71 | " end # line 367:\n", 72 | " PyCall.nothing\n", 73 | "end" 74 | ] 75 | }, 76 | "execution_count": 3, 77 | "metadata": {}, 78 | "output_type": "execute_result" 79 | } 80 | ], 81 | "source": [ 82 | "macroexpand(:(@pyimport math))" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "We can now mix and match Python calls, labelled by the `math.` qualifier, and Julia calls:" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 3, 95 | "metadata": { 96 | "collapsed": false 97 | }, 98 | "outputs": [ 99 | { 100 | "data": { 101 | "text/plain": [ 102 | "-1.1102230246251565e-16" 103 | ] 104 | }, 105 | "execution_count": 3, 106 | "metadata": {}, 107 | "output_type": "execute_result" 108 | } 109 | ], 110 | "source": [ 111 | "math.sin(0.3*math.pi) - sin(0.3*pi) " 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "Array objects are automatically converted:" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 9, 124 | "metadata": { 125 | "collapsed": false 126 | }, 127 | "outputs": [ 128 | { 129 | "data": { 130 | "text/plain": [ 131 | "3x4 Array{Float64,2}:\n", 132 | " 0.130444 0.9004 0.364677 0.321106\n", 133 | " 0.107789 0.0264795 0.369139 0.215905\n", 134 | " 0.723455 0.31165 0.110962 0.123888" 135 | ] 136 | }, 137 | "execution_count": 9, 138 | "metadata": {}, 139 | "output_type": "execute_result" 140 | } 141 | ], 142 | "source": [ 143 | "@pyimport numpy.random as nprandom\n", 144 | "nprandom.rand(3,4)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": {}, 150 | "source": [ 151 | "Let's define a Julia function:" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 4, 157 | "metadata": { 158 | "collapsed": false 159 | }, 160 | "outputs": [ 161 | { 162 | "data": { 163 | "text/plain": [ 164 | "(anonymous function)" 165 | ] 166 | }, 167 | "execution_count": 4, 168 | "metadata": {}, 169 | "output_type": "execute_result" 170 | } 171 | ], 172 | "source": [ 173 | "objective = x -> cos(x) - x" 174 | ] 175 | }, 176 | { 177 | "cell_type": "markdown", 178 | "metadata": {}, 179 | "source": [ 180 | "This is the Julia syntax for an anonymous function (like `lambda` in Python)." 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 5, 186 | "metadata": { 187 | "collapsed": false 188 | }, 189 | "outputs": [ 190 | { 191 | "data": { 192 | "text/plain": [ 193 | "-3.989992496600445" 194 | ] 195 | }, 196 | "execution_count": 5, 197 | "metadata": {}, 198 | "output_type": "execute_result" 199 | } 200 | ], 201 | "source": [ 202 | "objective(3)" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "We can pass this Julia function to a Python module:" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": 6, 215 | "metadata": { 216 | "collapsed": false 217 | }, 218 | "outputs": [ 219 | { 220 | "ename": "LoadError", 221 | "evalue": "so not defined\nwhile loading In[6], in expression starting on line 1", 222 | "output_type": "error", 223 | "traceback": [ 224 | "so not defined\nwhile loading In[6], in expression starting on line 1" 225 | ] 226 | } 227 | ], 228 | "source": [ 229 | "?so.newton" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": 7, 235 | "metadata": { 236 | "collapsed": false 237 | }, 238 | "outputs": [ 239 | { 240 | "data": { 241 | "text/plain": [ 242 | "0.7390851332151607" 243 | ] 244 | }, 245 | "execution_count": 7, 246 | "metadata": {}, 247 | "output_type": "execute_result" 248 | } 249 | ], 250 | "source": [ 251 | "@pyimport scipy.optimize as so\n", 252 | "so.newton(objective, 1)" 253 | ] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "metadata": {}, 258 | "source": [ 259 | "The main difference from Python is how to access member elements of Python structures." 260 | ] 261 | }, 262 | { 263 | "cell_type": "markdown", 264 | "metadata": {}, 265 | "source": [ 266 | "Julia has ODE solvers in the `ODE.jl` and `Sundials.jl` packages. But we can also call Python solvers:" 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": 11, 272 | "metadata": { 273 | "collapsed": false 274 | }, 275 | "outputs": [], 276 | "source": [ 277 | "@pyimport scipy.integrate as integrate" 278 | ] 279 | }, 280 | { 281 | "cell_type": "code", 282 | "execution_count": 12, 283 | "metadata": { 284 | "collapsed": false 285 | }, 286 | "outputs": [ 287 | { 288 | "data": { 289 | "text/plain": [ 290 | "f (generic function with 1 method)" 291 | ] 292 | }, 293 | "execution_count": 12, 294 | "metadata": {}, 295 | "output_type": "execute_result" 296 | } 297 | ], 298 | "source": [ 299 | "f(x,t) = -x " 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": 13, 305 | "metadata": { 306 | "collapsed": false 307 | }, 308 | "outputs": [], 309 | "source": [ 310 | "t = [0:0.1:10];" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 14, 316 | "metadata": { 317 | "collapsed": false 318 | }, 319 | "outputs": [], 320 | "source": [ 321 | "soln = integrate.odeint(f, 1, t);" 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": 9, 327 | "metadata": { 328 | "collapsed": false 329 | }, 330 | "outputs": [], 331 | "source": [ 332 | "using PyPlot" 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "metadata": {}, 338 | "source": [ 339 | "Note that the `PyPlot` module provides a higher-level wrapper than `PyCall` around `matplotlib`." 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 15, 345 | "metadata": { 346 | "collapsed": false 347 | }, 348 | "outputs": [ 349 | { 350 | "data": { 351 | "image/png": "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", 352 | "text/plain": [ 353 | "Figure(PyObject )" 354 | ] 355 | }, 356 | "metadata": {}, 357 | "output_type": "display_data" 358 | }, 359 | { 360 | "data": { 361 | "text/plain": [ 362 | "1-element Array{Any,1}:\n", 363 | " PyObject " 364 | ] 365 | }, 366 | "execution_count": 15, 367 | "metadata": {}, 368 | "output_type": "execute_result" 369 | } 370 | ], 371 | "source": [ 372 | "plot(t, soln)\n", 373 | "plot(t, exp(-t))" 374 | ] 375 | }, 376 | { 377 | "cell_type": "markdown", 378 | "metadata": {}, 379 | "source": [ 380 | "## Subtle difference from Python" 381 | ] 382 | }, 383 | { 384 | "cell_type": "markdown", 385 | "metadata": {}, 386 | "source": [ 387 | "Accessing fields (properties) and methods of Python objects uses the `obj.a` and `obj.b()` syntax, where `obj` is a Python object.\n", 388 | "However, currently the `obj.b` syntax in Julia is restricted to accessing fields of Julia composite types.\n", 389 | "\n", 390 | "For this reason, to access fields and methods of Python objects via PyCall, it is necessary to use the syntax\n", 391 | "\n", 392 | "`obj[:a]` for fields, and\n", 393 | "\n", 394 | "`obj[:a]()` for methods\n", 395 | "\n", 396 | "Here, we are using the Julia syntax `:a` to mean the Julia symbol `a`." 397 | ] 398 | }, 399 | { 400 | "cell_type": "markdown", 401 | "metadata": {}, 402 | "source": [ 403 | "## Lower level" 404 | ] 405 | }, 406 | { 407 | "cell_type": "markdown", 408 | "metadata": {}, 409 | "source": [ 410 | "The high-level `PyCall` interface is built on top of a lower-level interface which deals with the \"transport\" of objects between Python and Julia, based on a `PyObject` Julia type that wraps `PyObject*` in C, and represents a reference to a Python object.\n", 411 | "\n" 412 | ] 413 | }, 414 | { 415 | "cell_type": "code", 416 | "execution_count": 16, 417 | "metadata": { 418 | "collapsed": false 419 | }, 420 | "outputs": [ 421 | { 422 | "data": { 423 | "text/plain": [ 424 | "PyObject 3" 425 | ] 426 | }, 427 | "execution_count": 16, 428 | "metadata": {}, 429 | "output_type": "execute_result" 430 | } 431 | ], 432 | "source": [ 433 | "PyObject(3)" 434 | ] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "execution_count": 17, 439 | "metadata": { 440 | "collapsed": false 441 | }, 442 | "outputs": [ 443 | { 444 | "data": { 445 | "text/plain": [ 446 | "5x5 Array{Float64,2}:\n", 447 | " 0.887502 0.0246364 0.937582 0.684068 0.720231 \n", 448 | " 0.384961 0.160604 0.814357 0.827761 0.221047 \n", 449 | " 0.125212 0.333403 0.877111 0.949292 0.152891 \n", 450 | " 0.782374 0.47016 0.687562 0.846015 0.155578 \n", 451 | " 0.827994 0.375204 0.991652 0.79604 0.0131533" 452 | ] 453 | }, 454 | "execution_count": 17, 455 | "metadata": {}, 456 | "output_type": "execute_result" 457 | } 458 | ], 459 | "source": [ 460 | "x = rand(5, 5)" 461 | ] 462 | }, 463 | { 464 | "cell_type": "code", 465 | "execution_count": 18, 466 | "metadata": { 467 | "collapsed": false 468 | }, 469 | "outputs": [ 470 | { 471 | "data": { 472 | "text/plain": [ 473 | "PyObject array([[ 0.88750169, 0.02463637, 0.93758233, 0.68406787, 0.72023119],\n", 474 | " [ 0.38496148, 0.16060356, 0.81435705, 0.82776091, 0.22104671],\n", 475 | " [ 0.12521248, 0.33340264, 0.87711099, 0.94929151, 0.15289064],\n", 476 | " [ 0.78237384, 0.47015973, 0.68756236, 0.84601514, 0.15557803],\n", 477 | " [ 0.82799391, 0.37520387, 0.99165247, 0.79604021, 0.01315334]])" 478 | ] 479 | }, 480 | "execution_count": 18, 481 | "metadata": {}, 482 | "output_type": "execute_result" 483 | } 484 | ], 485 | "source": [ 486 | "xx = PyObject(x)" 487 | ] 488 | }, 489 | { 490 | "cell_type": "code", 491 | "execution_count": 19, 492 | "metadata": { 493 | "collapsed": false 494 | }, 495 | "outputs": [ 496 | { 497 | "data": { 498 | "text/plain": [ 499 | "PyObject (constructor with 29 methods)" 500 | ] 501 | }, 502 | "execution_count": 19, 503 | "metadata": {}, 504 | "output_type": "execute_result" 505 | } 506 | ], 507 | "source": [ 508 | "typeof(xx)" 509 | ] 510 | }, 511 | { 512 | "cell_type": "code", 513 | "execution_count": 20, 514 | "metadata": { 515 | "collapsed": false 516 | }, 517 | "outputs": [ 518 | { 519 | "data": { 520 | "text/plain": [ 521 | "1-element Array{Symbol,1}:\n", 522 | " :o" 523 | ] 524 | }, 525 | "execution_count": 20, 526 | "metadata": {}, 527 | "output_type": "execute_result" 528 | } 529 | ], 530 | "source": [ 531 | "names(xx)" 532 | ] 533 | }, 534 | { 535 | "cell_type": "code", 536 | "execution_count": 21, 537 | "metadata": { 538 | "collapsed": false 539 | }, 540 | "outputs": [ 541 | { 542 | "data": { 543 | "text/plain": [ 544 | "Ptr{PyObject_struct} @0x00007fdeaf7ccb40" 545 | ] 546 | }, 547 | "execution_count": 21, 548 | "metadata": {}, 549 | "output_type": "execute_result" 550 | } 551 | ], 552 | "source": [ 553 | "xx.o" 554 | ] 555 | }, 556 | { 557 | "cell_type": "code", 558 | "execution_count": 11, 559 | "metadata": { 560 | "collapsed": false 561 | }, 562 | "outputs": [ 563 | { 564 | "data": { 565 | "text/plain": [ 566 | "(5,5)" 567 | ] 568 | }, 569 | "execution_count": 11, 570 | "metadata": {}, 571 | "output_type": "execute_result" 572 | } 573 | ], 574 | "source": [ 575 | "# xx.shape in Python becomes:\n", 576 | "xx[:shape]" 577 | ] 578 | }, 579 | { 580 | "cell_type": "code", 581 | "execution_count": 14, 582 | "metadata": { 583 | "collapsed": false 584 | }, 585 | "outputs": [ 586 | { 587 | "data": { 588 | "text/plain": [ 589 | "(DataType,DataType)" 590 | ] 591 | }, 592 | "execution_count": 14, 593 | "metadata": {}, 594 | "output_type": "execute_result" 595 | } 596 | ], 597 | "source": [ 598 | "typeof(ans) # the result has already been translated back into a Julia object" 599 | ] 600 | }, 601 | { 602 | "cell_type": "markdown", 603 | "metadata": {}, 604 | "source": [ 605 | "Julia arrays are passed into Python without a copy. By default the resulting Python array is copied when a result is requested in Julia; this can be avoided at a lower level using `pycall` and `PyArray`." 606 | ] 607 | }, 608 | { 609 | "cell_type": "markdown", 610 | "metadata": {}, 611 | "source": [ 612 | "**Exercise**: Use your favourite Python package from Julia!" 613 | ] 614 | }, 615 | { 616 | "cell_type": "markdown", 617 | "metadata": {}, 618 | "source": [ 619 | "# Interoperability with C" 620 | ] 621 | }, 622 | { 623 | "cell_type": "markdown", 624 | "metadata": {}, 625 | "source": [ 626 | "Julia has a simple way to call C and Fortran functions in shared libraries, via the `ccall` function." 627 | ] 628 | }, 629 | { 630 | "cell_type": "code", 631 | "execution_count": 25, 632 | "metadata": { 633 | "collapsed": false 634 | }, 635 | "outputs": [ 636 | { 637 | "name": "stdout", 638 | "output_type": "stream", 639 | "text": [ 640 | "Base.ccall((symbol, library) or fptr, RetType, (ArgType1, ...), ArgVar1, ...)\n", 641 | "\n", 642 | " Call function in C-exported shared library, specified by\n", 643 | " \"(function name, library)\" tuple, where each component is a\n", 644 | " String or :Symbol. Alternatively, ccall may be used to call a\n", 645 | " function pointer returned by dlsym, but note that this usage is\n", 646 | " generally discouraged to facilitate future static compilation. Note\n", 647 | " that the argument type tuple must be a literal tuple, and not a\n", 648 | " tuple-valued variable or expression.\n" 649 | ] 650 | } 651 | ], 652 | "source": [ 653 | "help(\"ccall\")" 654 | ] 655 | }, 656 | { 657 | "cell_type": "markdown", 658 | "metadata": {}, 659 | "source": [ 660 | "We see that we must specify:\n", 661 | "\n", 662 | "- the name of the function, as a Julia symbol or as a string\n", 663 | "- and the name of the shared library where it lives; these are given as an ordered pair (tuple)\n", 664 | "\n", 665 | "\n", 666 | "- the return type of the function\n", 667 | "\n", 668 | "- the argument types that the function accepts, as a tuple\n", 669 | "\n", 670 | "- and the arguments themselves" 671 | ] 672 | }, 673 | { 674 | "cell_type": "markdown", 675 | "metadata": {}, 676 | "source": [ 677 | "A simple example is to call the clock function:" 678 | ] 679 | }, 680 | { 681 | "cell_type": "code", 682 | "execution_count": 4, 683 | "metadata": { 684 | "collapsed": false 685 | }, 686 | "outputs": [ 687 | { 688 | "data": { 689 | "text/plain": [ 690 | "17337016" 691 | ] 692 | }, 693 | "execution_count": 4, 694 | "metadata": {}, 695 | "output_type": "execute_result" 696 | } 697 | ], 698 | "source": [ 699 | "t = ccall( (:clock, \"libc\"), Int32, ())" 700 | ] 701 | }, 702 | { 703 | "cell_type": "code", 704 | "execution_count": 10, 705 | "metadata": { 706 | "collapsed": false 707 | }, 708 | "outputs": [ 709 | { 710 | "data": { 711 | "text/plain": [ 712 | "6646395" 713 | ] 714 | }, 715 | "execution_count": 10, 716 | "metadata": {}, 717 | "output_type": "execute_result" 718 | } 719 | ], 720 | "source": [ 721 | "t" 722 | ] 723 | }, 724 | { 725 | "cell_type": "code", 726 | "execution_count": 11, 727 | "metadata": { 728 | "collapsed": false 729 | }, 730 | "outputs": [ 731 | { 732 | "data": { 733 | "text/plain": [ 734 | "Int32" 735 | ] 736 | }, 737 | "execution_count": 11, 738 | "metadata": {}, 739 | "output_type": "execute_result" 740 | } 741 | ], 742 | "source": [ 743 | "typeof(t)" 744 | ] 745 | }, 746 | { 747 | "cell_type": "code", 748 | "execution_count": 36, 749 | "metadata": { 750 | "collapsed": false 751 | }, 752 | "outputs": [ 753 | { 754 | "name": "stdout", 755 | "output_type": "stream", 756 | "text": [ 757 | "Base.ccall((symbol, library) or fptr, RetType, (ArgType1, ...), ArgVar1, ...)\n", 758 | "\n", 759 | " Call function in C-exported shared library, specified by\n", 760 | " \"(function name, library)\" tuple, where each component is a\n", 761 | " String or :Symbol. Alternatively, ccall may be used to call a\n", 762 | " function pointer returned by dlsym, but note that this usage is\n", 763 | " generally discouraged to facilitate future static compilation. Note\n", 764 | " that the argument type tuple must be a literal tuple, and not a\n", 765 | " tuple-valued variable or expression.\n" 766 | ] 767 | } 768 | ], 769 | "source": [ 770 | "help(\"ccall\")" 771 | ] 772 | }, 773 | { 774 | "cell_type": "code", 775 | "execution_count": null, 776 | "metadata": { 777 | "collapsed": true 778 | }, 779 | "outputs": [], 780 | "source": [ 781 | "Clong" 782 | ] 783 | }, 784 | { 785 | "cell_type": "code", 786 | "execution_count": 12, 787 | "metadata": { 788 | "collapsed": false 789 | }, 790 | "outputs": [ 791 | { 792 | "data": { 793 | "text/plain": [ 794 | "Ptr{Uint8} @0x00007faac9d15f05" 795 | ] 796 | }, 797 | "execution_count": 12, 798 | "metadata": {}, 799 | "output_type": "execute_result" 800 | } 801 | ], 802 | "source": [ 803 | "path = ccall( (:getenv, \"libc\"), Ptr{Uint8}, (Ptr{Uint8},), \"PATH\")" 804 | ] 805 | }, 806 | { 807 | "cell_type": "markdown", 808 | "metadata": {}, 809 | "source": [ 810 | "Here, `Ptr` denotes a pointer to the given type." 811 | ] 812 | }, 813 | { 814 | "cell_type": "code", 815 | "execution_count": 31, 816 | "metadata": { 817 | "collapsed": false 818 | }, 819 | "outputs": [ 820 | { 821 | "data": { 822 | "text/plain": [ 823 | "Ptr{Uint8} @0x00007fff50e46ed5" 824 | ] 825 | }, 826 | "execution_count": 31, 827 | "metadata": {}, 828 | "output_type": "execute_result" 829 | } 830 | ], 831 | "source": [ 832 | "path" 833 | ] 834 | }, 835 | { 836 | "cell_type": "code", 837 | "execution_count": 13, 838 | "metadata": { 839 | "collapsed": false 840 | }, 841 | "outputs": [ 842 | { 843 | "data": { 844 | "text/plain": [ 845 | "\"/Users/david/development/julia/usr/bin:/Users/david/anaconda/bin:/usr/local/bin:/opt/local/bin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/texbin:.:/Users/david/bin:/Users/david/Dropbox/bin\"" 846 | ] 847 | }, 848 | "execution_count": 13, 849 | "metadata": {}, 850 | "output_type": "execute_result" 851 | } 852 | ], 853 | "source": [ 854 | "bytestring(path)" 855 | ] 856 | }, 857 | { 858 | "cell_type": "code", 859 | "execution_count": 34, 860 | "metadata": { 861 | "collapsed": false 862 | }, 863 | "outputs": [ 864 | { 865 | "name": "stdout", 866 | "output_type": "stream", 867 | "text": [ 868 | "Base.bytestring(::Ptr{Uint8}[, length])\n", 869 | "\n", 870 | " Create a string from the address of a C (0-terminated) string\n", 871 | " encoded in ASCII or UTF-8. A copy is made; the ptr can be safely\n", 872 | " freed. If \"length\" is specified, the string does not have to be\n", 873 | " 0-terminated.\n", 874 | "\n", 875 | "Base.bytestring(s)\n", 876 | "\n", 877 | " Convert a string to a contiguous byte array representation\n", 878 | " appropriate for passing it to C functions. The string will be\n", 879 | " encoded as either ASCII or UTF-8.\n" 880 | ] 881 | } 882 | ], 883 | "source": [ 884 | "?bytestring" 885 | ] 886 | }, 887 | { 888 | "cell_type": "code", 889 | "execution_count": 37, 890 | "metadata": { 891 | "collapsed": false 892 | }, 893 | "outputs": [ 894 | { 895 | "data": { 896 | "text/plain": [ 897 | "Ptr{T}" 898 | ] 899 | }, 900 | "execution_count": 37, 901 | "metadata": {}, 902 | "output_type": "execute_result" 903 | } 904 | ], 905 | "source": [ 906 | "Ptr" 907 | ] 908 | }, 909 | { 910 | "cell_type": "code", 911 | "execution_count": 38, 912 | "metadata": { 913 | "collapsed": false 914 | }, 915 | "outputs": [ 916 | { 917 | "data": { 918 | "text/plain": [ 919 | "Ptr{T}" 920 | ] 921 | }, 922 | "execution_count": 38, 923 | "metadata": {}, 924 | "output_type": "execute_result" 925 | } 926 | ], 927 | "source": [ 928 | "methods(Ptr)" 929 | ] 930 | }, 931 | { 932 | "cell_type": "code", 933 | "execution_count": 39, 934 | "metadata": { 935 | "collapsed": false 936 | }, 937 | "outputs": [ 938 | { 939 | "data": { 940 | "text/html": [ 941 | "58-element Array{Method,1}:" 942 | ], 943 | "text/plain": [ 944 | "58-element Array{Method,1}:\n", 945 | " show{T}(io::IO,p::Ptr{T}) at show.jl:116 \n", 946 | " unsafe_store!{T}(p::Ptr{T},x,i::Integer) at pointer.jl:48 \n", 947 | " unsafe_store!{T}(p::Ptr{T},x) at pointer.jl:49 \n", 948 | " msync(p::Ptr{T},len::Integer,flags::Integer) at mmap.jl:70 \n", 949 | " msync(p::Ptr{T},len::Integer) at mmap.jl:72 \n", 950 | " integer(x::Ptr{T}) at pointer.jl:55 \n", 951 | " read!(from::IOBuffer,p::Ptr{T},nb::Int64) at iobuffer.jl:70 \n", 952 | " read!(from::IOBuffer,p::Ptr{T},nb::Integer) at iobuffer.jl:68 \n", 953 | " show{T}(io::IO,p::Ptr{T}) at show.jl:116 \n", 954 | " -(x::Ptr{T},y::Ptr{T}) at pointer.jl:64 \n", 955 | " -(x::Ptr{T},y::Integer) at pointer.jl:67 \n", 956 | " write(to::IOBuffer,p::Ptr{T},nb::Int64) at iobuffer.jl:237 \n", 957 | " write(to::IOBuffer,p::Ptr{T},nb::Integer) at iobuffer.jl:235 \n", 958 | " ⋮ \n", 959 | " gzbuffer(gz_file::Ptr{T},gz_buf_size::Integer) at /Users/david/.julia/GZip/src/GZip.jl:197\n", 960 | " show{T}(io::IO,p::Ptr{T}) at show.jl:116 \n", 961 | " write(to::IOBuffer,p::Ptr{T},nb::Int64) at iobuffer.jl:237 \n", 962 | " write(to::IOBuffer,p::Ptr{T},nb::Integer) at iobuffer.jl:235 \n", 963 | " write(to::IOBuffer,p::Ptr{T}) at iobuffer.jl:278 \n", 964 | " write(s::IOStream,p::Ptr{T},nb::Integer) at iostream.jl:159 \n", 965 | " write(s::AsyncStream,p::Ptr{T},nb::Integer) at stream.jl:790 \n", 966 | " write(s::GZipStream,p::Ptr{T},nb::Integer) at /Users/david/.julia/GZip/src/GZip.jl:448 \n", 967 | " write(s::IO,p::Ptr{T},n::Integer) at io.jl:91 \n", 968 | " gzwrite(s::GZipStream,p::Ptr{T},len::Integer) at /Users/david/.julia/GZip/src/GZip.jl:184 \n", 969 | " read(from::IOBuffer,p::Ptr{T},nb::Integer) at deprecated.jl:26 \n", 970 | " PyObject(p::Ptr{T}) at /Users/david/.julia/PyCall/src/conversions.jl:131 " 971 | ] 972 | }, 973 | "execution_count": 39, 974 | "metadata": {}, 975 | "output_type": "execute_result" 976 | } 977 | ], 978 | "source": [ 979 | "methodswith(Ptr)" 980 | ] 981 | }, 982 | { 983 | "cell_type": "code", 984 | "execution_count": 1, 985 | "metadata": { 986 | "collapsed": false 987 | }, 988 | "outputs": [], 989 | "source": [ 990 | "type F\n", 991 | " f::Function\n", 992 | " x::Float64\n", 993 | "end" 994 | ] 995 | }, 996 | { 997 | "cell_type": "code", 998 | "execution_count": 2, 999 | "metadata": { 1000 | "collapsed": false 1001 | }, 1002 | "outputs": [ 1003 | { 1004 | "data": { 1005 | "text/plain": [ 1006 | "hello (generic function with 1 method)" 1007 | ] 1008 | }, 1009 | "execution_count": 2, 1010 | "metadata": {}, 1011 | "output_type": "execute_result" 1012 | } 1013 | ], 1014 | "source": [ 1015 | "hello(x) = x^2" 1016 | ] 1017 | }, 1018 | { 1019 | "cell_type": "code", 1020 | "execution_count": 6, 1021 | "metadata": { 1022 | "collapsed": false 1023 | }, 1024 | "outputs": [ 1025 | { 1026 | "data": { 1027 | "text/plain": [ 1028 | "F(hello,3.5)" 1029 | ] 1030 | }, 1031 | "execution_count": 6, 1032 | "metadata": {}, 1033 | "output_type": "execute_result" 1034 | } 1035 | ], 1036 | "source": [ 1037 | "myfunc = F(hello, 3.5)" 1038 | ] 1039 | }, 1040 | { 1041 | "cell_type": "code", 1042 | "execution_count": 4, 1043 | "metadata": { 1044 | "collapsed": false 1045 | }, 1046 | "outputs": [ 1047 | { 1048 | "ename": "LoadError", 1049 | "evalue": "myfunc not defined\nwhile loading In[4], in expression starting on line 1", 1050 | "output_type": "error", 1051 | "traceback": [ 1052 | "myfunc not defined\nwhile loading In[4], in expression starting on line 1" 1053 | ] 1054 | } 1055 | ], 1056 | "source": [ 1057 | "myfunc" 1058 | ] 1059 | }, 1060 | { 1061 | "cell_type": "code", 1062 | "execution_count": 27, 1063 | "metadata": { 1064 | "collapsed": false 1065 | }, 1066 | "outputs": [ 1067 | { 1068 | "data": { 1069 | "text/plain": [ 1070 | "hello (generic function with 1 method)" 1071 | ] 1072 | }, 1073 | "execution_count": 27, 1074 | "metadata": {}, 1075 | "output_type": "execute_result" 1076 | } 1077 | ], 1078 | "source": [ 1079 | "myfunc.f" 1080 | ] 1081 | }, 1082 | { 1083 | "cell_type": "code", 1084 | "execution_count": 8, 1085 | "metadata": { 1086 | "collapsed": false 1087 | }, 1088 | "outputs": [ 1089 | { 1090 | "data": { 1091 | "text/plain": [ 1092 | "12.25" 1093 | ] 1094 | }, 1095 | "execution_count": 8, 1096 | "metadata": {}, 1097 | "output_type": "execute_result" 1098 | } 1099 | ], 1100 | "source": [ 1101 | "myfunc.f(myfunc.x)" 1102 | ] 1103 | }, 1104 | { 1105 | "cell_type": "code", 1106 | "execution_count": null, 1107 | "metadata": { 1108 | "collapsed": false 1109 | }, 1110 | "outputs": [], 1111 | "source": [] 1112 | } 1113 | ], 1114 | "metadata": { 1115 | "kernelspec": { 1116 | "display_name": "Julia 0.3.8-pre", 1117 | "language": "julia", 1118 | "name": "julia 0.3" 1119 | }, 1120 | "language_info": { 1121 | "name": "julia", 1122 | "version": "0.3.10" 1123 | } 1124 | }, 1125 | "nbformat": 4, 1126 | "nbformat_minor": 0 1127 | } 1128 | -------------------------------------------------------------------------------- /5. Metaprogramming.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language": "Julia", 4 | "name": "", 5 | "signature": "sha256:6f4ffe27802546bed9ef87092586f49c78c6d17259042a6147ce8265e7c7271d" 6 | }, 7 | "nbformat": 3, 8 | "nbformat_minor": 0, 9 | "worksheets": [ 10 | { 11 | "cells": [ 12 | { 13 | "cell_type": "heading", 14 | "level": 1, 15 | "metadata": {}, 16 | "source": [ 17 | "Meta-ness" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "Julia allows us to talk in a \"meta\" way (\"one level up\"), about Julia code, that is to \"treat code as data\" and manipulate it as just another object in Julia. (This is very similar to Lisp.)" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "The basic objects in this approach are unevaluated *symbols*:" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "collapsed": false, 37 | "input": [ 38 | ":a # \"the symbol a\"" 39 | ], 40 | "language": "python", 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "metadata": {}, 45 | "output_type": "pyout", 46 | "prompt_number": 3, 47 | "text": [ 48 | ":a" 49 | ] 50 | } 51 | ], 52 | "prompt_number": 3 53 | }, 54 | { 55 | "cell_type": "code", 56 | "collapsed": false, 57 | "input": [ 58 | "typeof(:a)" 59 | ], 60 | "language": "python", 61 | "metadata": {}, 62 | "outputs": [ 63 | { 64 | "metadata": {}, 65 | "output_type": "pyout", 66 | "prompt_number": 4, 67 | "text": [ 68 | "Symbol" 69 | ] 70 | } 71 | ], 72 | "prompt_number": 4 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "`:a` refers to the symbol `a`. We can evaluate it with the `eval` function:" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "collapsed": false, 84 | "input": [ 85 | "eval(:a)" 86 | ], 87 | "language": "python", 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "ename": "LoadError", 92 | "evalue": "a not defined\nwhile loading In[5], in expression starting on line 1", 93 | "output_type": "pyerr", 94 | "traceback": [ 95 | "a not defined\nwhile loading In[5], in expression starting on line 1" 96 | ] 97 | } 98 | ], 99 | "prompt_number": 5 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "`a` must be defined for this to work:" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "collapsed": false, 111 | "input": [ 112 | "a = 3" 113 | ], 114 | "language": "python", 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "metadata": {}, 119 | "output_type": "pyout", 120 | "prompt_number": 6, 121 | "text": [ 122 | "3" 123 | ] 124 | } 125 | ], 126 | "prompt_number": 6 127 | }, 128 | { 129 | "cell_type": "code", 130 | "collapsed": false, 131 | "input": [ 132 | "eval(:a)" 133 | ], 134 | "language": "python", 135 | "metadata": {}, 136 | "outputs": [ 137 | { 138 | "metadata": {}, 139 | "output_type": "pyout", 140 | "prompt_number": 7, 141 | "text": [ 142 | "3" 143 | ] 144 | } 145 | ], 146 | "prompt_number": 7 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "metadata": {}, 151 | "source": [ 152 | "The `eval` function takes an expression and evaluates it, that is, *generates the corresponding code*" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "Everything is a symbol:" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "collapsed": false, 165 | "input": [ 166 | ":+, :sin" 167 | ], 168 | "language": "python", 169 | "metadata": {}, 170 | "outputs": [ 171 | { 172 | "metadata": {}, 173 | "output_type": "pyout", 174 | "prompt_number": 8, 175 | "text": [ 176 | "(:+,:sin)" 177 | ] 178 | } 179 | ], 180 | "prompt_number": 8 181 | }, 182 | { 183 | "cell_type": "code", 184 | "collapsed": false, 185 | "input": [ 186 | "typeof(:+)" 187 | ], 188 | "language": "python", 189 | "metadata": {}, 190 | "outputs": [ 191 | { 192 | "metadata": {}, 193 | "output_type": "pyout", 194 | "prompt_number": 9, 195 | "text": [ 196 | "Symbol" 197 | ] 198 | } 199 | ], 200 | "prompt_number": 9 201 | }, 202 | { 203 | "cell_type": "markdown", 204 | "metadata": {}, 205 | "source": [ 206 | "Symbols may be combined into *expressions*, which are the basic objects that represent pieces of Julia code:" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "collapsed": false, 212 | "input": [ 213 | "ex = :(a + b) # the expression 'a+b'" 214 | ], 215 | "language": "python", 216 | "metadata": {}, 217 | "outputs": [ 218 | { 219 | "metadata": {}, 220 | "output_type": "pyout", 221 | "prompt_number": 10, 222 | "text": [ 223 | ":(a + b)" 224 | ] 225 | } 226 | ], 227 | "prompt_number": 10 228 | }, 229 | { 230 | "cell_type": "code", 231 | "collapsed": false, 232 | "input": [ 233 | "typeof(ex)" 234 | ], 235 | "language": "python", 236 | "metadata": {}, 237 | "outputs": [ 238 | { 239 | "metadata": {}, 240 | "output_type": "pyout", 241 | "prompt_number": 11, 242 | "text": [ 243 | "Expr" 244 | ] 245 | } 246 | ], 247 | "prompt_number": 11 248 | }, 249 | { 250 | "cell_type": "code", 251 | "collapsed": false, 252 | "input": [ 253 | "ex" 254 | ], 255 | "language": "python", 256 | "metadata": {}, 257 | "outputs": [ 258 | { 259 | "metadata": {}, 260 | "output_type": "pyout", 261 | "prompt_number": 12, 262 | "text": [ 263 | ":(a + b)" 264 | ] 265 | } 266 | ], 267 | "prompt_number": 12 268 | }, 269 | { 270 | "cell_type": "code", 271 | "collapsed": false, 272 | "input": [ 273 | "b = 7\n", 274 | "eval(ex)" 275 | ], 276 | "language": "python", 277 | "metadata": {}, 278 | "outputs": [ 279 | { 280 | "metadata": {}, 281 | "output_type": "pyout", 282 | "prompt_number": 13, 283 | "text": [ 284 | "10" 285 | ] 286 | } 287 | ], 288 | "prompt_number": 13 289 | }, 290 | { 291 | "cell_type": "markdown", 292 | "metadata": {}, 293 | "source": [ 294 | "An expression is just a Julia object, so we can introspect (find out information about it):" 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "collapsed": false, 300 | "input": [ 301 | "names(ex)" 302 | ], 303 | "language": "python", 304 | "metadata": {}, 305 | "outputs": [ 306 | { 307 | "metadata": {}, 308 | "output_type": "pyout", 309 | "prompt_number": 60, 310 | "text": [ 311 | "3-element Array{Symbol,1}:\n", 312 | " :head\n", 313 | " :args\n", 314 | " :typ " 315 | ] 316 | } 317 | ], 318 | "prompt_number": 60 319 | }, 320 | { 321 | "cell_type": "code", 322 | "collapsed": false, 323 | "input": [ 324 | "# ex." 325 | ], 326 | "language": "python", 327 | "metadata": {}, 328 | "outputs": [], 329 | "prompt_number": 61 330 | }, 331 | { 332 | "cell_type": "code", 333 | "collapsed": false, 334 | "input": [ 335 | "ex.head" 336 | ], 337 | "language": "python", 338 | "metadata": {}, 339 | "outputs": [ 340 | { 341 | "metadata": {}, 342 | "output_type": "pyout", 343 | "prompt_number": 14, 344 | "text": [ 345 | ":call" 346 | ] 347 | } 348 | ], 349 | "prompt_number": 14 350 | }, 351 | { 352 | "cell_type": "code", 353 | "collapsed": false, 354 | "input": [ 355 | "ex.args" 356 | ], 357 | "language": "python", 358 | "metadata": {}, 359 | "outputs": [ 360 | { 361 | "metadata": {}, 362 | "output_type": "pyout", 363 | "prompt_number": 63, 364 | "text": [ 365 | "3-element Array{Any,1}:\n", 366 | " :+\n", 367 | " :a\n", 368 | " :b" 369 | ] 370 | } 371 | ], 372 | "prompt_number": 63 373 | }, 374 | { 375 | "cell_type": "code", 376 | "collapsed": false, 377 | "input": [ 378 | "ex.typ" 379 | ], 380 | "language": "python", 381 | "metadata": {}, 382 | "outputs": [ 383 | { 384 | "metadata": {}, 385 | "output_type": "pyout", 386 | "prompt_number": 64, 387 | "text": [ 388 | "Any" 389 | ] 390 | } 391 | ], 392 | "prompt_number": 64 393 | }, 394 | { 395 | "cell_type": "markdown", 396 | "metadata": {}, 397 | "source": [ 398 | "More complicated expressions are represented as \"abstract syntax trees\" (ASTs), consisting of expressions nested inside expressions:" 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "collapsed": false, 404 | "input": [ 405 | "ex = :( sin(3a + 2b^2) )" 406 | ], 407 | "language": "python", 408 | "metadata": {}, 409 | "outputs": [ 410 | { 411 | "metadata": {}, 412 | "output_type": "pyout", 413 | "prompt_number": 15, 414 | "text": [ 415 | ":(sin(3a + 2 * b^2))" 416 | ] 417 | } 418 | ], 419 | "prompt_number": 15 420 | }, 421 | { 422 | "cell_type": "code", 423 | "collapsed": false, 424 | "input": [ 425 | "ex.args" 426 | ], 427 | "language": "python", 428 | "metadata": {}, 429 | "outputs": [ 430 | { 431 | "metadata": {}, 432 | "output_type": "pyout", 433 | "prompt_number": 16, 434 | "text": [ 435 | "2-element Array{Any,1}:\n", 436 | " :sin \n", 437 | " :(3a + 2 * b^2)" 438 | ] 439 | } 440 | ], 441 | "prompt_number": 16 442 | }, 443 | { 444 | "cell_type": "code", 445 | "collapsed": false, 446 | "input": [ 447 | "typeof(ex.args[2])" 448 | ], 449 | "language": "python", 450 | "metadata": {}, 451 | "outputs": [ 452 | { 453 | "metadata": {}, 454 | "output_type": "pyout", 455 | "prompt_number": 17, 456 | "text": [ 457 | "Expr" 458 | ] 459 | } 460 | ], 461 | "prompt_number": 17 462 | }, 463 | { 464 | "cell_type": "code", 465 | "collapsed": false, 466 | "input": [ 467 | "ex.args[2].args" 468 | ], 469 | "language": "python", 470 | "metadata": {}, 471 | "outputs": [ 472 | { 473 | "metadata": {}, 474 | "output_type": "pyout", 475 | "prompt_number": 18, 476 | "text": [ 477 | "3-element Array{Any,1}:\n", 478 | " :+ \n", 479 | " :(3a) \n", 480 | " :(2 * b^2)" 481 | ] 482 | } 483 | ], 484 | "prompt_number": 18 485 | }, 486 | { 487 | "cell_type": "markdown", 488 | "metadata": {}, 489 | "source": [ 490 | "Expressions can be arbitrary Julia code that when evaluated will have side effects. For longer blocks of code, `quote...end` may be used instead of `:( ... )`" 491 | ] 492 | }, 493 | { 494 | "cell_type": "code", 495 | "collapsed": false, 496 | "input": [ 497 | "ex2 = \n", 498 | "quote\n", 499 | " y = 3\n", 500 | " z = sin(y+1)\n", 501 | "end\n", 502 | " " 503 | ], 504 | "language": "python", 505 | "metadata": {}, 506 | "outputs": [ 507 | { 508 | "metadata": {}, 509 | "output_type": "pyout", 510 | "prompt_number": 19, 511 | "text": [ 512 | ":(begin # In[19], line 3:\n", 513 | " y = 3 # line 4:\n", 514 | " z = sin(y + 1)\n", 515 | " end)" 516 | ] 517 | } 518 | ], 519 | "prompt_number": 19 520 | }, 521 | { 522 | "cell_type": "code", 523 | "collapsed": false, 524 | "input": [ 525 | "y" 526 | ], 527 | "language": "python", 528 | "metadata": {}, 529 | "outputs": [ 530 | { 531 | "ename": "LoadError", 532 | "evalue": "y not defined\nwhile loading In[70], in expression starting on line 1", 533 | "output_type": "pyerr", 534 | "traceback": [ 535 | "y not defined\nwhile loading In[70], in expression starting on line 1" 536 | ] 537 | } 538 | ], 539 | "prompt_number": 70 540 | }, 541 | { 542 | "cell_type": "code", 543 | "collapsed": false, 544 | "input": [ 545 | "eval(ex2)\n", 546 | "z" 547 | ], 548 | "language": "python", 549 | "metadata": {}, 550 | "outputs": [ 551 | { 552 | "metadata": {}, 553 | "output_type": "pyout", 554 | "prompt_number": 71, 555 | "text": [ 556 | "-0.7568024953079282" 557 | ] 558 | } 559 | ], 560 | "prompt_number": 71 561 | }, 562 | { 563 | "cell_type": "markdown", 564 | "metadata": {}, 565 | "source": [ 566 | "The full form of the abstract syntax tree in a style similar to a Lisp s-expression can be obtained using functions from the `Meta` module in `Base`:" 567 | ] 568 | }, 569 | { 570 | "cell_type": "code", 571 | "collapsed": false, 572 | "input": [ 573 | "Meta.show_sexpr(ex2)" 574 | ], 575 | "language": "python", 576 | "metadata": {}, 577 | "outputs": [ 578 | { 579 | "output_type": "stream", 580 | "stream": "stdout", 581 | "text": [ 582 | "(:" 583 | ] 584 | }, 585 | { 586 | "output_type": "stream", 587 | "stream": "stdout", 588 | "text": [ 589 | "block,\n", 590 | " (:line, 3, :In[19]),\n", 591 | " (:(=), :y, 3),\n", 592 | " :( # line 4:),\n", 593 | " (:(=), :z, (:call, :sin, (:call, :+, :y, 1)))\n", 594 | ")" 595 | ] 596 | } 597 | ], 598 | "prompt_number": 20 599 | }, 600 | { 601 | "cell_type": "markdown", 602 | "metadata": {}, 603 | "source": [ 604 | "Another way of seeing the structure is with `dump`:" 605 | ] 606 | }, 607 | { 608 | "cell_type": "code", 609 | "collapsed": false, 610 | "input": [ 611 | "dump(ex2)" 612 | ], 613 | "language": "python", 614 | "metadata": {}, 615 | "outputs": [ 616 | { 617 | "output_type": "stream", 618 | "stream": "stdout", 619 | "text": [ 620 | "Expr " 621 | ] 622 | }, 623 | { 624 | "output_type": "stream", 625 | "stream": "stdout", 626 | "text": [ 627 | "\n", 628 | " head: Symbol block\n", 629 | " args: Array(Any,(4,))\n", 630 | " 1: Expr \n", 631 | " head: Symbol line\n", 632 | " args: Array(Any,(2,))\n", 633 | " 1: Int64" 634 | ] 635 | }, 636 | { 637 | "output_type": "stream", 638 | "stream": "stdout", 639 | "text": [ 640 | " 3\n", 641 | " 2: Symbol In[19]\n", 642 | " typ: Any\n", 643 | " 2: Expr \n", 644 | " head: Symbol =\n", 645 | " args: Array(Any,(2,))\n", 646 | " 1: Symbol y\n", 647 | " 2: Int64 3\n", 648 | " typ: Any\n", 649 | " 3: LineNumberNode \n", 650 | " line: Int64 4\n", 651 | " 4: Expr \n", 652 | " head: Symbol =\n", 653 | " args: Array(Any,(2,))\n", 654 | " 1: Symbol z\n", 655 | " 2: Expr \n", 656 | " head: Symbol call\n", 657 | " args: Array(Any,(2,))\n", 658 | " typ: Any\n", 659 | " typ: Any\n", 660 | " typ: Any\n" 661 | ] 662 | } 663 | ], 664 | "prompt_number": 21 665 | }, 666 | { 667 | "cell_type": "heading", 668 | "level": 1, 669 | "metadata": {}, 670 | "source": [ 671 | "Macros" 672 | ] 673 | }, 674 | { 675 | "cell_type": "markdown", 676 | "metadata": {}, 677 | "source": [ 678 | "With the ability to think of code in terms of a data structure in the Julia language, we can now *manipulate* those data structures, allowing us to *create Julia code on the fly from within Julia*. This is known as *metaprogramming*: programming a program.\n", 679 | "\n", 680 | "The name *macro* is given to a kind of \"super-function\" that takes a piece of code as an argument, and returns an altered piece of code. A macro is thus a very different kind of object than a standard function. [Although it can be thought of as a function in the mathematical sense of the word.]" 681 | ] 682 | }, 683 | { 684 | "cell_type": "markdown", 685 | "metadata": {}, 686 | "source": [ 687 | "The [Julia manual](http://julia.readthedocs.org/en/latest/manual/metaprogramming/) puts it like this: \n", 688 | "\n", 689 | "> macros map a tuple of argument *expressions* to a returned\n", 690 | "> *expression*" 691 | ] 692 | }, 693 | { 694 | "cell_type": "markdown", 695 | "metadata": {}, 696 | "source": [ 697 | "Although metaprogramming is possible in many languages (including Python), Julia makes it particularly natural (although not exactly \"easy\"!)\n", 698 | "\n", 699 | "Metaprogramming is useful in a variety of settings:\n", 700 | "- to eliminate boilerplate (repetitive) code\n", 701 | "- to automatically generate complex code that would be painful by hand\n", 702 | "- to unroll loops for efficiency\n", 703 | "- to inline code for efficiency\n" 704 | ] 705 | }, 706 | { 707 | "cell_type": "markdown", 708 | "metadata": {}, 709 | "source": [ 710 | "\n", 711 | "Macros are invoked using the `@` sign, e.g." 712 | ] 713 | }, 714 | { 715 | "cell_type": "code", 716 | "collapsed": false, 717 | "input": [ 718 | "@time sin(10)" 719 | ], 720 | "language": "python", 721 | "metadata": {}, 722 | "outputs": [ 723 | { 724 | "output_type": "stream", 725 | "stream": "stdout", 726 | "text": [ 727 | "elapsed time: 0." 728 | ] 729 | }, 730 | { 731 | "output_type": "stream", 732 | "stream": "stdout", 733 | "text": [ 734 | "004374081 seconds (47856 bytes allocated)\n" 735 | ] 736 | }, 737 | { 738 | "metadata": {}, 739 | "output_type": "pyout", 740 | "prompt_number": 22, 741 | "text": [ 742 | "-0.5440211108893698" 743 | ] 744 | } 745 | ], 746 | "prompt_number": 22 747 | }, 748 | { 749 | "cell_type": "markdown", 750 | "metadata": {}, 751 | "source": [ 752 | "A trivial example of defining a macro is the following, which duplicates whatever code it is passed. The `$` sign is used to interpolate the value of the expression (similar to its usage for string interpolation):" 753 | ] 754 | }, 755 | { 756 | "cell_type": "code", 757 | "collapsed": false, 758 | "input": [ 759 | "macro duplicate(ex)\n", 760 | " quote\n", 761 | " $ex\n", 762 | " $ex\n", 763 | " end\n", 764 | "end" 765 | ], 766 | "language": "python", 767 | "metadata": {}, 768 | "outputs": [], 769 | "prompt_number": 23 770 | }, 771 | { 772 | "cell_type": "code", 773 | "collapsed": false, 774 | "input": [ 775 | "@duplicate println(sin(10))" 776 | ], 777 | "language": "python", 778 | "metadata": {}, 779 | "outputs": [ 780 | { 781 | "output_type": "stream", 782 | "stream": "stdout", 783 | "text": [ 784 | "-0." 785 | ] 786 | }, 787 | { 788 | "output_type": "stream", 789 | "stream": "stdout", 790 | "text": [ 791 | "5440211108893698\n", 792 | "-0.5440211108893698\n" 793 | ] 794 | } 795 | ], 796 | "prompt_number": 24 797 | }, 798 | { 799 | "cell_type": "code", 800 | "collapsed": false, 801 | "input": [ 802 | "ex = :(@duplicate println(sin(10)))" 803 | ], 804 | "language": "python", 805 | "metadata": {}, 806 | "outputs": [ 807 | { 808 | "metadata": {}, 809 | "output_type": "pyout", 810 | "prompt_number": 25, 811 | "text": [ 812 | ":(@duplicate println(sin(10)))" 813 | ] 814 | } 815 | ], 816 | "prompt_number": 25 817 | }, 818 | { 819 | "cell_type": "code", 820 | "collapsed": false, 821 | "input": [ 822 | "eval(ex)" 823 | ], 824 | "language": "python", 825 | "metadata": {}, 826 | "outputs": [ 827 | { 828 | "output_type": "stream", 829 | "stream": "stdout", 830 | "text": [ 831 | "-0." 832 | ] 833 | }, 834 | { 835 | "output_type": "stream", 836 | "stream": "stdout", 837 | "text": [ 838 | "5440211108893698\n", 839 | "-0.5440211108893698\n" 840 | ] 841 | } 842 | ], 843 | "prompt_number": 77 844 | }, 845 | { 846 | "cell_type": "code", 847 | "collapsed": false, 848 | "input": [ 849 | "typeof(ex)" 850 | ], 851 | "language": "python", 852 | "metadata": {}, 853 | "outputs": [ 854 | { 855 | "metadata": {}, 856 | "output_type": "pyout", 857 | "prompt_number": 78, 858 | "text": [ 859 | "Expr" 860 | ] 861 | } 862 | ], 863 | "prompt_number": 78 864 | }, 865 | { 866 | "cell_type": "markdown", 867 | "metadata": {}, 868 | "source": [ 869 | "We can see what effect the macro actually has using `macroexpand`:" 870 | ] 871 | }, 872 | { 873 | "cell_type": "code", 874 | "collapsed": false, 875 | "input": [ 876 | "macroexpand(ex)" 877 | ], 878 | "language": "python", 879 | "metadata": {}, 880 | "outputs": [ 881 | { 882 | "metadata": {}, 883 | "output_type": "pyout", 884 | "prompt_number": 26, 885 | "text": [ 886 | ":(begin # In[23], line 3:\n", 887 | " println(sin(10)) # line 4:\n", 888 | " println(sin(10))\n", 889 | " end)" 890 | ] 891 | } 892 | ], 893 | "prompt_number": 26 894 | }, 895 | { 896 | "cell_type": "code", 897 | "collapsed": false, 898 | "input": [ 899 | "macroexpand(:(@time sin(10)))" 900 | ], 901 | "language": "python", 902 | "metadata": {}, 903 | "outputs": [ 904 | { 905 | "metadata": {}, 906 | "output_type": "pyout", 907 | "prompt_number": 27, 908 | "text": [ 909 | ":(begin # util.jl, line 50:\n", 910 | " local #261#b0 = Base.gc_bytes() # line 51:\n", 911 | " local #262#t0 = Base.time_ns() # line 52:\n", 912 | " local #263#g0 = Base.gc_time_ns() # line 53:\n", 913 | " local #264#val = sin(10) # line 54:\n", 914 | " local #265#g1 = Base.gc_time_ns() # line 55:\n", 915 | " local #266#t1 = Base.time_ns() # line 56:\n", 916 | " local #267#b1 = Base.gc_bytes() # line 57:\n", 917 | " Base.time_print(Base.-(#266#t1,#262#t0),Base.-(#267#b1,#261#b0),Base.-(#265#g1,#263#g0)) # line 58:\n", 918 | " #264#val\n", 919 | " end)" 920 | ] 921 | } 922 | ], 923 | "prompt_number": 27 924 | }, 925 | { 926 | "cell_type": "markdown", 927 | "metadata": {}, 928 | "source": [ 929 | "----\n", 930 | "**Exercise**: Define a macro `@until` that does an `until` loop.\n", 931 | "\n", 932 | "----" 933 | ] 934 | }, 935 | { 936 | "cell_type": "code", 937 | "collapsed": false, 938 | "input": [ 939 | "macro until(expr1, expr2)\n", 940 | " quote\n", 941 | " #:(\n", 942 | " while !($expr1) # code interpolation\n", 943 | " $expr2\n", 944 | " end\n", 945 | " #)\n", 946 | " end\n", 947 | "end" 948 | ], 949 | "language": "python", 950 | "metadata": {}, 951 | "outputs": [], 952 | "prompt_number": 30 953 | }, 954 | { 955 | "cell_type": "code", 956 | "collapsed": false, 957 | "input": [ 958 | "i = 0\n", 959 | "@until i==10 begin\n", 960 | " println(i)\n", 961 | " i += 1\n", 962 | "end" 963 | ], 964 | "language": "python", 965 | "metadata": {}, 966 | "outputs": [ 967 | { 968 | "output_type": "stream", 969 | "stream": "stdout", 970 | "text": [ 971 | "0\n" 972 | ] 973 | }, 974 | { 975 | "output_type": "stream", 976 | "stream": "stdout", 977 | "text": [ 978 | "1\n", 979 | "2\n", 980 | "3\n", 981 | "4\n", 982 | "5\n", 983 | "6\n", 984 | "7\n", 985 | "8\n", 986 | "9\n" 987 | ] 988 | } 989 | ], 990 | "prompt_number": 34 991 | }, 992 | { 993 | "cell_type": "heading", 994 | "level": 2, 995 | "metadata": {}, 996 | "source": [ 997 | "A nontrivial example: Horner's method" 998 | ] 999 | }, 1000 | { 1001 | "cell_type": "markdown", 1002 | "metadata": {}, 1003 | "source": [ 1004 | "There are many interesting examples of macros in `Base`. One that is accessible is Horner's method for evaluating a polynomial:\n", 1005 | "\n", 1006 | "$$p(x) = a_n x^n + a_{n-1} x^{n-1} + \\cdots + a_1 x^1 + a_0$$\n", 1007 | "\n", 1008 | "may be evaluated efficiently as\n", 1009 | "\n", 1010 | "$$p(x) = a_0 + x(a_1 + \\cdots x(a_{n-2} + \\cdots + x(a_{n-1} + x a_n) \\cdots ) ) $$\n", 1011 | "with only $n$ multiplications.\n", 1012 | "\n", 1013 | "The obvious way to do this is with a `for` loop. But if we know the polynomial *at compile time*, this loop may be unrolled using metaprogramming. This is implemented in the `Math` module in `math.jl` in `Base`, so the name of the macro (which is not exported) is `@Base.Math.horner`\n", 1014 | "\n" 1015 | ] 1016 | }, 1017 | { 1018 | "cell_type": "code", 1019 | "collapsed": false, 1020 | "input": [ 1021 | "horner" 1022 | ], 1023 | "language": "python", 1024 | "metadata": {}, 1025 | "outputs": [ 1026 | { 1027 | "ename": "LoadError", 1028 | "evalue": "horner not defined\nwhile loading In[35], in expression starting on line 1", 1029 | "output_type": "pyerr", 1030 | "traceback": [ 1031 | "horner not defined\nwhile loading In[35], in expression starting on line 1" 1032 | ] 1033 | } 1034 | ], 1035 | "prompt_number": 35 1036 | }, 1037 | { 1038 | "cell_type": "code", 1039 | "collapsed": false, 1040 | "input": [ 1041 | "# copied from base/math.jl\n", 1042 | "macro horner(x, p...)\n", 1043 | " ex = esc(p[end])\n", 1044 | " for i = length(p)-1:-1:1\n", 1045 | " ex = :( $(esc(p[i])) + t * $ex )\n", 1046 | " end\n", 1047 | " Expr(:block, :(t = $(esc(x))), ex)\n", 1048 | "end" 1049 | ], 1050 | "language": "python", 1051 | "metadata": {}, 1052 | "outputs": [], 1053 | "prompt_number": 37 1054 | }, 1055 | { 1056 | "cell_type": "markdown", 1057 | "metadata": {}, 1058 | "source": [ 1059 | "This is called as follows: to evaluate the polynomial $p(x) = 2 + 3x + 4x^2$ at $x=3$, we do" 1060 | ] 1061 | }, 1062 | { 1063 | "cell_type": "code", 1064 | "collapsed": false, 1065 | "input": [ 1066 | "x = 3\n", 1067 | "@horner(x, 2, 3, 4)" 1068 | ], 1069 | "language": "python", 1070 | "metadata": {}, 1071 | "outputs": [ 1072 | { 1073 | "metadata": {}, 1074 | "output_type": "pyout", 1075 | "prompt_number": 38, 1076 | "text": [ 1077 | "47" 1078 | ] 1079 | } 1080 | ], 1081 | "prompt_number": 38 1082 | }, 1083 | { 1084 | "cell_type": "markdown", 1085 | "metadata": {}, 1086 | "source": [ 1087 | "[Even though the Horner macro is not exported in `Base`, we can access it as `@Base.Math.horner`]" 1088 | ] 1089 | }, 1090 | { 1091 | "cell_type": "markdown", 1092 | "metadata": {}, 1093 | "source": [ 1094 | "To see what the macro does to this call, we again use `macroexpand`:" 1095 | ] 1096 | }, 1097 | { 1098 | "cell_type": "code", 1099 | "collapsed": false, 1100 | "input": [ 1101 | "macroexpand(:(@horner(x, 2, 3, 4)))" 1102 | ], 1103 | "language": "python", 1104 | "metadata": {}, 1105 | "outputs": [ 1106 | { 1107 | "metadata": {}, 1108 | "output_type": "pyout", 1109 | "prompt_number": 39, 1110 | "text": [ 1111 | ":(begin \n", 1112 | " #269#t = x\n", 1113 | " 2 + #269#t * (3 + #269#t * 4)\n", 1114 | " end)" 1115 | ] 1116 | } 1117 | ], 1118 | "prompt_number": 39 1119 | }, 1120 | { 1121 | "cell_type": "code", 1122 | "collapsed": false, 1123 | "input": [ 1124 | "macroexpand(:(@Base.Math.horner(x, 2, 3, 4)))" 1125 | ], 1126 | "language": "python", 1127 | "metadata": {}, 1128 | "outputs": [ 1129 | { 1130 | "metadata": {}, 1131 | "output_type": "pyout", 1132 | "prompt_number": 88, 1133 | "text": [ 1134 | ":(begin \n", 1135 | " #292#t = x\n", 1136 | " Base.Math.+(2,Base.Math.*(#292#t,Base.Math.+(3,Base.Math.*(#292#t,4))))\n", 1137 | " end)" 1138 | ] 1139 | } 1140 | ], 1141 | "prompt_number": 88 1142 | }, 1143 | { 1144 | "cell_type": "code", 1145 | "collapsed": false, 1146 | "input": [ 1147 | "x = 3.5\n", 1148 | "@printf(\"%.5f\", x)" 1149 | ], 1150 | "language": "python", 1151 | "metadata": {}, 1152 | "outputs": [ 1153 | { 1154 | "output_type": "stream", 1155 | "stream": "stdout", 1156 | "text": [ 1157 | "3." 1158 | ] 1159 | }, 1160 | { 1161 | "output_type": "stream", 1162 | "stream": "stdout", 1163 | "text": [ 1164 | "50000" 1165 | ] 1166 | } 1167 | ], 1168 | "prompt_number": 101 1169 | }, 1170 | { 1171 | "cell_type": "code", 1172 | "collapsed": false, 1173 | "input": [ 1174 | "@printf" 1175 | ], 1176 | "language": "python", 1177 | "metadata": {}, 1178 | "outputs": [ 1179 | { 1180 | "ename": "LoadError", 1181 | "evalue": "@printf: called with zero arguments\nwhile loading In[2], in expression starting on line 1", 1182 | "output_type": "pyerr", 1183 | "traceback": [ 1184 | "@printf: called with zero arguments\nwhile loading In[2], in expression starting on line 1" 1185 | ] 1186 | } 1187 | ], 1188 | "prompt_number": 2 1189 | }, 1190 | { 1191 | "cell_type": "code", 1192 | "collapsed": false, 1193 | "input": [ 1194 | "ex = :(@time sin(10))" 1195 | ], 1196 | "language": "python", 1197 | "metadata": {}, 1198 | "outputs": [ 1199 | { 1200 | "metadata": {}, 1201 | "output_type": "pyout", 1202 | "prompt_number": 102, 1203 | "text": [ 1204 | ":(@time sin(10))" 1205 | ] 1206 | } 1207 | ], 1208 | "prompt_number": 102 1209 | }, 1210 | { 1211 | "cell_type": "code", 1212 | "collapsed": false, 1213 | "input": [ 1214 | "Meta.show_sexpr(ex)" 1215 | ], 1216 | "language": "python", 1217 | "metadata": {}, 1218 | "outputs": [ 1219 | { 1220 | "output_type": "stream", 1221 | "stream": "stdout", 1222 | "text": [ 1223 | "(:" 1224 | ] 1225 | }, 1226 | { 1227 | "output_type": "stream", 1228 | "stream": "stdout", 1229 | "text": [ 1230 | "macrocall, :@time, (:call, :sin, 10))" 1231 | ] 1232 | } 1233 | ], 1234 | "prompt_number": 103 1235 | }, 1236 | { 1237 | "cell_type": "code", 1238 | "collapsed": false, 1239 | "input": [ 1240 | "xdump(ex)" 1241 | ], 1242 | "language": "python", 1243 | "metadata": {}, 1244 | "outputs": [ 1245 | { 1246 | "output_type": "stream", 1247 | "stream": "stdout", 1248 | "text": [ 1249 | "Expr " 1250 | ] 1251 | }, 1252 | { 1253 | "output_type": "stream", 1254 | "stream": "stdout", 1255 | "text": [ 1256 | "\n", 1257 | " head: Symbol macrocall\n", 1258 | " args: Array(Any,(2,))\n", 1259 | " 1: Symbol @time\n", 1260 | " 2: Expr \n", 1261 | " head: Symbol call\n", 1262 | " args: Array(Any,(2,))\n", 1263 | " 1: Symbol sin\n", 1264 | " 2: Int64" 1265 | ] 1266 | }, 1267 | { 1268 | "output_type": "stream", 1269 | "stream": "stdout", 1270 | "text": [ 1271 | " 10\n", 1272 | " typ: Any::DataType <: Any\n", 1273 | " typ: Any::DataType <: Any\n" 1274 | ] 1275 | } 1276 | ], 1277 | "prompt_number": 5 1278 | }, 1279 | { 1280 | "cell_type": "code", 1281 | "collapsed": false, 1282 | "input": [ 1283 | "macroexpand(ex)" 1284 | ], 1285 | "language": "python", 1286 | "metadata": {}, 1287 | "outputs": [ 1288 | { 1289 | "metadata": {}, 1290 | "output_type": "pyout", 1291 | "prompt_number": 6, 1292 | "text": [ 1293 | ":(begin # util.jl, line 50:\n", 1294 | " local #254#b0 = Base.gc_bytes() # line 51:\n", 1295 | " local #255#t0 = Base.time_ns() # line 52:\n", 1296 | " local #256#g0 = Base.gc_time_ns() # line 53:\n", 1297 | " local #257#val = sin(10) # line 54:\n", 1298 | " local #258#g1 = Base.gc_time_ns() # line 55:\n", 1299 | " local #259#t1 = Base.time_ns() # line 56:\n", 1300 | " local #260#b1 = Base.gc_bytes() # line 57:\n", 1301 | " Base.time_print(Base.-(#259#t1,#255#t0),Base.-(#260#b1,#254#b0),Base.-(#258#g1,#256#g0)) # line 58:\n", 1302 | " #257#val\n", 1303 | " end)" 1304 | ] 1305 | } 1306 | ], 1307 | "prompt_number": 6 1308 | }, 1309 | { 1310 | "cell_type": "code", 1311 | "collapsed": false, 1312 | "input": [ 1313 | "@time sin(10)" 1314 | ], 1315 | "language": "python", 1316 | "metadata": {}, 1317 | "outputs": [ 1318 | { 1319 | "output_type": "stream", 1320 | "stream": "stdout", 1321 | "text": [ 1322 | "elapsed time: 0." 1323 | ] 1324 | }, 1325 | { 1326 | "output_type": "stream", 1327 | "stream": "stdout", 1328 | "text": [ 1329 | "006097425 seconds (47856 bytes allocated)\n" 1330 | ] 1331 | }, 1332 | { 1333 | "metadata": {}, 1334 | "output_type": "pyout", 1335 | "prompt_number": 7, 1336 | "text": [ 1337 | "-0.5440211108893698" 1338 | ] 1339 | } 1340 | ], 1341 | "prompt_number": 7 1342 | }, 1343 | { 1344 | "cell_type": "code", 1345 | "collapsed": false, 1346 | "input": [ 1347 | "dump(ex)" 1348 | ], 1349 | "language": "python", 1350 | "metadata": {}, 1351 | "outputs": [ 1352 | { 1353 | "output_type": "stream", 1354 | "stream": "stdout", 1355 | "text": [ 1356 | "Expr " 1357 | ] 1358 | }, 1359 | { 1360 | "output_type": "stream", 1361 | "stream": "stdout", 1362 | "text": [ 1363 | "\n", 1364 | " head: Symbol macrocall\n", 1365 | " args: Array(Any,(2,))\n", 1366 | " 1: Symbol @time\n", 1367 | " 2: Expr \n", 1368 | " head: Symbol call\n", 1369 | " args: Array(Any,(2,))\n", 1370 | " 1: Symbol sin\n", 1371 | " 2: Int64 10\n", 1372 | " typ: Any\n", 1373 | " typ: Any\n" 1374 | ] 1375 | } 1376 | ], 1377 | "prompt_number": 8 1378 | }, 1379 | { 1380 | "cell_type": "code", 1381 | "collapsed": false, 1382 | "input": [ 1383 | "xdump(ex)" 1384 | ], 1385 | "language": "python", 1386 | "metadata": {}, 1387 | "outputs": [ 1388 | { 1389 | "output_type": "stream", 1390 | "stream": "stdout", 1391 | "text": [ 1392 | "Expr " 1393 | ] 1394 | }, 1395 | { 1396 | "output_type": "stream", 1397 | "stream": "stdout", 1398 | "text": [ 1399 | "\n", 1400 | " head: Symbol macrocall\n", 1401 | " args: Array(Any,(2,))\n", 1402 | " 1: Symbol @time\n", 1403 | " 2: Expr \n", 1404 | " head: Symbol call\n", 1405 | " args: Array(Any,(2,))\n", 1406 | " 1: Symbol sin\n", 1407 | " 2: Int64 10\n", 1408 | " typ: Any::DataType <: Any\n", 1409 | " typ: Any::DataType <: Any\n" 1410 | ] 1411 | } 1412 | ], 1413 | "prompt_number": 9 1414 | }, 1415 | { 1416 | "cell_type": "code", 1417 | "collapsed": false, 1418 | "input": [ 1419 | "type Vector2D{T <: Real}\n", 1420 | " x::T\n", 1421 | " y::T\n", 1422 | "end" 1423 | ], 1424 | "language": "python", 1425 | "metadata": {}, 1426 | "outputs": [], 1427 | "prompt_number": 8 1428 | }, 1429 | { 1430 | "cell_type": "code", 1431 | "collapsed": false, 1432 | "input": [ 1433 | "methods(Vector2D)" 1434 | ], 1435 | "language": "python", 1436 | "metadata": {}, 1437 | "outputs": [ 1438 | { 1439 | "html": [ 1440 | "1 method for generic function Vector2D:
  • Vector2D{T<:Real}(x::T<:Real,y::T<:Real)
" 1441 | ], 1442 | "metadata": {}, 1443 | "output_type": "pyout", 1444 | "prompt_number": 9, 1445 | "text": [ 1446 | "# 1 method for generic function \"Vector2D\":\n", 1447 | "Vector2D{T<:Real}(x::T<:Real,y::T<:Real)" 1448 | ] 1449 | } 1450 | ], 1451 | "prompt_number": 9 1452 | }, 1453 | { 1454 | "cell_type": "code", 1455 | "collapsed": false, 1456 | "input": [ 1457 | "v = Vector2D{Float64}(3, 4)" 1458 | ], 1459 | "language": "python", 1460 | "metadata": {}, 1461 | "outputs": [ 1462 | { 1463 | "metadata": {}, 1464 | "output_type": "pyout", 1465 | "prompt_number": 10, 1466 | "text": [ 1467 | "Vector2D{Float64}(3.0,4.0)" 1468 | ] 1469 | } 1470 | ], 1471 | "prompt_number": 10 1472 | }, 1473 | { 1474 | "cell_type": "code", 1475 | "collapsed": false, 1476 | "input": [ 1477 | "v = Vector2D(3., 4)" 1478 | ], 1479 | "language": "python", 1480 | "metadata": {}, 1481 | "outputs": [ 1482 | { 1483 | "ename": "LoadError", 1484 | "evalue": "no method Vector2D{T<:Real}(Float64, Int64)\nwhile loading In[11], in expression starting on line 1", 1485 | "output_type": "pyerr", 1486 | "traceback": [ 1487 | "no method Vector2D{T<:Real}(Float64, Int64)\nwhile loading In[11], in expression starting on line 1" 1488 | ] 1489 | } 1490 | ], 1491 | "prompt_number": 11 1492 | }, 1493 | { 1494 | "cell_type": "code", 1495 | "collapsed": false, 1496 | "input": [ 1497 | "v = Vector2D(3., 4.)" 1498 | ], 1499 | "language": "python", 1500 | "metadata": {}, 1501 | "outputs": [ 1502 | { 1503 | "metadata": {}, 1504 | "output_type": "pyout", 1505 | "prompt_number": 18, 1506 | "text": [ 1507 | "Vector2D{Float64}(3.0,4.0)" 1508 | ] 1509 | } 1510 | ], 1511 | "prompt_number": 18 1512 | }, 1513 | { 1514 | "cell_type": "code", 1515 | "collapsed": false, 1516 | "input": [ 1517 | "# clear" 1518 | ], 1519 | "language": "python", 1520 | "metadata": {}, 1521 | "outputs": [], 1522 | "prompt_number": 2 1523 | }, 1524 | { 1525 | "cell_type": "code", 1526 | "collapsed": false, 1527 | "input": [ 1528 | "# uses show(io::IO, v::DataType) by default" 1529 | ], 1530 | "language": "python", 1531 | "metadata": {}, 1532 | "outputs": [], 1533 | "prompt_number": 4 1534 | }, 1535 | { 1536 | "cell_type": "code", 1537 | "collapsed": false, 1538 | "input": [ 1539 | "typeof(Vector2D)" 1540 | ], 1541 | "language": "python", 1542 | "metadata": {}, 1543 | "outputs": [ 1544 | { 1545 | "metadata": {}, 1546 | "output_type": "pyout", 1547 | "prompt_number": 15, 1548 | "text": [ 1549 | "DataType" 1550 | ] 1551 | } 1552 | ], 1553 | "prompt_number": 15 1554 | }, 1555 | { 1556 | "cell_type": "code", 1557 | "collapsed": false, 1558 | "input": [ 1559 | "super(Vector2D)" 1560 | ], 1561 | "language": "python", 1562 | "metadata": {}, 1563 | "outputs": [ 1564 | { 1565 | "metadata": {}, 1566 | "output_type": "pyout", 1567 | "prompt_number": 13, 1568 | "text": [ 1569 | "Any" 1570 | ] 1571 | } 1572 | ], 1573 | "prompt_number": 13 1574 | }, 1575 | { 1576 | "cell_type": "code", 1577 | "collapsed": false, 1578 | "input": [ 1579 | "methods(show)" 1580 | ], 1581 | "language": "python", 1582 | "metadata": {}, 1583 | "outputs": [ 1584 | { 1585 | "html": [ 1586 | "89 methods for generic function show:" 1587 | ], 1588 | "metadata": {}, 1589 | "output_type": "pyout", 1590 | "prompt_number": 3, 1591 | "text": [ 1592 | "# 89 methods for generic function \"show\":\n", 1593 | "show(io::IO,r::UnitRange{T<:Real}) at range.jl:283\n", 1594 | "show(io::IO,r::Range{T}) at range.jl:281\n", 1595 | "show(io::IO,tv::TypeVar) at expr.jl:46\n", 1596 | "show(io::IO,z::Complex{T<:Real}) at complex.jl:80\n", 1597 | "show(io::IO,x::Rational{T<:Integer}) at rational.jl:35\n", 1598 | "show(io::IO,s::IntSet) at intset.jl:170\n", 1599 | "show(io::IO,::EnvHash) at env.jl:168\n", 1600 | "show{K,V}(io::IO,t::Associative{K,V}) at dict.jl:20\n", 1601 | "show(io::IO,iter::Union(KeyIterator{T<:Associative{K,V}},ValueIterator{T<:Associative{K,V}})) at dict.jl:118\n", 1602 | "show(io::IO,s::Set{T}) at set.jl:10\n", 1603 | "show(io::IO,c::Char) at char.jl:53\n", 1604 | "show(io::IO,b::IOBuffer) at iobuffer.jl:27\n", 1605 | "show(io::IO,s::String) at string.jl:69\n", 1606 | "show(io::IO,re::Regex) at regex.jl:61\n", 1607 | "show(io::IO,m::RegexMatch) at regex.jl:89\n", 1608 | "show(io::IO,s::IOStream) at iostream.jl:26\n", 1609 | "show(io::IO,t::Task) at task.jl:3\n", 1610 | "show(io::IO,f::Function) at show.jl:57\n", 1611 | "show(io::IO,x::IntrinsicFunction) at show.jl:67\n", 1612 | "show(io::IO,x::UnionType) at show.jl:71\n", 1613 | "show(io::IO,x::TypeConstructor) at show.jl:80\n", 1614 | "show(io::IO,x::DataType) at show.jl:83\n", 1615 | "show(io::IO,tn::TypeName) at show.jl:200\n", 1616 | "show(io::IO,::Nothing) at show.jl:201\n", 1617 | "show(io::IO,b::Bool) at show.jl:202\n", 1618 | "show(io::IO,n::Signed) at show.jl:203\n", 1619 | "show(io::IO,n::Unsigned) at show.jl:204\n", 1620 | "show{T}(io::IO,p::Ptr{T}) at show.jl:116\n", 1621 | "show(io::IO,m::Module) at show.jl:120\n", 1622 | "show(io::IO,l::LambdaStaticData) at show.jl:128\n", 1623 | "show(io::IO,t::(Any...,)) at show.jl:197\n", 1624 | "show(io::IO,s::Symbol) at show.jl:199\n", 1625 | "show(io::IO,ex::Union(LabelNode,LineNumberNode,Expr,GotoNode,SymbolNode,TopNode,QuoteNode)) at show.jl:234\n", 1626 | "show(io::IO,W::Woodbury{T}) at linalg/woodbury.jl:42\n", 1627 | "show(io::IO,M::Bidiagonal{T}) at linalg/bidiag.jl:56\n", 1628 | "show(io::IO,v::AbstractArray{Any,1}) at show.jl:1102\n", 1629 | "show(io::IO,v::AbstractArray{T,1}) at show.jl:1103\n", 1630 | "show(io::IO,X::AbstractArray{T,N}) at show.jl:1038\n", 1631 | "show(io::IO,stream::Pipe) at stream.jl:171\n", 1632 | "show(io::IO,stream::PipeServer) at stream.jl:173\n", 1633 | "show(io::IO,stream::TTY) at stream.jl:215\n", 1634 | "show(io::IO,e::UVError) at stream.jl:824\n", 1635 | "show(io::IO,ip::IPv4) at socket.jl:29\n", 1636 | "show(io::IO,ip::IPv6) at socket.jl:81\n", 1637 | "show(io::IO,sock::TcpSocket) at socket.jl:324\n", 1638 | "show(io::IO,sock::TcpServer) at socket.jl:327\n", 1639 | "show(io::IO,st::StatStruct) at stat.jl:31\n", 1640 | "show(io::IO,cmd::Cmd) at process.jl:33\n", 1641 | "show(io::IO,cmds::OrCmds) at process.jl:51\n", 1642 | "show(io::IO,cmds::AndCmds) at process.jl:69\n", 1643 | "show(io::IO,cr::CmdRedirect) at process.jl:123\n", 1644 | "show(io::IO,p::Process) at process.jl:622\n", 1645 | "show{mime}(io::IO,::MIME{mime}) at multimedia.jl:16\n", 1646 | "show(io::IO,x::Float64) at grisu.jl:114\n", 1647 | "show(io::IO,x::Float32) at grisu.jl:115\n", 1648 | "show(io::IO,x::Float16) at grisu.jl:116\n", 1649 | "show(io::IO,m::Method) at methodshow.jl:35\n", 1650 | "show(io::IO,mt::MethodTable) at methodshow.jl:74\n", 1651 | "show(io::IO,cman::LocalManager) at multi.jl:1109\n", 1652 | "show(io::IO,cman::SSHManager) at multi.jl:1144\n", 1653 | "show(io::IO,x::BigInt) at gmp.jl:417\n", 1654 | "show(io::IO,b::BigFloat) at mpfr.jl:762\n", 1655 | "show(io::IO,u::UUID) at random.jl:297\n", 1656 | "show(io::IO,v::VersionNumber) at version.jl:57\n", 1657 | "show(io::IO,x::Prompt) at LineEdit.jl:48\n", 1658 | "show(io::IO,C::Cholesky{T}) at linalg/factorization.jl:83\n", 1659 | "show(io::IO,J::UniformScaling{T<:Number}) at linalg/uniformscaling.jl:14\n", 1660 | "show(io::IO,f::UmfpackLU{Tv<:Union(Float64,Complex{Float64}),Ti<:Union(Int64,Int32)}) at linalg/umfpack.jl:134\n", 1661 | "show(io::IO,cd::CholmodDense{T<:Union(Complex{Float32},Float64,Float32,Complex{Float64})}) at linalg/cholmod.jl:382\n", 1662 | "show(io::IO,L::CholmodFactor{Tv<:Union(Complex{Float32},Float64,Float32,Complex{Float64}),Ti<:Union(Int64,Int32)}) at linalg/cholmod.jl:914\n", 1663 | "show(io::IO,A::CholmodSparse{Tv<:Union(Complex{Float32},Float64,Float32,Complex{Float64}),Ti<:Union(Int64,Int32)}) at linalg/cholmod.jl:915\n", 1664 | "show(io::IO,info::CPUinfo) at sysinfo.jl:58\n", 1665 | "show(io::IO,info::CPUinfo,header::Bool) at sysinfo.jl:58\n", 1666 | "show(io::IO,info::CPUinfo,header::Bool,prefix::String) at sysinfo.jl:58\n", 1667 | "show{sym}(io::IO,x::MathConst{sym}) at constants.jl:5\n", 1668 | "show(io::IO,i::VersionInterval) at pkg/types.jl:13\n", 1669 | "show(io::IO,s::VersionSet) at pkg/types.jl:36\n", 1670 | "show(io::IO,a::Available) at pkg/types.jl:69\n", 1671 | "show(io::IO,f::Fixed) at pkg/types.jl:81\n", 1672 | "show(io::IO,blk::DequeBlock{T}) at /Users/david/.julia/DataStructures/src/deque.jl:46\n", 1673 | "show(io::IO,q::Deque{T}) at /Users/david/.julia/DataStructures/src/deque.jl:139\n", 1674 | "show(io::IO,h::MutableBinaryHeap{VT,Comp}) at /Users/david/.julia/DataStructures/src/heaps/mutable_binary_heap.jl:177\n", 1675 | "show(io::IO,s::OrderedSet{T}) at /Users/david/.julia/DataStructures/src/orderedset.jl:18\n", 1676 | "show{T}(io::IO,l::LinkedList{T}) at /Users/david/.julia/DataStructures/src/list.jl:20\n", 1677 | "show{T<:HashAlgorithm}(io::IO,::HashState{T<:HashAlgorithm}) at /Users/david/.julia/Nettle/src/hash.jl:94\n", 1678 | "show{T<:HashAlgorithm}(io::IO,::HMACState{T<:HashAlgorithm}) at /Users/david/.julia/Nettle/src/hmac.jl:16\n", 1679 | "show(io::IO,msg::Msg) at /Users/david/.julia/IJulia/src/msg.jl:38\n", 1680 | "show(io::IO,x::ANY) at show.jl:7\n", 1681 | "show(x) at show.jl:2" 1682 | ] 1683 | } 1684 | ], 1685 | "prompt_number": 3 1686 | }, 1687 | { 1688 | "cell_type": "code", 1689 | "collapsed": false, 1690 | "input": [ 1691 | "Base.show(io::IO, v::Vector2D) = print(io, \"[$(v.x), $(v.y)]\")" 1692 | ], 1693 | "language": "python", 1694 | "metadata": {}, 1695 | "outputs": [ 1696 | { 1697 | "metadata": {}, 1698 | "output_type": "pyout", 1699 | "prompt_number": 20, 1700 | "text": [ 1701 | "show (generic function with 91 methods)" 1702 | ] 1703 | } 1704 | ], 1705 | "prompt_number": 20 1706 | }, 1707 | { 1708 | "cell_type": "code", 1709 | "collapsed": false, 1710 | "input": [ 1711 | "v" 1712 | ], 1713 | "language": "python", 1714 | "metadata": {}, 1715 | "outputs": [ 1716 | { 1717 | "metadata": {}, 1718 | "output_type": "pyout", 1719 | "prompt_number": 18, 1720 | "text": [ 1721 | "[3.0, 4.0]" 1722 | ] 1723 | } 1724 | ], 1725 | "prompt_number": 18 1726 | }, 1727 | { 1728 | "cell_type": "code", 1729 | "collapsed": false, 1730 | "input": [ 1731 | "Vector2D(3im, 4im)" 1732 | ], 1733 | "language": "python", 1734 | "metadata": {}, 1735 | "outputs": [ 1736 | { 1737 | "ename": "LoadError", 1738 | "evalue": "no method Vector2D{T<:Real}(Complex{Int64}, Complex{Int64})\nwhile loading In[19], in expression starting on line 1", 1739 | "output_type": "pyerr", 1740 | "traceback": [ 1741 | "no method Vector2D{T<:Real}(Complex{Int64}, Complex{Int64})\nwhile loading In[19], in expression starting on line 1" 1742 | ] 1743 | } 1744 | ], 1745 | "prompt_number": 19 1746 | }, 1747 | { 1748 | "cell_type": "code", 1749 | "collapsed": false, 1750 | "input": [ 1751 | "code = \n", 1752 | "\"\"\"\n", 1753 | "function testinf(a, b)\n", 1754 | " y = a + b\n", 1755 | " return sin(y)\n", 1756 | "end\n", 1757 | "\"\"\"\n", 1758 | "ex = parse(code)\n", 1759 | "eval(ex)" 1760 | ], 1761 | "language": "python", 1762 | "metadata": {}, 1763 | "outputs": [ 1764 | { 1765 | "metadata": {}, 1766 | "output_type": "pyout", 1767 | "prompt_number": 29, 1768 | "text": [ 1769 | "testinf (generic function with 1 method)" 1770 | ] 1771 | } 1772 | ], 1773 | "prompt_number": 29 1774 | }, 1775 | { 1776 | "cell_type": "code", 1777 | "collapsed": false, 1778 | "input": [ 1779 | "function testinf(a, b)\n", 1780 | " y = a + b\n", 1781 | " return sin(y)\n", 1782 | "end\n" 1783 | ], 1784 | "language": "python", 1785 | "metadata": {}, 1786 | "outputs": [ 1787 | { 1788 | "metadata": {}, 1789 | "output_type": "pyout", 1790 | "prompt_number": 21, 1791 | "text": [ 1792 | "testinf (generic function with 1 method)" 1793 | ] 1794 | } 1795 | ], 1796 | "prompt_number": 21 1797 | }, 1798 | { 1799 | "cell_type": "code", 1800 | "collapsed": false, 1801 | "input": [ 1802 | "code_lowered(testinf,(Int, Int))" 1803 | ], 1804 | "language": "python", 1805 | "metadata": {}, 1806 | "outputs": [ 1807 | { 1808 | "metadata": {}, 1809 | "output_type": "pyout", 1810 | "prompt_number": 24, 1811 | "text": [ 1812 | "1-element Array{Any,1}:\n", 1813 | " :($(Expr(:lambda, {:a,:b}, {{:y},{{:a,:Any,0},{:b,:Any,0},{:y,:Any,18}},{}}, :(begin # In[21], line 2:\n", 1814 | " y = a + b # line 3:\n", 1815 | " return sin(y)\n", 1816 | " end))))" 1817 | ] 1818 | } 1819 | ], 1820 | "prompt_number": 24 1821 | }, 1822 | { 1823 | "cell_type": "code", 1824 | "collapsed": false, 1825 | "input": [ 1826 | "code_typed(testinf, (Int, Int))" 1827 | ], 1828 | "language": "python", 1829 | "metadata": {}, 1830 | "outputs": [ 1831 | { 1832 | "metadata": {}, 1833 | "output_type": "pyout", 1834 | "prompt_number": 22, 1835 | "text": [ 1836 | "1-element Array{Any,1}:\n", 1837 | " :($(Expr(:lambda, {:a,:b}, {{:y,:_var1},{{:a,Int64,0},{:b,Int64,0},{:y,Int64,18},{:_var1,Float64,18}},{}}, :(begin # In[21], line 2:\n", 1838 | " y = top(box)(Int64,top(add_int)(a::Int64,b::Int64))::Int64 # line 3:\n", 1839 | " _var1 = GetfieldNode(Base.Math,:box,Any)(Float64,top(sitofp)(Float64,y::Int64))::Float64\n", 1840 | " return GetfieldNode(Base.Math,:nan_dom_err,Any)(top(ccall)($(Expr(:call1, :(top(tuple)), \"sin\", GetfieldNode(Base.Math,:libm,Any)))::(ASCIIString,ASCIIString),Float64,$(Expr(:call1, :(top(tuple)), :Float64))::(Type{Float64},),_var1::Float64,0)::Float64,_var1::Float64)::Float64\n", 1841 | " end::Float64))))" 1842 | ] 1843 | } 1844 | ], 1845 | "prompt_number": 22 1846 | }, 1847 | { 1848 | "cell_type": "code", 1849 | "collapsed": false, 1850 | "input": [ 1851 | "code_typed(testinf, (Float64, Float64))" 1852 | ], 1853 | "language": "python", 1854 | "metadata": {}, 1855 | "outputs": [ 1856 | { 1857 | "metadata": {}, 1858 | "output_type": "pyout", 1859 | "prompt_number": 23, 1860 | "text": [ 1861 | "1-element Array{Any,1}:\n", 1862 | " :($(Expr(:lambda, {:a,:b}, {{:y},{{:a,Float64,0},{:b,Float64,0},{:y,Float64,18}},{}}, :(begin # In[21], line 2:\n", 1863 | " y = top(box)(Float64,top(add_float)(a::Float64,b::Float64))::Float64 # line 3:\n", 1864 | " return GetfieldNode(Base.Math,:nan_dom_err,Any)(top(ccall)($(Expr(:call1, :(top(tuple)), \"sin\", GetfieldNode(Base.Math,:libm,Any)))::(ASCIIString,ASCIIString),Float64,$(Expr(:call1, :(top(tuple)), :Float64))::(Type{Float64},),y::Float64,0)::Float64,y::Float64)::Float64\n", 1865 | " end::Float64))))" 1866 | ] 1867 | } 1868 | ], 1869 | "prompt_number": 23 1870 | }, 1871 | { 1872 | "cell_type": "code", 1873 | "collapsed": false, 1874 | "input": [ 1875 | "code_llvm(testinf, (Int, Int))" 1876 | ], 1877 | "language": "python", 1878 | "metadata": {}, 1879 | "outputs": [ 1880 | { 1881 | "output_type": "stream", 1882 | "stream": "stdout", 1883 | "text": [ 1884 | "\n", 1885 | "define double @\"julia_testinf;19510\"(i64, i64) {\n", 1886 | "top:\n", 1887 | " %2 = add i64 %1, %0, !dbg !2501\n", 1888 | " %3 = sitofp i64 %2 to double, !dbg !2502\n", 1889 | " %4 = call double inttoptr (i64 4514612992 to double (double)*)(double %3), !dbg !2502\n", 1890 | " %5 = fcmp ord double %4, 0.000000e+00, !dbg !2502\n", 1891 | " %6 = fcmp uno double %3, 0.000000e+00, !dbg !2502\n", 1892 | " %7 = or i1 %5, %6, !dbg !2502\n", 1893 | " br i1 %7, label %pass, label %fail, !dbg !2502\n", 1894 | "\n", 1895 | "fail: ; preds = %top\n", 1896 | " %8 = load %jl_value_t** @jl_domain_exception, align 8, !dbg !2502, !tbaa %jtbaa_const\n", 1897 | " call void @jl_throw_with_superfluous_argument(%jl_value_t* %8, i32 3), !dbg !2502\n", 1898 | " unreachable, !dbg !2502\n", 1899 | "\n", 1900 | "pass: ; preds = %top\n", 1901 | " ret double %4, !dbg !2502\n", 1902 | "}\n" 1903 | ] 1904 | } 1905 | ], 1906 | "prompt_number": 25 1907 | }, 1908 | { 1909 | "cell_type": "code", 1910 | "collapsed": false, 1911 | "input": [ 1912 | "code_native(testinf, (Int, Int))" 1913 | ], 1914 | "language": "python", 1915 | "metadata": {}, 1916 | "outputs": [ 1917 | { 1918 | "output_type": "stream", 1919 | "stream": "stdout", 1920 | "text": [ 1921 | "\t.section\t__TEXT,__text,regular,pure_instructions\n", 1922 | "Filename: In[21]\n", 1923 | "Source line: 2\n", 1924 | "\tpush\tRBP\n", 1925 | "\tmov\tRBP, RSP\n", 1926 | "Source line: 2\n", 1927 | "\tsub\tRSP, 16\n", 1928 | "\tadd\tRDI, RSI\n", 1929 | "Source line: 3\n", 1930 | "\tvcvtsi2sd\tXMM0, XMM0, RDI\n", 1931 | "\tvmovsd\tQWORD PTR [RBP - 8], XMM0\n", 1932 | "\tmovabs\tRAX, 4514612992\n", 1933 | "\tcall\tRAX\n", 1934 | "\tvucomisd\tXMM0, XMM0\n", 1935 | "\tjp\t6\n", 1936 | "\tadd\tRSP, 16\n", 1937 | "\tpop\tRBP\n", 1938 | "\tret\n", 1939 | "\tvmovsd\tXMM1, QWORD PTR [RBP - 8]\n", 1940 | "\tvucomisd\tXMM1, XMM1\n", 1941 | "\tjp\t-21\n", 1942 | "\tmovabs\tRAX, 4380089384\n", 1943 | "\tmov\tRDI, QWORD PTR [RAX]\n", 1944 | "\tmovabs\tRAX, 4367555552\n", 1945 | "\tmov\tESI, 3\n", 1946 | "\tcall\tRAX\n" 1947 | ] 1948 | } 1949 | ], 1950 | "prompt_number": 26 1951 | }, 1952 | { 1953 | "cell_type": "code", 1954 | "collapsed": false, 1955 | "input": [ 1956 | "names(testinf)" 1957 | ], 1958 | "language": "python", 1959 | "metadata": {}, 1960 | "outputs": [ 1961 | { 1962 | "metadata": {}, 1963 | "output_type": "pyout", 1964 | "prompt_number": 32, 1965 | "text": [ 1966 | "3-element Array{Symbol,1}:\n", 1967 | " :fptr\n", 1968 | " :env \n", 1969 | " :code" 1970 | ] 1971 | } 1972 | ], 1973 | "prompt_number": 32 1974 | }, 1975 | { 1976 | "cell_type": "code", 1977 | "collapsed": false, 1978 | "input": [ 1979 | "testinf.fptr" 1980 | ], 1981 | "language": "python", 1982 | "metadata": {}, 1983 | "outputs": [ 1984 | { 1985 | "metadata": {}, 1986 | "output_type": "pyout", 1987 | "prompt_number": 34, 1988 | "text": [ 1989 | "Ptr{Void} @0x00000001044f2e50" 1990 | ] 1991 | } 1992 | ], 1993 | "prompt_number": 34 1994 | }, 1995 | { 1996 | "cell_type": "code", 1997 | "collapsed": false, 1998 | "input": [ 1999 | "testinf.code" 2000 | ], 2001 | "language": "python", 2002 | "metadata": {}, 2003 | "outputs": [ 2004 | { 2005 | "ename": "LoadError", 2006 | "evalue": "access to undefined reference\nwhile loading In[38], in expression starting on line 1", 2007 | "output_type": "pyerr", 2008 | "traceback": [ 2009 | "access to undefined reference\nwhile loading In[38], in expression starting on line 1" 2010 | ] 2011 | } 2012 | ], 2013 | "prompt_number": 38 2014 | }, 2015 | { 2016 | "cell_type": "code", 2017 | "collapsed": false, 2018 | "input": [ 2019 | "?dump" 2020 | ], 2021 | "language": "python", 2022 | "metadata": {}, 2023 | "outputs": [ 2024 | { 2025 | "output_type": "stream", 2026 | "stream": "stderr", 2027 | "text": [ 2028 | "INFO: Loading help data...\n" 2029 | ] 2030 | }, 2031 | { 2032 | "output_type": "stream", 2033 | "stream": "stdout", 2034 | "text": [ 2035 | "Base.dump(x)\n", 2036 | "\n", 2037 | " Show all user-visible structure of a value.\n" 2038 | ] 2039 | } 2040 | ], 2041 | "prompt_number": 11 2042 | }, 2043 | { 2044 | "cell_type": "heading", 2045 | "level": 2, 2046 | "metadata": {}, 2047 | "source": [ 2048 | "Possible solution of the `@until` exercise:" 2049 | ] 2050 | }, 2051 | { 2052 | "cell_type": "code", 2053 | "collapsed": false, 2054 | "input": [ 2055 | "macro until(ex1, ex2)\n", 2056 | " quote\n", 2057 | " while !($ex1)\n", 2058 | " $ex2\n", 2059 | " end\n", 2060 | " end\n", 2061 | "end" 2062 | ], 2063 | "language": "python", 2064 | "metadata": {}, 2065 | "outputs": [], 2066 | "prompt_number": 2 2067 | }, 2068 | { 2069 | "cell_type": "code", 2070 | "collapsed": false, 2071 | "input": [ 2072 | "i = 1\n", 2073 | "\n", 2074 | "@until i > 10 begin\n", 2075 | " println(i)\n", 2076 | " i += 1\n", 2077 | "end" 2078 | ], 2079 | "language": "python", 2080 | "metadata": {}, 2081 | "outputs": [ 2082 | { 2083 | "output_type": "stream", 2084 | "stream": "stdout", 2085 | "text": [ 2086 | "1\n" 2087 | ] 2088 | }, 2089 | { 2090 | "output_type": "stream", 2091 | "stream": "stdout", 2092 | "text": [ 2093 | "2\n", 2094 | "3\n", 2095 | "4\n", 2096 | "5\n", 2097 | "6\n", 2098 | "7\n", 2099 | "8\n", 2100 | "9\n", 2101 | "10\n" 2102 | ] 2103 | } 2104 | ], 2105 | "prompt_number": 10 2106 | }, 2107 | { 2108 | "cell_type": "code", 2109 | "collapsed": false, 2110 | "input": [ 2111 | "i = 1\n", 2112 | "\n", 2113 | "@until i > 10 \n", 2114 | "begin\n", 2115 | " println(i)\n", 2116 | " i += 1\n", 2117 | "end" 2118 | ], 2119 | "language": "python", 2120 | "metadata": {}, 2121 | "outputs": [ 2122 | { 2123 | "ename": "LoadError", 2124 | "evalue": "wrong number of arguments\nwhile loading In[11], in expression starting on line 4", 2125 | "output_type": "pyerr", 2126 | "traceback": [ 2127 | "wrong number of arguments\nwhile loading In[11], in expression starting on line 4" 2128 | ] 2129 | } 2130 | ], 2131 | "prompt_number": 11 2132 | }, 2133 | { 2134 | "cell_type": "code", 2135 | "collapsed": false, 2136 | "input": [ 2137 | ":while" 2138 | ], 2139 | "language": "python", 2140 | "metadata": {}, 2141 | "outputs": [ 2142 | { 2143 | "metadata": {}, 2144 | "output_type": "pyout", 2145 | "prompt_number": 13, 2146 | "text": [ 2147 | ":while" 2148 | ] 2149 | } 2150 | ], 2151 | "prompt_number": 13 2152 | }, 2153 | { 2154 | "cell_type": "code", 2155 | "collapsed": false, 2156 | "input": [], 2157 | "language": "python", 2158 | "metadata": {}, 2159 | "outputs": [] 2160 | } 2161 | ], 2162 | "metadata": {} 2163 | } 2164 | ] 2165 | } --------------------------------------------------------------------------------