{ "cells": [ { "cell_type": "markdown", "metadata": { "nbpresent": { "id": "d8145165-8d8e-4c7d-8511-710cae0113ed" }, "slideshow": { "slide_type": "slide" } }, "source": [ "# 最新Juliaチュートリアル\n", "\n", "2017/08/22 @JuliaTokyo #7 (https://juliatokyo.connpass.com/event/62233/)" ] }, { "cell_type": "markdown", "metadata": { "nbpresent": { "id": "385e0a13-6529-48cc-8a68-5401cb5e11ed" }, "slideshow": { "slide_type": "slide" } }, "source": [ "# 今日の話\n", "\n", "概要\n", "- Juliaとは?\n", "- Juliaの基礎知識\n", "- Juliaの実行モデル\n", "- 今後の動向\n", "\n", "目的\n", "- 構文や基本的な機能を理解する\n", "- 実行の仕方を理解し、高速なプログラムが書けるようになる\n", "- 最新の動向にキャッチアップする" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 自己紹介" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "https://github.com/bicycle1885" ] }, { "cell_type": "markdown", "metadata": { "nbpresent": { "id": "c825d089-a85d-4f52-9b30-88f6e5f6ce3b" }, "slideshow": { "slide_type": "slide" } }, "source": [ "# Juliaとは?\n", "\n", "科学技術計算を目的として作られた動的プログラミング言語\n", "\n", "- 数値計算用の豊富な標準ライブラリ\n", "- `for`ループが超速い\n", "- 平易な構文・シンプルな言語機能\n", "- CやFortranとの連携が容易\n", "- オープンソース (MITライセンス)\n", "\n", "http://julialang.org\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Hello, PCA!" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "pca (generic function with 1 method)" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function pca(X)\n", " X̄ = X .- mean(X, 1)\n", " U, Σ, V = svd(X̄)\n", " return X̄ * V\n", "end" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "150×4 Array{Float64,2}:\n", " 5.1 3.5 1.4 0.2\n", " 4.9 3.0 1.4 0.2\n", " 4.7 3.2 1.3 0.2\n", " 4.6 3.1 1.5 0.2\n", " 5.0 3.6 1.4 0.2\n", " 5.4 3.9 1.7 0.4\n", " 4.6 3.4 1.4 0.3\n", " 5.0 3.4 1.5 0.2\n", " 4.4 2.9 1.4 0.2\n", " 4.9 3.1 1.5 0.1\n", " 5.4 3.7 1.5 0.2\n", " 4.8 3.4 1.6 0.2\n", " 4.8 3.0 1.4 0.1\n", " ⋮ \n", " 6.0 3.0 4.8 1.8\n", " 6.9 3.1 5.4 2.1\n", " 6.7 3.1 5.6 2.4\n", " 6.9 3.1 5.1 2.3\n", " 5.8 2.7 5.1 1.9\n", " 6.8 3.2 5.9 2.3\n", " 6.7 3.3 5.7 2.5\n", " 6.7 3.0 5.2 2.3\n", " 6.3 2.5 5.0 1.9\n", " 6.5 3.0 5.2 2.0\n", " 6.2 3.4 5.4 2.3\n", " 5.9 3.0 5.1 1.8" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "iris = readcsv(\"iris.csv\", header=true)[1]\n", "X = convert(Matrix{Float64}, iris[:,1:4])" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "150×4 Array{Float64,2}:\n", " -2.68413 -0.319397 0.0279148 0.00226244\n", " -2.71414 0.177001 0.210464 0.0990266 \n", " -2.88899 0.144949 -0.0179003 0.0199684 \n", " -2.74534 0.318299 -0.0315594 -0.0755758 \n", " -2.72872 -0.326755 -0.0900792 -0.0612586 \n", " -2.28086 -0.74133 -0.168678 -0.0242009 \n", " -2.82054 0.0894614 -0.257892 -0.0481431 \n", " -2.62614 -0.163385 0.0218793 -0.0452979 \n", " -2.88638 0.578312 -0.0207596 -0.0267447 \n", " -2.67276 0.113774 0.197633 -0.0562954 \n", " -2.50695 -0.645069 0.075318 -0.0150199 \n", " -2.61276 -0.0147299 -0.10215 -0.156379 \n", " -2.78611 0.235112 0.206844 -0.00788791\n", " ⋮ \n", " 1.16933 0.16499 -0.281836 0.0204618 \n", " 2.10761 -0.372288 -0.0272911 0.210622 \n", " 2.31415 -0.183651 -0.322694 0.277654 \n", " 1.92227 -0.409203 -0.113587 0.505305 \n", " 1.41524 0.574916 -0.296323 -0.0153047 \n", " 2.56301 -0.277863 -0.29257 0.0579127 \n", " 2.41875 -0.304798 -0.504483 0.241091 \n", " 1.94411 -0.187532 -0.177825 0.426196 \n", " 1.52717 0.375317 0.121898 0.254367 \n", " 1.76435 -0.0788589 -0.130482 0.137001 \n", " 1.90094 -0.116628 -0.723252 0.0445953 \n", " 1.39019 0.282661 -0.36291 -0.155039 " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X_pca = pca(X)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "PyPlot.Figure(PyObject )" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "using PyPlot\n", "species = iris[:,5]\n", "cmap = Dict(s => \"C$(i-1)\" for (i, s) in enumerate(unique(species)))\n", "scatter(X_pca[:,1], X_pca[:,2], c=getindex.(cmap, species));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 数値計算への強さ" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**多次元配列**を標準搭載\n", "- 任意次元の配列\n", "- ブロードキャスト\n", "- 平均・分散・中央値など統計量の計算関数\n", "\n", "**高速な数値計算ライブラリ**を標準搭載\n", "- OpenBLAS: 各アーキテクチャに最適化された行列計算ライブラリ\n", "- LAPACK: 行列分解など線型方程式を扱うライブラリ\n", "- DSFMT: 高速なメルセンヌ・ツイスター擬似乱生成器" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], "source": [ "srand(1234);" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Float64,1}:\n", " 0.590845\n", " 0.766797\n", " 0.566237" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rand(3) # 1次元配列" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Float64,2}:\n", " 0.460085 0.200586 0.579672 \n", " 0.794026 0.298614 0.648882 \n", " 0.854147 0.246837 0.0109059" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rand(3, 3) # 2次元配列" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×3×3 Array{Float64,3}:\n", "[:, :, 1] =\n", " 0.066423 0.112486 0.0566425\n", " 0.956753 0.276021 0.842714 \n", " 0.646691 0.651664 0.950498 \n", "\n", "[:, :, 2] =\n", " 0.96467 0.82116 0.314926\n", " 0.945775 0.0341601 0.12781 \n", " 0.789904 0.0945445 0.374187\n", "\n", "[:, :, 3] =\n", " 0.931115 0.0118196 0.732 \n", " 0.438939 0.0460428 0.299058\n", " 0.246862 0.496169 0.449182" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rand(3, 3, 3) # 3次元配列" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4×3 Array{Float64,2}:\n", " 0.9481 1.22519 1.05156 \n", " 1.40751 1.71371 0.97805 \n", " 0.561272 0.733818 0.669705\n", " 0.0696456 0.112251 0.200629" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = randn(4, 2)\n", "B = randn(2, 3)\n", "A * B # 行列積" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rank(A * B)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "U, Σ, V = svd(A * B); # 特異値分解" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4×3 Array{Float64,2}:\n", " -0.571725 0.532279 0.619488\n", " -0.740511 -0.643106 -0.146947\n", " -0.347219 0.4311 -0.621254\n", " -0.0649046 0.342412 -0.45682 " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Float64,1}:\n", " 3.26033 \n", " 0.332009 \n", " 2.64666e-16" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Σ" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Float64,2}:\n", " -0.547103 -0.405747 0.732153\n", " -0.684464 -0.286656 -0.670326\n", " -0.481859 0.86787 0.120889" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "V" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "欧米を中心に、数値計算の授業でもJuliaが使われている: https://julialang.org/teaching/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## forループも速い" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ユーザーの声\n", "\n", "- https://twitter.com/sammy_suyama/status/899271832234151937\n", "- https://twitter.com/genkuroki/status/899171709839745024\n", "- https://twitter.com/tkf/status/804218261248176128\n", "- https://twitter.com/antiplastics/status/874982350509047808\n", "- https://twitter.com/bicycle1885/status/879493129933438976\n", "\n", "※ 個人の感想です" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "add (generic function with 1 method)" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function add(x, y)\n", " output = similar(x)\n", " @inbounds for i in 1:endof(x)\n", " output[i] = x[i] + y[i]\n", " end\n", " return output\n", "end" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x = randn(100_000);\n", "y = randn(100_000);" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0.008612 seconds (2 allocations: 781.328 KiB, 92.76% gc time)\n", " 0.000611 seconds (2 allocations: 781.328 KiB)\n", " 0.000707 seconds (2 allocations: 781.328 KiB)\n", " 0.000664 seconds (2 allocations: 781.328 KiB)\n", " 0.000565 seconds (2 allocations: 781.328 KiB)\n" ] } ], "source": [ "x + y\n", "for _ in 1:5\n", " @time x + y\n", "end" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0.000556 seconds (2 allocations: 781.328 KiB)\n", " 0.000637 seconds (2 allocations: 781.328 KiB)\n", " 0.000612 seconds (2 allocations: 781.328 KiB)\n", " 0.000671 seconds (2 allocations: 781.328 KiB)\n", " 0.000528 seconds (2 allocations: 781.328 KiB)\n" ] } ], "source": [ "add(x, y)\n", "for _ in 1:5\n", " @time add(x, y)\n", "end" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": true }, "outputs": [], "source": [ "using PyCall" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "v\"3.5.2\"" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "PyCall.pyversion" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": true }, "outputs": [], "source": [ "py\"\"\"\n", "import numpy as np\n", "\n", "def add(x, y):\n", " output = np.empty(x.shape)\n", " for i in range(len(x)):\n", " output[i] = x[i] + y[i]\n", " return output\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0.047117 seconds (2.01 k allocations: 115.593 KiB)\n" ] } ], "source": [ "@time py\"add($(x), $(y))\"o;" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": true }, "outputs": [], "source": [ "using BenchmarkTools" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Julia Version 0.6.0\n", "Commit 903644385b* (2017-06-19 13:05 UTC)\n", "Platform Info:\n", " OS: macOS (x86_64-apple-darwin16.6.0)\n", " CPU: Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz\n", " WORD_SIZE: 64\n", " BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)\n", " LAPACK: libopenblas64_\n", " LIBM: libopenlibm\n", " LLVM: libLLVM-3.9.1 (ORCJIT, skylake)\n" ] } ], "source": [ "versioninfo()" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 781.33 KiB\n", " allocs estimate: 2\n", " --------------\n", " minimum time: 71.093 μs (0.00% GC)\n", " median time: 126.816 μs (0.00% GC)\n", " mean time: 380.584 μs (21.48% GC)\n", " maximum time: 16.920 ms (0.00% GC)\n", " --------------\n", " samples: 10000\n", " evals/sample: 1" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b1 = @benchmark x + y" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.4066082455375352e9" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# FLOPS\n", "100_000 / (minimum(b1).time / 10^9)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 781.33 KiB\n", " allocs estimate: 2\n", " --------------\n", " minimum time: 70.281 μs (0.00% GC)\n", " median time: 99.873 μs (0.00% GC)\n", " mean time: 318.488 μs (20.56% GC)\n", " maximum time: 7.014 ms (86.54% GC)\n", " --------------\n", " samples: 10000\n", " evals/sample: 1" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b2 = @benchmark add(x, y)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.4228596633514037e9" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# FLOPS\n", "100_000 / (minimum(b2).time / 10^9)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.TrialJudgement: \n", " time: +1.16% => invariant (5.00% tolerance)\n", " memory: +0.00% => invariant (1.00% tolerance)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "judge(minimum(b1), minimum(b2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 速さの秘密\n", "\n", "主に2つの要素\n", "- **型推論**による実行時の曖昧性の排除\n", "- **LLVM**によるネイティブコードへの変換\n", "\n", "これらにより他の動的言語では実現が難しいほどの最適化ができる" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`add(x, y)`の型推論の結果" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/plain": [ "CodeInfo(:(begin \n", " $(Expr(:inbounds, false))\n", " # meta: location array.jl similar 189\n", " SSAValue(3) = (Base.arraysize)(x, 1)::Int64\n", " # meta: pop location\n", " $(Expr(:inbounds, :pop))\n", " output = $(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Float64,1}, svec(Any, Int64), Array{Float64,1}, 0, SSAValue(3), 0)) # line 3:\n", " $(Expr(:inbounds, true))\n", " $(Expr(:inbounds, false))\n", " # meta: location abstractarray.jl endof 134\n", " $(Expr(:inbounds, false))\n", " # meta: location abstractarray.jl linearindices 99\n", " # meta: location abstractarray.jl indices1 71\n", " # meta: location abstractarray.jl indices 64\n", " SSAValue(7) = (Base.arraysize)(x, 1)::Int64\n", " # meta: pop location\n", " # meta: pop location\n", " # meta: pop location\n", " $(Expr(:inbounds, :pop))\n", " # meta: pop location\n", " $(Expr(:inbounds, :pop))\n", " SSAValue(8) = (Base.select_value)((Base.slt_int)(SSAValue(7), 0)::Bool, 0, SSAValue(7))::Int64\n", " SSAValue(9) = (Base.select_value)((Base.sle_int)(1, SSAValue(8))::Bool, SSAValue(8), (Base.sub_int)(1, 1)::Int64)::Int64\n", " #temp# = 1\n", " 25: \n", " unless (Base.not_int)((#temp# === (Base.add_int)(SSAValue(9), 1)::Int64)::Bool)::Bool goto 36\n", " SSAValue(10) = #temp#\n", " SSAValue(11) = (Base.add_int)(#temp#, 1)::Int64\n", " i = SSAValue(10)\n", " #temp# = SSAValue(11) # line 4:\n", " SSAValue(2) = (Base.add_float)((Base.arrayref)(x, i)::Float64, (Base.arrayref)(y, i)::Float64)::Float64\n", " (Base.arrayset)(output, SSAValue(2), i)::Array{Float64,1}\n", " 34: \n", " goto 25\n", " 36: \n", " $(Expr(:inbounds, :pop)) # line 6:\n", " return output\n", " end))=>Array{Float64,1}" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@code_typed add(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "LLVMによるネイティブコードへの変換" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\t.section\t__TEXT,__text,regular,pure_instructions\n", "Filename: In[15]\n", "\tpushq\t%rbp\n", "\tmovq\t%rsp, %rbp\n", "\tpushq\t%r15\n", "\tpushq\t%r14\n", "\tpushq\t%rbx\n", "\tsubq\t$40, %rsp\n", "\tmovq\t%rsi, %r15\n", "\tmovq\t%rdi, %rbx\n", "\tmovabsq\t$jl_get_ptls_states_fast, %rax\n", "\tcallq\t*%rax\n", "\tmovq\t%rax, %r14\n", "\tvxorpd\t%xmm0, %xmm0, %xmm0\n", "\tvmovupd\t%xmm0, -40(%rbp)\n", "\tmovq\t$4, -56(%rbp)\n", "\tmovq\t(%r14), %rax\n", "\tmovq\t%rax, -48(%rbp)\n", "\tleaq\t-56(%rbp), %rax\n", "\tmovq\t%rax, (%r14)\n", "Source line: 189\n", "\tmovq\t24(%rbx), %rsi\n", "Source line: 2\n", "\tmovabsq\t$jl_alloc_array_1d, %rax\n", "\tleaq\t99153040(%rax), %rdi\n", "\tcallq\t*%rax\n", "\tmovq\t%rax, -40(%rbp)\n", "Source line: 64\n", "\tmovq\t24(%rbx), %rcx\n", "Source line: 3\n", "\ttestq\t%rcx, %rcx\n", "\tjle\tL354\n", "Source line: 4\n", "\tmovq\t(%rbx), %r9\n", "\tmovq\t(%r15), %r10\n", "\tmovq\t(%rax), %r11\n", "\tmovl\t$1, %r15d\n", "Source line: 3\n", "\tcmpq\t$8, %rcx\n", "\tjb\tL290\n", "\tmovq\t%rcx, %r8\n", "\tmovl\t$1, %r15d\n", "\tandq\t$-8, %r8\n", "\tje\tL290\n", "\tleaq\t(%r11,%rcx,8), %rsi\n", "\tleaq\t(%r9,%rcx,8), %rdx\n", "\tleaq\t(%r10,%rcx,8), %rdi\n", "\tcmpq\t%rdx, %r11\n", "\tsbbb\t%dl, %dl\n", "\tcmpq\t%rsi, %r9\n", "\tsbbb\t%bl, %bl\n", "\tandb\t%dl, %bl\n", "\tcmpq\t%rdi, %r11\n", "\tsbbb\t%dl, %dl\n", "\tcmpq\t%rsi, %r10\n", "\tsbbb\t%sil, %sil\n", "\tmovl\t$1, %r15d\n", "\ttestb\t$1, %bl\n", "\tjne\tL290\n", "\tandb\t%sil, %dl\n", "\tandb\t$1, %dl\n", "\tjne\tL290\n", "\tmovq\t%r8, %r15\n", "\torq\t$1, %r15\n", "\tleaq\t32(%r9), %rdx\n", "\tleaq\t32(%r10), %rsi\n", "\tleaq\t32(%r11), %rdi\n", "\tmovq\t%r8, %rbx\n", "\tnopw\t%cs:(%rax,%rax)\n", "Source line: 4\n", "L240:\n", "\tvmovupd\t-32(%rdx), %ymm0\n", "\tvmovupd\t(%rdx), %ymm1\n", "\tvaddpd\t-32(%rsi), %ymm0, %ymm0\n", "\tvaddpd\t(%rsi), %ymm1, %ymm1\n", "\tvmovupd\t%ymm0, -32(%rdi)\n", "\tvmovupd\t%ymm1, (%rdi)\n", "Source line: 3\n", "\taddq\t$64, %rdx\n", "\taddq\t$64, %rsi\n", "\taddq\t$64, %rdi\n", "\taddq\t$-8, %rbx\n", "\tjne\tL240\n", "\tcmpq\t%r8, %rcx\n", "\tje\tL350\n", "L290:\n", "\taddq\t$1, %rcx\n", "\tsubq\t%r15, %rcx\n", "\tleaq\t-8(%r11,%r15,8), %rdx\n", "\tleaq\t-8(%r10,%r15,8), %rsi\n", "\tleaq\t-8(%r9,%r15,8), %rdi\n", "\tnopl\t(%rax,%rax)\n", "Source line: 4\n", "L320:\n", "\tvmovsd\t(%rdi), %xmm0 ## xmm0 = mem[0],zero\n", "\tvaddsd\t(%rsi), %xmm0, %xmm0\n", "\tvmovsd\t%xmm0, (%rdx)\n", "Source line: 3\n", "\taddq\t$8, %rdx\n", "\taddq\t$8, %rsi\n", "\taddq\t$8, %rdi\n", "\taddq\t$-1, %rcx\n", "\tjne\tL320\n", "Source line: 4\n", "L350:\n", "\tmovq\t%rax, -32(%rbp)\n", "Source line: 6\n", "L354:\n", "\tmovq\t-48(%rbp), %rcx\n", "\tmovq\t%rcx, (%r14)\n", "\taddq\t$40, %rsp\n", "\tpopq\t%rbx\n", "\tpopq\t%r14\n", "\tpopq\t%r15\n", "\tpopq\t%rbp\n", "\tvzeroupper\n", "\tretq\n", "\tnopw\t(%rax,%rax)\n" ] } ], "source": [ "@code_native add(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ネイティブコードはCPUで直接実行されるので、仮想マシン(VM)を使う他のインタプリター方式の言語より高速" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Juliaの基礎知識" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "もうちょっと包括的な日本語のチュートリアル➥ https://github.com/bicycle1885/Julia-Tutorial" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 基本構文 - 分岐" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "zero!\n" ] } ], "source": [ "x = rand([-1, 0, 1])\n", "\n", "if x > 0\n", " println(\"positive!\")\n", "elseif x == 0\n", " println(\"zero!\")\n", "else\n", " println(\"negative!\")\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 基本構文 - 反復" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n", "3\n", "4\n", "5\n", "6\n", "7\n", "8\n", "9\n", "10\n" ] } ], "source": [ "for i in 1:10\n", " println(i)\n", "end" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "r = 0.824963896731119\n", "r = 0.3864837619109138\n", "r = 0.19716180707125286\n", "r = 0.4707863823067948\n", "r = 0.9122340342619175\n", "r = 0.27714398262365547\n", "r = 0.40275437809947934\n", "r = 0.12027556668360484\n", "r = 0.09447130478733246\n", "r = 0.24197683192547736\n", "r = 0.8619030597650075\n", "r = 0.5945882942644753\n", "r = 0.49438472096360275\n", "r = 0.49150286529392995\n", "r = 0.39888971732793155\n", "r = 0.04482709506506044\n" ] } ], "source": [ "while true\n", " r = rand()\n", " @show r\n", " if r < 0.05\n", " break\n", " end\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 基本構文 - 関数定義" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "hello (generic function with 1 method)" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# functioを使う関数定義\n", "function hello(name)\n", " return \"hello, $(name)!\"\n", "end" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "hello (generic function with 1 method)" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 1行関数定義\n", "hello(name) = \"hello, $(name)!!\"" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "hello (generic function with 2 methods)" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 引数の型制約付き\n", "function hello(name::AbstractString)\n", " return \"hello, $(name)!!!\"\n", "end" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "hello (generic function with 2 methods)" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 引数と返り値の型制約付き\n", "function hello(name::AbstractString)::String\n", " return \"hello, $(name)!!!!\"\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Juliaの型" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Void" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# nothingの型\n", "Void" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Void" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(nothing)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Bool" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 真偽型\n", "Bool" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Bool" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(true)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Int8, Int16, Int32, Int64, Int128)" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 符号付き整数\n", "Int8, Int16, Int32, Int64, Int128" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Int64" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(1)" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(UInt8, UInt16, UInt32, UInt64, UInt128)" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 符号無し整数\n", "UInt8, UInt16, UInt32, UInt64, UInt128" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "UInt64" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(0x0000000000000001)" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# エイリアス\n", "Int == Int64" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# エイリアス\n", "UInt == UInt64" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Float16, Float32, Float64)" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 浮動小数点数\n", "Float16, Float32, Float64" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Float64" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(1.0)" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Char" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 文字\n", "Char" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Char" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof('a')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "リテラルによる型の違い" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Int64" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(1)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "UInt8" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(0x01)" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "UInt16" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(0x0001)" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Float64" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(1.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "文字列" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "String" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "String" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"abracadabra\"" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"abracadabra\"" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"アブラカダブラ\"" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"アブラカダブラ\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "配列" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Array" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Array" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 1\n", " 2\n", " 3" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 1次元配列 (ベクトルとも言う)\n", "[1, 2, 3]" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×3 Array{Int64,2}:\n", " 1 2 3\n", " 4 5 6" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 2次元配列 (行列とも言う)\n", "[1 2 3\n", " 4 5 6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "JuliaにPythonでいう`list`型はないが、1次元配列がその代わり" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "集合" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Set" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Set" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Set([2, 3, 1])" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Set([1, 2, 3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "辞書" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Dict" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Dict{String,Int64} with 2 entries:\n", " \"two\" => 2\n", " \"one\" => 1" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(\"one\" => 1, \"two\" => 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Nullable`型" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Nullable" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Nullable" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Nullable{Int64}(1)" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Nullable(1)" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Nullable{Int64}()" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Nullable{Int64}()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 抽象型" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Int64`など具体型をまとめる型" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Int64" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Int" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Signed" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "supertype(Int)" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Integer" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "supertype(supertype(Int))" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Real" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "supertype(supertype(supertype(Int)))" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Number" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "supertype(supertype(supertype(supertype(Int))))" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Any" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "supertype(supertype(supertype(supertype(supertype(Int)))))" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Any" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "supertype(supertype(supertype(supertype(supertype(supertype(Int))))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "抽象型`AbstractMatrix`のサブタイプ" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "21-element Array{Union{DataType, UnionAll},1}:\n", " AbstractSparseArray{Tv,Ti,2} where Ti where Tv \n", " Base.LinAlg.AbstractTriangular \n", " Base.LinAlg.HessenbergQ \n", " Base.LinAlg.LQPackedQ \n", " Base.LinAlg.QRCompactWYQ \n", " Base.LinAlg.QRPackedQ \n", " Base.LinAlg.SVDOperator \n", " Base.ReshapedArray{T,2,P,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where P<:AbstractArray where T\n", " Base.SparseArrays.CHOLMOD.FactorComponent \n", " Bidiagonal \n", " ConjArray{T,2,A} where A<:AbstractArray where T \n", " DenseArray{T,2} where T \n", " Diagonal \n", " Hermitian \n", " PermutedDimsArray{T,2,perm,iperm,AA} where AA<:AbstractArray where iperm where perm where T \n", " PyCall.PyArray{T,2} where T \n", " RowVector \n", " SubArray{T,2,P,I,L} where L where I where P where T \n", " SymTridiagonal \n", " Symmetric \n", " Tridiagonal " ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "subtypes(AbstractMatrix)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## パラメトリック型" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "型パラメーターを取る型" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Array" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Array" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Array{Int64,N} where N" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Array{Int}" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Array{Int64,1}" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Array{Int,1}" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Array{Int64,2}" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Array{Int,2}" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Array{Int64,1}" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof([1,2,3])" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Array{Int64,2}" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof([1 2 3; 4 5 6])" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Dict{String,Int64} with 2 entries:\n", " \"two\" => 2\n", " \"one\" => 1" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d = Dict(\"one\" => 1, \"two\" => 2)" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Dict{String,Int64}" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(d)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 型定義" ] }, { "cell_type": "code", "execution_count": 86, "metadata": { "collapsed": true }, "outputs": [], "source": [ "struct User\n", " name::String\n", " registerdate::Date\n", "end" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "User(\"Jeff Bezanson\", 2010-03-04)" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "jeff = User(\"Jeff Bezanson\", Date(2010, 3, 4))" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"Jeff Bezanson\"" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "jeff.name" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2010-03-04" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "jeff.registerdate" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mtype User is immutable\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mtype User is immutable\u001b[39m", "", "Stacktrace:", " [1] \u001b[1minclude_string\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::String, ::String\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:515\u001b[22m\u001b[22m" ] } ], "source": [ "jeff.name = \"Stefan Karpinski\"" ] }, { "cell_type": "code", "execution_count": 91, "metadata": { "collapsed": true }, "outputs": [], "source": [ "mutable struct MutableUser\n", " name::String\n", " registerdate::Date\n", "end" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "MutableUser(\"Viral Shah\", 2013-10-02)" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "viral = MutableUser(\"Viral Shah\", Date(2013, 10, 2))" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"Viral Shah\"" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "viral.name" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"Alan Edelman\"" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "viral.name = \"Alan Edelman\"" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "MutableUser(\"Alan Edelman\", 2013-10-02)" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "viral" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 多重ディスパッチ" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "関数`+`には180を超えるメソッドが定義されている" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "+ (generic function with 185 methods)" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "+" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "data": { "text/html": [ "185 methods for generic function +:" ], "text/plain": [ "# 185 methods for generic function \"+\":\n", "+(x::Bool, z::Complex{Bool}) in Base at complex.jl:232\n", "+(x::Bool, y::Bool) in Base at bool.jl:89\n", "+(x::Bool) in Base at bool.jl:86\n", "+(x::Bool, y::T) where T<:AbstractFloat in Base at bool.jl:96\n", "+(x::Bool, z::Complex) in Base at complex.jl:239\n", "+(a::Float16, b::Float16) in Base at float.jl:372\n", "+(x::Float32, y::Float32) in Base at float.jl:374\n", "+(x::Float64, y::Float64) in Base at float.jl:375\n", "+(z::Complex{Bool}, x::Bool) in Base at complex.jl:233\n", "+(z::Complex{Bool}, x::Real) in Base at complex.jl:247\n", "+(x::Char, y::Integer) in Base at char.jl:40\n", "+(c::BigInt, x::BigFloat) in Base.MPFR at mpfr.jl:312\n", "+(a::BigInt, b::BigInt, c::BigInt, d::BigInt, e::BigInt) in Base.GMP at gmp.jl:334\n", "+(a::BigInt, b::BigInt, c::BigInt, d::BigInt) in Base.GMP at gmp.jl:327\n", "+(a::BigInt, b::BigInt, c::BigInt) in Base.GMP at gmp.jl:321\n", "+(x::BigInt, y::BigInt) in Base.GMP at gmp.jl:289\n", "+(x::BigInt, c::Union{UInt16, UInt32, UInt64, UInt8}) in Base.GMP at gmp.jl:346\n", "+(x::BigInt, c::Union{Int16, Int32, Int64, Int8}) in Base.GMP at gmp.jl:362\n", "+(a::BigFloat, b::BigFloat, c::BigFloat, d::BigFloat, e::BigFloat) in Base.MPFR at mpfr.jl:460\n", "+(a::BigFloat, b::BigFloat, c::BigFloat, d::BigFloat) in Base.MPFR at mpfr.jl:453\n", "+(a::BigFloat, b::BigFloat, c::BigFloat) in Base.MPFR at mpfr.jl:447\n", "+(x::BigFloat, c::BigInt) in Base.MPFR at mpfr.jl:308\n", "+(x::BigFloat, y::BigFloat) in Base.MPFR at mpfr.jl:277\n", "+(x::BigFloat, c::Union{UInt16, UInt32, UInt64, UInt8}) in Base.MPFR at mpfr.jl:284\n", "+(x::BigFloat, c::Union{Int16, Int32, Int64, Int8}) in Base.MPFR at mpfr.jl:292\n", "+(x::BigFloat, c::Union{Float16, Float32, Float64}) in Base.MPFR at mpfr.jl:300\n", "+(B::BitArray{2}, J::UniformScaling) in Base.LinAlg at linalg/uniformscaling.jl:59\n", "+(a::Base.Pkg.Resolve.VersionWeights.VWPreBuildItem, b::Base.Pkg.Resolve.VersionWeights.VWPreBuildItem) in Base.Pkg.Resolve.VersionWeights at pkg/resolve/versionweight.jl:87\n", "+(a::Base.Pkg.Resolve.VersionWeights.VWPreBuild, b::Base.Pkg.Resolve.VersionWeights.VWPreBuild) in Base.Pkg.Resolve.VersionWeights at pkg/resolve/versionweight.jl:135\n", "+(a::Base.Pkg.Resolve.VersionWeights.VersionWeight, b::Base.Pkg.Resolve.VersionWeights.VersionWeight) in Base.Pkg.Resolve.VersionWeights at pkg/resolve/versionweight.jl:197\n", "+(a::Base.Pkg.Resolve.MaxSum.FieldValues.FieldValue, b::Base.Pkg.Resolve.MaxSum.FieldValues.FieldValue) in Base.Pkg.Resolve.MaxSum.FieldValues at pkg/resolve/fieldvalue.jl:44\n", "+(x::Base.Dates.CompoundPeriod, y::Base.Dates.CompoundPeriod) in Base.Dates at dates/periods.jl:349\n", "+(x::Base.Dates.CompoundPeriod, y::Base.Dates.Period) in Base.Dates at dates/periods.jl:347\n", "+(x::Base.Dates.CompoundPeriod, y::Base.Dates.TimeType) in Base.Dates at dates/periods.jl:387\n", "+(x::Date, y::Base.Dates.Day) in Base.Dates at dates/arithmetic.jl:77\n", "+(x::Date, y::Base.Dates.Week) in Base.Dates at dates/arithmetic.jl:75\n", "+(dt::Date, z::Base.Dates.Month) in Base.Dates at dates/arithmetic.jl:58\n", "+(dt::Date, y::Base.Dates.Year) in Base.Dates at dates/arithmetic.jl:32\n", "+(dt::Date, t::Base.Dates.Time) in Base.Dates at dates/arithmetic.jl:20\n", "+(t::Base.Dates.Time, dt::Date) in Base.Dates at dates/arithmetic.jl:24\n", "+(x::Base.Dates.Time, y::Base.Dates.TimePeriod) in Base.Dates at dates/arithmetic.jl:81\n", "+(dt::DateTime, z::Base.Dates.Month) in Base.Dates at dates/arithmetic.jl:52\n", "+(dt::DateTime, y::Base.Dates.Year) in Base.Dates at dates/arithmetic.jl:28\n", "+(x::DateTime, y::Base.Dates.Period) in Base.Dates at dates/arithmetic.jl:79\n", "+(a::PyCall.PyObject) in PyCall at /Users/kenta/.julia/v0.6/PyCall/src/pyoperators.jl:36\n", "+(a::PyCall.PyObject, b) in PyCall at /Users/kenta/.julia/v0.6/PyCall/src/pyoperators.jl:11\n", "+(y::AbstractFloat, x::Bool) in Base at bool.jl:98\n", "+(x::T, y::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at int.jl:32\n", "+(x::Integer, y::Ptr) in Base at pointer.jl:128\n", "+(z::Complex, w::Complex) in Base at complex.jl:221\n", "+(z::Complex, x::Bool) in Base at complex.jl:240\n", "+(x::Real, z::Complex{Bool}) in Base at complex.jl:246\n", "+(x::Real, z::Complex) in Base at complex.jl:258\n", "+(z::Complex, x::Real) in Base at complex.jl:259\n", "+(x::Rational, y::Rational) in Base at rational.jl:245\n", "+(x::Integer, y::Char) in Base at char.jl:41\n", "+(i::Integer, index::CartesianIndex) in Base.IteratorsMD at multidimensional.jl:79\n", "+(c::Union{UInt16, UInt32, UInt64, UInt8}, x::BigInt) in Base.GMP at gmp.jl:350\n", "+(c::Union{Int16, Int32, Int64, Int8}, x::BigInt) in Base.GMP at gmp.jl:363\n", "+(c::Union{UInt16, UInt32, UInt64, UInt8}, x::BigFloat) in Base.MPFR at mpfr.jl:288\n", "+(c::Union{Int16, Int32, Int64, Int8}, x::BigFloat) in Base.MPFR at mpfr.jl:296\n", "+(c::Union{Float16, Float32, Float64}, x::BigFloat) in Base.MPFR at mpfr.jl:304\n", "+(x::Irrational, y::Irrational) in Base at irrationals.jl:109\n", "+(x::Real, r::Base.Use_StepRangeLen_Instead) in Base at deprecated.jl:1223\n", "+(x::FixedPointNumbers.Fixed{T,f}, y::FixedPointNumbers.Fixed{T,f}) where {T, f} in FixedPointNumbers at /Users/kenta/.julia/v0.6/FixedPointNumbers/src/fixed.jl:30\n", "+(x::FixedPointNumbers.Normed{T,f}, y::FixedPointNumbers.Normed{T,f}) where {T, f} in FixedPointNumbers at /Users/kenta/.julia/v0.6/FixedPointNumbers/src/normed.jl:81\n", "+(x::Number) in Base at operators.jl:399\n", "+(x::T, y::T) where T<:Number in Base at promotion.jl:335\n", "+(x::Number, y::Number) in Base at promotion.jl:249\n", "+(x::Real, r::AbstractUnitRange) in Base at range.jl:721\n", "+(x::Number, r::AbstractUnitRange) in Base at range.jl:723\n", "+(x::Number, r::StepRangeLen) in Base at range.jl:726\n", "+(x::Number, r::LinSpace) in Base at range.jl:730\n", "+(x::Number, r::Range) in Base at range.jl:724\n", "+(r::Range, x::Number) in Base at range.jl:732\n", "+(r1::OrdinalRange, r2::OrdinalRange) in Base at range.jl:882\n", "+(r1::LinSpace{T}, r2::LinSpace{T}) where T in Base at range.jl:889\n", "+(r1::StepRangeLen{T,R,S} where S, r2::StepRangeLen{T,R,S} where S) where {R<:Base.TwicePrecision, T} in Base at twiceprecision.jl:300\n", "+(r1::StepRangeLen{T,S,S} where S, r2::StepRangeLen{T,S,S} where S) where {T, S} in Base at range.jl:905\n", "+(r1::Union{LinSpace, OrdinalRange, StepRangeLen}, r2::Union{LinSpace, OrdinalRange, StepRangeLen}) in Base at range.jl:896\n", "+(x::Base.TwicePrecision, y::Number) in Base at twiceprecision.jl:454\n", "+(x::Number, y::Base.TwicePrecision) in Base at twiceprecision.jl:457\n", "+(x::Base.TwicePrecision{T}, y::Base.TwicePrecision{T}) where T in Base at twiceprecision.jl:460\n", "+(x::Base.TwicePrecision, y::Base.TwicePrecision) in Base at twiceprecision.jl:464\n", "+(x::Ptr, y::Integer) in Base at pointer.jl:126\n", "+(A::BitArray, B::BitArray) in Base at bitarray.jl:1176\n", "+(A::SymTridiagonal, B::SymTridiagonal) in Base.LinAlg at linalg/tridiag.jl:128\n", "+(A::Tridiagonal, B::Tridiagonal) in Base.LinAlg at linalg/tridiag.jl:624\n", "+(A::UpperTriangular, B::UpperTriangular) in Base.LinAlg at linalg/triangular.jl:374\n", "+(A::LowerTriangular, B::LowerTriangular) in Base.LinAlg at linalg/triangular.jl:375\n", "+(A::UpperTriangular, B::Base.LinAlg.UnitUpperTriangular) in Base.LinAlg at linalg/triangular.jl:376\n", "+(A::LowerTriangular, B::Base.LinAlg.UnitLowerTriangular) in Base.LinAlg at linalg/triangular.jl:377\n", "+(A::Base.LinAlg.UnitUpperTriangular, B::UpperTriangular) in Base.LinAlg at linalg/triangular.jl:378\n", "+(A::Base.LinAlg.UnitLowerTriangular, B::LowerTriangular) in Base.LinAlg at linalg/triangular.jl:379\n", "+(A::Base.LinAlg.UnitUpperTriangular, B::Base.LinAlg.UnitUpperTriangular) in Base.LinAlg at linalg/triangular.jl:380\n", "+(A::Base.LinAlg.UnitLowerTriangular, B::Base.LinAlg.UnitLowerTriangular) in Base.LinAlg at linalg/triangular.jl:381\n", "+(A::Base.LinAlg.AbstractTriangular, B::Base.LinAlg.AbstractTriangular) in Base.LinAlg at linalg/triangular.jl:382\n", "+(A::Symmetric, x::Bool) in Base.LinAlg at linalg/symmetric.jl:272\n", "+(A::Symmetric, x::Number) in Base.LinAlg at linalg/symmetric.jl:274\n", "+(A::Hermitian, x::Bool) in Base.LinAlg at linalg/symmetric.jl:272\n", "+(A::Hermitian, x::Real) in Base.LinAlg at linalg/symmetric.jl:274\n", "+(Da::Diagonal, Db::Diagonal) in Base.LinAlg at linalg/diagonal.jl:140\n", "+(A::Bidiagonal, B::Bidiagonal) in Base.LinAlg at linalg/bidiag.jl:330\n", "+(UL::UpperTriangular, J::UniformScaling) in Base.LinAlg at linalg/uniformscaling.jl:72\n", "+(UL::Base.LinAlg.UnitUpperTriangular, J::UniformScaling) in Base.LinAlg at linalg/uniformscaling.jl:75\n", "+(UL::LowerTriangular, J::UniformScaling) in Base.LinAlg at linalg/uniformscaling.jl:72\n", "+(UL::Base.LinAlg.UnitLowerTriangular, J::UniformScaling) in Base.LinAlg at linalg/uniformscaling.jl:75\n", "+(A::Array, B::SparseMatrixCSC) in Base.SparseArrays at sparse/sparsematrix.jl:1462\n", "+(x::Union{Base.ReshapedArray{T,1,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray, DenseArray{T,1}, SubArray{T,1,A,I,L} where L} where I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex, Int64, Range{Int64}},N} where N} where A<:Union{Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray where N where T, DenseArray} where T, y::AbstractSparseArray{Tv,Ti,1} where Ti where Tv) in Base.SparseArrays at sparse/sparsevector.jl:1333\n", "+(x::Union{Base.ReshapedArray{#s267,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray, DenseArray{#s267,N}, SubArray{#s267,N,A,I,L} where L} where I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex, Int64, Range{Int64}},N} where N} where A<:Union{Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray where N where T, DenseArray} where N where #s267<:Union{Base.Dates.CompoundPeriod, Base.Dates.Period}) in Base.Dates at dates/periods.jl:358\n", "+(A::SparseMatrixCSC, J::UniformScaling) in Base.SparseArrays at sparse/sparsematrix.jl:3512\n", "+(A::AbstractArray{TA,2}, J::UniformScaling{TJ}) where {TA, TJ} in Base.LinAlg at linalg/uniformscaling.jl:119\n", "+(A::Diagonal, B::Bidiagonal) in Base.LinAlg at linalg/special.jl:113\n", "+(A::Bidiagonal, B::Diagonal) in Base.LinAlg at linalg/special.jl:114\n", "+(A::Diagonal, B::Tridiagonal) in Base.LinAlg at linalg/special.jl:113\n", "+(A::Tridiagonal, B::Diagonal) in Base.LinAlg at linalg/special.jl:114\n", "+(A::Diagonal, B::Array{T,2} where T) in Base.LinAlg at linalg/special.jl:113\n", "+(A::Array{T,2} where T, B::Diagonal) in Base.LinAlg at linalg/special.jl:114\n", "+(A::Bidiagonal, B::Tridiagonal) in Base.LinAlg at linalg/special.jl:113\n", "+(A::Tridiagonal, B::Bidiagonal) in Base.LinAlg at linalg/special.jl:114\n", "+(A::Bidiagonal, B::Array{T,2} where T) in Base.LinAlg at linalg/special.jl:113\n", "+(A::Array{T,2} where T, B::Bidiagonal) in Base.LinAlg at linalg/special.jl:114\n", "+(A::Tridiagonal, B::Array{T,2} where T) in Base.LinAlg at linalg/special.jl:113\n", "+(A::Array{T,2} where T, B::Tridiagonal) in Base.LinAlg at linalg/special.jl:114\n", "+(A::SymTridiagonal, B::Tridiagonal) in Base.LinAlg at linalg/special.jl:122\n", "+(A::Tridiagonal, B::SymTridiagonal) in Base.LinAlg at linalg/special.jl:123\n", "+(A::SymTridiagonal, B::Array{T,2} where T) in Base.LinAlg at linalg/special.jl:122\n", "+(A::Array{T,2} where T, B::SymTridiagonal) in Base.LinAlg at linalg/special.jl:123\n", "+(A::Diagonal, B::SymTridiagonal) in Base.LinAlg at linalg/special.jl:131\n", "+(A::SymTridiagonal, B::Diagonal) in Base.LinAlg at linalg/special.jl:132\n", "+(A::Bidiagonal, B::SymTridiagonal) in Base.LinAlg at linalg/special.jl:131\n", "+(A::SymTridiagonal, B::Bidiagonal) in Base.LinAlg at linalg/special.jl:132\n", "+(A::Diagonal, B::UpperTriangular) in Base.LinAlg at linalg/special.jl:143\n", "+(A::UpperTriangular, B::Diagonal) in Base.LinAlg at linalg/special.jl:144\n", "+(A::Diagonal, B::Base.LinAlg.UnitUpperTriangular) in Base.LinAlg at linalg/special.jl:143\n", "+(A::Base.LinAlg.UnitUpperTriangular, B::Diagonal) in Base.LinAlg at linalg/special.jl:144\n", "+(A::Diagonal, B::LowerTriangular) in Base.LinAlg at linalg/special.jl:143\n", "+(A::LowerTriangular, B::Diagonal) in Base.LinAlg at linalg/special.jl:144\n", "+(A::Diagonal, B::Base.LinAlg.UnitLowerTriangular) in Base.LinAlg at linalg/special.jl:143\n", "+(A::Base.LinAlg.UnitLowerTriangular, B::Diagonal) in Base.LinAlg at linalg/special.jl:144\n", "+(A::Base.LinAlg.AbstractTriangular, B::SymTridiagonal) in Base.LinAlg at linalg/special.jl:150\n", "+(A::SymTridiagonal, B::Base.LinAlg.AbstractTriangular) in Base.LinAlg at linalg/special.jl:151\n", "+(A::Base.LinAlg.AbstractTriangular, B::Tridiagonal) in Base.LinAlg at linalg/special.jl:150\n", "+(A::Tridiagonal, B::Base.LinAlg.AbstractTriangular) in Base.LinAlg at linalg/special.jl:151\n", "+(A::Base.LinAlg.AbstractTriangular, B::Bidiagonal) in Base.LinAlg at linalg/special.jl:150\n", "+(A::Bidiagonal, B::Base.LinAlg.AbstractTriangular) in Base.LinAlg at linalg/special.jl:151\n", "+(A::Base.LinAlg.AbstractTriangular, B::Array{T,2} where T) in Base.LinAlg at linalg/special.jl:150\n", "+(A::Array{T,2} where T, B::Base.LinAlg.AbstractTriangular) in Base.LinAlg at linalg/special.jl:151\n", "+(Y::Union{Base.ReshapedArray{#s266,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray, DenseArray{#s266,N}, SubArray{#s266,N,A,I,L} where L} where I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex, Int64, Range{Int64}},N} where N} where A<:Union{Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray where N where T, DenseArray} where N where #s266<:Union{Base.Dates.CompoundPeriod, Base.Dates.Period}, x::Union{Base.Dates.CompoundPeriod, Base.Dates.Period}) in Base.Dates at dates/periods.jl:363\n", "+(X::Union{Base.ReshapedArray{#s265,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray, DenseArray{#s265,N}, SubArray{#s265,N,A,I,L} where L} where I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex, Int64, Range{Int64}},N} where N} where A<:Union{Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray where N where T, DenseArray} where N where #s265<:Union{Base.Dates.CompoundPeriod, Base.Dates.Period}, Y::Union{Base.ReshapedArray{#s264,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray, DenseArray{#s264,N}, SubArray{#s264,N,A,I,L} where L} where I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex, Int64, Range{Int64}},N} where N} where A<:Union{Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray where N where T, DenseArray} where N where #s264<:Union{Base.Dates.CompoundPeriod, Base.Dates.Period}) in Base.Dates at dates/periods.jl:364\n", "+(x::Union{Base.ReshapedArray{#s267,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray, DenseArray{#s267,N}, SubArray{#s267,N,A,I,L} where L} where I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex, Int64, Range{Int64}},N} where N} where A<:Union{Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray where N where T, DenseArray} where N where #s267<:Union{Base.Dates.CompoundPeriod, Base.Dates.Period}, y::Base.Dates.TimeType) in Base.Dates at dates/arithmetic.jl:86\n", "+(r::Range{#s267} where #s267<:Base.Dates.TimeType, x::Base.Dates.Period) in Base.Dates at dates/ranges.jl:47\n", "+(A::SparseMatrixCSC, B::SparseMatrixCSC) in Base.SparseArrays at sparse/sparsematrix.jl:1458\n", "+(A::SparseMatrixCSC, B::Array) in Base.SparseArrays at sparse/sparsematrix.jl:1461\n", "+(x::AbstractSparseArray{Tv,Ti,1} where Ti where Tv, y::AbstractSparseArray{Tv,Ti,1} where Ti where Tv) in Base.SparseArrays at sparse/sparsevector.jl:1332\n", "+(x::AbstractSparseArray{Tv,Ti,1} where Ti where Tv, y::Union{Base.ReshapedArray{T,1,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray, DenseArray{T,1}, SubArray{T,1,A,I,L} where L} where I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex, Int64, Range{Int64}},N} where N} where A<:Union{Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray where N where T, DenseArray} where T) in Base.SparseArrays at sparse/sparsevector.jl:1334\n", "+(x::AbstractArray{#s45,N} where N where #s45<:Number) in Base at abstractarraymath.jl:93\n", "+(A::AbstractArray, B::AbstractArray) in Base at arraymath.jl:37\n", "+(A::Number, B::AbstractArray) in Base at arraymath.jl:44\n", "+(A::AbstractArray, B::Number) in Base at arraymath.jl:47\n", "+(index1::CartesianIndex{N}, index2::CartesianIndex{N}) where N in Base.IteratorsMD at multidimensional.jl:70\n", "+(index::CartesianIndex{N}, i::Integer) where N in Base.IteratorsMD at multidimensional.jl:80\n", "+(J1::UniformScaling, J2::UniformScaling) in Base.LinAlg at linalg/uniformscaling.jl:58\n", "+(J::UniformScaling, B::BitArray{2}) in Base.LinAlg at linalg/uniformscaling.jl:60\n", "+(J::UniformScaling, A::AbstractArray{T,2} where T) in Base.LinAlg at linalg/uniformscaling.jl:61\n", "+(a::Base.Pkg.Resolve.VersionWeights.HierarchicalValue{T}, b::Base.Pkg.Resolve.VersionWeights.HierarchicalValue{T}) where T in Base.Pkg.Resolve.VersionWeights at pkg/resolve/versionweight.jl:23\n", "+(x::P, y::P) where P<:Base.Dates.Period in Base.Dates at dates/periods.jl:70\n", "+(x::Base.Dates.Period, y::Base.Dates.Period) in Base.Dates at dates/periods.jl:346\n", "+(y::Base.Dates.Period, x::Base.Dates.CompoundPeriod) in Base.Dates at dates/periods.jl:348\n", "+(x::Union{Base.Dates.CompoundPeriod, Base.Dates.Period}) in Base.Dates at dates/periods.jl:357\n", "+(x::Union{Base.Dates.CompoundPeriod, Base.Dates.Period}, Y::Union{Base.ReshapedArray{#s267,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray, DenseArray{#s267,N}, SubArray{#s267,N,A,I,L} where L} where I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex, Int64, Range{Int64}},N} where N} where A<:Union{Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray where N where T, DenseArray} where N where #s267<:Union{Base.Dates.CompoundPeriod, Base.Dates.Period}) in Base.Dates at dates/periods.jl:362\n", "+(x::Base.Dates.TimeType) in Base.Dates at dates/arithmetic.jl:8\n", "+(a::Base.Dates.TimeType, b::Base.Dates.Period, c::Base.Dates.Period) in Base.Dates at dates/periods.jl:378\n", "+(a::Base.Dates.TimeType, b::Base.Dates.Period, c::Base.Dates.Period, d::Base.Dates.Period...) in Base.Dates at dates/periods.jl:379\n", "+(x::Base.Dates.TimeType, y::Base.Dates.CompoundPeriod) in Base.Dates at dates/periods.jl:382\n", "+(x::Base.Dates.Instant) in Base.Dates at dates/arithmetic.jl:4\n", "+(y::Base.Dates.Period, x::Base.Dates.TimeType) in Base.Dates at dates/arithmetic.jl:83\n", "+(x::AbstractArray{#s267,N} where N where #s267<:Base.Dates.TimeType, y::Union{Base.Dates.CompoundPeriod, Base.Dates.Period}) in Base.Dates at dates/arithmetic.jl:85\n", "+(x::Base.Dates.Period, r::Range{#s267} where #s267<:Base.Dates.TimeType) in Base.Dates at dates/ranges.jl:46\n", "+(y::Union{Base.Dates.CompoundPeriod, Base.Dates.Period}, x::AbstractArray{#s267,N} where N where #s267<:Base.Dates.TimeType) in Base.Dates at dates/arithmetic.jl:87\n", "+(y::Base.Dates.TimeType, x::Union{Base.ReshapedArray{#s267,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray, DenseArray{#s267,N}, SubArray{#s267,N,A,I,L} where L} where I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex, Int64, Range{Int64}},N} where N} where A<:Union{Base.ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N} where N} where A<:DenseArray where N where T, DenseArray} where N where #s267<:Union{Base.Dates.CompoundPeriod, Base.Dates.Period}) in Base.Dates at dates/arithmetic.jl:88\n", "+(J::UniformScaling, x::Number) in Base at deprecated.jl:56\n", "+(x::Number, J::UniformScaling) in Base at deprecated.jl:56\n", "+(a::C, b::C) where C<:Union{ColorTypes.LMS, ColorTypes.XYZ} in Colors at /Users/kenta/.julia/v0.6/Colors/src/algorithms.jl:4\n", "+(a, b, c, xs...) in Base at operators.jl:424" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "methods(+)" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [ { "data": { "text/html": [ "5-element Array{Method,1}:" ], "text/plain": [ "5-element Array{Method,1}:\n", " +(x::BigInt, c::Union{Int16, Int32, Int64, Int8}) in Base.GMP at gmp.jl:362 \n", " +(x::BigFloat, c::Union{Int16, Int32, Int64, Int8}) in Base.MPFR at mpfr.jl:292 \n", " +(x::T, y::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at int.jl:32\n", " +(c::Union{Int16, Int32, Int64, Int8}, x::BigInt) in Base.GMP at gmp.jl:363 \n", " +(c::Union{Int16, Int32, Int64, Int8}, x::BigFloat) in Base.MPFR at mpfr.jl:296 " ] }, "execution_count": 98, "metadata": {}, "output_type": "execute_result" } ], "source": [ "methodswith(Int, +)" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 99, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 + 1" ] }, { "cell_type": "code", "execution_count": 100, "metadata": { "collapsed": true }, "outputs": [], "source": [ "struct Point{T}\n", " x::T\n", " y::T\n", "end" ] }, { "cell_type": "code", "execution_count": 101, "metadata": { "collapsed": true }, "outputs": [], "source": [ "Base.:(+)(p::Point, q::Point) = Point(p.x + q.x, p.y + q.y)" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "+ (generic function with 186 methods)" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "+" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Point{Int64}(-2, 4)" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = Point(1, 2)\n", "q = Point(-2, 4)" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Point{Int64}(-1, 6)" ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p + q" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mMethodError: no method matching +(::Point{Int64}, ::Int64)\u001b[0m\nClosest candidates are:\n +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m) at operators.jl:424\n +(\u001b[91m::Complex{Bool}\u001b[39m, ::Real) at complex.jl:247\n +(\u001b[91m::Char\u001b[39m, ::Integer) at char.jl:40\n ...\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mMethodError: no method matching +(::Point{Int64}, ::Int64)\u001b[0m\nClosest candidates are:\n +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m) at operators.jl:424\n +(\u001b[91m::Complex{Bool}\u001b[39m, ::Real) at complex.jl:247\n +(\u001b[91m::Char\u001b[39m, ::Integer) at char.jl:40\n ...\u001b[39m", "", "Stacktrace:", " [1] \u001b[1minclude_string\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::String, ::String\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:515\u001b[22m\u001b[22m" ] } ], "source": [ "p + 1" ] }, { "cell_type": "code", "execution_count": 106, "metadata": { "collapsed": true }, "outputs": [], "source": [ "Base.:(+)(p::Point, d::Real) = Point(p.x + d, p.y + d)" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Point{Int64}(2, 3)" ] }, "execution_count": 107, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p + 1" ] }, { "cell_type": "code", "execution_count": 108, "metadata": { "collapsed": true }, "outputs": [], "source": [ "Base.:(*)(p::Point, s::Real) = Point(p.x * s, p.y * s)" ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Point{Int64}(3, 6)" ] }, "execution_count": 109, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p * 3" ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 110, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(p + 1) * 3 == p * 3 + 3" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "distance (generic function with 1 method)" ] }, "execution_count": 111, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function distance(p::Point)\n", " return sqrt(p.x^2 + p.y^2)\n", "end" ] }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.23606797749979" ] }, "execution_count": 112, "metadata": {}, "output_type": "execute_result" } ], "source": [ "distance(p)" ] }, { "cell_type": "code", "execution_count": 113, "metadata": { "collapsed": true }, "outputs": [], "source": [ "function Base.:(+)(p::Point, n::Integer)\n", " println(\"You called Point + Integer!\")\n", " return Point(p.x + n, p.y + n)\n", "end" ] }, { "cell_type": "code", "execution_count": 114, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "You called Point + Integer!\n" ] }, { "data": { "text/plain": [ "Point{Int64}(2, 3)" ] }, "execution_count": 114, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p + 1" ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Point{Float64}(2.0, 3.0)" ] }, "execution_count": 115, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p + 1.0" ] }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "move_right (generic function with 1 method)" ] }, "execution_count": 116, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function move_right(p::Point)\n", " return p + Point(1, 0)\n", "end" ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Point{Int64}(1, 2)" ] }, "execution_count": 117, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p" ] }, { "cell_type": "code", "execution_count": 118, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Point{Int64}(2, 2)" ] }, "execution_count": 118, "metadata": {}, "output_type": "execute_result" } ], "source": [ "move_right(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "多重ディスパッチのポイント\n", "\n", "- すべての引数の扱いは平等 (右も左もない)\n", "- メソッドのうち、型が一番良く合うものが実際に呼ばれる" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## C言語との連携" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`ccall`でC言語の関数を呼び出せる" ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 119, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# https://www.gnu.org/software/libc/manual/html_node/Trig-Functions.html\n", "ccall((:sin, \"libc\"), Cdouble, (Cdouble,), π/2)" ] }, { "cell_type": "code", "execution_count": 120, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"/usr/local/bin/fish\"" ] }, "execution_count": 120, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html\n", "unsafe_string(ccall((:getenv, \"libc\"), Cstring, (Cstring,), \"SHELL\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "JuliaとCの構造体はメモリレイアウトの互換性があるので、互いに読み書きできる。具体例は以下のパッケージを参照\n", "- https://github.com/bicycle1885/CodecZlib.jl/blob/master/src/libz.jl\n", "- https://github.com/bicycle1885/EzXML.jl/blob/master/src/node.jl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ブロードキャスト" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "スカラーや配列を同じ形に揃えて、要素毎の演算をすること。" ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 4\n", " 5\n", " 6" ] }, "execution_count": 121, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = [1,2,3]; y = [4,5,6]" ] }, { "cell_type": "code", "execution_count": 122, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 3\n", " 6\n", " 9" ] }, "execution_count": 122, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# スカラー倍 (ブロードキャストとは言わない)\n", "x * 3" ] }, { "cell_type": "code", "execution_count": 123, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 5\n", " 7\n", " 9" ] }, "execution_count": 123, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ベクトル和 (ブロードキャストとは言わない)\n", "x + y" ] }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 3\n", " 6\n", " 9" ] }, "execution_count": 124, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 要素毎の積 (ブロードキャスト)\n", "x .* 3" ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 5\n", " 7\n", " 9" ] }, "execution_count": 125, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 要素毎の和 (ブロードキャスト)\n", "x .+ y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "列ベクトルと列ベクトルの積は計算できない" ] }, { "cell_type": "code", "execution_count": 126, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mDimensionMismatch(\"Cannot multiply two vectors\")\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mDimensionMismatch(\"Cannot multiply two vectors\")\u001b[39m", "", "Stacktrace:", " [1] \u001b[1m*\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::Array{Int64,1}, ::Array{Int64,1}\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./linalg/rowvector.jl:184\u001b[22m\u001b[22m", " [2] \u001b[1minclude_string\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::String, ::String\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:515\u001b[22m\u001b[22m" ] } ], "source": [ "x * y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ブロードキャストを使えば要素毎の積なら計算できる" ] }, { "cell_type": "code", "execution_count": 127, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 4\n", " 10\n", " 18" ] }, "execution_count": 127, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x .* y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "列ベクトルと行ベクトルの和は計算できない" ] }, { "cell_type": "code", "execution_count": 128, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mDimensionMismatch(\"dimensions must match\")\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mDimensionMismatch(\"dimensions must match\")\u001b[39m", "", "Stacktrace:", " [1] \u001b[1mpromote_shape\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}, ::Tuple{Base.OneTo{Int64}}\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./indices.jl:79\u001b[22m\u001b[22m", " [2] \u001b[1mpromote_shape\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::Tuple{Base.OneTo{Int64}}, ::Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./indices.jl:75\u001b[22m\u001b[22m", " [3] \u001b[1m+\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::Array{Int64,1}, ::RowVector{Int64,Array{Int64,1}}\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./arraymath.jl:37\u001b[22m\u001b[22m", " [4] \u001b[1minclude_string\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::String, ::String\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:515\u001b[22m\u001b[22m" ] } ], "source": [ "x + y'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ブロードキャストはできる" ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×3 Array{Int64,2}:\n", " 5 6 7\n", " 6 7 8\n", " 7 8 9" ] }, "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x .+ y'" ] }, { "cell_type": "code", "execution_count": 130, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×2 Array{Int64,2}:\n", " 1 2\n", " 3 4\n", " 5 6" ] }, "execution_count": 130, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = [\n", " 1 2\n", " 3 4\n", " 5 6\n", "]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "行列と列ベクトルの和は計算できない" ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mDimensionMismatch(\"dimensions must match\")\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mDimensionMismatch(\"dimensions must match\")\u001b[39m", "", "Stacktrace:", " [1] \u001b[1mpromote_shape\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}, ::Tuple{Base.OneTo{Int64}}\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./indices.jl:84\u001b[22m\u001b[22m", " [2] \u001b[1m+\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::Array{Int64,2}, ::Array{Int64,1}\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./arraymath.jl:37\u001b[22m\u001b[22m", " [3] \u001b[1minclude_string\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::String, ::String\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:515\u001b[22m\u001b[22m" ] } ], "source": [ "A + x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ブロードキャストはできる" ] }, { "cell_type": "code", "execution_count": 132, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×2 Array{Int64,2}:\n", " 2 3\n", " 5 6\n", " 8 9" ] }, "execution_count": 132, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A .+ x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## マクロ" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 関数では実現できない、コードの操作ができる\n", "- Cのマクロとは異なるLispから受け継いだマクロ" ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-3" ] }, "execution_count": 133, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = -3" ] }, { "cell_type": "code", "execution_count": 134, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x = -3\n" ] } ], "source": [ "@show x;" ] }, { "cell_type": "code", "execution_count": 135, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mAssertionError: x > 0\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mAssertionError: x > 0\u001b[39m", "", "Stacktrace:", " [1] \u001b[1minclude_string\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::String, ::String\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:515\u001b[22m\u001b[22m" ] } ], "source": [ "@assert x > 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "標準ライブラリで提供されているマクロは何種類かに分けられる。\n", "\n", "1. 開発支援系: `@show`, `@less`, `@which`, `@code_warntype`, etc.\n", "2. 特殊構文系: `@assert`, `@goto`, `@label`, `@async`, `@parallel`, etc.\n", "3. コンパイラヒント系: `@inbounds`, `@inline`, `@fastmath`, etc.\n", "4. メタデータ系: `@__DIR__`, `@__FILE__`, etc.\n", "5. 非標準文字列系: `@r_str`, `@ip_str`, `@v_str`, etc." ] }, { "cell_type": "code", "execution_count": 136, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 136, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ismatch(r\"0x[0-9A-Fa-f]{2}\", \"0x3F\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Juliaの実行モデル" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Juliaの実行モデルを理解することは速いコードを書く上で非常に重要\n", "- Juliaはちょっと特殊な実行の仕方をするので、最初は少し戸惑う" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Juliaは本当に速い?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "答: 速い\n", "\n", "現時点でC/C++より遅くなりそうなケース\n", "- マルチスレッドプログラミング (理由: Juliaのマルチスレッドサポートが弱い)\n", "- 細かいSIMDを使ったプログラミング (理由: x86のSIMD intrinsicsがない)\n", "\n", "これ以外のケースでは、バグでないJuliaの制約でパフォーマンスが出なかったことは体験してない(個人の感想です)。\n", "\n", "希望の光\n", "- より柔軟なマルチスレッドのサポートが開発中 (https://github.com/JuliaLang/julia/pull/22631)\n", "- `llvmcall`命令で細かいSIMDの制御もできないことはない? (https://github.com/eschnett/SIMD.jl)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "具体例: Base64のデコーダー\n", "\n", "64+1種類のASCII文字を使ってエンコードされたバイナリデータを元のデータに復元する。\n", "\n", "ポイント\n", "- 4バイトのASCII文字列にエンコードされたデータを3バイトのバイナリに変換\n", "- 特定の文字の無視・パディングの処理などがあり、それなりに複雑\n", "- 表引きによるアルゴリズム\n", "\n", "```julia\n", "function TranscodingStreams.process(\n", " codec :: Base64Decoder,\n", " input :: Memory,\n", " output :: Memory,\n", " error :: Error)\n", " table = codec.table\n", " state = codec.state\n", " buffer = codec.buffer\n", "\n", " # Check if we can encode data.\n", " if !is_running(state)\n", " error[] = ArgumentError(\"decoding is already finished\")\n", " return 0, 0, :error\n", " elseif output.size < 3\n", " # Need more output space.\n", " return 0, 0, :ok\n", " end\n", "\n", " # Load the frist bytes.\n", " i = j = 0\n", " while buffer.size < 3 && i < input.size\n", " buffer[buffer.size+=1] = input[i+=1]\n", " end\n", " c1 = c2 = c3 = c4 = BASE64_CODEIGN\n", " if buffer.size ≥ 1\n", " c1 = decode(table, buffer[1])\n", " end\n", " if buffer.size ≥ 2\n", " c2 = decode(table, buffer[2])\n", " end\n", " if buffer.size ≥ 3\n", " c3 = decode(table, buffer[3])\n", " end\n", " empty!(buffer)\n", "\n", " # Start decoding loop.\n", " status = :ok\n", " @inbounds while true\n", " if c1 > 0x3f || c2 > 0x3f || c3 > 0x3f || c4 > 0x3f\n", " i, j, status = decode_irregular(table, c1, c2, c3, c4, input, i, output, j, error)\n", " else\n", " output[j+1] = c1 << 2 | c2 >> 4\n", " output[j+2] = c2 << 4 | c3 >> 2\n", " output[j+3] = c3 << 6 | c4\n", " j += 3\n", " end\n", " if i + 4 ≤ input.size && j + 3 ≤ output.size && status == :ok\n", " c1 = decode(table, input[i+1])\n", " c2 = decode(table, input[i+2])\n", " c3 = decode(table, input[i+3])\n", " c4 = decode(table, input[i+4])\n", " i += 4\n", " else\n", " break\n", " end\n", " end\n", "\n", " # Epilogue.\n", " if status == :end || status == :error\n", " finish!(state)\n", " end\n", " return i, j, status\n", "end\n", "\n", "# Decode irregular code (e.g. non-alphabet, padding, etc.).\n", "function decode_irregular(table, c1, c2, c3, c4, input, i, output, j, error)\n", " # Skip ignored chars.\n", " while true\n", " if c1 == BASE64_CODEIGN\n", " c1, c2, c3 = c2, c3, c4\n", " elseif c2 == BASE64_CODEIGN\n", " c2, c3 = c3, c4\n", " elseif c3 == BASE64_CODEIGN\n", " c3 = c4\n", " elseif c4 == BASE64_CODEIGN\n", " # pass\n", " else\n", " break\n", " end\n", " if i + 1 ≤ input.size\n", " c4 = decode(table, input[i+=1])\n", " else\n", " c4 = BASE64_CODEEND\n", " break\n", " end\n", " end\n", "\n", " # Write output.\n", " if c1 ≤ 0x3f && c2 ≤ 0x3f && c3 ≤ 0x3f && c4 ≤ 0x3f\n", " output[j+=1] = c1 << 2 | c2 >> 4\n", " output[j+=1] = c2 << 4 | c3 >> 2\n", " output[j+=1] = c3 << 6 | c4\n", " status = :ok\n", " elseif c1 ≤ 0x3f && c2 ≤ 0x3f && c3 ≤ 0x3f && c4 == BASE64_CODEPAD\n", " c4 = 0x00\n", " output[j+=1] = c1 << 2 | c2 >> 4\n", " output[j+=1] = c2 << 4 | c3 >> 2\n", " status = :end\n", " elseif c1 ≤ 0x3f && c2 ≤ 0x3f && c3 == c4 == BASE64_CODEPAD\n", " c3 = c4 = 0x00\n", " output[j+=1] = c1 << 2 | c2 >> 4\n", " status = :end\n", " elseif c1 == c2 == c3 == BASE64_CODEIGN && c4 == BASE64_CODEEND\n", " status = :end\n", " else\n", " error[] = ArgumentError(\"invalid data\")\n", " status = :error\n", " end\n", " return i, j, status\n", "end\n", "```\n", "\n", "\n", "\n", "ベンチマーク\n", "\n", "Pythonの標準ライブラリのC言語による実装より高速\n", "\n", "Julia 0.6.0:\n", "```\n", "julia> sizeof(data)\n", "286180\n", "\n", "julia> @benchmark transcode(Base64Decoder(), data)\n", "BenchmarkTools.Trial:\n", " memory estimate: 490.31 KiB\n", " allocs estimate: 19\n", " --------------\n", " minimum time: 372.894 μs (0.00% GC)\n", " median time: 561.580 μs (0.00% GC)\n", " mean time: 594.615 μs (6.84% GC)\n", " maximum time: 4.291 ms (68.99% GC)\n", " --------------\n", " samples: 8379\n", " evals/sample: 1\n", "\n", "```\n", "\n", "Python 3.5.2:\n", "```\n", "In [13]: len(data)\n", "Out[13]: 286180\n", "\n", "In [14]: %timeit base64.decodebytes(data)\n", "1.16 ms ± 14.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 実行するまでの流れ\n", "\n", "ユーザーがREPLに打ち込んだ処理が実行されるまでの流れ\n", "\n", "1. コンパイラーがJuliaのソースコードをパースする\n", "2. マクロ・構文糖衣の展開などを行う\n", "3. 低レベルなJuliaの中間表現に落とし込む\n", "4. 型推論を行う\n", "5. LLVMの中間表現に落とし込む\n", "6. ネイティブコードに落とし込む\n", "7. 実行する" ] }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [ { "data": { "text/plain": [ ":(1 + 1)" ] }, "execution_count": 137, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ソースコードのパース\n", "parse(\"1 + 1\")" ] }, { "cell_type": "code", "execution_count": 138, "metadata": {}, "outputs": [ { "data": { "text/plain": [ ":(function foobar(x) # none, line 2:\n", " @assert x > 0\n", " end)" ] }, "execution_count": 138, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parse(\"\"\"\n", "function foobar(x)\n", " @assert x > 0\n", "end\n", "\"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`parse`は`Expr`のオブジェクトを返す。`Expr`は抽象構文木(AST)。" ] }, { "cell_type": "code", "execution_count": 139, "metadata": {}, "outputs": [ { "data": { "text/plain": [ ":(1 + 2 * 3)" ] }, "execution_count": 139, "metadata": {}, "output_type": "execute_result" } ], "source": [ "expr = parse(\"1 + 2 * 3\")" ] }, { "cell_type": "code", "execution_count": 140, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Expr\n", " head: Symbol call\n", " args: Array{Any}((3,))\n", " 1: Symbol +\n", " 2: Int64 1\n", " 3: Expr\n", " head: Symbol call\n", " args: Array{Any}((3,))\n", " 1: Symbol *\n", " 2: Int64 2\n", " 3: Int64 3\n", " typ: Any\n", " typ: Any\n" ] } ], "source": [ "dump(expr)" ] }, { "cell_type": "code", "execution_count": 141, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "quote # In[141], line 3:\n", " if x < 0 # In[141], line 4:\n", " println(\"x is negative\")\n", " else # In[141], line 5:\n", " if x == 0 # In[141], line 6:\n", " println(\"x is zero\")\n", " else # In[141], line 8:\n", " println(\"x is positive\")\n", " end\n", " end\n", "end" ] }, "execution_count": 141, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ifelseなどは複数のif-elseに展開される\n", "quote\n", " if x < 0\n", " println(\"x is negative\")\n", " elseif x == 0\n", " println(\"x is zero\")\n", " else\n", " println(\"x is positive\")\n", " end\n", "end" ] }, { "cell_type": "code", "execution_count": 142, "metadata": {}, "outputs": [ { "data": { "text/plain": [ ":(1 + 2 * 3)" ] }, "execution_count": 142, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# マクロの展開する関数\n", "macroexpand(expr)" ] }, { "cell_type": "code", "execution_count": 143, "metadata": {}, "outputs": [ { "data": { "text/plain": [ ":(if x > 0\n", " nothing\n", " else \n", " (Base.throw)(Base.Main.Base.AssertionError(\"x > 0\"))\n", " end)" ] }, "execution_count": 143, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# @から始まるマクロはこの関数で展開される\n", "macroexpand(:(@assert x > 0))" ] }, { "cell_type": "code", "execution_count": 144, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "quote # In[144], line 2:\n", " function foobar(x) # In[144], line 3:\n", " if x > 0\n", " nothing\n", " else \n", " (Base.throw)(Base.Main.Base.AssertionError(\"x > 0\"))\n", " end\n", " end\n", "end" ] }, "execution_count": 144, "metadata": {}, "output_type": "execute_result" } ], "source": [ "macroexpand(quote\n", " function foobar(x)\n", " @assert x > 0\n", " end\n", "end)" ] }, { "cell_type": "code", "execution_count": 145, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "foobar (generic function with 1 method)" ] }, "execution_count": 145, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function foobar(x)\n", " @assert x > 0\n", "end" ] }, { "cell_type": "code", "execution_count": 146, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1-element Array{CodeInfo,1}:\n", " CodeInfo(:(begin \n", " nothing\n", " unless x > 0 goto 4\n", " return\n", " 4: \n", " return (Base.throw)(((Core.getfield)((Core.getfield)(Base.Main, :Base), :AssertionError))(\"x > 0\"))\n", " end))" ] }, "execution_count": 146, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Juliaの中間表現はunlessの分岐とgotoばかりのフラットなコード\n", "code_lowered(foobar, (Int,))" ] }, { "cell_type": "code", "execution_count": 147, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "foobar (generic function with 1 method)" ] }, "execution_count": 147, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function foobar(n)\n", " x = 0\n", " for i in 1:n\n", " x += i\n", " end\n", " return x\n", "end" ] }, { "cell_type": "code", "execution_count": 148, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1-element Array{CodeInfo,1}:\n", " CodeInfo(:(begin \n", " nothing\n", " x = 0 # line 3:\n", " SSAValue(0) = (Main.colon)(1, n)\n", " #temp# = (Base.start)(SSAValue(0))\n", " 6: \n", " unless !((Base.done)(SSAValue(0), #temp#)) goto 15\n", " SSAValue(1) = (Base.next)(SSAValue(0), #temp#)\n", " i = (Core.getfield)(SSAValue(1), 1)\n", " #temp# = (Core.getfield)(SSAValue(1), 2) # line 4:\n", " x = x + i\n", " 13: \n", " goto 6\n", " 15: # line 6:\n", " return x\n", " end))" ] }, "execution_count": 148, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# forループもunlessとgotoへ展開\n", "code_lowered(foobar, (Int,))" ] }, { "cell_type": "code", "execution_count": 149, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1-element Array{Any,1}:\n", " CodeInfo(:(begin \n", " x = 0 # line 3:\n", " SSAValue(2) = (Base.select_value)((Base.sle_int)(1, n)::Bool, n, (Base.sub_int)(1, 1)::Int64)::Int64\n", " #temp# = 1\n", " 5: \n", " unless (Base.not_int)((#temp# === (Base.add_int)(SSAValue(2), 1)::Int64)::Bool)::Bool goto 15\n", " SSAValue(3) = #temp#\n", " SSAValue(4) = (Base.add_int)(#temp#, 1)::Int64\n", " i = SSAValue(3)\n", " #temp# = SSAValue(4) # line 4:\n", " x = (Base.add_int)(x, i)::Int64\n", " 13: \n", " goto 5\n", " 15: # line 6:\n", " return x\n", " end))=>Int64" ] }, "execution_count": 149, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Juliaの中間表現に型推論で型をつける\n", "code_typed(foobar, (Int,))" ] }, { "cell_type": "code", "execution_count": 150, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "define i64 @julia_foobar_63146(i64) #0 !dbg !5 {\n", "top:\n", " %1 = icmp slt i64 %0, 1\n", " br i1 %1, label %L15, label %if.lr.ph\n", "\n", "if.lr.ph: ; preds = %top\n", " %2 = shl i64 %0, 1\n", " %3 = add i64 %0, -1\n", " %4 = zext i64 %3 to i65\n", " %5 = add i64 %0, -2\n", " %6 = zext i64 %5 to i65\n", " %7 = mul i65 %4, %6\n", " %8 = lshr i65 %7, 1\n", " %9 = trunc i65 %8 to i64\n", " %10 = add i64 %2, %9\n", " %11 = add i64 %10, -1\n", " br label %L15\n", "\n", "L15: ; preds = %if.lr.ph, %top\n", " %x.0.lcssa = phi i64 [ %11, %if.lr.ph ], [ 0, %top ]\n", " ret i64 %x.0.lcssa\n", "}\n" ] } ], "source": [ "# LLVM中間表現に変換\n", "code_llvm(foobar, (Int,))" ] }, { "cell_type": "code", "execution_count": 151, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\t.section\t__TEXT,__text,regular,pure_instructions\n", "Filename: In[147]\n", "\tpushq\t%rbp\n", "\tmovq\t%rsp, %rbp\n", "\txorl\t%eax, %eax\n", "Source line: 3\n", "\ttestq\t%rdi, %rdi\n", "\tjle\tL34\n", "\tleaq\t-1(%rdi), %rdx\n", "\tleaq\t-2(%rdi), %rax\n", "\tmulxq\t%rax, %rax, %rcx\n", "\tshldq\t$63, %rax, %rcx\n", "\tleaq\t-1(%rcx,%rdi,2), %rax\n", "Source line: 6\n", "L34:\n", "\tpopq\t%rbp\n", "\tretq\n", "\tnopw\t%cs:(%rax,%rax)\n" ] } ], "source": [ "# nativeコードに変換\n", "code_native(foobar, (Int,))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "REPLにコードを打ち込むと上の処理を行う" ] }, { "cell_type": "code", "execution_count": 152, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "55" ] }, "execution_count": 152, "metadata": {}, "output_type": "execute_result" } ], "source": [ "foobar(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 特殊化 (specialization)" ] }, { "cell_type": "code", "execution_count": 153, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "foobar (generic function with 1 method)" ] }, "execution_count": 153, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function foobar(n)\n", " return n * 2\n", "end" ] }, { "cell_type": "code", "execution_count": 154, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "CodeInfo(:(begin \n", " return (Base.mul_int)(n, 2)::Int64\n", " end))=>Int64" ] }, "execution_count": 154, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@code_typed foobar(1)" ] }, { "cell_type": "code", "execution_count": 155, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "CodeInfo(:(begin \n", " return (Base.mul_float)(n, (Base.sitofp)(Float64, 2)::Float64)::Float64\n", " end))=>Float64" ] }, "execution_count": 155, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@code_typed foobar(1.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 引数の型が異なれば、型推論の結果も違う\n", "- 関数は引数の型の組み合わせだけ特殊化(specialize)される" ] }, { "cell_type": "code", "execution_count": 156, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "foobar (generic function with 1 method)" ] }, "execution_count": 156, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function foobar(n)\n", " if n isa Integer\n", " println(\"Integer!\")\n", " end\n", " return n * 2\n", "end" ] }, { "cell_type": "code", "execution_count": 157, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Integer!\n" ] }, { "data": { "text/plain": [ "2" ] }, "execution_count": 157, "metadata": {}, "output_type": "execute_result" } ], "source": [ "foobar(1)" ] }, { "cell_type": "code", "execution_count": 158, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.0" ] }, "execution_count": 158, "metadata": {}, "output_type": "execute_result" } ], "source": [ "foobar(1.0)" ] }, { "cell_type": "code", "execution_count": 159, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "CodeInfo(:(begin # line 3:\n", " $(Expr(:inbounds, false))\n", " # meta: location coreio.jl println 5\n", " SSAValue(0) = (Core.typeassert)(Base.STDOUT, Base.IO)::IO\n", " # meta: pop location\n", " $(Expr(:inbounds, :pop))\n", " (Base.print)(SSAValue(0), \"Integer!\", $(QuoteNode('\\n')))::Void\n", " 8: # line 5:\n", " return (Base.mul_int)(n, 2)::Int64\n", " end))=>Int64" ] }, "execution_count": 159, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@code_typed foobar(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "特殊化によりprintlnが分岐ごと消えている!" ] }, { "cell_type": "code", "execution_count": 160, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "CodeInfo(:(begin \n", " goto 3 # line 3:\n", " 3: # line 5:\n", " return (Base.mul_float)(n, (Base.sitofp)(Float64, 2)::Float64)::Float64\n", " end))=>Float64" ] }, "execution_count": 160, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@code_typed foobar(1.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## トップレベル" ] }, { "cell_type": "code", "execution_count": 161, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Int(time_ns() - start_ns) = 87514105\n" ] }, { "data": { "text/plain": [ "87514105" ] }, "execution_count": 161, "metadata": {}, "output_type": "execute_result" } ], "source": [ "start_ns = time_ns()\n", "s = 0.0\n", "for _ in 1:1_000_000\n", " s += rand()\n", "end\n", "@show Int(time_ns() - start_ns)" ] }, { "cell_type": "code", "execution_count": 162, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "loop (generic function with 1 method)" ] }, "execution_count": 162, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function loop()\n", " s = 0.0\n", " for _ in 1:1_000_000\n", " s += rand()\n", " end\n", " return s\n", "end" ] }, { "cell_type": "code", "execution_count": 163, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Int(time_ns() - start_ns) = 14248780\n" ] }, { "data": { "text/plain": [ "14248780" ] }, "execution_count": 163, "metadata": {}, "output_type": "execute_result" } ], "source": [ "start_ns = time_ns()\n", "s = loop()\n", "@show Int(time_ns() - start_ns)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 同じ計算なのに上のコードは20倍くらい遅い!\n", "- 上のコードはトップレベルで実行されているのに対し、下のコードは関数内のループ\n", "- トップレベルの処理はJITコンパイルされない!\n", "\n", "使い分け:\n", "- トップレベルでは、関数の定義や関数呼び出しを行う\n", "- 関数内では、重い処理を行う" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 型の安定性" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Juliaの高速化は、曖昧性の少ないコードを書くこと\n", "- 型が決定できないとき、Juliaはすごく遅くなる!" ] }, { "cell_type": "code", "execution_count": 164, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "collatz1 (generic function with 1 method)" ] }, "execution_count": 164, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function collatz1(n)\n", " step = 0\n", " while n != 1\n", " step += 1\n", " if mod(n, 2) == 0\n", " n /= 2\n", " else\n", " n = n * 3 + 1\n", " end\n", " end\n", " return step\n", "end" ] }, { "cell_type": "code", "execution_count": 165, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 165, "metadata": {}, "output_type": "execute_result" } ], "source": [ "collatz1(10)" ] }, { "cell_type": "code", "execution_count": 166, "metadata": { "collapsed": true }, "outputs": [], "source": [ "using BenchmarkTools" ] }, { "cell_type": "code", "execution_count": 167, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 86.06 MiB\n", " allocs estimate: 5640009\n", " --------------\n", " minimum time: 110.469 ms (5.88% GC)\n", " median time: 116.169 ms (5.97% GC)\n", " mean time: 117.584 ms (5.84% GC)\n", " maximum time: 132.606 ms (5.19% GC)\n", " --------------\n", " samples: 43\n", " evals/sample: 1" ] }, "execution_count": 167, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@benchmark for n in 1:10000; collatz1(n); end" ] }, { "cell_type": "code", "execution_count": 168, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "CodeInfo(:(begin \n", " n@_4 = n@_2\n", " step = 0 # line 3:\n", " 4: \n", " unless (n@_4 isa Float64)::Bool goto 8\n", " #temp#@_5 = MethodInstance for !=(::Float64, ::Int64)\n", " goto 17\n", " 8: \n", " unless (n@_4 isa Int64)::Bool goto 12\n", " #temp#@_5 = MethodInstance for !=(::Int64, ::Int64)\n", " goto 17\n", " 12: \n", " goto 14\n", " 14: \n", " #temp#@_6 = (n@_4 != 1)::Bool\n", " goto 19\n", " 17: \n", " #temp#@_6 = $(Expr(:invoke, :(#temp#@_5), :(Main.!=), :(n@_4), 1))\n", " 19: \n", " unless #temp#@_6 goto 108 # line 4:\n", " step = (Base.add_int)(step, 1)::Int64 # line 5:\n", " unless (n@_4 isa Float64)::Bool goto 27\n", " #temp#@_7 = MethodInstance for mod(::Float64, ::Int64)\n", " goto 36\n", " 27: \n", " unless (n@_4 isa Int64)::Bool goto 31\n", " #temp#@_7 = MethodInstance for mod(::Int64, ::Int64)\n", " goto 36\n", " 31: \n", " goto 33\n", " 33: \n", " #temp#@_8 = (Main.mod)(n@_4, 2)::Union{Float64, Int64}\n", " goto 38\n", " 36: \n", " #temp#@_8 = $(Expr(:invoke, :(#temp#@_7), :(Main.mod), :(n@_4), 2))\n", " 38: \n", " unless (#temp#@_8 isa Float64)::Bool goto 42\n", " #temp#@_9 = MethodInstance for ==(::Float64, ::Int64)\n", " goto 51\n", " 42: \n", " unless (#temp#@_8 isa Int64)::Bool goto 46\n", " #temp#@_9 = MethodInstance for ==(::Int64, ::Int64)\n", " goto 51\n", " 46: \n", " goto 48\n", " 48: \n", " #temp#@_10 = (#temp#@_8 == 0)::Bool\n", " goto 53\n", " 51: \n", " #temp#@_10 = $(Expr(:invoke, :(#temp#@_9), :(Main.==), :(#temp#@_8), 0))\n", " 53: \n", " unless #temp#@_10 goto 73 # line 6:\n", " unless (n@_4 isa Float64)::Bool goto 59\n", " #temp#@_11 = MethodInstance for /(::Float64, ::Int64)\n", " goto 68\n", " 59: \n", " unless (n@_4 isa Int64)::Bool goto 63\n", " #temp#@_11 = MethodInstance for /(::Int64, ::Int64)\n", " goto 68\n", " 63: \n", " goto 65\n", " 65: \n", " #temp#@_12 = (n@_4 / 2)::Float64\n", " goto 70\n", " 68: \n", " #temp#@_12 = $(Expr(:invoke, :(#temp#@_11), :(Main./), :(n@_4), 2))\n", " 70: \n", " n@_4 = #temp#@_12\n", " goto 106\n", " 73: # line 8:\n", " unless (n@_4 isa Float64)::Bool goto 78\n", " #temp#@_13 = MethodInstance for *(::Float64, ::Int64)\n", " goto 87\n", " 78: \n", " unless (n@_4 isa Int64)::Bool goto 82\n", " #temp#@_13 = MethodInstance for *(::Int64, ::Int64)\n", " goto 87\n", " 82: \n", " goto 84\n", " 84: \n", " #temp#@_14 = (n@_4 * 3)::Union{Float64, Int64}\n", " goto 89\n", " 87: \n", " #temp#@_14 = $(Expr(:invoke, :(#temp#@_13), :(Main.*), :(n@_4), 3))\n", " 89: \n", " unless (#temp#@_14 isa Float64)::Bool goto 93\n", " #temp#@_15 = MethodInstance for +(::Float64, ::Int64)\n", " goto 102\n", " 93: \n", " unless (#temp#@_14 isa Int64)::Bool goto 97\n", " #temp#@_15 = MethodInstance for +(::Int64, ::Int64)\n", " goto 102\n", " 97: \n", " goto 99\n", " 99: \n", " #temp#@_16 = (#temp#@_14 + 1)::Union{Float64, Int64}\n", " goto 104\n", " 102: \n", " #temp#@_16 = $(Expr(:invoke, :(#temp#@_15), :(Main.+), :(#temp#@_14), 1))\n", " 104: \n", " n@_4 = #temp#@_16\n", " 106: \n", " goto 4\n", " 108: # line 11:\n", " return step\n", " end))=>Int64" ] }, "execution_count": 168, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@code_typed collatz1(10)" ] }, { "cell_type": "code", "execution_count": 169, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "collatz2 (generic function with 1 method)" ] }, "execution_count": 169, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function collatz2(n)\n", " step = 0\n", " while n != 1\n", " step += 1\n", " if mod(n, 2) == 0\n", " n = div(n, 2)\n", " else\n", " n = n * 3 + 1\n", " end\n", " end\n", " return step\n", "end" ] }, { "cell_type": "code", "execution_count": 170, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 170, "metadata": {}, "output_type": "execute_result" } ], "source": [ "collatz2(10)" ] }, { "cell_type": "code", "execution_count": 171, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BenchmarkTools.Trial: \n", " memory estimate: 0 bytes\n", " allocs estimate: 0\n", " --------------\n", " minimum time: 3.080 ms (0.00% GC)\n", " median time: 3.298 ms (0.00% GC)\n", " mean time: 3.386 ms (0.00% GC)\n", " maximum time: 17.355 ms (0.00% GC)\n", " --------------\n", " samples: 1473\n", " evals/sample: 1" ] }, "execution_count": 171, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@benchmark for n in 1:10000; collatz2(n); end" ] }, { "cell_type": "code", "execution_count": 172, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Variables:\n", " #self#::#collatz2\n", " n@_2::Int64\n", " step::Int64\n", " n@_4::Int64\n", " d::Int64\n", " #temp#::Int64\n", "\n", "Body:\n", " begin \n", " n@_4::Int64 = n@_2::Int64\n", " step::Int64 = 0 # line 3:\n", " 4: \n", " unless (Base.not_int)((n@_4::Int64 === 1)::Bool)::Bool goto 32 # line 4:\n", " step::Int64 = (Base.add_int)(step::Int64, 1)::Int64 # line 5:\n", " $(Expr(:inbounds, false))\n", " # meta: location int.jl mod 170\n", " unless (2 === -1)::Bool goto 14\n", " #temp#::Int64 = 0\n", " goto 20\n", " 14: # line 171:\n", " # meta: location int.jl fld 191\n", " d::Int64 = (Base.checked_sdiv_int)(n@_4::Int64, 2)::Int64\n", " # meta: pop location\n", " #temp#::Int64 = (Base.sub_int)(n@_4::Int64, (Base.mul_int)((Base.sub_int)(d::Int64, (Base.and_int)((Base.zext_int)(Int64, (Base.and_int)((Base.slt_int)((Base.xor_int)(n@_4::Int64, 2)::Int64, 0)::Bool, (Base.not_int)(((Base.mul_int)(d::Int64, 2)::Int64 === n@_4::Int64)::Bool)::Bool)::Bool)::Int64, 1)::Int64)::Int64, 2)::Int64)::Int64\n", " 20: \n", " # meta: pop location\n", " $(Expr(:inbounds, :pop))\n", " unless (#temp#::Int64 === 0)::Bool goto 27 # line 6:\n", " n@_4::Int64 = (Base.checked_sdiv_int)(n@_4::Int64, 2)::Int64\n", " goto 30\n", " 27: # line 8:\n", " n@_4::Int64 = (Base.add_int)((Base.mul_int)(n@_4::Int64, 3)::Int64, 1)::Int64\n", " 30: \n", " goto 4\n", " 32: # line 11:\n", " return step::Int64\n", " end::Int64\n" ] } ], "source": [ "@code_warntype collatz2(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## メタプログラミング" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- マクロを使うと、コードをコードで編集できる\n", "- `@show`や`@assert`が標準にもあるマクロ\n", "- もちろん自分でも定義できる" ] }, { "cell_type": "code", "execution_count": 173, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "@myassert (macro with 1 method)" ] }, "execution_count": 173, "metadata": {}, "output_type": "execute_result" } ], "source": [ "macro myassert(ex)\n", " msg = \"$(sprint(print, ex)) is not satisfied\"\n", " quote\n", " if !$(ex)\n", " throw(AssertionError($(msg)))\n", " end\n", " end\n", "end" ] }, { "cell_type": "code", "execution_count": 174, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 174, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = 1" ] }, { "cell_type": "code", "execution_count": 175, "metadata": { "collapsed": true }, "outputs": [], "source": [ "@myassert x > 0" ] }, { "cell_type": "code", "execution_count": 176, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 176, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = 0" ] }, { "cell_type": "code", "execution_count": 177, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mAssertionError: x > 0 is not satisfied\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mAssertionError: x > 0 is not satisfied\u001b[39m", "", "Stacktrace:", " [1] \u001b[1minclude_string\u001b[22m\u001b[22m\u001b[1m(\u001b[22m\u001b[22m::String, ::String\u001b[1m)\u001b[22m\u001b[22m at \u001b[1m./loading.jl:515\u001b[22m\u001b[22m" ] } ], "source": [ "@myassert x > 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "具体例: 正規表現をJuliaへコンパイル\n", "\n", "Automa.jlを使って、実行時のコード生成でどういうことができるかをデモンストレーションしてみる。" ] }, { "cell_type": "code", "execution_count": 178, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import Automa\n", "import Automa.RegExp: @re_str\n", "const re = Automa.RegExp\n", "\n", "oct = re\"0o[0-7]+\"\n", "dec = re\"[-+]?[0-9]+\"\n", "hex = re\"0x[0-9A-Fa-f]+\"\n", "prefloat = re\"[-+]?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+)\"\n", "float = prefloat | re.cat(prefloat | re\"[-+]?[0-9]+\", re\"[eE][-+]?[0-9]+\")\n", "number = oct | dec | hex | float\n", "numbers = re.cat(re.opt(number), re.rep(re\" +\" * number), re\" *\");" ] }, { "cell_type": "code", "execution_count": 179, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1-element Array{Symbol,1}:\n", " :float" ] }, "execution_count": 179, "metadata": {}, "output_type": "execute_result" } ], "source": [ "number.actions[:enter] = [:mark]\n", "oct.actions[:exit] = [:oct]\n", "dec.actions[:exit] = [:dec]\n", "hex.actions[:exit] = [:hex]\n", "float.actions[:exit] = [:float]" ] }, { "cell_type": "code", "execution_count": 180, "metadata": { "collapsed": true }, "outputs": [], "source": [ "actions = Dict(\n", " :mark => :(mark = p),\n", " :oct => :(emit(:oct)),\n", " :dec => :(emit(:dec)),\n", " :hex => :(emit(:hex)),\n", " :float => :(emit(:float)),\n", ");" ] }, { "cell_type": "code", "execution_count": 181, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "tokenize (generic function with 1 method)" ] }, "execution_count": 181, "metadata": {}, "output_type": "execute_result" } ], "source": [ "machine = Automa.compile(numbers)\n", "context = Automa.CodeGenContext(generator=:goto, clean=true)\n", "@eval function tokenize(data::String)\n", " tokens = Tuple{Symbol,String}[]\n", " mark = 0\n", " $(Automa.generate_init_code(context, machine))\n", " p_end = p_eof = endof(data)\n", " emit(kind) = push!(tokens, (kind, data[mark:p-1]))\n", " $(Automa.generate_exec_code(context, machine, actions))\n", " return tokens, cs == 0 ? :ok : cs < 0 ? :error : :incomplete\n", "end" ] }, { "cell_type": "code", "execution_count": 182, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6-element Array{Tuple{Symbol,String},1}:\n", " (:dec, \"1\") \n", " (:hex, \"0x0123BEEF\") \n", " (:oct, \"0o754\") \n", " (:float, \"3.14\") \n", " (:float, \"-1e4\") \n", " (:float, \"+6.022045e23\")" ] }, "execution_count": 182, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tokens, status = tokenize(\"1 0x0123BEEF 0o754 3.14 -1e4 +6.022045e23\")\n", "tokens" ] }, { "cell_type": "code", "execution_count": 183, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "HTML{String}(\"\")" ] }, "execution_count": 183, "metadata": {}, "output_type": "execute_result" } ], "source": [ "write(\"numbers.dot\", Automa.machine2dot(machine))\n", "run(`dot -Tpng -o numbers.png numbers.dot`)\n", "html\"\"" ] }, { "cell_type": "code", "execution_count": 184, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Tuple{Symbol,String}[], :incomplete)" ] }, "execution_count": 184, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tokenize(\"0x\")" ] }, { "cell_type": "code", "execution_count": 185, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Tuple{Symbol,String}[(:hex, \"0x1234\")], :ok)" ] }, "execution_count": 185, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tokenize(\"0x1234\")" ] }, { "cell_type": "code", "execution_count": 186, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Tuple{Symbol,String}[], :error)" ] }, "execution_count": 186, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tokenize(\"0x1234G\")" ] }, { "cell_type": "code", "execution_count": 187, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/plain": [ "quote \n", " if p > p_end\n", " @goto exit\n", " end\n", " ##722 = (Automa.SizedMemory)(data)\n", " if cs == 1\n", " @goto state_case_1\n", " else \n", " if cs == 2\n", " @goto state_case_2\n", " else \n", " if cs == 3\n", " @goto state_case_3\n", " else \n", " if cs == 4\n", " @goto state_case_4\n", " else \n", " if cs == 5\n", " @goto state_case_5\n", " else \n", " if cs == 6\n", " @goto state_case_6\n", " else \n", " if cs == 7\n", " @goto state_case_7\n", " else \n", " if cs == 8\n", " @goto state_case_8\n", " else \n", " if cs == 9\n", " @goto state_case_9\n", " else \n", " if cs == 10\n", " @goto state_case_10\n", " else \n", " if cs == 11\n", " @goto state_case_11\n", " else \n", " if cs == 12\n", " @goto state_case_12\n", " else \n", " if cs == 13\n", " @goto state_case_13\n", " else \n", " @goto exit\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " @label state_1_action_2\n", " emit(:float)\n", " @goto state_1\n", " @label state_1_action_3\n", " emit(:dec)\n", " @goto state_1\n", " @label state_1_action_4\n", " emit(:hex)\n", " @goto state_1\n", " @label state_1_action_5\n", " emit(:oct)\n", " @goto state_1\n", " @label state_1\n", " p += 1\n", " if p > p_end\n", " cs = 1\n", " @goto exit\n", " end\n", " @label state_case_1\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x31:0x39 || false) && true\n", " @goto state_3_action_1\n", " else \n", " if (##723 in 0x2b:0x2b || (##723 in 0x2d:0x2d || false)) && true\n", " @goto state_4_action_1\n", " else \n", " if (##723 in 0x20:0x20 || false) && true\n", " @goto state_1\n", " else \n", " if (##723 in 0x30:0x30 || false) && true\n", " @goto state_2_action_1\n", " else \n", " if (##723 in 0x2e:0x2e || false) && true\n", " @goto state_5_action_1\n", " else \n", " cs = -1\n", " @goto exit\n", " end\n", " end\n", " end\n", " end\n", " end\n", " @label state_5_action_1\n", " mark = p\n", " @goto state_5\n", " @label state_5\n", " p += 1\n", " if p > p_end\n", " cs = 5\n", " @goto exit\n", " end\n", " @label state_case_5\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || false) && true\n", " @goto state_6\n", " else \n", " cs = -5\n", " @goto exit\n", " end\n", " @label state_6\n", " p += 1\n", " if p > p_end\n", " cs = 6\n", " @goto exit\n", " end\n", " @label state_case_6\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || false) && true\n", " @goto state_6\n", " else \n", " if (##723 in 0x45:0x45 || (##723 in 0x65:0x65 || false)) && true\n", " @goto state_7\n", " else \n", " if (##723 in 0x20:0x20 || false) && true\n", " @goto state_1_action_2\n", " else \n", " cs = -6\n", " @goto exit\n", " end\n", " end\n", " end\n", " @label state_7\n", " p += 1\n", " if p > p_end\n", " cs = 7\n", " @goto exit\n", " end\n", " @label state_case_7\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || false) && true\n", " @goto state_8\n", " else \n", " if (##723 in 0x2b:0x2b || (##723 in 0x2d:0x2d || false)) && true\n", " @goto state_9\n", " else \n", " cs = -7\n", " @goto exit\n", " end\n", " end\n", " @label state_9\n", " p += 1\n", " if p > p_end\n", " cs = 9\n", " @goto exit\n", " end\n", " @label state_case_9\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || false) && true\n", " @goto state_8\n", " else \n", " cs = -9\n", " @goto exit\n", " end\n", " @label state_8\n", " p += 1\n", " if p > p_end\n", " cs = 8\n", " @goto exit\n", " end\n", " @label state_case_8\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || false) && true\n", " @goto state_8\n", " else \n", " if (##723 in 0x20:0x20 || false) && true\n", " @goto state_1_action_2\n", " else \n", " cs = -8\n", " @goto exit\n", " end\n", " end\n", " @label state_4_action_1\n", " mark = p\n", " @goto state_4\n", " @label state_4\n", " p += 1\n", " if p > p_end\n", " cs = 4\n", " @goto exit\n", " end\n", " @label state_case_4\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || false) && true\n", " @goto state_3\n", " else \n", " if (##723 in 0x2e:0x2e || false) && true\n", " @goto state_5\n", " else \n", " cs = -4\n", " @goto exit\n", " end\n", " end\n", " @label state_3_action_1\n", " mark = p\n", " @goto state_3\n", " @label state_3\n", " p += 1\n", " if p > p_end\n", " cs = 3\n", " @goto exit\n", " end\n", " @label state_case_3\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || false) && true\n", " @goto state_3\n", " else \n", " if (##723 in 0x45:0x45 || (##723 in 0x65:0x65 || false)) && true\n", " @goto state_7\n", " else \n", " if (##723 in 0x20:0x20 || false) && true\n", " @goto state_1_action_3\n", " else \n", " if (##723 in 0x2e:0x2e || false) && true\n", " @goto state_6\n", " else \n", " cs = -3\n", " @goto exit\n", " end\n", " end\n", " end\n", " end\n", " @label state_2_action_1\n", " mark = p\n", " @goto state_2\n", " @label state_2\n", " p += 1\n", " if p > p_end\n", " cs = 2\n", " @goto exit\n", " end\n", " @label state_case_2\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || false) && true\n", " @goto state_3\n", " else \n", " if (##723 in 0x45:0x45 || (##723 in 0x65:0x65 || false)) && true\n", " @goto state_7\n", " else \n", " if (##723 in 0x6f:0x6f || false) && true\n", " @goto state_10\n", " else \n", " if (##723 in 0x20:0x20 || false) && true\n", " @goto state_1_action_3\n", " else \n", " if (##723 in 0x78:0x78 || false) && true\n", " @goto state_11\n", " else \n", " if (##723 in 0x2e:0x2e || false) && true\n", " @goto state_6\n", " else \n", " cs = -2\n", " @goto exit\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " @label state_11\n", " p += 1\n", " if p > p_end\n", " cs = 11\n", " @goto exit\n", " end\n", " @label state_case_11\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || (##723 in 0x41:0x46 || (##723 in 0x61:0x66 || false))) && true\n", " @goto state_12\n", " else \n", " cs = -11\n", " @goto exit\n", " end\n", " @label state_12\n", " p += 1\n", " if p > p_end\n", " cs = 12\n", " @goto exit\n", " end\n", " @label state_case_12\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x39 || (##723 in 0x41:0x46 || (##723 in 0x61:0x66 || false))) && true\n", " @goto state_12\n", " else \n", " if (##723 in 0x20:0x20 || false) && true\n", " @goto state_1_action_4\n", " else \n", " cs = -12\n", " @goto exit\n", " end\n", " end\n", " @label state_10\n", " p += 1\n", " if p > p_end\n", " cs = 10\n", " @goto exit\n", " end\n", " @label state_case_10\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x37 || false) && true\n", " @goto state_13\n", " else \n", " cs = -10\n", " @goto exit\n", " end\n", " @label state_13\n", " p += 1\n", " if p > p_end\n", " cs = 13\n", " @goto exit\n", " end\n", " @label state_case_13\n", " ##723 = (getindex)(##722, p + 0)\n", " if (##723 in 0x30:0x37 || false) && true\n", " @goto state_13\n", " else \n", " if (##723 in 0x20:0x20 || false) && true\n", " @goto state_1_action_5\n", " else \n", " cs = -13\n", " @goto exit\n", " end\n", " end\n", " @label exit\n", " if p > p_eof ≥ 0 && cs ∈ Automa.StableSet{Int64}(Automa.StableDict(1=>nothing,6=>nothing,8=>nothing,3=>nothing,2=>nothing,12=>nothing,13=>nothing))\n", " if cs == 1\n", " else \n", " if cs == 6\n", " emit(:float)\n", " else \n", " if cs == 8\n", " emit(:float)\n", " else \n", " if cs == 3\n", " emit(:dec)\n", " else \n", " if cs == 2\n", " emit(:dec)\n", " else \n", " if cs == 12\n", " emit(:hex)\n", " else \n", " if cs == 13\n", " emit(:oct)\n", " else \n", " ()\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " end\n", " cs = 0\n", " end\n", "end" ] }, "execution_count": 187, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Automa.generate_exec_code(context, machine, actions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 今後の動向" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Juliaの人気\n", "\n", "TIOBE(August 2017)では46位 (https://www.tiobe.com/tiobe-index/)\n", "- HaskellやGroovyの上\n", "- Lua, Kotlin, Clojureよりは下\n", "\n", "IEEE Spectrum 2017では31位 (http://spectrum.ieee.org/static/interactive-the-top-programming-languages-2017)\n", "- Clojure, Kotlin, Groovyより上\n", "- Haskell, Luaより下" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Juliaの開発状況\n", "\n", "- Juliaの最新版はv0.6.0\n", "- GitHubのスター数は9,000を超えた\n", "- 600人以上がJulia本体にコントリビュート\n", "- 過去1ヶ月で200以上のプルリクがマージされ、150以上のイシューがクローズされた\n", "- 1500以上のパッケージ (打ち捨てられたものもあるが...)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Juliaの開発体制\n", "\n", "[NumFOCUS](https://www.numfocus.org/)の支援プロジェクトの1つ\n", "\n", "\n", "[Julia Computing Inc.](https://juliacomputing.com/)というJuliaの開発者達による企業が作られた\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Julia 1.0?\n", "\n", "- まだ未定だが、運が良ければ今年か、来年に出る?\n", "- Juliaのリリースは毎回半年ぐらい遅れるので、多分来年の上旬くらいか\n", "- Julia 1.0が出れば、とりあえず数年は安定して使えそう\n", "\n", "入りそうな機能\n", "- Pkg3: パッケージシステムのメジャーアップデート\n", " - 現在のPkg2がデカいレポジトリをガンガン書き換えながら管理するので色々問題が\n", " - Pkg2では、パッケージのバージョンを固定した環境などが作りにくい\n", " - Pkg3では、分散管理・TOMLによるバージョン固定など使いやすくなる予定\n", " - https://github.com/JuliaLang/Juleps/blob/master/Pkg3.md\n", "- `NamedTuple`: 名前付きタプル\n", " - Juliaの`Tuple`は位置(1,2,...)で要素を指定\n", " - `NamedTuple`は名前でも要素を指定できるように\n", " - `(foo=1.0, bar=\"hoge\")`のような構文も追加される\n", " - https://github.com/JuliaLang/julia/pull/22194\n", "- `Null`値: 欠損値の扱いの向上\n", " - 現在`Nullable`でnullかもしれない値を表現\n", " - 配列とかに入れるとちょっと面倒 (いちいち`Nullable`を外さないといけない)\n", " - `Union{Float32,Void}`みたいなのが高速に扱えるようになる\n", " - https://github.com/JuliaLang/julia/pull/22441 (マージ済み)\n", "- Parallel Task Runtime: マルチスレッド機能の本気実装\n", " - Juliaの同時実行できるタスクは1つだけ\n", " - `@threads`を使えばforループを局所的に並列実行できるが...\n", " - タスクを別スレッドで並列実行できるようになりそう\n", " - https://github.com/JuliaLang/julia/pull/22631" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# (おまけ) 作ったパッケージの紹介" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "全部or大半のコードを書いた公式パッケージ\n", "\n", "- [TranscodingStreams.jl](https://github.com/bicycle1885/TranscodingStreams.jl)\n", "- [CodecZlib.jl](https://github.com/bicycle1885/CodecZlib.jl)\n", "- [CodecBzip2.jl](https://github.com/bicycle1885/CodecBzip2.jl)\n", "- [CodecXz.jl](https://github.com/bicycle1885/CodecXz.jl)\n", "- [CodecZstd.jl](https://github.com/bicycle1885/CodecZstd.jl)\n", "- [CodecBase.jl](https://github.com/bicycle1885/CodecBase.jl)\n", "- [EzXML.jl](https://github.com/bicycle1885/EzXML.jl)\n", "- [DocOpt.jl](https://github.com/docopt/DocOpt.jl)\n", "- [Snappy.jl](https://github.com/bicycle1885/Snappy.jl)\n", "- [BioCore.jl](https://github.com/BioJulia/BioCore.jl)\n", "- [BioSymbols.jl](https://github.com/BioJulia/BioSymbols.jl)\n", "- [BioSequences.jl](https://github.com/BioJulia/BioSequences.jl)\n", "- [BioAlignments.jl](https://github.com/BioJulia/BioAlignments.jl)\n", "- [GenomicFeatures.jl](https://github.com/BioJulia/GenomicFeatures.jl)\n", "- [BGZFStreams.jl](https://github.com/BioJulia/BGZFStreams.jl)\n", "- [Automa.jl](https://github.com/BioJulia/Automa.jl)\n", "- [IndexableBitVectors.jl](https://github.com/BioJulia/IndexableBitVectors.jl)\n", "- [FMIndexes.jl](https://github.com/BioJulia/FMIndexes.jl)" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Julia 0.6.0", "language": "julia", "name": "julia-0.6" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "0.6.0" }, "nbpresent": { "slides": { "0c6a42d0-560d-4400-875d-c7063bb04e15": { "id": "0c6a42d0-560d-4400-875d-c7063bb04e15", "prev": "4cf4bb21-c3c8-48c5-bcf4-b63ec5bb5997", "regions": { "3e96ccd7-3541-4750-b4e4-76ae05591bce": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "385e0a13-6529-48cc-8a68-5401cb5e11ed", "part": "whole" }, "id": "3e96ccd7-3541-4750-b4e4-76ae05591bce" } } }, "4129f5d0-78d8-424e-ad72-0775ccbbdc53": { "id": "4129f5d0-78d8-424e-ad72-0775ccbbdc53", "prev": "0c6a42d0-560d-4400-875d-c7063bb04e15", "regions": { "94eb76a6-811b-4535-81b1-118d4df52e5b": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "c825d089-a85d-4f52-9b30-88f6e5f6ce3b", "part": "whole" }, "id": "94eb76a6-811b-4535-81b1-118d4df52e5b" } } }, "4cf4bb21-c3c8-48c5-bcf4-b63ec5bb5997": { "id": "4cf4bb21-c3c8-48c5-bcf4-b63ec5bb5997", "prev": null, "regions": { "a0a1cbdb-6666-42af-bd4c-2ecaf9fcb641": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "d8145165-8d8e-4c7d-8511-710cae0113ed", "part": "whole" }, "id": "a0a1cbdb-6666-42af-bd4c-2ecaf9fcb641" } } }, "f92d0851-8379-4d31-9d41-1ac5342d070d": { "id": "f92d0851-8379-4d31-9d41-1ac5342d070d", "prev": "4129f5d0-78d8-424e-ad72-0775ccbbdc53", "regions": { "3371c62e-213a-4c56-88f9-781a4da9aa52": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "2a494f69-3536-4096-bfc1-32ebdc500a86", "part": "whole" }, "id": "3371c62e-213a-4c56-88f9-781a4da9aa52" } } } }, "themes": {} }, "toc": { "colors": { "hover_highlight": "#DAA520", "navigate_num": "#000000", "navigate_text": "#333333", "running_highlight": "#FF0000", "selected_highlight": "#FFD700", "sidebar_border": "#EEEEEE", "wrapper_background": "#FFFFFF" }, "moveMenuLeft": true, "nav_menu": { "height": "84px", "width": "252px" }, "navigate_menu": true, "number_sections": false, "sideBar": true, "threshold": 4, "toc_cell": false, "toc_position": { "height": "710px", "left": "0px", "right": "1068px", "top": "32px", "width": "212px" }, "toc_section_display": "block", "toc_window_display": true, "widenNotebook": false } }, "nbformat": 4, "nbformat_minor": 2 }