{ "cells": [ { "cell_type": "markdown", "metadata": { "toc": "true" }, "source": [ "# Table of Contents\n", "

1  Introduction to Julia
1.1  Types of computer languages
1.2  Messages
1.3  What's Julia?
1.4  R is great, but...
1.5  Gibbs sampler example by Doug Bates
1.6  Learning resources
1.7  Julia REPL (Read-Evaluation-Print-Loop)
1.8  Seek help
1.9  Which IDE?
1.10  Julia package system
1.11  Calling R from Julia
1.12  Some basic Julia code
1.13  Timing and benchmark
1.13.1  Julia
1.13.2  C
1.13.3  R, buildin sum
1.13.4  R, handwritten loop
1.13.5  Python, builtin sum
1.13.6  Python, handwritten loop
1.13.7  Python, numpy
1.13.8  Summary
1.14  Matrices and vectors
1.14.1  Dimensions
1.14.2  Indexing
1.14.3  Concatenate matrices
1.14.4  Dot operation
1.14.5  Basic linear algebra
1.14.6  Sparse matrices
1.15  Control flow and loops
1.16  Functions
1.17  Type system
1.18  Multiple dispatch
1.19  Just-in-time compilation (JIT)
1.20  Profiling Julia code
1.21  Memory profiling
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to Julia\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Types of computer languages\n", "\n", "* **Compiled languages**: C/C++, Fortran, ... \n", " - Directly compiled to machine code that is executed by CPU \n", " - Pros: fast, memory efficient\n", " - Cons: longer development time, hard to debug\n", "\n", "* **Interpreted language**: R, Matlab, Python, SAS IML, JavaScript, ... \n", " - Interpreted by interpreter\n", " - Pros: fast prototyping\n", " - Cons: excruciatingly slow for loops\n", "\n", "* Mixed (dynamic) languages: Matlab (JIT), R (`compiler` package), Julia, Cython, JAVA, ...\n", " - Pros and cons: between the compiled and interpreted languages\n", "\n", "* Script languages: Linux shell scripts, Perl, ...\n", " - Extremely useful for some data preprocessing and manipulation\n", "\n", "* Database languages: SQL, Hive (Hadoop). \n", " - Data analysis *never* happens if we do not know how to retrieve data from databases " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Messages\n", "\n", "* To be versatile in the big data era, master at least one language in each category.\n", "\n", "* To improve efficiency of interpreted languages such as R or Matlab, conventional wisdom is to avoid loops as much as possible. Aka, **vectorize code**\n", "> The only loop you are allowed to have is that for an iterative algorithm.\n", "\n", "* When looping is unavoidable, need to code in C, C++, or Fortran. \n", "Success stories: the popular `glmnet` package in R is coded in Fortran; `tidyverse` packages use a lot RCpp/C++.\n", "\n", "* Modern languages such as Julia tries to solve the **two language problem**. That is to achieve efficiency without vectorizing code.\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What's Julia?\n", "\n", "> Julia is a high-level, high-performance dynamic programming language for technical computing, with syntax that is familiar to users of other technical computing environments\n", "\n", "* History:\n", " - Project started in 2009. First public release in 2012 \n", " - Creators: Jeff Bezanson, Alan Edelman, Stefan Karpinski, Viral Shah\n", " - First major release v1.0 was released on Aug 8, 2018\n", " - Current stable release v1.1.0\n", "\n", "* Aim to solve the notorious **two language problem**: Prototype code goes into high-level languages like R/Python, production code goes into low-level language like C/C++. \n", "\n", " Julia aims to:\n", "> Walks like Python. Runs like C.\n", "\n", "\n", "\n", "See for the details of benchmark.\n", "\n", "* Write high-level, abstract code that closely resembles mathematical formulas\n", " - yet produces fast, low-level machine code that has traditionally only been generated by static languages.\n", "\n", "* Julia is more than just \"Fast R\" or \"Fast Matlab\"\n", " - Performance comes from features that work well together. \n", " - You can't just take the magic dust that makes Julia fast and sprinkle it on [language of choice]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## R is great, but...\n", "\n", "* It's not meant for high performance computing\n", " - http://adv-r.had.co.nz/Performance.html\n", " - Section on performance starts with \"Why is R slow?\" \n", "\n", "* Deficiencies in the core language \n", " - Many fixed with packages (`devtools`, `roxygen2`, `Matrix`)\n", " - Others harder to fix (R uses an old version of BLAS)\n", " - Some impossible to fix (clunky syntax, poor design choices)\n", "\n", "* Only 6 active developers left (out of 20 R-Core members)\n", " - JuliaLang organization has 75 members, with 567 total contributors (as of 3/3/17)\n", " - https://github.com/JuliaLang/julia/graphs/contributors\n", "\n", "* Doug Bates (member of R-Core, `Matrix` and `lme4`)\n", " - Getting Doug on board was a big win for statistics with Julia, as he brought a lot of knowledge about the history of R development and design choices\n", " - https://github.com/dmbates/MixedModels.jl\n", " \n", " > As some of you may know, I have had a (rather late) mid-life crisis and run off with another language called Julia. \n", " >\n", " > -- Doug Bates (on the `knitr` Google Group)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Gibbs sampler example by Doug Bates\n", "\n", "* An example from Dr. Doug Bates's slides [Julia for R Programmers](http://www.stat.wisc.edu/~bates/JuliaForRProgrammers.pdf).\n", "\n", "* The task is to create a Gibbs sampler for the density \n", "$$\n", "f(x, y) = k x^2 exp(- x y^2 - y^2 + 2y - 4x), x > 0\n", "$$\n", "using the conditional distributions\n", "$$\n", "\\begin{eqnarray*}\n", " X | Y &\\sim& \\Gamma \\left( 3, \\frac{1}{y^2 + 4} \\right) \\\\\n", " Y | X &\\sim& N \\left(\\frac{1}{1+x}, \\frac{1}{2(1+x)} \\right).\n", "\\end{eqnarray*}\n", "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* R solution. The `RCall.jl` package allows us to execute R code without leaving the `Julia` environment. We first define an R function `Rgibbs()`." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "RObject{ClosSxp}\n", "function (N, thin) \n", "{\n", " mat <- matrix(0, nrow = N, ncol = 2)\n", " x <- y <- 0\n", " for (i in 1:N) {\n", " for (j in 1:thin) {\n", " x <- rgamma(1, 3, y * y + 4)\n", " y <- rnorm(1, 1/(x + 1), 1/sqrt(2 * (x + 1)))\n", " }\n", " mat[i, ] <- c(x, y)\n", " }\n", " mat\n", "}\n" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using RCall\n", "\n", "R\"\"\"\n", "library(Matrix)\n", "Rgibbs <- function(N, thin) {\n", " mat <- matrix(0, nrow=N, ncol=2)\n", " x <- y <- 0\n", " for (i in 1:N) {\n", " for (j in 1:thin) {\n", " x <- rgamma(1, 3, y * y + 4) # 3rd arg is rate\n", " y <- rnorm(1, 1 / (x + 1), 1 / sqrt(2 * (x + 1)))\n", " }\n", " mat[i,] <- c(x, y)\n", " }\n", " mat\n", "}\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To generate a sample of size 10,000 with a thinning of 500. How long does it take?" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "RObject{RealSxp}\n", " user system elapsed \n", " 21.038 2.197 23.265 \n" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "R\"\"\"\n", "system.time(Rgibbs(10000, 500))\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* This is a Julia function for the simple Gibbs sampler:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "jgibbs (generic function with 1 method)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Distributions\n", "\n", "function jgibbs(N, thin)\n", " mat = zeros(N, 2)\n", " x = y = 0.0\n", " for i in 1:N\n", " for j in 1:thin\n", " x = rand(Gamma(3, 1 / (y * y + 4)))\n", " y = rand(Normal(1 / (x + 1), 1 / sqrt(2(x + 1))))\n", " end\n", " mat[i, 1] = x\n", " mat[i, 2] = y\n", " end\n", " mat\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Generate the same number of samples. How long does it take?" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.317547402" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "jgibbs(100, 5); # warm-up\n", "@elapsed jgibbs(10000, 500)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see 40-80 fold speed up of `Julia` over `R` on this example, **with similar coding effort**!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Learning resources\n", "\n", "1. YouTube: [Intro to Julia](https://www.youtube.com/watch?v=8h8rQyEpiZA&t) (2h28m), by Jane Herriman. \n", "\n", "2. Cheat sheet: [The Fast Track to Julia](https://juliadocs.github.io/Julia-Cheat-Sheet/). \n", "\n", "3. Browse the Julia [documentation](https://docs.julialang.org/en). \n", "\n", "4. For Matlab users, read [Noteworthy Differences From Matlab](https://docs.julialang.org/en/v1/manual/noteworthy-differences/#Noteworthy-differences-from-MATLAB-1). \n", "\n", " For R users, read [Noteworthy Differences From R](https://docs.julialang.org/en/v1/manual/noteworthy-differences/#Noteworthy-differences-from-R-1). \n", "\n", " For Python users, read [Noteworthy Differences From Python](https://docs.julialang.org/en/v1/manual/noteworthy-differences/?highlight=matlab#Noteworthy-differences-from-Python-1). \n", "\n", "5. The [Learning page](http://julialang.org/learning/) on Julia's website has pointers to many other learning resources. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Julia REPL (Read-Evaluation-Print-Loop)\n", "\n", "The `Julia` REPL, or `Julia` shell, has at least five modes.\n", "\n", "1. **Default mode** is the Julian prompt `julia>`. Type backspace in other modes to enter default mode. \n", "\n", "2. **Help mode** `help?>`. Type `?` to enter help mode. `?search_term` does a fuzzy search for `search_term`. \n", "\n", "3. **Shell mode** `shell>`. Type `;` to enter shell mode. \n", "\n", "4. **Package mode** `v(1.1) Pkg>`. Type `]` to enter package mode for managing Julia packages (install, uninstall, update, ...).\n", "\n", "5. **Search mode** `(reverse-i-search)`. Press `ctrl+R` to enter search model. \n", "\n", "6. With `RCall.jl` package installed, we can enter the **R mode** by typing `$` (shift+4) at Julia REPL.\n", "\n", "Some survival commands in Julia REPL: \n", "1. `quit()` or `Ctrl+D`: exit Julia.\n", "\n", "2. `Ctrl+C`: interrupt execution.\n", "\n", "3. `Ctrl+L`: clear screen.\n", "\n", "0. Append `;` (semi-colon) to suppress displaying output from a command. Same as Matlab.\n", "\n", "0. `include(\"filename.jl\")` to source a Julia code file." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Seek help\n", "\n", "* Online help from REPL: `?function_name`.\n", "\n", "* Google (of course).\n", "\n", "* Julia documentation: .\n", "\n", "* Look up source code: `@edit fun(x)`.\n", "\n", "* .\n", "\n", "* Friends." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Which IDE?\n", "\n", "* Julia homepage lists many choices: Juno, VS Code, Vim, ...\n", "\n", "* Unfortunately at the moment there are no mature RStudio- or Matlab-like IDE for Julia yet.\n", "\n", "* For dynamic document, e.g., homework, I recommend [Jupyter Notebook](https://jupyter.org/install.html) or [JupyterLab](http://jupyterlab.readthedocs.io/en/stable/). JupyterLab is supposed to replace Jupyter Notebook after it reaches v1.0.\n", "\n", "* For extensive Julia coding, myself has good experience with the editor [VS Code](https://code.visualstudio.com) with extensions `Julia` and `VS Code Jupyter Notebook Previewer` installed. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Julia package system\n", "\n", "* Each Julia package is a Git repository. Each Julia package name ends with `.jl`. E.g., `Distributions.jl` package lives at . \n", "Google search with `PackageName.jl` usually leads to the package on github.com. \n", "\n", "* The package ecosystem is rapidly maturing; a complete list of **registered** packages (which are required to have a certain level of testing and documentation) is at [http://pkg.julialang.org/](http://pkg.julialang.org/).\n", "\n", "* For example, the package called `Distributions.jl` is added with\n", "```julia\n", "# in Pkg mode\n", "(v1.1) pkg> add Distributions\n", "```\n", "and \"removed\" (although not completely deleted) with\n", "```julia\n", "# in Pkg mode\n", "(v1.1) pkg> rm Distributions\n", "```\n", "* The package manager provides a dependency solver that determines which packages are actually required to be installed.\n", "\n", "* **Non-registered** packages are added by cloning the relevant Git repository. E.g.,\n", "```julia\n", "# in Pkg mode\n", "(v1.1) pkg> add https://github.com/OpenMendel/SnpArrays.jl\n", "```\n", "\n", "* A package needs only be added once, at which point it is downloaded into your local `.julia/packages` directory in your home directory. " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "┌ Warning: special characters \"#{}()[]<>|&*?~;\" should now be quoted in commands\n", "│ caller = #shell_parse#351(::String, ::Function, ::String, ::Bool) at shell.jl:100\n", "└ @ Base ./shell.jl:100\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "AbstractFFTs\n", "AccurateArithmetic\n", "AlgorithmsFromTheBook\n", "Arpack\n", "AssetRegistry\n", "AxisAlgorithms\n", "AxisArrays\n", "BEDFiles\n", "BenchmarkTools\n", "BinDeps\n", "BinaryProvider\n", "Blink\n", "BufferedStreams\n", "CMake\n", "CMakeWrapper\n", "CSSUtil\n", "CSTParser\n", "CSV\n", "Cairo\n", "Calculus\n", "CatIndices\n", "CategoricalArrays\n", "Cbc\n", "Clp\n", "Clustering\n", "CodecBzip2\n", "CodecXz\n", "CodecZlib\n", "CodecZstd\n", "Codecs\n", "ColorTypes\n", "ColorVectorSpace\n", "Colors\n", "CommonSubexpressions\n", "Compat\n", "Compose\n", "ComputationalResources\n", "Conda\n", "Contour\n", "Convex\n", "CoordinateTransformations\n", "CoupledFields\n", "CustomUnitRanges\n", "DataArrays\n", "DataFrames\n", "DataStreams\n", "DataStructures\n", "DataValues\n", "DecFP\n", "DecisionTree\n", "DeepDiffs\n", "DiffEqDiffTools\n", "DiffResults\n", "DiffRules\n", "Distances\n", "Distributions\n", "DocStringExtensions\n", "Documenter\n", "DocumenterTools\n", "DoubleFloats\n", "ECOS\n", "EzXML\n", "FFTViews\n", "FFTW\n", "FactCheck\n", "FileIO\n", "FilePaths\n", "FilePathsBase\n", "FixedPointNumbers\n", "Fontconfig\n", "ForwardDiff\n", "FunctionalCollections\n", "GLM\n", "GLPK\n", "GLPKMathProgInterface\n", "GR\n", "GZip\n", "Gadfly\n", "GenericLinearAlgebra\n", "Glob\n", "Graphics\n", "Gurobi\n", "HTTP\n", "HTTPClient\n", "Hexagons\n", "Hiccup\n", "Highlights\n", "Homebrew\n", "HttpCommon\n", "HttpParser\n", "IJulia\n", "IdentityRanges\n", "ImageAxes\n", "ImageCore\n", "ImageDistances\n", "ImageFiltering\n", "ImageMagick\n", "ImageMetadata\n", "ImageMorphology\n", "ImageShow\n", "ImageTransformations\n", "Images\n", "IndirectArrays\n", "IniFile\n", "Interact\n", "InteractBase\n", "InteractBulma\n", "InternedStrings\n", "Interpolations\n", "IntervalSets\n", "Ipopt\n", "IterTools\n", "IterableTables\n", "IterativeSolvers\n", "IteratorInterfaceExtensions\n", "JLD2\n", "JSExpr\n", "JSON\n", "JuMP\n", "Juno\n", "KernelDensity\n", "Knockout\n", "LaTeXStrings\n", "Lazy\n", "LibCURL\n", "LibExpat\n", "Libz\n", "LinQuadOptInterface\n", "LineSearches\n", "LinearMaps\n", "Literate\n", "Loess\n", "MATLAB\n", "MPI\n", "MacroTools\n", "MappedArrays\n", "MathOptInterface\n", "MathProgBase\n", "MbedTLS\n", "Measures\n", "Media\n", "MendelPlots\n", "Missings\n", "Mocking\n", "Mosek\n", "Mustache\n", "Mux\n", "NLSolversBase\n", "NLopt\n", "NaNMath\n", "NamedTuples\n", "NearestNeighbors\n", "NodeJS\n", "Nullables\n", "ORCA\n", "Observables\n", "OffsetArrays\n", "Optim\n", "OptimTestProblems\n", "OrderedCollections\n", "OrdinalGWAS\n", "OrdinalMultinomialModels\n", "PDMats\n", "PaddedViews\n", "Parameters\n", "Parsers\n", "Pidfile\n", "PlotReferenceImages\n", "PlotThemes\n", "PlotUtils\n", "Plotly\n", "PlotlyBase\n", "PlotlyJS\n", "Plots\n", "PolrGWAS\n", "PolrModels\n", "Polynomials\n", "PooledArrays\n", "PositiveFactorizations\n", "Primes\n", "ProgressMeter\n", "PyCall\n", "PyPlot\n", "QuadGK\n", "QuartzImageIO\n", "RCall\n", "RData\n", "RDatasets\n", "RangeArrays\n", "Ratios\n", "RecipesBase\n", "RecursiveArrayTools\n", "Reexport\n", "Requests\n", "Requires\n", "ReverseDiffSparse\n", "Rmath\n", "Roots\n", "Rotations\n", "Rsvg\n", "SCS\n", "SIUnits\n", "ScikitLearnBase\n", "ShowItLikeYouBuildIt\n", "Showoff\n", "SimpleTraits\n", "SnpArrays\n", "SoftGlobalScope\n", "SortingAlgorithms\n", "SpecialFunctions\n", "StatPlots\n", "StaticArrays\n", "StatsBase\n", "StatsFuns\n", "StatsModels\n", "StatsPlots\n", "Suppressor\n", "TableShowUtils\n", "TableTraits\n", "TableTraitsUtils\n", "Tables\n", "TestImages\n", "TestSetExtensions\n", "TexExtensions\n", "TextParse\n", "TiledIteration\n", "TimeZones\n", "Tokenize\n", "TranscodingStreams\n", "URIParser\n", "UnicodePlots\n", "VarianceComponentModels\n", "VarianceComponentTest\n", "VegaDatasets\n", "VegaLite\n", "VersionParsing\n", "VisualRegressionTests\n", "WeakRefStrings\n", "Weave\n", "WebIO\n", "WebSockets\n", "Widgets\n", "WinRPM\n", "WinReg\n", "WoodburyMatrices\n", "YAML\n", "ZMQ\n", "ZipFile\n" ] } ], "source": [ ";ls ~/.julia/packages" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Directory of a specific package can be queried by `pathof()`:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"/Users/huazhou/.julia/packages/Distributions/fMt8c/src/Distributions.jl\"" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Distributions\n", "\n", "pathof(Distributions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* If you start having problems with packages that seem to be unsolvable, you may try just deleting your .julia directory and reinstalling all your packages. \n", "\n", "* Periodically, one should run `update` in Pkg mode, which checks for, downloads and installs updated versions of all the packages you currently have installed.\n", "\n", "* `status` lists the status of all installed packages.\n", "\n", "* Using functions in package.\n", "```julia\n", "using Distributions\n", "```\n", "This pulls all of the *exported* functions in the module into your local namespace, as you can check using the `whos()` command. An alternative is\n", "```julia\n", "import Distributions\n", "```\n", "Now, the functions from the Distributions package are available only using \n", "```julia\n", "Distributions.\n", "```\n", "All functions, not only exported functions, are always available like this." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calling R from Julia\n", "\n", "* The [`RCall.jl`](https://github.com/JuliaInterop/RCall.jl) package allows us to embed R code inside of Julia.\n", "\n", "* There are also `PyCall.jl`, `MATLAB.jl`, `JavaCall.jl`, `CxxWrap.jl` packages for interfacing with other languages." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/png": "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" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "RObject{VecSxp}\n", "$breaks\n", " [1] -5 -4 -3 -2 -1 0 1 2 3 4\n", "\n", "$counts\n", "[1] 1 0 28 119 369 320 142 19 2\n", "\n", "$density\n", "[1] 0.001 0.000 0.028 0.119 0.369 0.320 0.142 0.019 0.002\n", "\n", "$mids\n", "[1] -4.5 -3.5 -2.5 -1.5 -0.5 0.5 1.5 2.5 3.5\n", "\n", "$xname\n", "[1] \"`#JL`$x\"\n", "\n", "$equidist\n", "[1] TRUE\n", "\n", "attr(,\"class\")\n", "[1] \"histogram\"\n" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using RCall\n", "\n", "x = randn(1000)\n", "R\"\"\"\n", "hist($x, main=\"I'm plotting a Julia vector\")\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/png": "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" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "RObject{VecSxp}\n" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" }, { "name": "stderr", "output_type": "stream", "text": [ "┌ Warning: RCall.jl: `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.\n", "└ @ RCall /Users/huazhou/.julia/packages/RCall/ffM0W/src/io.jl:113\n" ] } ], "source": [ "R\"\"\"\n", "library(ggplot2)\n", "qplot($x)\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "RObject{RealSxp}\n", " [1] -1.76152465 0.28402321 -1.18674201 0.38532610 0.66327415 -0.07548059\n", " [7] -1.22814518 -0.36132394 -1.58982131 1.00019919\n" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = R\"\"\"\n", "rnorm(10)\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10-element Array{Float64,1}:\n", " -1.761524654252555 \n", " 0.2840232126371199 \n", " -1.1867420051409112 \n", " 0.38532610091816666\n", " 0.6632741501853096 \n", " -0.07548059232008238\n", " -1.2281451847872713 \n", " -0.36132394376250476\n", " -1.589821307258373 \n", " 1.0001991932779424 " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# collect R variable into Julia workspace\n", "y = collect(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Access Julia variables in R REPL mode:\n", "```julia\n", "julia> x = rand(5) # Julia variable\n", "R> y <- $x\n", "```\n", "\n", "* Pass Julia expression in R REPL mode:\n", "```julia\n", "R> y <- $(rand(5))\n", "```\n", "\n", "* Put Julia variable into R environment:\n", "```julia\n", "julia> @rput x\n", "R> x\n", "```\n", "\n", "* Get R variable into Julia environment:\n", "```julia\n", "R> r <- 2\n", "Julia> @rget r\n", "```\n", "\n", "* If you want to call Julia within R, check out the [`XRJulia`](https://cran.r-project.org/web/packages/XRJulia/) package by John Chambers." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Some basic Julia code" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Int64" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# an integer, same as int in R\n", "y = 1\n", "typeof(y) " ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Float64" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# a Float64 number, same as double in R\n", "y = 1.0\n", "typeof(y) " ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "π = 3.1415926535897..." ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Greek letters: `\\pi`\n", "π" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Irrational{:π}" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(π)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4.141592653589793" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Greek letters: `\\theta`\n", "θ = y + π" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.0" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# emoji! `\\:kissing_cat:`\n", "😽 = 5.0" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "π = 3.1415926535897..." ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# `\\alpha\\hat`\n", "α̂ = π" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element Array{Float64,1}:\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# vector of Float64 0s\n", "x = zeros(5)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element Array{Int64,1}:\n", " 0\n", " 0\n", " 0\n", " 0\n", " 0" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# vector Int64 0s\n", "x = zeros(Int, 5)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.0 0.0 0.0\n", " 0.0 0.0 0.0\n", " 0.0 0.0 0.0\n", " 0.0 0.0 0.0\n", " 0.0 0.0 0.0" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# matrix of Float64 0s\n", "x = zeros(5, 3)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 1.0 1.0 1.0\n", " 1.0 1.0 1.0\n", " 1.0 1.0 1.0\n", " 1.0 1.0 1.0\n", " 1.0 1.0 1.0" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# matrix of Float64 1s\n", "x = ones(5, 3)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 2.353e-314 2.35072e-314 2.33123e-314\n", " 2.353e-314 2.33123e-314 0.0 \n", " 2.33123e-314 2.34943e-314 0.0 \n", " 2.34943e-314 2.33123e-314 0.0 \n", " 2.35132e-314 2.33123e-314 0.0 " ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# define array without initialization\n", "x = Matrix{Float64}(undef, 5, 3)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.0 0.0 0.0\n", " 0.0 0.0 0.0\n", " 0.0 0.0 0.0\n", " 0.0 0.0 0.0\n", " 0.0 0.0 0.0" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# fill a matrix by 0s\n", "fill!(x, 0)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 2.5 2.5 2.5\n", " 2.5 2.5 2.5\n", " 2.5 2.5 2.5\n", " 2.5 2.5 2.5\n", " 2.5 2.5 2.5" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# initialize an array to be constant 2.5\n", "fill(2.5, (5, 3))" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3//5" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# rational number\n", "a = 3//5" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Rational{Int64}" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(a)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3//7" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = 3//7" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "36//35" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.697832 0.521255 0.635389\n", " 0.795756 0.821073 0.046378\n", " 0.330146 0.200252 0.997733\n", " 0.12915 0.951122 0.227358\n", " 0.833891 0.494311 0.428478" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# uniform [0, 1) random numbers\n", "x = rand(5, 3)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float16,2}:\n", " 0.8604 0.798 0.1611\n", " 0.717 0.4043 0.0762\n", " 0.5312 0.0742 0.8906\n", " 0.2373 0.1309 0.632 \n", " 0.5137 0.42 0.5244" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# uniform random numbers (in single precision)\n", "x = rand(Float16, 5, 3)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Int64,2}:\n", " 1 4 5\n", " 2 2 2\n", " 5 2 3\n", " 2 3 5\n", " 1 1 1" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# random numbers from {1,...,5}\n", "x = rand(1:5, 5, 3)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 1.14235 -0.681071 0.360989\n", " 1.95432 -0.0724878 0.329729\n", " -0.288511 -1.22229 1.32657 \n", " -0.774164 1.37268 -1.37873 \n", " -0.2116 0.861211 -1.25181 " ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# standard normal random numbers\n", "x = randn(5, 3)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1:10" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# range\n", "1:10" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "UnitRange{Int64}" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(1:10)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1:2:9" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1:2:10" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "StepRange{Int64,Int64}" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(1:2:10)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10-element Array{Int64,1}:\n", " 1\n", " 2\n", " 3\n", " 4\n", " 5\n", " 6\n", " 7\n", " 8\n", " 9\n", " 10" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# integers 1-10\n", "x = collect(1:10)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10-element Array{Int64,1}:\n", " 1\n", " 2\n", " 3\n", " 4\n", " 5\n", " 6\n", " 7\n", " 8\n", " 9\n", " 10" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# or equivalently\n", "[1:10...]" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10-element Array{Float64,1}:\n", " 1.0\n", " 2.0\n", " 3.0\n", " 4.0\n", " 5.0\n", " 6.0\n", " 7.0\n", " 8.0\n", " 9.0\n", " 10.0" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Float64 numbers 1-10\n", "x = collect(1.0:10)" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10-element Array{Float64,1}:\n", " 1.0\n", " 2.0\n", " 3.0\n", " 4.0\n", " 5.0\n", " 6.0\n", " 7.0\n", " 8.0\n", " 9.0\n", " 10.0" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# convert to a specific type\n", "convert(Vector{Float64}, 1:10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Timing and benchmark" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Julia\n", "\n", "`@time`, `@elapsed`, `@allocated` macros:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0.032345 seconds (95.66 k allocations: 4.858 MiB)\n" ] }, { "data": { "text/plain": [ "500060.34072352527" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Random # standard library\n", "Random.seed!(123) # seed\n", "x = rand(1_000_000) # 1 million random numbers in [0, 1)\n", "\n", "@time sum(x) # first run includes compilation time" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0.000456 seconds (5 allocations: 176 bytes)\n" ] }, { "data": { "text/plain": [ "500060.34072352527" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@time sum(x) # no compilation time after first run" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.000449506" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# just the runtime\n", "@elapsed sum(x)" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "16" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# just the allocation\n", "@allocated sum(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use package `BenchmarkTools.jl` for more robust benchmarking. Analog of `microbenchmark` package in R." ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 0 bytes\n", " allocs estimate: 0\n", " --------------\n", " minimum time: 244.108 μs (0.00% GC)\n", " median time: 268.166 μs (0.00% GC)\n", " mean time: 280.042 μs (0.00% GC)\n", " maximum time: 2.854 ms (0.00% GC)\n", " --------------\n", " samples: 10000\n", " evals/sample: 1" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using BenchmarkTools\n", "\n", "bm = @benchmark sum($x)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.2681655" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Statistics # standard library\n", "benchmark_result = Dict() # a dictionary to store median runtime (in milliseconds)\n", "benchmark_result[\"Julia builtin\"] = median(bm.times) / 1e6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### C\n", "\n", "We would use the low-level C code as the baseline for copmarison. In Julia, we can easily run compiled C code using the `ccall` function." ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "c_sum (generic function with 1 method)" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Libdl\n", "\n", "C_code = \"\"\"\n", "#include \n", "double c_sum(size_t n, double *X) {\n", " double s = 0.0;\n", " for (size_t i = 0; i < n; ++i) {\n", " s += X[i];\n", " }\n", " return s;\n", "}\n", "\"\"\"\n", "\n", "const Clib = tempname() # make a temporary file\n", "\n", "# compile to a shared library by piping C_code to gcc\n", "# (works only if you have gcc installed):\n", "\n", "open(`gcc -std=c99 -fPIC -O3 -msse3 -xc -shared -o $(Clib * \".\" * Libdl.dlext) -`, \"w\") do f\n", " print(f, C_code) \n", "end\n", "\n", "# define a Julia function that calls the C function:\n", "c_sum(X::Array{Float64}) = ccall((\"c_sum\", Clib), Float64, (Csize_t, Ptr{Float64}), length(X), X)" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "500060.340723512" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# make sure it gives same answer\n", "c_sum(x)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 0 bytes\n", " allocs estimate: 0\n", " --------------\n", " minimum time: 1.117 ms (0.00% GC)\n", " median time: 1.134 ms (0.00% GC)\n", " mean time: 1.161 ms (0.00% GC)\n", " maximum time: 3.056 ms (0.00% GC)\n", " --------------\n", " samples: 4297\n", " evals/sample: 1" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bm = @benchmark c_sum($x)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.134183" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# store median runtime (in milliseconds)\n", "benchmark_result[\"C\"] = median(bm.times) / 1e6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### R, buildin sum\n", "\n", "Next we compare to the build in `sum` function in R, which is implemented using C." ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "RObject{VecSxp}\n", "Unit: microseconds\n", " expr min lq mean median uq max neval\n", " sum(y) 897.061 902.984 978.2313 995.058 1006.212 1239.114 100\n" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using RCall\n", "\n", "R\"\"\"\n", "library(microbenchmark)\n", "y <- $x\n", "rbm <- microbenchmark(sum(y))\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.995058" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# store median runtime (in milliseconds)\n", "@rget rbm # dataframe\n", "benchmark_result[\"R builtin\"] = median(rbm[:time]) / 1e6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### R, handwritten loop\n", "\n", "Handwritten loop in R is much slower." ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "RObject{VecSxp}\n", "Unit: milliseconds\n", " expr min lq mean median uq max neval\n", " sum_r(y) 25.42925 26.79393 27.30556 27.21291 27.72341 33.88999 100\n" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using RCall\n", "\n", "R\"\"\"\n", "sum_r <- function(x) {\n", " s <- 0\n", " for (xi in x) {\n", " s <- s + xi\n", " }\n", " s\n", "}\n", "library(microbenchmark)\n", "y <- $x\n", "rbm <- microbenchmark(sum_r(y))\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "27.212913" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# store median runtime (in milliseconds)\n", "@rget rbm # dataframe\n", "benchmark_result[\"R loop\"] = median(rbm[:time]) / 1e6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Python, builtin sum\n", "\n", "Built in function `sum` in Python." ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "v\"3.7.3\"" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using PyCall\n", "PyCall.pyversion" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 368 bytes\n", " allocs estimate: 8\n", " --------------\n", " minimum time: 81.864 ms (0.00% GC)\n", " median time: 83.359 ms (0.00% GC)\n", " mean time: 83.663 ms (0.00% GC)\n", " maximum time: 89.594 ms (0.00% GC)\n", " --------------\n", " samples: 60\n", " evals/sample: 1" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# get the Python built-in \"sum\" function:\n", "pysum = pybuiltin(\"sum\")\n", "bm = @benchmark $pysum($x)" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "83.3590615" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# store median runtime (in miliseconds)\n", "benchmark_result[\"Python builtin\"] = median(bm.times) / 1e6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Python, handwritten loop" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 368 bytes\n", " allocs estimate: 8\n", " --------------\n", " minimum time: 96.864 ms (0.00% GC)\n", " median time: 101.652 ms (0.00% GC)\n", " mean time: 101.390 ms (0.00% GC)\n", " maximum time: 109.707 ms (0.00% GC)\n", " --------------\n", " samples: 50\n", " evals/sample: 1" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using PyCall\n", "\n", "py\"\"\"\n", "def py_sum(A):\n", " s = 0.0\n", " for a in A:\n", " s += a\n", " return s\n", "\"\"\"\n", "\n", "sum_py = py\"py_sum\"\n", "\n", "bm = @benchmark $sum_py($x)" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "101.652003" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# store median runtime (in miliseconds)\n", "benchmark_result[\"Python loop\"] = median(bm.times) / 1e6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Python, numpy\n", "\n", "Numpy is the high-performance scientific computing library for Python." ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "PyObject " ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# bring in sum function from Numpy \n", "numpy_sum = pyimport(\"numpy\").\"sum\"" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 368 bytes\n", " allocs estimate: 8\n", " --------------\n", " minimum time: 303.052 μs (0.00% GC)\n", " median time: 336.714 μs (0.00% GC)\n", " mean time: 357.059 μs (0.00% GC)\n", " maximum time: 2.370 ms (0.00% GC)\n", " --------------\n", " samples: 10000\n", " evals/sample: 1" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bm = @benchmark $numpy_sum($x)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.336714" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# store median runtime (in miliseconds)\n", "benchmark_result[\"Python numpy\"] = median(bm.times) / 1e6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Numpy performance is on a par with Julia build-in sum function. Both are about 3 times faster than C, possibly because of usage of [SIMD](https://en.wikipedia.org/wiki/SIMD)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Summary" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Dict{Any,Any} with 7 entries:\n", " \"R builtin\" => 0.995058\n", " \"Julia builtin\" => 0.268166\n", " \"Python builtin\" => 83.3591\n", " \"C\" => 1.13418\n", " \"Python loop\" => 101.652\n", " \"Python numpy\" => 0.336714\n", " \"R loop\" => 27.2129" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "benchmark_result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `C` and `R builtin` are the baseline C performance (gold standard).\n", "\n", "* `Python builtin` and `Python loop` are 80-100 fold slower than C because the loop is interpreted.\n", "\n", "* `R loop` is about 30 folder slower than C and indicates the performance of bytecode generated by its compiler package (turned on by default since R v3.4.0 (Apr 2017)). \n", "\n", "* `Julia builtin` and `Python numpy` are 3-4 folder faster than C because of SIMD (???)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Matrices and vectors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dimensions" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.598655 -0.649164 -0.20795 \n", " -1.50715 1.41208 0.29778 \n", " -2.08909 0.283026 -1.37727 \n", " 0.0489631 2.06727 -0.0209721\n", " -0.0975634 -0.194017 0.133924 " ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = randn(5, 3)" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(5, 3)" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "size(x)" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "size(x, 1) # nrow() in R" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "size(x, 2)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "15" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# total number of elements\n", "length(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Indexing" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 1.40584 -0.435559 -1.77228 0.616302 0.979726 \n", " -0.434523 0.986161 0.942634 -1.27926 -1.15752 \n", " 0.643141 0.39562 0.396688 -0.220179 -0.841993 \n", " -1.23652 -1.03567 -1.227 -1.13857 -1.86035 \n", " 0.528711 -1.36271 -0.387252 0.79865 0.00320293" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 5 × 5 matrix of random Normal(0, 1)\n", "x = randn(5, 5)" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element Array{Float64,1}:\n", " 1.405836567860699 \n", " -0.4345229408667341\n", " 0.6431414215485608\n", " -1.2365159892763888\n", " 0.5287106504891519" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# first column\n", "x[:, 1]" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element Array{Float64,1}:\n", " 1.405836567860699 \n", " -0.4355593559026318\n", " -1.7722776947141923\n", " 0.6163015601209474\n", " 0.9797260369028392" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# first row\n", "x[1, :]" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 Array{Float64,2}:\n", " -0.435559 -1.77228 \n", " 0.986161 0.942634" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# sub-array\n", "x[1:2, 2:3]" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 view(::Array{Float64,2}, 1:2, 2:3) with eltype Float64:\n", " -0.435559 -1.77228 \n", " 0.986161 0.942634" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# getting a subset of a matrix creates a copy, but you can also create \"views\"\n", "z = view(x, 1:2, 2:3)" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 view(::Array{Float64,2}, 1:2, 2:3) with eltype Float64:\n", " -0.435559 -1.77228 \n", " 0.986161 0.942634" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# same as\n", "@views z = x[1:2, 2:3]" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 1.40584 -0.435559 -1.77228 0.616302 0.979726 \n", " -0.434523 0.986161 0.0 -1.27926 -1.15752 \n", " 0.643141 0.39562 0.396688 -0.220179 -0.841993 \n", " -1.23652 -1.03567 -1.227 -1.13857 -1.86035 \n", " 0.528711 -1.36271 -0.387252 0.79865 0.00320293" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# change in z (view) changes x as well\n", "z[2, 2] = 0.0\n", "x" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 1.40584 -0.435559 -1.77228 0.616302 0.979726 \n", " -0.434523 0.986161 0.0 -1.27926 -1.15752 \n", " 0.643141 0.39562 0.396688 -0.220179 -0.841993 \n", " -1.23652 -1.03567 -1.227 -1.13857 -1.86035 \n", " 0.528711 -1.36271 -0.387252 0.79865 0.00320293" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# y points to same data as x\n", "y = x" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Ptr{Float64} @0x000000011a458050, Ptr{Float64} @0x000000011a458050)" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# x and y point to same data\n", "pointer(x), pointer(y)" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 0.0 -0.435559 -1.77228 0.616302 0.979726 \n", " 0.0 0.986161 0.0 -1.27926 -1.15752 \n", " 0.0 0.39562 0.396688 -0.220179 -0.841993 \n", " 0.0 -1.03567 -1.227 -1.13857 -1.86035 \n", " 0.0 -1.36271 -0.387252 0.79865 0.00320293" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# changing y also changes x\n", "y[:, 1] .= 0\n", "x" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 0.0 -0.435559 -1.77228 0.616302 0.979726 \n", " 0.0 0.986161 0.0 -1.27926 -1.15752 \n", " 0.0 0.39562 0.396688 -0.220179 -0.841993 \n", " 0.0 -1.03567 -1.227 -1.13857 -1.86035 \n", " 0.0 -1.36271 -0.387252 0.79865 0.00320293" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# create a new copy of data\n", "z = copy(x)" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Ptr{Float64} @0x000000011a458050, Ptr{Float64} @0x000000011a458950)" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pointer(x), pointer(z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Concatenate matrices" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1×3 Array{Int64,2}:\n", " 1 2 3" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 1-by-3 array\n", "[1 2 3]" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 1\n", " 2\n", " 3" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 3-by-1 vector\n", "[1, 2, 3]" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "([1.07455 2.55508 1.26546; 0.385123 -0.660738 -1.64513; … ; -0.583523 0.43622 0.385691; 0.832241 -1.32354 0.177505], [-0.997382 -0.488503; -0.817314 0.673586; … ; -1.39357 0.729497; 0.53823 0.57519], [-2.30427 1.62085 … 0.054552 0.49251; 1.3284 -1.14737 … 0.167511 -1.1699; -0.908365 0.423386 … -1.26891 0.883105])" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# multiple assignment by tuple\n", "x, y, z = randn(5, 3), randn(5, 2), randn(3, 5)" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×5 Array{Float64,2}:\n", " 1.07455 2.55508 1.26546 -0.997382 -0.488503\n", " 0.385123 -0.660738 -1.64513 -0.817314 0.673586\n", " -2.38285 -0.693591 -0.465704 0.605258 0.302012\n", " -0.583523 0.43622 0.385691 -1.39357 0.729497\n", " 0.832241 -1.32354 0.177505 0.53823 0.57519 " ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[x y] # 5-by-5 matrix" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8×5 Array{Float64,2}:\n", " 1.07455 2.55508 1.26546 -0.997382 -0.488503\n", " 0.385123 -0.660738 -1.64513 -0.817314 0.673586\n", " -2.38285 -0.693591 -0.465704 0.605258 0.302012\n", " -0.583523 0.43622 0.385691 -1.39357 0.729497\n", " 0.832241 -1.32354 0.177505 0.53823 0.57519 \n", " -2.30427 1.62085 -0.0751243 0.054552 0.49251 \n", " 1.3284 -1.14737 -0.121207 0.167511 -1.1699 \n", " -0.908365 0.423386 -0.163381 -1.26891 0.883105" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[x y; z] # 8-by-5 matrix" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dot operation\n", "\n", "Dot operation in Julia is elementwise operation, similar to Matlab." ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 1.42693 1.1571 0.352857\n", " 0.270257 -0.17928 0.137277\n", " -0.0178663 -1.02672 -0.321545\n", " 0.865855 -0.232668 1.1365 \n", " 0.0332832 0.886387 -1.66359 " ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = randn(5, 3)" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 1.0 1.0 1.0\n", " 1.0 1.0 1.0\n", " 1.0 1.0 1.0\n", " 1.0 1.0 1.0\n", " 1.0 1.0 1.0" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = ones(5, 3)" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 1.42693 1.1571 0.352857\n", " 0.270257 -0.17928 0.137277\n", " -0.0178663 -1.02672 -0.321545\n", " 0.865855 -0.232668 1.1365 \n", " 0.0332832 0.886387 -1.66359 " ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x .* y # same x * y in R" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.491126 0.746898 8.0316 \n", " 13.6914 31.1127 53.0649 \n", " 3132.79 0.948625 9.67199 \n", " 1.33386 18.4725 0.774221\n", " 902.711 1.27278 0.361334" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x .^ (-2)" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.98967 0.91564 0.34558 \n", " 0.266979 -0.178321 0.136846\n", " -0.0178653 -0.855607 -0.316033\n", " 0.76165 -0.230575 0.907164\n", " 0.0332771 0.774793 -0.995698" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sin.(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basic linear algebra" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element Array{Float64,1}:\n", " -0.48876941581527183\n", " -1.8898912365052984 \n", " 0.4752801478661729 \n", " 0.5986586722127957 \n", " 1.8129740483514514 " ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = randn(5)" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.77159570508093" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using LinearAlgebra\n", "# vector L2 norm\n", "norm(x)" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.77159570508093" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# same as\n", "sqrt(sum(abs2, x))" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-2.0757729618710195" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = randn(5) # another vector\n", "# dot product\n", "dot(x, y) # x' * y" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-2.0757729618710195" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# same as\n", "x'y" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×2 Array{Float64,2}:\n", " -0.159807 0.579995\n", " 0.621269 1.32793 \n", " 0.591513 -1.99637 \n", " -0.713616 0.684772\n", " -0.557596 0.75847 " ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x, y = randn(5, 3), randn(3, 2)\n", "# matrix multiplication, same as %*% in R\n", "x * y" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Float64,2}:\n", " 0.153422 1.0588 0.277495\n", " 0.271558 0.0482019 0.326489\n", " -1.21251 -0.0983329 -0.623121" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = randn(3, 3)" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×3 Adjoint{Float64,Array{Float64,2}}:\n", " 0.153422 0.271558 -1.21251 \n", " 1.0588 0.0482019 -0.0983329\n", " 0.277495 0.326489 -0.623121 " ] }, "execution_count": 98, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# conjugate transpose\n", "x'" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Float64,1}:\n", " -0.8462924095954427 \n", " 0.46434157973051327\n", " -0.1889119302892237 " ] }, "execution_count": 99, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = rand(3)\n", "x'b # same as x' * b" ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-0.4214969667533476" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# trace\n", "tr(x)" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-0.2308584804640239" ] }, "execution_count": 101, "metadata": {}, "output_type": "execute_result" } ], "source": [ "det(x)" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rank(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sparse matrices" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10×10 SparseMatrixCSC{Float64,Int64} with 10 stored entries:\n", " [6 , 1] = -0.251681\n", " [5 , 2] = -0.778148\n", " [9 , 4] = -0.119565\n", " [2 , 5] = -0.616153\n", " [7 , 5] = -1.40975\n", " [2 , 7] = 0.84617\n", " [7 , 7] = -0.207459\n", " [9 , 8] = -0.0429563\n", " [5 , 9] = -0.388533\n", " [2 , 10] = -0.209722" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using SparseArrays\n", "\n", "# 10-by-10 sparse matrix with sparsity 0.1\n", "X = sprandn(10, 10, .1)" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10×10 Array{Float64,2}:\n", " 0.0 0.0 0.0 0.0 … 0.0 0.0 0.0 \n", " 0.0 0.0 0.0 0.0 0.0 0.0 -0.209722\n", " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", " 0.0 -0.778148 0.0 0.0 0.0 -0.388533 0.0 \n", " -0.251681 0.0 0.0 0.0 … 0.0 0.0 0.0 \n", " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", " 0.0 0.0 0.0 -0.119565 -0.0429563 0.0 0.0 \n", " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 " ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# convert to dense matrix; be cautious when dealing with big data\n", "Xfull = convert(Matrix{Float64}, X)" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10×10 SparseMatrixCSC{Float64,Int64} with 10 stored entries:\n", " [6 , 1] = -0.251681\n", " [5 , 2] = -0.778148\n", " [9 , 4] = -0.119565\n", " [2 , 5] = -0.616153\n", " [7 , 5] = -1.40975\n", " [2 , 7] = 0.84617\n", " [7 , 7] = -0.207459\n", " [9 , 8] = -0.0429563\n", " [5 , 9] = -0.388533\n", " [2 , 10] = -0.209722" ] }, "execution_count": 105, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# convert a dense matrix to sparse matrix\n", "sparse(Xfull)" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10-element Array{Float64,1}:\n", " 0.0 \n", " 0.02029443774752057\n", " 0.0 \n", " 0.0 \n", " -1.1666816429212037 \n", " -0.25168069117368247\n", " -1.617210771834139 \n", " 0.0 \n", " -0.1625211385544279 \n", " 0.0 " ] }, "execution_count": 106, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# syntax for sparse linear algebra is same as dense linear algebra\n", "β = ones(10)\n", "X * β" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-3.177799806735933" ] }, "execution_count": 107, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# many functions apply to sparse matrices as well\n", "sum(X)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Control flow and loops\n", "\n", "* if-elseif-else-end\n", "\n", "```julia\n", "if condition1\n", " # do something\n", "elseif condition2\n", " # do something\n", "else\n", " # do something\n", "end\n", "```\n", "\n", "* `for` loop\n", "\n", "```julia\n", "for i in 1:10\n", " println(i)\n", "end\n", "```\n", "\n", "* Nested `for` loop:\n", "\n", "```julia\n", "for i in 1:10\n", " for j in 1:5\n", " println(i * j)\n", " end\n", "end\n", "```\n", "Same as\n", "\n", "```julia\n", "for i in 1:10, j in 1:5\n", " println(i * j)\n", "end\n", "```\n", "\n", "* Exit loop:\n", "\n", "```julia\n", "for i in 1:10\n", " # do something\n", " if condition1\n", " break # skip remaining loop\n", " end\n", "end\n", "```\n", "\n", "* Exit iteration: \n", "\n", "```julia\n", "for i in 1:10\n", " # do something\n", " if condition1\n", " continue # skip to next iteration\n", " end\n", " # do something\n", "end\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions \n", "\n", "* In Julia, all arguments to functions are **passed by reference**, in contrast to R and Matlab.\n", "\n", "* Function names ending with `!` indicates that function mutates at least one argument, typically the first.\n", "```julia\n", "sort!(x) # vs sort(x)\n", "```\n", "\n", "* Function definition\n", "\n", "```julia\n", "function func(req1, req2; key1=dflt1, key2=dflt2)\n", " # do stuff\n", " return out1, out2, out3\n", "end\n", "```\n", "**Required arguments** are separated with a comma and use the positional notation. \n", "**Optional arguments** need a default value in the signature. \n", "**Semicolon** is not required in function call. \n", "**return** statement is optional. \n", "Multiple outputs can be returned as a **tuple**, e.g., `return out1, out2, out3`. \n", "\n", "* Anonymous functions, e.g., `x -> x^2`, is commonly used in collection function or list comprehensions.\n", "```julia\n", "map(x -> x^2, y) # square each element in x\n", "```\n", "\n", "* Functions can be nested:\n", "\n", "```julia\n", "function outerfunction()\n", " # do some outer stuff\n", " function innerfunction()\n", " # do inner stuff\n", " # can access prior outer definitions\n", " end\n", " # do more outer stuff\n", "end\n", "```\n", "\n", "* Functions can be vectorized using the Dot syntax:" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.639626 0.0671957 0.275807 \n", " 0.139496 0.387134 0.414554 \n", " 0.721616 0.00984144 0.79227 \n", " -0.633982 -0.556283 0.0602744 \n", " 0.544461 0.156409 0.00768604" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function myfunc(x)\n", " return sin(x^2)\n", "end\n", "\n", "x = randn(5, 3)\n", "myfunc.(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Collection function** (think this as the series of `apply` functions in R).\n", "\n", " Apply a function to each element of a collection:\n", "\n", "```julia\n", "map(f, coll) # or\n", "map(coll) do elem\n", " # do stuff with elem\n", " # must contain return\n", "end\n", "```" ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.639626 0.0671957 0.275807 \n", " 0.139496 0.387134 0.414554 \n", " 0.721616 0.00984144 0.79227 \n", " -0.633982 -0.556283 0.0602744 \n", " 0.544461 0.156409 0.00768604" ] }, "execution_count": 109, "metadata": {}, "output_type": "execute_result" } ], "source": [ "map(x -> sin(x^2), x)" ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.639626 0.0671957 0.275807 \n", " 0.139496 0.387134 0.414554 \n", " 0.721616 0.00984144 0.79227 \n", " -0.633982 -0.556283 0.0602744 \n", " 0.544461 0.156409 0.00768604" ] }, "execution_count": 110, "metadata": {}, "output_type": "execute_result" } ], "source": [ "map(x) do elem\n", " elem = elem^2\n", " return sin(elem)\n", "end" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.026104609456178" ] }, "execution_count": 111, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Mapreduce\n", "mapreduce(x -> sin(x^2), +, x)" ] }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.026104609456178" ] }, "execution_count": 112, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# same as\n", "sum(x -> sin(x^2), x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* List **comprehension**" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5×3 Array{Float64,2}:\n", " 0.14112 -0.756802 -0.958924\n", " -0.958924 -0.279415 0.656987\n", " 0.656987 0.989358 0.412118\n", " 0.412118 -0.544021 -0.99999 \n", " -0.99999 -0.536573 0.420167" ] }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[sin(2i + j) for i in 1:5, j in 1:3] # similar to Python" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Type system\n", "\n", "* Every variable in Julia has a type.\n", "\n", "* When thinking about types, think about sets.\n", "\n", "* Everything is a subtype of the abstract type `Any`.\n", "\n", "* An abstract type defines a set of types\n", " - Consider types in Julia that are a `Number`:\n", "\n", "\n", "\n", "* We can explore type hierarchy with `typeof()`, `supertype()`, and `subtypes()`." ] }, { "cell_type": "code", "execution_count": 114, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Float64, Int64)" ] }, "execution_count": 114, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(1.0), typeof(1)" ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "AbstractFloat" ] }, "execution_count": 115, "metadata": {}, "output_type": "execute_result" } ], "source": [ "supertype(Float64)" ] }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4-element Array{Any,1}:\n", " BigFloat\n", " Float16 \n", " Float32 \n", " Float64 " ] }, "execution_count": 116, "metadata": {}, "output_type": "execute_result" } ], "source": [ "subtypes(AbstractFloat)" ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 117, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Is Float64 a subtype of AbstractFloat?\n", "Float64 <: AbstractFloat" ] }, { "cell_type": "code", "execution_count": 118, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 118, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# On 64bit machine, Int == Int64\n", "Int == Int64" ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 119, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# convert to Float64\n", "convert(Float64, 1)" ] }, { "cell_type": "code", "execution_count": 120, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 120, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# same as\n", "Float64(1)" ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element Array{Float32,1}:\n", " -0.27314892\n", " -1.4175588 \n", " 0.06751722\n", " -2.4249308 \n", " -0.9561249 " ] }, "execution_count": 121, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Float32 vector\n", "x = randn(Float32, 5)" ] }, { "cell_type": "code", "execution_count": 122, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element Array{Float64,1}:\n", " -0.27314892411231995\n", " -1.4175587892532349 \n", " 0.0675172209739685 \n", " -2.4249308109283447 \n", " -0.9561249017715454 " ] }, "execution_count": 122, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# convert to Float64\n", "convert(Vector{Float64}, x)" ] }, { "cell_type": "code", "execution_count": 123, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element Array{Float64,1}:\n", " -0.27314892411231995\n", " -1.4175587892532349 \n", " 0.0675172209739685 \n", " -2.4249308109283447 \n", " -0.9561249017715454 " ] }, "execution_count": 123, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# same as\n", "Float64.(x)" ] }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 124, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# convert Float64 to Int64\n", "convert(Int, 1.0)" ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [ { "ename": "InexactError", "evalue": "InexactError: Int64(1.5)", "output_type": "error", "traceback": [ "InexactError: Int64(1.5)", "", "Stacktrace:", " [1] Type at ./float.jl:703 [inlined]", " [2] convert(::Type{Int64}, ::Float64) at ./number.jl:7", " [3] top-level scope at In[125]:1" ] } ], "source": [ "convert(Int, 1.5) # should use round(1.5)" ] }, { "cell_type": "code", "execution_count": 126, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 126, "metadata": {}, "output_type": "execute_result" } ], "source": [ "round(Int, 1.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Multiple dispatch\n", "\n", "* Multiple dispatch lies in the core of Julia design. It allows built-in and user-defined functions to be overloaded for different combinations of argument types.\n", "\n", "* Let's consider a simple \"doubling\" function:" ] }, { "cell_type": "code", "execution_count": 127, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "g (generic function with 1 method)" ] }, "execution_count": 127, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g(x) = x + x" ] }, { "cell_type": "code", "execution_count": 128, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.0" ] }, "execution_count": 128, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g(1.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This definition is too broad, since some things, e.g., strings, can't be added " ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "ename": "MethodError", "evalue": "MethodError: no method matching +(::String, ::String)\nClosest candidates are:\n +(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:502\n +(!Matched::PyObject, ::Any) at /Users/huazhou/.julia/packages/PyCall/a5Jd3/src/pyoperators.jl:13\n +(::Any, !Matched::PyObject) at /Users/huazhou/.julia/packages/PyCall/a5Jd3/src/pyoperators.jl:14", "output_type": "error", "traceback": [ "MethodError: no method matching +(::String, ::String)\nClosest candidates are:\n +(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:502\n +(!Matched::PyObject, ::Any) at /Users/huazhou/.julia/packages/PyCall/a5Jd3/src/pyoperators.jl:13\n +(::Any, !Matched::PyObject) at /Users/huazhou/.julia/packages/PyCall/a5Jd3/src/pyoperators.jl:14", "", "Stacktrace:", " [1] g(::String) at ./In[127]:1", " [2] top-level scope at In[129]:1" ] } ], "source": [ "g(\"hello world\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* This definition is correct but too restrictive, since any `Number` can be added." ] }, { "cell_type": "code", "execution_count": 130, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "g (generic function with 2 methods)" ] }, "execution_count": 130, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g(x::Float64) = x + x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* This definition will automatically work on the entire type tree above!" ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "g (generic function with 3 methods)" ] }, "execution_count": 131, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g(x::Number) = x + x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is a lot nicer than \n", "```julia\n", "function g(x)\n", " if isa(x, Number)\n", " return x + x\n", " else\n", " throw(ArgumentError(\"x should be a number\"))\n", " end\n", "end\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `methods(func)` function display all methods defined for `func`." ] }, { "cell_type": "code", "execution_count": 132, "metadata": {}, "outputs": [ { "data": { "text/html": [ "3 methods for generic function g:
  • g(x::Float64) in Main at In[130]:1
  • g(x::Number) in Main at In[131]:1
  • g(x) in Main at In[127]:1
" ], "text/plain": [ "# 3 methods for generic function \"g\":\n", "[1] g(x::Float64) in Main at In[130]:1\n", "[2] g(x::Number) in Main at In[131]:1\n", "[3] g(x) in Main at In[127]:1" ] }, "execution_count": 132, "metadata": {}, "output_type": "execute_result" } ], "source": [ "methods(g)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* When calling a function with multiple definitions, Julia will search from the narrowest signature to the broadest signature.\n", "\n", "* `@which func(x)` marco tells which method is being used for argument signature `x`." ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [ { "data": { "text/html": [ "g(x::Number) in Main at In[131]:1" ], "text/plain": [ "g(x::Number) in Main at In[131]:1" ] }, "execution_count": 133, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# an Int64 input\n", "@which g(1)" ] }, { "cell_type": "code", "execution_count": 134, "metadata": {}, "outputs": [ { "data": { "text/html": [ "g(x) in Main at In[127]:1" ], "text/plain": [ "g(x) in Main at In[127]:1" ] }, "execution_count": 134, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# a Vector{Float64} input\n", "@which g(randn(5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Just-in-time compilation (JIT)\n", "\n", "Following figures are taken from Arch D. Robinson's slides [Introduction to Writing High Performance Julia](https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxibG9uem9uaWNzfGd4OjMwZjI2YTYzNDNmY2UzMmE).\n", "\n", "| \"Julia | \"Julia |\n", "|----------------------------------|------------------------------------|\n", "|||\n", "\n", "* `Julia`'s efficiency results from its capability to infer the types of **all** variables within a function and then call LLVM to generate optimized machine code at run-time. \n", "\n", "Consider the `g` (doubling) function defined earlier. This function will work on **any** type which has a method for `+`." ] }, { "cell_type": "code", "execution_count": 135, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(4, 4.0)" ] }, "execution_count": 135, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g(2), g(2.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Step 1**: Parse Julia code into [abstract syntax tree (AST)](https://en.wikipedia.org/wiki/Abstract_syntax_tree)." ] }, { "cell_type": "code", "execution_count": 136, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "CodeInfo(\n", "\u001b[90m1 ─\u001b[39m %1 = x + x\n", "\u001b[90m└──\u001b[39m return %1\n", ")" ] }, "execution_count": 136, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@code_lowered g(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Step 2**: Type inference according to input type." ] }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Body\u001b[36m::Int64\u001b[39m\n", "\u001b[90m1 ─\u001b[39m %1 = (Base.add_int)(x, x)\u001b[36m::Int64\u001b[39m\n", "\u001b[90m└──\u001b[39m return %1\n" ] } ], "source": [ "@code_warntype g(2)" ] }, { "cell_type": "code", "execution_count": 138, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Body\u001b[36m::Float64\u001b[39m\n", "\u001b[90m1 ─\u001b[39m %1 = (Base.add_float)(x, x)\u001b[36m::Float64\u001b[39m\n", "\u001b[90m└──\u001b[39m return %1\n" ] } ], "source": [ "@code_warntype g(2.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Step 3**: Compile into **LLVM bytecode** (equivalent of R bytecode generated by compiler package)." ] }, { "cell_type": "code", "execution_count": 139, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "; @ In[131]:1 within `g'\n", "define i64 @julia_g_15080(i64) {\n", "top:\n", "; ┌ @ int.jl:53 within `+'\n", " %1 = shl i64 %0, 1\n", "; └\n", " ret i64 %1\n", "}\n" ] } ], "source": [ "@code_llvm g(2)" ] }, { "cell_type": "code", "execution_count": 140, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "; @ In[130]:1 within `g'\n", "define double @julia_g_15081(double) {\n", "top:\n", "; ┌ @ float.jl:395 within `+'\n", " %1 = fadd double %0, %0\n", "; └\n", " ret double %1\n", "}\n" ] } ], "source": [ "@code_llvm g(2.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We didn't provide a type annotation. But different LLVM code gets generated depending on the argument type!\n", "\n", "In R or Python, `g(2)` and `g(2.0)` would use the same code for both.\n", " \n", "In Julia, `g(2)` and `g(2.0)` dispatches to optimized code for `Int64` and `Float64`, respectively.\n", "\n", "For integer input `x`, LLVM compiler is smart enough to know `x + x` is simple shifting `x` by 1 bit, which is faster than addition.\n", " \n", "* **Step 4**: Lowest level is the **assembly code**, which is machine dependent." ] }, { "cell_type": "code", "execution_count": 141, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\t.section\t__TEXT,__text,regular,pure_instructions\n", "; ┌ @ In[131]:1 within `g'\n", "; │┌ @ In[131]:1 within `+'\n", "\tdecl\t%eax\n", "\tleal\t(%edi,%edi), %eax\n", "; │└\n", "\tretl\n", "\tnopw\t%cs:(%eax,%eax)\n", "; └\n" ] } ], "source": [ "@code_native g(2)" ] }, { "cell_type": "code", "execution_count": 142, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\t.section\t__TEXT,__text,regular,pure_instructions\n", "; ┌ @ In[130]:1 within `g'\n", "; │┌ @ In[130]:1 within `+'\n", "\tvaddsd\t%xmm0, %xmm0, %xmm0\n", "; │└\n", "\tretl\n", "\tnopw\t%cs:(%eax,%eax)\n", "; └\n" ] } ], "source": [ "@code_native g(2.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Profiling Julia code\n", "\n", "Julia has several built-in tools for profiling. The `@time` marco outputs run time and heap allocation." ] }, { "cell_type": "code", "execution_count": 143, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0.036713 seconds (5.84 k allocations: 276.576 KiB)\n" ] }, { "data": { "text/plain": [ "1.0000233387279043e7" ] }, "execution_count": 143, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# a function defined earlier\n", "function tally(x::Array)\n", " s = zero(eltype(x))\n", " for v in x\n", " s += v\n", " end\n", " s\n", "end\n", "\n", "using Random\n", "Random.seed!(123)\n", "a = rand(20_000_000)\n", "@time tally(a) # first run: include compile time" ] }, { "cell_type": "code", "execution_count": 144, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0.026384 seconds (5 allocations: 176 bytes)\n" ] }, { "data": { "text/plain": [ "1.0000233387279043e7" ] }, "execution_count": 144, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@time tally(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more robust benchmarking, the [BenchmarkTools.jl](https://github.com/JuliaCI/BenchmarkTools.jl) package is highly recommended." ] }, { "cell_type": "code", "execution_count": 145, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 0 bytes\n", " allocs estimate: 0\n", " --------------\n", " minimum time: 21.450 ms (0.00% GC)\n", " median time: 23.802 ms (0.00% GC)\n", " mean time: 23.774 ms (0.00% GC)\n", " maximum time: 29.245 ms (0.00% GC)\n", " --------------\n", " samples: 211\n", " evals/sample: 1" ] }, "execution_count": 145, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using BenchmarkTools\n", "\n", "@benchmark tally($a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `Profile` module gives line by line profile results." ] }, { "cell_type": "code", "execution_count": 146, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Count File Line Function \n", " 23 ./In[143] 5 tally(::Array{Float64,1}) \n", " 25 ./boot.jl 328 eval \n", " 1 ./broadcast.jl 551 _broadcast_getindex(::Base.Broadcast...\n", " 1 ./broadcast.jl 578 _broadcast_getindex \n", " 1 ./broadcast.jl 578 _broadcast_getindex_evalf(::typeof(S...\n", " 1 ./broadcast.jl 791 copy \n", " 1 ./broadcast.jl 791 copy(::Base.Broadcast.Broadcasted{Ba...\n", " 2 ./broadcast.jl 928 copyto_nonleaf!(::Array{Expr,1}, ::B...\n", " 2 ./broadcast.jl 511 getindex \n", " 2 ./broadcast.jl 753 materialize(::Base.Broadcast.Broadca...\n", " 26 ./essentials.jl 742 #invokelatest#1 \n", " 26 ./essentials.jl 741 invokelatest \n", " 23 ./float.jl 395 + \n", " 26 ./task.jl 259 (::getfield(IJulia, Symbol(\"##15#18\"...\n", " 26 .../9ajf8/src/eventloop.jl 8 eventloop(::ZMQ.Socket) \n", " 26 .../src/execute_request.jl 67 execute_request(::ZMQ.Socket, ::IJul...\n", " 2 .../src/SoftGlobalScope.jl 124 _softscope \n", " 1 .../src/SoftGlobalScope.jl 144 _softscope(::Expr, ::Set{Symbol}, ::...\n", " 1 .../src/SoftGlobalScope.jl 152 _softscope(::Expr, ::Set{Symbol}, ::...\n", " 1 .../src/SoftGlobalScope.jl 154 _softscope(::Expr, ::Set{Symbol}, ::...\n", " 1 .../src/SoftGlobalScope.jl 177 softscope(::Module, ::Expr) \n", " 1 .../src/SoftGlobalScope.jl 217 softscope_include_string(::Module, :...\n", " 25 .../src/SoftGlobalScope.jl 218 softscope_include_string(::Module, :...\n" ] } ], "source": [ "using Profile\n", "\n", "Profile.clear()\n", "@profile tally(a)\n", "Profile.print(format=:flat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One can use [`ProfileView`](https://github.com/timholy/ProfileView.jl) package for better visualization of profile data:\n", "\n", "```julia\n", "using ProfileView\n", "\n", "ProfileView.view()\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Memory profiling\n", "\n", "Detailed memory profiling requires a detour. First let's write a script `bar.jl`, which contains the workload function `tally` and a wrapper for profiling." ] }, { "cell_type": "code", "execution_count": 147, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "using Profile\n", "\n", "function tally(x::Array)\n", " s = zero(eltype(x))\n", " for v in x\n", " s += v\n", " end\n", " s\n", "end\n", "\n", "# call workload from wrapper to avoid misattribution bug\n", "function wrapper()\n", " y = rand(10000)\n", " # force compilation\n", " println(tally(y))\n", " # clear allocation counters\n", " Profile.clear_malloc_data()\n", " # run compiled workload\n", " println(tally(y))\n", "end\n", "\n", "wrapper()\n" ] } ], "source": [ ";cat bar.jl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, in terminal, we run the script with `--track-allocation=user` option." ] }, { "cell_type": "code", "execution_count": 148, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5012.163648117665\n", "5012.163648117665\n" ] } ], "source": [ ";julia --track-allocation=user bar.jl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The profiler outputs a file `bar.jl.21740.mem`." ] }, { "cell_type": "code", "execution_count": 149, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " - using Profile\n", " - \n", " - function tally(x::Array)\n", " - s = zero(eltype(x))\n", " - for v in x\n", " - s += v\n", " - end\n", " - s\n", " - end\n", " - \n", " - # call workload from wrapper to avoid misattribution bug\n", " - function wrapper()\n", " 0 y = rand(10000)\n", " - # force compilation\n", " 0 println(tally(y))\n", " - # clear allocation counters\n", " 0 Profile.clear_malloc_data()\n", " - # run compiled workload\n", " 144 println(tally(y))\n", " - end\n", " - \n", " - wrapper()\n", " - \n" ] } ], "source": [ ";cat bar.jl.21740.mem" ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.1.0", "language": "julia", "name": "julia-1.1" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.1.0" }, "toc": { "colors": { "hover_highlight": "#DAA520", "running_highlight": "#FF0000", "selected_highlight": "#FFD700" }, "moveMenuLeft": true, "nav_menu": { "height": "511.7391357421875px", "width": "251.7391357421875px" }, "navigate_menu": true, "number_sections": true, "sideBar": true, "skip_h1_title": true, "threshold": 4, "toc_cell": true, "toc_position": { "height": "640.4212036132812px", "left": "0px", "right": "1210.6114501953125px", "top": "109.57880401611328px", "width": "211.99728393554688px" }, "toc_section_display": "block", "toc_window_display": true, "widenNotebook": false } }, "nbformat": 4, "nbformat_minor": 2 }