Broadcasting 入門 === <!-- .element: style="font-size: 300%" --> <!-- .slide: data-background-color="rgba(102,130,223,0.3)" --> 2020/08/08 JuliaTokai \#07 antimon2(後藤 俊介) Note: Julia の Broadcasting と触れ合おう! ---- <!-- .slide: data-background-color="rgba(102,130,223,0.3)" --> ## お品書き + お前誰よ? + 簡単なJuliaの紹介 + Broadcasting --- <!-- .slide: data-background-color="rgba(102,130,223,0.3)" --> # お前誰よ? ---- <!-- .slide: data-background-color="rgba(102,130,223,0.3)" --> ## 自己紹介 + 名前:後藤 俊介 + 所属:**[有限会社 来栖川電算](https://www.kurusugawa.jp)** + コミュニティ:**:star2:[JuliaTokai](https://juliatokai.connpass.com/)**, :star2:[機械学習名古屋](https://machine-learning.connpass.com/), :star:[Python東海](https://connpass.com/series/292/), … + 言語:**[Julia](https://julialang.org)**, Python, Scala(勉強中), … + ![Twitter](https://i.imgur.com/HqouMIg.png)<!-- .element: class="plain" style="vertical-align:middle;background:transparent" --> [@antimon2](https://twitter.com/antimon2) / ![Facebook](https://i.imgur.com/01nPd37.png)<!-- .element: class="plain" style="vertical-align:middle;background:transparent" --> [antimon2](https://www.facebook.com/antimon2) + ![Github](https://i.imgur.com/yBKtii5.png)<!-- .element: class="plain" style="vertical-align:middle;background:transparent" --> [antimon2](https://github.com/antimon2/) / ![Qiita](https://i.imgur.com/FxHMi64.png)<!-- .element: class="plain" style="vertical-align:middle;background:transparent" --> [@antimon2](http://qiita.com/antimon2) / [<i class="fa fa-file-text"><!-- .element style="font-size:120%" --></i> @antimon2](https://hackmd.io/@antimon2) Note: 今日は(も?)大っぴらに Julia の話ができるっ ---- <!-- .slide: data-background-color="rgba(44,214,221,0.3)" --> [![有限会社来栖川電算](https://i.imgur.com/8Kuhfel.png) https://www.kurusugawa.jp](https://www.kurusugawa.jp) Note: 普段は Python で仕事してますっ ---- <!-- .slide: data-background-color="rgba(204,102,51,0.3)" --> [![機械学習名古屋 第25回勉強会 Watson Studio Auto AI ハンズオン(オンライン) - connpass](https://i.imgur.com/cQ4PS7r.png) https://machine-learning.connpass.com/event/183476/](https://machine-learning.connpass.com/event/183476/) Note: 今月末開催! --- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> # <small>簡単な</small><br>Julia の紹介 Note: Julia の紹介っ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> [![Julia](https://raw.githubusercontent.com/JuliaLang/julia-logo-graphics/master/images/julia-logo-color.svg?sanitize=true)<!-- .element: style="background:white;width:80%" -->](https://julialang.org) Note: 実は何気にロゴマイナーチェンジしてますっ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ## Julia とは?(1) + [The Julia Language](https://julialang.org) + 最新 v1.5.0(2020/08/01) + LTS v1.0.5(2019/09/09) + DEV v1.6.0 → 次のLTS! + 科学技術計算に強い! + 動作が速い!(LLVM JIT コンパイル) Note: ググるときはなるべく [julialang](https://www.google.co.jp/search?q=julialang) で! ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ## Julia とは?(2) > + Rのように中身がぐちゃぐちゃでなく、 > + Rubyのように遅くなく、 > + Lispのように原始的またはエレファントでなく、 > + Prologのように変態的なところはなく、 > + Javaのように硬すぎることはなく、 > + Haskellのように抽象的すぎない > > ほどよい言語である <!-- .element: style="font-size:66%" --> 引用元:http://www.slideshare.net/Nikoriks/julia-28059489/8 <!-- .element: style="font-size:71%" --> ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ## Julia とは?(3) > + C のように高速だけど、 Ruby のような動的型付言語である > + Lisp のようにプログラムと同等に扱えるマクロがあって、しかも Matlab のような直感的な数式表現もできる > + Python のように総合的なプログラミングができて、 R のように統計処理も得意で、 Perl のように文字列処理もできて、 Matlab のように線形代数もできて、 shell のように複数のプログラムを組み合わせることもできる > + 超初心者にも習得は簡単で、 超上級者の満足にも応えられる > + インタラクティブにも動作して、コンパイルもできる <!-- .element: style="font-size:50%" --> ([Why We Created Julia](http://julialang.org/blog/2012/02/why-we-created-julia) から抜粋・私訳) <!-- .element: style="font-size:71%" --> Note: いろんな言語の「いいとこどり」言語!ってことでっ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ## 要するに <!-- .element: style="font-size:300%" --> + 動的言語なのに速い! + 文法も覚えやすい! + 数値計算に強い! <!-- .element: style="font-size:180%" --> Note: 機械学習とかにも持って来いっ! ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ## 主な機能 <!-- .element: style="font-size:280%" --> + [多重ディスパッチ](https://docs.julialang.org/en/v1/manual/methods/) + [動的型システム](https://docs.julialang.org/en/v1/manual/types/) + [並行・並列処理](https://docs.julialang.org/en/v1/manual/parallel-computing/)、コルーチン + [組込パッケージマネージャ](https://docs.julialang.org/en/v1/stdlib/Pkg/) <!-- .element: style="font-size:160%" --> Note: っ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ## 文法・関数 Note: 以降、ほぼ過去スライドからのコピペ。すっ飛ばして先へ進んで戴いてもOKっ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### 基本的な演算 ```julia julia> 1 + 2 - 3 * 4 # 四則演算(除算以外) -9 julia> 7 / 5 # `整数 / 整数` の結果は浮動小数 1.4 julia> 7 ÷ 5 # `整数 ÷ 整数` の結果は整数 1 julia> 2 ^ 10 # 冪乗は `^` 1024 julia> 123 & 234 | 345 # 論理積 / 論理和 376 julia> 123 ⊻ 234 # 排他的論理和(==`xor(123, 234)`) 145 ``` <!-- .element: style="font-size:46%" --> Note: 整数同士の除算は実数になりますっ 整数除算演算子 `÷` が別に存在します(Python の `//` 相当)っ また冪乗も(`**` ではなく)`^` ですっ `⊻` は `\xor`+<kbd>Tab</kbd> または `\veebar`+<kbd>Tab</kbd> で変換できますっ ちなみに先ほどの `÷` も `\div`+<kbd>Tab</kbd>で(基本的に ${\rm \TeX}$ の書式)っ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### 配列 ```julia julia> a = [1, 2, 3, 4, 5] 5-element Array{Int64,1}: 1 2 3 4 5 julia> a[1] # Julia は 1-origin 1 julia> println(a[2:3]) # 範囲指定は両端含む [2, 3] ``` <!-- .element: style="font-size:50%" --> Note: 1-origin であることに注意すればあとは普通の配列っ あと `a:b` は範囲(`Range`)の記法。両端を含む(Ruby の `a..b` と同じ)っ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### 配列の内包表記 (1) ```julia julia> a = [n^2 for n=1:5] 5-element Array{Int64,1}: 1 4 9 16 25 julia> A = [x+10y for y=1:3, x=1:3] 3×3 Array{Int64,2}: 11 12 13 21 22 23 31 32 33 ``` <!-- .element: style="font-size:50%" --> Note: 内包表記の記法は Python に類似っ かつ、`for` にカンマ区切りで複数のイテレータを渡すことで2次元以上の配列も作成可能っ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### 配列の内包表記 (2) ```julia julia> [(a,b,c) for c=1:15,b=1:15,a=1:15 if a^2+a*b+b^2==c^2] 6-element Array{Tuple{Int64,Int64,Int64},1}: (3, 5, 7) (5, 3, 7) (6, 10, 14) (7, 8, 13) (8, 7, 13) (10, 6, 14) ``` Note: Python と同様に `if` で条件を指定することも可能っ あと Python と同様、`[○ for ○=○]` を `(○ for ○=○)` と書くと配列ではなくて `Generator` が返りますっ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### ベクトル ```julia julia> x = [1., 2., 3.]; y = [3., 1., 2.]; julia> x + y # `x .+ y` と書いても同じ(elementwise operation) [4., 3., 5.] julia> x .* y # これは `x * y` と書くとNG [3., 2., 6.] julia> using LinearAlgebra julia> x ⋅ y # 内積(dot積、`dot(x, y)` と書いても同じ) 11.0 julia> x × y # 外積(cross積、`cross(x, y)` と書いても同じ) [1., 7., -5.] ``` <!-- .element: style="font-size:50%" --> Note: Julia では実は1次元配列がベクトルの扱いっ `⋅` は `\cdot`+<kbd>Tab</kbd>、`×` は `\times`+<kbd>Tab</kbd>(これらを利用するには `using LinearAlgebra` 必要)っ あとこれらや先ほどの `÷` や `⊻` などのように、ASCIIの範囲を超えたUnicode文字の演算子(そのほとんどが $\TeX$ 由来)が Julia にはたくさんあります(他には例えば比較演算子の `≤` `≥` や、集合の要素 `∈` や包含関係 `⊆` などなど) ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### 行列 ```julia julia> A = [1 2; 3 4] # この記法は MATLAB/Octave 由来 2×2 Array{Int64,2}: 1 2 3 4 julia> A' # `○'` は転置行列の記法(これも MATLAB/Octave 由来) 2×2 LinearAlgebra.Adjoint{Int64,Array{Int64,2}}: 1 3 2 4 julia> transpose(A) # 正確には転置行列はこっち 2×2 LinearAlgebra.Transpose{Int64,Array{Int64,2}}: 1 3 2 4 ``` <!-- .element: style="font-size:50%" --> Note: Julia では2次元配列が行列の扱いっ あと `○.'` という書式は廃止されました(`transpose(A)` 使ってね)っ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### 行列の演算 ```julia julia> A = [1 2; 3 4]; B = [3 0; 0 6]; julia> A + B # A .+ B でも同様 2×2 Array{Int64,2}: 4 2 3 10 julia> A * B # matrix multiply 2×2 Array{Int64,2}: 3 12 9 24 julia> A .* B # elementwise multiply 2×2 Array{Int64,2}: 3 0 0 24 ``` <!-- .element: style="font-size:48%" --> Note: 行列は `*` で通常の行列積になりますっこれ便利っ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### ブロードキャスト ```julia julia> sin(0.1) 0.09983341664682815 julia> sin.([0.1, 0.2, 0.3, 0.4]) 4-element Array{Float64,1}: 0.0998334 0.198669 0.29552 0.389418 julia> [0.1, 0.2, 0.3, 0.4] .^ 2 # => [0.01, 0.04, 0.09, 0.16] ``` <!-- .element: style="font-size:50%" --> <big>※この後詳しく!<!-- .element: class="fragment" data-fragment-index="1" --></big> Note: 関数名と `(` の間に `.` を置くと、普通の関数を配列に拡張してくれる(ブロードキャスト)っ `.^` のように演算子の前に `.` を書いても同様(先ほど出た `.+` `.*` もブロードキャスト)っ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### 関数定義 ```julia julia> f(x) = x^2 + 2x - 1 f (generic function with 1 method) julia> f(1) 2 julia> f.(1:5) # => [2, 7, 14, 23, 34] ``` Note: 数学のように直感的な記述で関数を定義可能っ `2x` は `2*x` の省略形、曖昧さがなければリテラルと他の識別子が続く場合などに勝手に乗算と解釈してくれるっ またユーザ定義関数も `.` をつけて自動的にブロードキャスト対応っ ---- <!-- .slide: data-background-color="rgba(213,99,92,0.3)" --> ### 有理数・複素数 ```julia julia> 1//2 == 0.5 true julia> 1//2 - 1//3 1//6 julia> 1im ^ 2 == -1 true julia> (1.0 + 0.5im) * (2.0 - 3.0im) 3.5 - 2.0im ``` Note: 有理数・複素数を標準サポート。 `//` は有理数除算(結果は有理数) `im` は虚数単位。 どちらも四則演算も普通に書けますっ --- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> # Broadcasting Note: Julia 標準の目玉機能の1つ --- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ## ドット構文 + [Dot Syntax for Vectorizing Functions - Julia Documentation](https://docs.julialang.org/en/v1/manual/functions/#man-vectorized-1) + 関数を簡単にベクタ化できる便利な機能 Note: まずはこちらの説明っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> sin(0.1) 0.09983341664682815 julia> sin.([0.1, 0.2, 0.3, 0.4]) 4-element Array{Float64,1}: 0.0998334 0.198669 0.29552 0.389418 julia> [0.1, 0.2, 0.3, 0.4] .^ 2 # => [0.01, 0.04, 0.09, 0.16] ``` Note: `sin()` はスカラーを引数に取る関数。 `sin.()` と、関数名と`()` の間に `.` を書くだけで、配列(等)を引数に受け取ってそれぞれに適用した結果を配列(等)で返すことが出来る。 これがJuliaのドット構文(とそれによるベクタ化)! ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ### Point + どんな関数も `.` を付けるだけでベクタ化可能 + ユーザ定義関数でもOK! + 演算子の場合は前に `.` を付ければOK Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> x = [3., 1., 4., 1., 6.] # => [3.0, 1.0, 4.0, 1.0, 6.0] julia> sqrt.(sort(x) .+ .25) # => [1.118033988749895, 1.118033988749895, # 1.8027756377319946, 2.0615528128088303, 2.5] julia> @. sqrt($sort(x) + .25) # => [1.118033988749895, 1.118033988749895, # 1.8027756377319946, 2.0615528128088303, 2.5] ``` Note: `@.` っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ### Point + ドット構文はネスト可能 + `@.` マクロで一連のドット構文を簡略化 + ベクタ化せずに呼び出したい関数の前には `$` を付ける Note: っ --- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ## ブロードキャスト + [Broadcasting - Julia Documentation](https://docs.julialang.org/en/v1/manual/arrays/#Broadcasting-1) + ドット構文で2つ(以上)の値の演算を行うとき、各軸を拡張して次元数と各次元の要素数を揃えて処理すること。 Note: 続いて本題っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> a = [10, 20]; A = [1 2 3; 4 5 6]; julia> a .+ A 2×3 Array{Int64,2}: 11 12 13 24 25 26 julia> repeat(a, 1, 3) + A # equivalent to above 2×3 Array{Int64,2}: 11 12 13 24 25 26 ``` Note: ベクトル(1次元配列)は縦ベクトルであることに注意っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ### Point + 次元の要素数の少ない方は、繰り返し処理により拡張される + ただし実際にはその分のメモリを消費するわけではない(省メモリ) Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> b = [10 30; 20 40]; B = reshape(1:6, (2, 1, 3)); julia> size(b) # => (2, 2) julia> size(B) # => (2, 1, 3) julia> size(b .+ B) # => (2, 2, 3) ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ### Point + 次元拡張ルール: + 次元数が足りない場合は、後ろに追加して揃える + 同じ次元の一方の要素数が`1`だったら他方に合わせて拡張 + 両方同じ数だったらそのまま Note: 同じ次元の要素数がいずれも1でなくて異なる場合は `DimensionMismatch` エラーになりますっ! あと特に最初のルールはNumpyのそれと違う(行指向か列指向かの違いによる)のでちょっとだけ注意っ! --- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> # ブロードキャストのカスタマイズ Note: ユーザ定義型(など)にブロードキャスト(ドット構文)を適用させようっ --- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ## 事例1:2次元ベクトル Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia mutable struct Vec2{T} <: AbstractVector{T} x::T y::T end ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia Base.length(::Vec2) = 2 Base.size(::Vec2) = (2,) Base.getindex(a::Vec2, i::Integer) = getfield(a, fieldnames(Vec2)[i]) Base.setindex!(a::Vec2{T}, v::T, i::Integer) where {T} = setfield!(a, fieldnames(Vec2)[i], v) Base.setindex!(a::Vec2{T}, v, i::Integer) where {T} = setindex!(a, convert(T, v), i) ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> vec2 = Vec2(1.0, 2.0) 2-element Vec2{Float64}: 1.0 2.0 julia> vec2 .+ vec2 2-element Array{Float64,1}: 2.0 4.0 ``` Note: `AbstractArray` を継承した型を作って、インデクシング(`getindex()`)を実装すれば、とりあえずそれだけでブロードキャスト対応可能っ ただし、演算結果が `Array` になってしまう→ `Vec2` のまま演算させたい! ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia struct Vec2Style <: Broadcast.AbstractArrayStyle{1} end Broadcast.BroadcastStyle(::Type{<:Vec2}) = Vec2Style() Vec2Style(::Val{0}) = Vec2Style() Vec2Style(::Val{1}) = Vec2Style() Vec2Style(::Val{M}) where {M} = Broadcast.DefaultArrayStyle{M}() ``` Note: `Broadcast.BroadcastStyle` を継承した型(ブロードキャストスタイル)を作って、それと多次元配列とのブロードキャスト時の演算結果に対応するスタイルを定義っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia Base.similar(bc::Broadcast.Broadcasted{Vec2Style}, ::Type{T}) where {T} = Vec2(zero(T), zero(T)) ``` Note: 定義したブロードキャストスタイルに対応する出力先の型をこのように定義するっ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> vec2 .+ vec2 2-element Vec2{Float64}: 2.0 4.0 julia> vec2 .+ [3, 4] 2-element Vec2{Float64}: 4.0 6.0 julia> 2 .* vec2 2-element Vec2{Float64}: 2.0 4.0 ``` Note: するとブロードキャストの演算結果がユーザ定義型になるっ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> [1 2;3 4] .+ vec2 2×2 Array{Float64,2}: 2.0 3.0 5.0 6.0 ``` Note: 2次元(以上)の配列とのブロードキャストは2次元(以上)の配列になりますっ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ### Point + `AbstractArray` から派生した型を定義するとそのまま ブロードキャスト 対応! + `BroadcastStyle` および `Base.similar()` を定義すると演算結果の型などもカスタマイズできる! Note: っ! --- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ## 事例2:配列じゃない型 Note: あと mutable でもない型っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia struct FibRange{R<:AbstractRange{<:Integer}} range::R end ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia Base.IteratorEltype(::Type{<:FibRange}) = Base.HasEltype() Base.eltype(::Type{<:FibRange}) = BigInt Base.IteratorSize(::Type{<:FibRange}) = Base.HasShape{1}() Base.length(fr::FibRange) = length(fr.range) Base.size(fr::FibRange) = size(fr.range) ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia function Base.iterate(fr::FibRange{<:UnitRange}) index = fr.range.start start = Fib[index] prev = Fib[index - 1] len = length(fr) iterate(fr, (start, prev, len)) end function Base.iterate(fr::FibRange{<:UnitRange}, (current, prev, len)::Tuple{BigInt, BigInt, Int}) len <= 0 && return nothing (current, (current + prev, current, len - 1)) end ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> collect(FibRange(1:10)) 10-element Array{BigInt,1}: 1 1 2 3 5 8 13 21 34 55 ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> FibRange(1:10) .+ FibRange(2:11) # => BigInt[2, 3, 5, 8, 13, 21, 34, 55, 89, 144] julia> FibRange(1:10) .+ (1:10) # => BigInt[2, 3, 5, 7, 10, 14, 20, 29, 43, 65] julia> 2 .* FibRange(1:10) # => BigInt[2, 2, 4, 6, 10, 16, 26, 42, 68, 110] ``` Note: っ! ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ### Point + `AbstractArray` から派生させなくても、[Iteration プロトコル](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-iteration-1) を実装すればそのまま ブロードキャスト 対応! + ↑ `collect(〜)` の結果を利用する仕組みのため。 Note: 簡単ですねっ! --- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ## 事例3:関数の方を拡張 Note: ちょっと込み入った例っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ### やりたいこと ```julia julia> 1 .|> fizz .|> buzz == 1 julia> 3 .|> fizz .|> buzz == "Fizz" julia> 5 .|> fizz .|> buzz == "Buzz" julia> 15 .|> fizz .|> buzz == "FizzBuzz" julia> 1:15 .|> fizz .|> buzz # => [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, # "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"] ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia fizz(val::Int) = val % 3 == 0 ? "Fizz" : val fizz(val) = val buzz(val::Int) = val % 5 == 0 ? "Buzz" : val buzz(val) = val ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia struct WrappedFizzBuzzFn0d{F} fn::F val::Int end (fn::WrappedFizzBuzzFn0d)(val::Int) = fn.fn(val) (fn::WrappedFizzBuzzFn0d)(val) = _combine(val, fn.fn(fn.val)) _combine(n::Int, ::Int) = n _combine(val::String, ::Int) = val _combine(::Int, val::String) = val _combine(val1::String, val2::String) = val1 * val2 ``` <!-- .element: style="font-size:45%" --> Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia struct FizzBuzzStyle{N} <: Broadcast.AbstractArrayStyle{N} end const _FizzBuzzFn = Union{typeof(fizz), typeof(buzz)} const FizzBuzzFn = Union{_FizzBuzzFn, WrappedFizzBuzzFn0d{<:_FizzBuzzFn}} Broadcast.broadcasted(fn::FizzBuzzFn, n::Int) = Broadcast.Broadcasted{FizzBuzzStyle{0}}(WrappedFizzBuzzFn0d(fn, n), (n,)) Broadcast.broadcasted(fn::FizzBuzzFn, bc::Broadcast.Broadcasted{FizzBuzzStyle{0}}) = Broadcast.Broadcasted{FizzBuzzStyle{0}}(WrappedFizzBuzzFn0d(fn, bc.f.val), (bc,)) Broadcast.broadcasted(::typeof(|>), val, fn::FizzBuzzFn) = Broadcast.broadcasted(fn, val) ``` <!-- .element: style="font-size:40%" --> Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia struct WrappedFizzBuzzFnNd{N} fn::FizzBuzzFn val::AbstractArray{Int, N} end Base.getindex(fn::WrappedFizzBuzzFnNd, idx) = WrappedFizzBuzzFn0d(fn.fn, fn.val[idx]) Broadcast.broadcasted(fn::FizzBuzzFn, val::AbstractArray{Int, N}) where {N} = Broadcast.Broadcasted{FizzBuzzStyle{N}}(WrappedFizzBuzzFnNd{N}(fn, val), (val,)) Broadcast.broadcasted(fn::FizzBuzzFn, bc::Broadcast.Broadcasted{FizzBuzzStyle{N}}) where {N} = Broadcast.Broadcasted{FizzBuzzStyle{N}}(WrappedFizzBuzzFnNd{N}(fn, bc.f.val), (bc,)) Broadcast.broadcasted(fn::FizzBuzzFn, bc::Broadcast.Broadcasted{<:Broadcast.AbstractArrayStyle{N}}) where {N} = Broadcast.Broadcasted{FizzBuzzStyle{N}}(WrappedFizzBuzzFnNd{N}(fn, copy(bc)), (bc,)) Broadcast.broadcasted(fn::FizzBuzzFn, v::Broadcast.Extruded{<:AbstractArray{T, N}}) where {T, N} = Broadcast.Broadcasted{FizzBuzzStyle{N}}(WrappedFizzBuzzFnNd{N}(fn, v.x), (v.x,)) Base.similar(bc::Broadcast.Broadcasted{FizzBuzzStyle{N}}, ::Type{ElType}) where {N,ElType} = similar(Array{ElType}, axes(bc)) Base.@propagate_inbounds function Broadcast._broadcast_getindex(bc::Broadcast.Broadcasted{FizzBuzzStyle{0},<:Any,<:Any,<:Any}, I) args = Broadcast._getindex(bc.args, I) return Broadcast._broadcast_getindex_evalf(bc.f, args...) end Base.@propagate_inbounds function Broadcast._broadcast_getindex(bc::Broadcast.Broadcasted{FizzBuzzStyle{N},<:Any,<:Any,<:Any}, I) where {N} args = Broadcast._getindex(bc.args, I) return Broadcast._broadcast_getindex_evalf(bc.f[I], args...) end (::Type{FizzBuzzStyle{N}})(::Val{M}) where {N, M} = Broadcast.DefaultArrayStyle{M}() ``` <!-- .element: style="font-size:35%" --> Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ```julia julia> 1:15 .|> fizz .|> buzz .|> println; 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz ``` Note: っ ---- <!-- .slide: data-background-color="rgba(96,173,81,0.3)" --> ### Point + ブロードキャストの仕組みを悪用するとこんなこともできますっ! + よい子は真似しないでね♪ Note: 少しだけ真面目な話をすると、ブロードキャストの仕組み上、内部に「状態」を持つことが(がんばれば)出来るので、それを利用したものっ --- <!-- .slide: data-background-color="rgba(170,121,193,0.3)" --> # まとめ ---- <!-- .slide: data-background-color="rgba(170,121,193,0.3)" --> + Broadcasting (Dot Syntax) 便利! + 使いこなせるともっと楽しくなる! + Julia 楽しい! Note: っ --- <!-- .slide: data-background-color="rgba(170,121,193,0.3)" --> # リンク ---- <!-- .slide: data-background-color="rgba(170,121,193,0.3)" --> ## 実験Note + [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/antimon2/BroadCastingSample.jl/master?urlpath=tree%2Fexamples) + [Vec2Sample.jl.ipynb](https://github.com/antimon2/BroadCastingSample.jl/blob/master/examples/Vec2Sample.jl.ipynb) ([nbviewer](https://nbviewer.jupyter.org/github/antimon2/BroadCastingSample.jl/blob/master/examples/Vec2Sample.jl.ipynb)) + [FibRange.jl.ipynb](https://github.com/antimon2/BroadCastingSample.jl/blob/master/examples/FibRange.jl.ipynb) ([nbviewer](https://nbviewer.jupyter.org/github/antimon2/BroadCastingSample.jl/blob/master/examples/FibRange.jl.ipynb)) + [FizzBuzzSample.jl.ipynb](https://github.com/antimon2/BroadCastingSample.jl/blob/master/examples/FizzBuzzSample.jl.ipynb) ([nbviewer](https://nbviewer.jupyter.org/github/antimon2/BroadCastingSample.jl/blob/master/examples/FizzBuzzSample.jl.ipynb)) ---- <!-- .slide: data-background-color="rgba(170,121,193,0.3)" --> ## 参考リンク + [Julia Documentation](https://docs.julialang.org/en/v1/) + [Dot Syntax for Vectorizing Functions - Functions - Manual](https://docs.julialang.org/en/v1/manual/functions/#man-vectorized-1) + [Broadcasting - Multi-dimensional Arrays - Manual](https://docs.julialang.org/en/v1/manual/arrays/#Broadcasting-1) + [Customizing broadcasting - Interfaces - Manual](https://docs.julialang.org/en/v1/manual/interfaces/#man-interfaces-broadcasting-1) + [Broadcast and vectorization - Arrays - Base](https://docs.julialang.org/en/v1/base/arrays/#Broadcast-and-vectorization-1) --- <!-- .slide: data-background-color="rgba(170,121,193,0.3)" --> # おまけ ---- <!-- .slide: data-background-color="rgba(204,102,51,0.3)" --> ## 機械学習名古屋 ---- <!-- .slide: data-background-color="rgba(204,102,51,0.3)" --> [![機械学習名古屋 第25回勉強会 Watson Studio Auto AI ハンズオン(オンライン) - connpass](https://i.imgur.com/cQ4PS7r.png) https://machine-learning.connpass.com/event/183476/](https://machine-learning.connpass.com/event/183476/) Note: 今月末開催!(再) --- <!-- .slide: data-background-color="rgba(170,121,193,0.3)" --> ご清聴ありがとうございます。 Note: ご清聴ありがとうございますっ!
{"metaMigratedAt":"2023-06-15T11:30:11.774Z","metaMigratedFrom":"YAML","title":"Broadcasting 入門","breaks":true,"slideOptions":"{\"transition\":\"slide\",\"theme\":\"league\"}","contributors":"[{\"id\":\"80062a4b-8dad-49ac-95bf-848ce0686e9e\",\"add\":17492,\"del\":16530}]"}
    1488 views