<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Yueh-Hua Tu</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://yuehhua.github.io/blog/</id>
  <link href="https://yuehhua.github.io/blog/" rel="alternate"/>
  <link href="https://yuehhua.github.io/blog/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Yueh-Hua Tu</rights>
  <subtitle>Love Math, Science, Biology, Computer science</subtitle>
  <title>Dream Maker</title>
  <updated>2021-11-17T01:55:02.247Z</updated>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>一般設定 random seed 的方式則像以下的程式碼：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">using</span> Random</span><br><span class="line">Random.seed!(<span class="number">0</span>)</span><br></pre></td></tr></table></figure><p>所以我們可以得出一個隨機矩陣看起來像是這樣。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; rand(<span class="number">5</span>, <span class="number">5</span>)</span><br><span class="line"><span class="number">5</span>×<span class="number">5</span> <span class="built_in">Matrix</span>&#123;<span class="built_in">Float64</span>&#125;:</span><br><span class="line"> <span class="number">0.823648</span>  <span class="number">0.203477</span>   <span class="number">0.585812</span>  <span class="number">0.655448</span>  <span class="number">0.469304</span></span><br><span class="line"> <span class="number">0.910357</span>  <span class="number">0.0423017</span>  <span class="number">0.539289</span>  <span class="number">0.575887</span>  <span class="number">0.0623676</span></span><br><span class="line"> <span class="number">0.164566</span>  <span class="number">0.0682693</span>  <span class="number">0.260036</span>  <span class="number">0.868279</span>  <span class="number">0.353129</span></span><br><span class="line"> <span class="number">0.177329</span>  <span class="number">0.361828</span>   <span class="number">0.910047</span>  <span class="number">0.9678</span>    <span class="number">0.767602</span></span><br><span class="line"> <span class="number">0.27888</span>   <span class="number">0.973216</span>   <span class="number">0.167036</span>  <span class="number">0.76769</span>   <span class="number">0.043141</span></span><br></pre></td></tr></table></figure><p>如果我們要對每個執行緒都設定同樣的 random seed，那就可以在每個執行緒內直接設定即可。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Threads.<span class="meta">@threads</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>:<span class="number">5</span></span><br><span class="line">    Random.seed!(<span class="number">0</span>)</span><br><span class="line">    tid = Threads.threadid()</span><br><span class="line">    println(tid, <span class="string">&quot;: &quot;</span>, rand(<span class="number">5</span>, <span class="number">5</span>))</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>所以每個執行緒內印出來的矩陣就會像這樣。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">5: [0.8236475079774124 0.20347655804192266 0.5858115517433242 0.6554484126999125 0.46930370935301835; 0.9103565379264364 0.042301665932029664 0.5392892841426182 0.5758873948500367 0.06236755817015882; 0.16456579813368521 0.06826925550564478 0.26003585026904785 0.8682787096942046 0.35312877270491705; 0.17732884646626457 0.3618283907762174 0.910046541351011 0.9677995536192001 0.767601895961374; 0.278880109331201 0.9732164043865108 0.16703619444214968 0.7676903325581188 0.043141023329413164]</span><br><span class="line">2: [0.8236475079774124 0.20347655804192266 0.5858115517433242 0.6554484126999125 0.46930370935301835; 0.9103565379264364 0.042301665932029664 0.5392892841426182 0.5758873948500367 0.06236755817015882; 0.16456579813368521 0.06826925550564478 0.26003585026904785 0.8682787096942046 0.35312877270491705; 0.17732884646626457 0.3618283907762174 0.910046541351011 0.9677995536192001 0.767601895961374; 0.278880109331201 0.9732164043865108 0.16703619444214968 0.7676903325581188 0.043141023329413164]</span><br><span class="line">4: [0.8236475079774124 0.20347655804192266 0.5858115517433242 0.6554484126999125 0.46930370935301835; 0.9103565379264364 0.042301665932029664 0.5392892841426182 0.5758873948500367 0.06236755817015882; 0.16456579813368521 0.06826925550564478 0.26003585026904785 0.8682787096942046 0.35312877270491705; 0.17732884646626457 0.3618283907762174 0.910046541351011 0.9677995536192001 0.767601895961374; 0.278880109331201 0.9732164043865108 0.16703619444214968 0.7676903325581188 0.043141023329413164]</span><br><span class="line">3: [0.8236475079774124 0.20347655804192266 0.5858115517433242 0.6554484126999125 0.46930370935301835; 0.9103565379264364 0.042301665932029664 0.5392892841426182 0.5758873948500367 0.06236755817015882; 0.16456579813368521 0.06826925550564478 0.26003585026904785 0.8682787096942046 0.35312877270491705; 0.17732884646626457 0.3618283907762174 0.910046541351011 0.9677995536192001 0.767601895961374; 0.278880109331201 0.9732164043865108 0.16703619444214968 0.7676903325581188 0.043141023329413164]</span><br><span class="line">1: [0.8236475079774124 0.20347655804192266 0.5858115517433242 0.6554484126999125 0.46930370935301835; 0.9103565379264364 0.042301665932029664 0.5392892841426182 0.5758873948500367 0.06236755817015882; 0.16456579813368521 0.06826925550564478 0.26003585026904785 0.8682787096942046 0.35312877270491705; 0.17732884646626457 0.3618283907762174 0.910046541351011 0.9677995536192001 0.767601895961374; 0.278880109331201 0.9732164043865108 0.16703619444214968 0.7676903325581188 0.043141023329413164]</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/11/17/fix-random-numbers-in-threads/</id>
    <link href="https://yuehhua.github.io/blog/2021/11/17/fix-random-numbers-in-threads/"/>
    <published>2021-11-17T01:50:30.000Z</published>
    <summary>
      <![CDATA[<p>一般設定 random seed 的方式則像以下的程式碼：</p>
<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span]]>
    </summary>
    <title>要如何固定 Julia 執行緒中的亂數？</title>
    <updated>2021-11-17T01:55:02.247Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>一般我們會在函式的引數上加上參數，這樣可以讓函式去推論引數的型別，這樣有多種用途，其中之一當然是增進效能。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; foo(a::T) <span class="keyword">where</span> &#123;T&#125; = zero(T)</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br><span class="line"></span><br><span class="line">julia&gt; foo(<span class="number">5</span>)</span><br><span class="line"><span class="number">0</span></span><br></pre></td></tr></table></figure><p>那我們有沒有辦法對回傳值的型別做參數化呢？</p><p>有的，可以這樣做。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; (foo(a::T)::T) <span class="keyword">where</span> &#123;T&#125; = zero(T)</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br><span class="line"></span><br><span class="line">julia&gt; foo(<span class="number">5</span>)</span><br><span class="line"><span class="number">0</span></span><br></pre></td></tr></table></figure><p>一般要標記回傳值的型別，要寫在整個 function signature 的後面，也就是</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">foo(a)::<span class="built_in">Int</span></span><br></pre></td></tr></table></figure><p>如果要將他標記為參數，那就需要寫成</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(foo(a)::T) <span class="keyword">where</span> &#123;T&#125;</span><br></pre></td></tr></table></figure><p>這樣就寫出來啦！！</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/10/14/parametric-return-type/</id>
    <link href="https://yuehhua.github.io/blog/2021/10/14/parametric-return-type/"/>
    <published>2021-10-14T01:30:50.000Z</published>
    <summary>
      <![CDATA[<p>一般我們會在函式的引數上加上參數，這樣可以讓函式去推論引數的型別，這樣有多種用途，其中之一當然是增進效能。</p>
<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class=]]>
    </summary>
    <title>參數化回傳值</title>
    <updated>2021-10-14T01:46:28.843Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>有鑑於 Debugger.jl 的說明文件有點難懂，就自己來寫一篇教學。</p><p>Debugger.jl 是在 Julia 上，由官方開發及維護的除錯器（debugger），debugger 如同其他語言的 debugger 一樣，可以預先設定斷點（breakpoint）、在丟出例外（exception）時停下來、逐行執行及檢查變數等等功能。這篇文章會示範最基礎的 debugger 的用法。</p><span id="more"></span><h2 id="安裝-Debugger">安裝 Debugger</h2><p>安裝 Julia 套件都是差不多的方式，切換到套件模式，並且 <code>add PACKAGE</code>。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">]add Debugger</span><br></pre></td></tr></table></figure><p>等他跑好就把 <code>Debugger</code> 安裝好了。</p><h2 id="在-REPL-執行-Debugger">在 REPL 執行 Debugger</h2><p>基本上，<code>Debugger</code> 是一種直譯器，所以比較好的執行環境是在 REPL 中。</p><p>當然在 VS code 也有內建，但是我個人嘗試過，他跑得蠻慢的，不知道為什麼。= =&quot;</p><p>所以以下的示範都是在 REPL 上。</p><h2 id="逐行執行">逐行執行</h2><p>為了示範，所以就先定義兩個函式。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">using</span> Debugger</span><br><span class="line"></span><br><span class="line">julia&gt; <span class="keyword">function</span> foo(x, y)</span><br><span class="line">           z = x + <span class="number">2</span></span><br><span class="line">           y = y*(y + z)</span><br><span class="line">           <span class="keyword">return</span> y</span><br><span class="line">       <span class="keyword">end</span></span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br><span class="line"></span><br><span class="line">julia&gt; bar(x) = foo(x, <span class="number">5</span>)</span><br><span class="line">bar (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br></pre></td></tr></table></figure><h3 id="逐步執行">逐步執行</h3><p>Debugger 都會有個進入點，進入點需要在前面標記 <code>@enter</code>，後面可以接著一個表示式。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="meta">@enter</span> bar(<span class="number">3</span>)</span><br><span class="line">In bar(x) at REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line">&gt;<span class="number">1</span>  bar(x) = foo(x, <span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">About to run: (foo)(<span class="number">3</span>, <span class="number">5</span>)</span><br><span class="line"><span class="number">1</span>|debug&gt; s</span><br><span class="line">In foo(x, y) at REPL[<span class="number">1</span>]:<span class="number">1</span></span><br><span class="line"> <span class="number">1</span>  <span class="keyword">function</span> foo(x, y)</span><br><span class="line">&gt;<span class="number">2</span>      z = x + <span class="number">2</span></span><br><span class="line"> <span class="number">3</span>      y = y*(y + z)</span><br><span class="line"> <span class="number">4</span>      <span class="keyword">return</span> y</span><br><span class="line"> <span class="number">5</span>  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">About to run: _J3</span><br><span class="line"><span class="number">1</span>|debug&gt; s</span><br><span class="line">In +(x, y) at int.jl:<span class="number">87</span></span><br><span class="line">&gt;<span class="number">87</span>  (+)(x::T, y::T) <span class="keyword">where</span> &#123;T&lt;:BitInteger&#125; = add_int(x, y)</span><br><span class="line"></span><br><span class="line">About to run: (Core.Intrinsics.add_int)(<span class="number">3</span>, <span class="number">2</span>)</span><br></pre></td></tr></table></figure><p>以上進入了 <code>bar(3)</code> 這個函式呼叫。剛進入的時候，他會停在函式呼叫的第一步：<code>(foo)(3, 5)</code>。</p><p>接著，他會進入除錯（debug）模式，在這個模式下，就可以藉由指令來操作這個 debugger。</p><p>如果輸入 <code>s</code>，他會逐步執行程式碼，所以可以看到他進入到 <code>foo</code> 函式中，並且指標指到第二行的 <code>z = x + 2</code>。</p><p>如果再輸入一次 <code>s</code>，讓他執行下一步，這時候加法就會被執行，所以就會進到 <code>(Core.Intrinsics.add_int)(3, 2)</code> 的執行。</p><h3 id="逐行執行-2">逐行執行</h3><p>如果我們希望他可以逐行執行，可以用 <code>n</code>。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="meta">@enter</span> bar(<span class="number">3</span>)</span><br><span class="line">In bar(x) at REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line">&gt;<span class="number">1</span>  bar(x) = foo(x, <span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">About to run: (foo)(<span class="number">3</span>, <span class="number">5</span>)</span><br><span class="line"><span class="number">1</span>|debug&gt; n</span><br><span class="line">In bar(x) at REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line">&gt;<span class="number">1</span>  bar(x) = foo(x, <span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">About to run: <span class="keyword">return</span> %J1</span><br><span class="line"><span class="number">1</span>|debug&gt; n</span><br><span class="line"><span class="number">50</span></span><br></pre></td></tr></table></figure><p>如果輸入 <code>n</code> 之後，debugger 會直接計算該行的計算結果，<code>foo(x, 5)</code> 就會被執行，並回傳 <code>50</code>。</p><h2 id="執行到丟出例外">執行到丟出例外</h2><p>比較實用的是讓他執行直到一個例外被拋出。這時我們需要修改一下函式：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> foo(x, y)</span><br><span class="line">    z = x + <span class="number">2</span></span><br><span class="line">    throw(<span class="built_in">ErrorException</span>(<span class="string">&quot;This is an error.&quot;</span>))</span><br><span class="line">    y = y*(y + z)</span><br><span class="line">    <span class="keyword">return</span> y</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>在第二行中插入一條拋出 <code>ErrorException</code> 例外的表示式。</p><p>要執行到直到丟出例外，並且停下，有幾種方法。</p><h3 id="在除錯模式，例外前插入斷點法">在除錯模式，例外前插入斷點法</h3><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="meta">@enter</span> bar(<span class="number">3</span>)</span><br><span class="line">In bar(x) at REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line">&gt;<span class="number">1</span>  bar(x) = foo(x, <span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">About to run: (foo)(<span class="number">3</span>, <span class="number">5</span>)</span><br><span class="line"><span class="number">1</span>|debug&gt; bp on throw</span><br><span class="line">Breaking on throw</span><br><span class="line"><span class="number">1</span>|debug&gt; c</span><br><span class="line">Breaking <span class="keyword">for</span> error:</span><br><span class="line">ERROR: This is an error.</span><br><span class="line">Stacktrace:</span><br><span class="line"> [<span class="number">1</span>] foo(x::<span class="built_in">Int64</span>, y::<span class="built_in">Int64</span>)</span><br><span class="line">   @ Main REPL[<span class="number">10</span>]:<span class="number">3</span></span><br><span class="line"> [<span class="number">2</span>] bar(x::<span class="built_in">Int64</span>)</span><br><span class="line">   @ Main REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line"></span><br><span class="line">In foo(x, y) at REPL[<span class="number">10</span>]:<span class="number">1</span></span><br><span class="line"> <span class="number">1</span>  <span class="keyword">function</span> foo(x, y)</span><br><span class="line"> <span class="number">2</span>      z = x + <span class="number">2</span></span><br><span class="line">&gt;<span class="number">3</span>      throw(<span class="built_in">ErrorException</span>(<span class="string">&quot;This is an error.&quot;</span>))</span><br><span class="line"> <span class="number">4</span>      y = y*(y + z)</span><br><span class="line"> <span class="number">5</span>      <span class="keyword">return</span> y</span><br><span class="line"> <span class="number">6</span>  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">About to run: (throw)(<span class="built_in">ErrorException</span>(<span class="string">&quot;This is an error.&quot;</span>))</span><br></pre></td></tr></table></figure><p>一樣是利用 <code>@enter</code> 來製造進入點，接著利用 <code>bp on throw</code> 來設定斷點，他的意思是在拋出例外時設定斷點。</p><p>相對，這個斷點是可以關閉的，用 <code>bp off throw</code>。</p><p>接著，可以輸入 <code>c</code> 讓程式持續執行，最後他就會停在斷點處。</p><h3 id="在-REPL-模式，例外前插入斷點法">在 REPL 模式，例外前插入斷點法</h3><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; break_on(:error)</span><br><span class="line"></span><br><span class="line">julia&gt; <span class="meta">@run</span> bar(<span class="number">3</span>)</span><br><span class="line">Breaking <span class="keyword">for</span> error:</span><br><span class="line">ERROR: This is an error.</span><br><span class="line">Stacktrace:</span><br><span class="line"> [<span class="number">1</span>] foo(x::<span class="built_in">Int64</span>, y::<span class="built_in">Int64</span>)</span><br><span class="line">   @ Main REPL[<span class="number">10</span>]:<span class="number">3</span></span><br><span class="line"> [<span class="number">2</span>] bar(x::<span class="built_in">Int64</span>)</span><br><span class="line">   @ Main REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line"></span><br><span class="line">In foo(x, y) at REPL[<span class="number">10</span>]:<span class="number">1</span></span><br><span class="line"> <span class="number">1</span>  <span class="keyword">function</span> foo(x, y)</span><br><span class="line"> <span class="number">2</span>      z = x + <span class="number">2</span></span><br><span class="line">&gt;<span class="number">3</span>      throw(<span class="built_in">ErrorException</span>(<span class="string">&quot;This is an error.&quot;</span>))</span><br><span class="line"> <span class="number">4</span>      y = y*(y + z)</span><br><span class="line"> <span class="number">5</span>      <span class="keyword">return</span> y</span><br><span class="line"> <span class="number">6</span>      <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">About to run: (throw)(<span class="built_in">ErrorException</span>(<span class="string">&quot;This is an error.&quot;</span>))</span><br></pre></td></tr></table></figure><p>跟前面的想法差不多，只是這次是在 REPL 下操作。</p><p>這次就不用急著進入除錯模式，可以直接在 REPL 下設定在拋出例外前的斷點，可以用 <code>break_on(:error)</code>。</p><p><code>@run</code> 這個 macro 就等同於 <code>@enter</code> + <code>c</code>，所以他會執行直到斷點發生。</p><h2 id="查看變數的值">查看變數的值</h2><p>我們停在斷點之後可以做什麼事情呢？除錯就是要在執行環境中去檢查執行時期的變數是不是符合預期。</p><p>這時候我們可以把 backtrace 給列出來。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>|debug&gt; bt</span><br><span class="line">[<span class="number">1</span>] foo(x, y) at REPL[<span class="number">10</span>]:<span class="number">3</span></span><br><span class="line">  | x::<span class="built_in">Int64</span> = <span class="number">3</span></span><br><span class="line">  | y::<span class="built_in">Int64</span> = <span class="number">5</span></span><br><span class="line">  | z::<span class="built_in">Int64</span> = <span class="number">5</span></span><br><span class="line">[<span class="number">2</span>] bar(x) at REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line">  | x::<span class="built_in">Int64</span> = <span class="number">3</span></span><br></pre></td></tr></table></figure><p>輸入 <code>bt</code> 可以列出停在目前的斷點，在 <code>foo</code> 及 <code>bar</code> 函式中存有的區域變數以及他的值有哪些。</p><p>我們可以發現我們首先呼叫 <code>bar</code>，<code>bar</code> 會去呼叫 <code>foo</code>。我們知道函式呼叫會在堆疊（stack）中，推入一個新的呼叫框（frame），呼叫框中包含著函式呼叫的引數（arguments）、區域變數等等資訊。</p><p><code>foo</code> 的呼叫會在整個堆疊的最上面，也就是第一個 frame，所以看到他標示 <code>[1]</code>，而 <code>bar</code> 的呼叫就是位於第二個 frame。</p><h3 id="叫出指定-frame-中的變數">叫出指定 frame 中的變數</h3><p>我們可以叫出指定的 frame 的區域變數，只要在除錯模式中輸入 <code>fr [i::Int]</code>，<code>i</code> 則是指定第幾個 frame。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>|debug&gt; fr <span class="number">1</span></span><br><span class="line">[<span class="number">1</span>] foo(x, y) at REPL[<span class="number">10</span>]:<span class="number">1</span></span><br><span class="line">  | x::<span class="built_in">Int64</span> = <span class="number">3</span></span><br><span class="line">  | y::<span class="built_in">Int64</span> = <span class="number">5</span></span><br><span class="line">  | z::<span class="built_in">Int64</span> = <span class="number">5</span></span><br></pre></td></tr></table></figure><p>我們就可以看到在這個階段第一個 frame 的 <code>x</code>、<code>y</code> 跟 <code>z</code> 變數的值各是多少。</p><p>我們可以再試試看第二個 frame 的內容。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>|debug&gt; fr <span class="number">2</span></span><br><span class="line">[<span class="number">2</span>] bar(x) at REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line">  | x::<span class="built_in">Int64</span> = <span class="number">3</span></span><br></pre></td></tr></table></figure><h3 id="切換目前的-frame">切換目前的 frame</h3><p>剛進入斷點的話，我們都會是位於第一個 frame 中。有時候我們會想要知道在其他 frame 的狀況，這時候我們就需要切換 frame 的位置。</p><p>這時候只要輸入 <code>f [i::Int]</code> 就可以切換不同的 frame，例如，想要切換到第二個 frame 就可以輸入 <code>f 2</code>。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>|debug&gt; f <span class="number">2</span></span><br><span class="line">In bar(x) at REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line">&gt;<span class="number">1</span>  bar(x) = foo(x, <span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">About to run: (foo)(<span class="number">3</span>, <span class="number">5</span>)</span><br><span class="line"><span class="number">2</span>|debug&gt; </span><br></pre></td></tr></table></figure><p>還可以發現在除錯模式的 prompt <code>2|debug&gt;</code>，最開頭的數字改變了，一開始是 <code>1</code>，後來變成 <code>2</code>。</p><p>這就表示目前所在第幾個 frame。</p><h3 id="切換成-Julia-REPL-模式">切換成 Julia REPL 模式</h3><p>在除錯模式輸入 `（鍵盤左上），就可以切換到 Julia REPL 模式，並且存取變數。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>|debug&gt; fr <span class="number">2</span></span><br><span class="line">[<span class="number">2</span>] bar(x) at REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line">  | x::<span class="built_in">Int64</span> = <span class="number">3</span></span><br><span class="line"><span class="number">1</span>|debug&gt; f <span class="number">2</span></span><br><span class="line">In bar(x) at REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line">&gt;<span class="number">1</span>  bar(x) = foo(x, <span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">About to run: (foo)(<span class="number">3</span>, <span class="number">5</span>)</span><br><span class="line"><span class="number">2</span>|julia&gt; x</span><br><span class="line"><span class="number">3</span></span><br></pre></td></tr></table></figure><p>切換之後，你會看到 <code>2|debug&gt;</code> 切換成 <code>2|julia</code>，並且可以直接存取該變數 <code>x</code>。如果要切換回除錯模式，只要按 backspace 鍵，把 ` 刪除即可。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2</span>|julia&gt; x</span><br><span class="line"><span class="number">3</span></span><br></pre></td></tr></table></figure><p>也可以對該變數做運算。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2</span>|julia&gt; x + <span class="number">2</span></span><br><span class="line"><span class="number">5</span></span><br></pre></td></tr></table></figure><p>但是沒辦法存新的變數。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2</span>|julia&gt; y = x + <span class="number">2</span></span><br><span class="line"><span class="number">5</span></span><br><span class="line"></span><br><span class="line"><span class="number">2</span>|julia&gt; y</span><br><span class="line">ERROR: <span class="built_in">UndefVarError</span>: y not defined</span><br><span class="line">Stacktrace:</span><br><span class="line"> [<span class="number">1</span>] top-level scope</span><br><span class="line">   @ none:<span class="number">1</span></span><br></pre></td></tr></table></figure><h2 id="結論">結論</h2><p>我們有了這些工具跟方法，可以讓我們在不同的 frame 之間做跳躍，去看在上層或是下層的 frame 中變數的數值各是多少。</p><p>同時，也可以測試你自己寫的函式是否正常執行。</p><p>我們就可以用這些方法來除錯程式碼。</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/05/25/how-to-use-julia-debugger/</id>
    <link href="https://yuehhua.github.io/blog/2021/05/25/how-to-use-julia-debugger/"/>
    <published>2021-05-25T08:27:28.000Z</published>
    <summary>
      <![CDATA[<p>有鑑於 Debugger.jl 的說明文件有點難懂，就自己來寫一篇教學。</p>
<p>Debugger.jl 是在 Julia 上，由官方開發及維護的除錯器（debugger），debugger 如同其他語言的 debugger 一樣，可以預先設定斷點（breakpoint）、在丟出例外（exception）時停下來、逐行執行及檢查變數等等功能。這篇文章會示範最基礎的 debugger 的用法。</p>]]>
    </summary>
    <title>要怎麼用 Julia debugger？</title>
    <updated>2021-05-25T08:27:27.785Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>基本上，我們知道 Julia 的命名空間的概念不是很強，命名空間的概念是由模組（module）所建構的。</p><p>介紹模組前先要介紹幾個比較基本的語法：<code>using</code>、<code>import</code> 跟 <code>include</code>。</p><span id="more"></span><h2 id="基本語法">基本語法</h2><h3 id="using">using</h3><p><code>using</code> 是用在一般要<strong>載入一個套件</strong>的時候用的。像是要使用標準函式庫（stdlib）中的 <code>LinearAlgebra</code> 的時候，會這樣做</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">using</span> LinearAlgebra</span><br></pre></td></tr></table></figure><p>如此一來，你就可以使用像是</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tr</span><br></pre></td></tr></table></figure><p>或是</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LinearAlgebra.tr</span><br></pre></td></tr></table></figure><p>然而，像是 <code>LinearAlgebra.tr</code> 這樣由 <code>[module].[function]</code> 構成的，則是去呼叫 <code>[module]</code> 底下的 <code>[function]</code>。像是 <code>tr</code> 則是由 <code>LinearAlgebra</code> 模組，藉由 <code>using LinearAlgebra</code> 語法，匯出（export）到我們載入的空間。</p><p>例如，</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; tr</span><br><span class="line">ERROR: <span class="built_in">UndefVarError</span>: tr not defined</span><br><span class="line"></span><br><span class="line">julia&gt; Main.tr</span><br><span class="line">ERROR: <span class="built_in">UndefVarError</span>: tr not defined</span><br><span class="line">Stacktrace:</span><br><span class="line"> [<span class="number">1</span>] top-level scope</span><br><span class="line">   @ REPL[<span class="number">2</span>]:<span class="number">1</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="keyword">using</span> LinearAlgebra</span><br><span class="line"></span><br><span class="line">julia&gt; tr</span><br><span class="line">tr (generic <span class="keyword">function</span> with <span class="number">7</span> methods)</span><br><span class="line"></span><br><span class="line">julia&gt; Main.tr</span><br><span class="line">tr (generic <span class="keyword">function</span> with <span class="number">7</span> methods)</span><br></pre></td></tr></table></figure><p>基本上，無論是由腳本（script）執行或是 REPL 執行，我們所在的是在 <code>Main</code> 這個模組下，可以用 <code>parentmodule(Base)</code> 測試。</p><h3 id="import">import</h3><p>如果要重複定義同名的函式，會被視為是要延伸（extend）該函式的定義，幫該函式新增更多的方法（method）。我們先來看看 <code>string</code> 這個函式。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; parentmodule(string)</span><br><span class="line">Base</span><br><span class="line"></span><br><span class="line">julia&gt; methods(string)</span><br><span class="line"><span class="comment"># 20 methods for generic function &quot;string&quot;:</span></span><br><span class="line">[<span class="number">1</span>] string() <span class="keyword">in</span> Base at strings/basic.jl:<span class="number">221</span></span><br><span class="line">[<span class="number">2</span>] string(x::T) <span class="keyword">where</span> T&lt;:<span class="built_in">Union</span>&#123;<span class="built_in">Float16</span>, <span class="built_in">Float32</span>, <span class="built_in">Float64</span>&#125; <span class="keyword">in</span> Base.Ryu at ryu/Ryu.jl:<span class="number">121</span></span><br><span class="line">[<span class="number">3</span>] string(f::Printf.Spec&#123;T&#125;; modifier) <span class="keyword">where</span> T <span class="keyword">in</span> Printf at /usr/share/julia/stdlib/v1<span class="number">.6</span>/Printf/src/Printf.jl:<span class="number">35</span></span><br><span class="line">[<span class="number">4</span>] string(u::Base.UUID) <span class="keyword">in</span> Base at uuid.jl:<span class="number">86</span></span><br><span class="line">[<span class="number">5</span>] string(a::<span class="built_in">Symbol</span>) <span class="keyword">in</span> Base at strings/io.jl:<span class="number">176</span></span><br><span class="line">[<span class="number">6</span>] string(a::<span class="built_in">String</span>) <span class="keyword">in</span> Base at strings/substring.jl:<span class="number">177</span></span><br><span class="line">[<span class="number">7</span>] string(t::Dates.Time) <span class="keyword">in</span> Dates at /usr/share/julia/stdlib/v1<span class="number">.6</span>/Dates/src/io.jl:<span class="number">44</span></span><br><span class="line">[<span class="number">8</span>] string(hash::Base.SHA1) <span class="keyword">in</span> Base at loading.jl:<span class="number">106</span></span><br><span class="line">[<span class="number">9</span>] string(b::<span class="built_in">Bool</span>) <span class="keyword">in</span> Base at intfuncs.jl:<span class="number">779</span></span><br><span class="line">[<span class="number">10</span>] string(a::<span class="built_in">SubString</span>&#123;<span class="built_in">String</span>&#125;) <span class="keyword">in</span> Base at strings/substring.jl:<span class="number">178</span></span><br><span class="line">[<span class="number">11</span>] string(a::<span class="built_in">Union</span>&#123;<span class="built_in">Char</span>, <span class="built_in">SubString</span>&#123;<span class="built_in">String</span>&#125;, <span class="built_in">String</span>&#125;...) <span class="keyword">in</span> Base at strings/substring.jl:<span class="number">208</span></span><br><span class="line">[<span class="number">12</span>] string(s::<span class="built_in">AbstractString</span>) <span class="keyword">in</span> Base at strings/basic.jl:<span class="number">222</span></span><br><span class="line">[<span class="number">13</span>] string(b::<span class="built_in">BigFloat</span>) <span class="keyword">in</span> Base.MPFR at mpfr.jl:<span class="number">999</span></span><br><span class="line">[<span class="number">14</span>] string(id::LibGit2.GitShortHash) <span class="keyword">in</span> LibGit2 at /usr/share/julia/stdlib/v1<span class="number">.6</span>/LibGit2/src/oid.jl:<span class="number">181</span></span><br><span class="line">[<span class="number">15</span>] string(f::Random.DSFMT.GF2X) <span class="keyword">in</span> Random.DSFMT at /usr/share/julia/stdlib/v1<span class="number">.6</span>/Random/src/DSFMT.jl:<span class="number">108</span></span><br><span class="line">[<span class="number">16</span>] string(x::Dates.CompoundPeriod) <span class="keyword">in</span> Dates at /usr/share/julia/stdlib/v1<span class="number">.6</span>/Dates/src/periods.jl:<span class="number">337</span></span><br><span class="line">[<span class="number">17</span>] string(n::<span class="built_in">BigInt</span>; base, pad) <span class="keyword">in</span> Base.GMP at gmp.jl:<span class="number">682</span></span><br><span class="line">[<span class="number">18</span>] string(n::<span class="built_in">Integer</span>; base, pad) <span class="keyword">in</span> Base at intfuncs.jl:<span class="number">760</span></span><br><span class="line">[<span class="number">19</span>] string(mode::Pkg.GitTools.GitMode) <span class="keyword">in</span> Pkg.GitTools at /usr/share/julia/stdlib/v1<span class="number">.6</span>/Pkg/src/GitTools.jl:<span class="number">171</span></span><br><span class="line">[<span class="number">20</span>] string(xs...) <span class="keyword">in</span> Base at strings/io.jl:<span class="number">174</span></span><br></pre></td></tr></table></figure><p>例如，想要延伸 <code>string</code> 這個函式的定義，我們先得從 <code>Base</code> 模組匯入所有關於 <code>string</code> 的方法，以便延伸方法。所以需要</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Base: string</span><br></pre></td></tr></table></figure><p>如此會把 <code>Base</code> 裡頭關於 <code>string</code> 的定義都匯出，如此一來，就可以定義新的方法。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">struct</span> Foo <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">julia&gt; string(::Foo) = <span class="string">&quot;foo&quot;</span></span><br><span class="line">string (generic <span class="keyword">function</span> with <span class="number">21</span> methods)</span><br><span class="line"></span><br><span class="line">julia&gt; string(Foo())</span><br><span class="line"><span class="string">&quot;foo&quot;</span></span><br></pre></td></tr></table></figure><h3 id="include">include</h3><p><code>include</code> 則是對於檔案的操作，它可以將其他檔案中的程式碼包含（include）進來。例如有個 a.jl 這個檔案，其內容有：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">println(<span class="string">&quot;a.jl file is included.&quot;</span>)</span><br><span class="line"></span><br><span class="line">foo(x) = x</span><br></pre></td></tr></table></figure><p>這時候可以在另一個檔案 main.jl 中寫：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">include(<span class="string">&quot;a.jl&quot;</span>)</span><br><span class="line"></span><br><span class="line">println(foo(<span class="number">5</span>))</span><br></pre></td></tr></table></figure><p>執行 main.jl 之後，會看到：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">a.jl file is included.</span><br><span class="line"><span class="number">5</span></span><br></pre></td></tr></table></figure><p>代表在包含 a.jl 檔案的過程中，裡頭的程式碼都會被執行過，所以會看到 <code>a.jl file is included.</code>，並且可以使用 <code>foo</code> 函式，則代表 <code>foo</code> 函式的定義一併被帶到 main.jl 當中。</p><p>這就是 <code>include</code> 的作用了。</p><h2 id="模組">模組</h2><p>一個模組是由以下的程式碼定義的</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> Foo</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> foo</span><br><span class="line"></span><br><span class="line">foo(x) = x</span><br><span class="line">foo(x::<span class="built_in">String</span>) = <span class="string">&quot;!!&quot;</span> * x * <span class="string">&quot;!!&quot;</span></span><br><span class="line">bar(x::<span class="built_in">String</span>) = <span class="string">&quot;bar: &quot;</span> * x</span><br><span class="line"></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>模組中可以定義型別或是函式等等程式碼，而模組中所定義的型別或是函式能不能自動地匯出，主要是由 <code>export</code> 語法指定。</p><p><code>export</code> 會匯出那些被指定的型別或是函式，會在有 <code>using Foo</code> 的作用域可以見到 <code>foo</code>，並且可以使用，但是沒有匯出的，像是 <code>bar</code> 就沒辦法直接使用，但是還是可以藉由 <code>Foo.bar</code> 來使用它。</p><h2 id="命名空間">命名空間</h2><p>從以上的例子，我們不難發現，<code>Foo</code> 模組形成了一個命名空間（namespace），這個命名空間所定義的變數、函式或是型別等等程式元素，都有自己的識別子（identifier），也就是命名是唯一的。然而，Julia 模組中的 <code>export</code> 會自動把該模組中的特定識別子匯出到 <code>Main</code> 這個命名空間中，所以可以在 <code>Main</code> 裡直接使用 <code>foo</code>，而沒有匯出的則需要使用 <code>Foo.bar</code> 來使用它。</p><p>在 Julia 是沒有硬性的命名空間的，命名空間則是由模組名稱所組成的，例如像先前介紹的 <code>LinearAlgebra</code> 就是由 <code>LinearAlgebra</code> 模組構成。</p><h2 id="套件">套件</h2><p>套件跟模組的概念是不一樣的。套件包含了一系列定義的型別或是函式，最重要的是，套件的資料夾中含有 Project.toml 來對套件進行管理。</p><p>而且模組是沒有辦法被 <code>using</code> 或是 <code>import</code> 的，要 <code>]add PACKAGE</code> 才行。</p><p>套件主要會有一個主模組，其中可以包含其他子模組，變得有點像資料夾結構的樣子。</p><p>一個套件要可以被其他套件加為相依套件的話，則需要該套件有 git 版本控制。</p><h3 id="例子">例子</h3><p>這邊我分別做了 <code>A</code> 跟 <code>B</code> 兩個套件，並且讓 <code>B</code> 有加 <code>A</code> 為其相依套件。</p><p>在 <code>A</code> 中有（src/A.jl）</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> A</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> foo</span><br><span class="line"></span><br><span class="line">foo(x) = x</span><br><span class="line">foo(x::<span class="built_in">String</span>) = <span class="string">&quot;!!&quot;</span> * x * <span class="string">&quot;!!&quot;</span></span><br><span class="line">bar(x::<span class="built_in">String</span>) = <span class="string">&quot;bar: &quot;</span> * x</span><br><span class="line"></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>在 <code>B</code> 中有（src/B.jl）</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> B</span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> A</span><br><span class="line"></span><br><span class="line">foo(::<span class="built_in">Number</span>) = <span class="number">5</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>後續的介紹裡會用到這邊的例子進行解說。</p><h3 id="匯入其他套件">匯入其他套件</h3><p>讓我們來假設幾種狀況，接下來會討論這些狀況，以及一些解決方法。</p><h3 id="子模組與命名空間">子模組與命名空間</h3><h4 id="using-A">using A</h4><p>如果按照以上的例子，在其他的檔案中 <code>using B</code> 的話，會有什麼呢？</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">using</span> B</span><br><span class="line"></span><br><span class="line">julia&gt; B</span><br><span class="line">B</span><br><span class="line"></span><br><span class="line">julia&gt; B.foo</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br><span class="line"></span><br><span class="line">julia&gt; methods(B.foo)</span><br><span class="line"><span class="comment"># 1 method for generic function &quot;foo&quot;:</span></span><br><span class="line">[<span class="number">1</span>] foo(::<span class="built_in">Number</span>) <span class="keyword">in</span> B at /media/yuehhua/Workbench/workspace/B/src/B.jl:<span class="number">7</span></span><br><span class="line"></span><br><span class="line">julia&gt; B.A</span><br><span class="line">A</span><br><span class="line"></span><br><span class="line">julia&gt; B.A.foo</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">2</span> methods)</span><br><span class="line"></span><br><span class="line">julia&gt; methods(B.A.foo)</span><br><span class="line"><span class="comment"># 2 methods for generic function &quot;foo&quot;:</span></span><br><span class="line">[<span class="number">1</span>] foo(x::<span class="built_in">String</span>) <span class="keyword">in</span> A at /home/yuehhua/.julia/packages/A/dbyNq/src/A.jl:<span class="number">6</span></span><br><span class="line">[<span class="number">2</span>] foo(x) <span class="keyword">in</span> A at /home/yuehhua/.julia/packages/A/dbyNq/src/A.jl:<span class="number">5</span></span><br><span class="line"></span><br><span class="line">julia&gt; B.A.bar</span><br><span class="line">bar (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br></pre></td></tr></table></figure><p>如此一來，<code>A</code> 套件就會變成 <code>B</code> 下的其中一個子模組，所以可以使用 <code>B.A</code> 來找到所有 <code>A</code> 底下的函式。也可以進一步發現，在 <code>B</code> 中定義的 <code>foo</code> 跟在 <code>A</code> 中定義的 <code>foo</code> 是分開來的。</p><h4 id="import-A-foo">import A: foo</h4><p>那如果我們把 <code>B</code> 套件中的 <code>using A</code> 改成 <code>import A: foo</code> 會發生什麼事情呢？</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">using</span> B</span><br><span class="line"></span><br><span class="line">julia&gt; B</span><br><span class="line">B</span><br><span class="line"></span><br><span class="line">julia&gt; B.A</span><br><span class="line">ERROR: <span class="built_in">UndefVarError</span>: A not defined</span><br><span class="line">Stacktrace:</span><br><span class="line"> [<span class="number">1</span>] top-level scope</span><br><span class="line">   @ REPL[<span class="number">3</span>]:<span class="number">1</span></span><br><span class="line"></span><br><span class="line">julia&gt; B.foo</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">3</span> methods)</span><br><span class="line"></span><br><span class="line">julia&gt; methods(B.foo)</span><br><span class="line"><span class="comment"># 3 methods for generic function &quot;foo&quot;:</span></span><br><span class="line">[<span class="number">1</span>] foo(x::<span class="built_in">String</span>) <span class="keyword">in</span> A at /home/yuehhua/.julia/packages/A/dbyNq/src/A.jl:<span class="number">6</span></span><br><span class="line">[<span class="number">2</span>] foo(::<span class="built_in">Number</span>) <span class="keyword">in</span> B at /media/yuehhua/Workbench/workspace/B/src/B.jl:<span class="number">7</span></span><br><span class="line">[<span class="number">3</span>] foo(x) <span class="keyword">in</span> A at /home/yuehhua/.julia/packages/A/dbyNq/src/A.jl:<span class="number">5</span></span><br><span class="line"></span><br><span class="line">julia&gt; B.bar</span><br><span class="line">ERROR: <span class="built_in">UndefVarError</span>: bar not defined</span><br><span class="line">Stacktrace:</span><br><span class="line"> [<span class="number">1</span>] top-level scope</span><br><span class="line">   @ REPL[<span class="number">6</span>]:<span class="number">1</span></span><br></pre></td></tr></table></figure><p>我們可以發現 <code>B</code> 套件中的子模組 <code>A</code> 就消失了，而且所有 <code>A</code> 套件中 <code>foo</code> 都會跑到 <code>B</code> 套件當中。當然，<code>bar</code> 則不會在 <code>B</code> 套件當中。</p><h4 id="import-A">import A</h4><p>那如果我們把 <code>B</code> 套件中的 <code>using A</code> 改成 <code>import A</code> 呢？</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">using</span> B</span><br><span class="line"></span><br><span class="line">julia&gt; B</span><br><span class="line">B</span><br><span class="line"></span><br><span class="line">julia&gt; B.foo</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br><span class="line"></span><br><span class="line">julia&gt; B.bar</span><br><span class="line">ERROR: <span class="built_in">UndefVarError</span>: bar not defined</span><br><span class="line">Stacktrace:</span><br><span class="line"> [<span class="number">1</span>] top-level scope</span><br><span class="line">   @ REPL[<span class="number">4</span>]:<span class="number">1</span></span><br><span class="line"></span><br><span class="line">julia&gt; B.A</span><br><span class="line">A</span><br><span class="line"></span><br><span class="line">julia&gt; B.A.foo</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">2</span> methods)</span><br><span class="line"></span><br><span class="line">julia&gt; B.A.bar</span><br><span class="line">bar (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br></pre></td></tr></table></figure><p>看來 <code>import A</code> 跟 <code>using A</code> 沒有太大的差別。</p><h4 id="有子模組也有所有方法的定義">有子模組也有所有方法的定義</h4><p>如果要讓 <code>A</code> 子模組存在，並且可以在 <code>B</code> 套件中使用到所有 <code>A</code> 子模組中的方法，則需要</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">using</span> A</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> A: foo</span><br></pre></td></tr></table></figure><p>如此則會變成</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">using</span> B</span><br><span class="line"></span><br><span class="line">julia&gt; B</span><br><span class="line">B</span><br><span class="line"></span><br><span class="line">julia&gt; B.foo</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">3</span> methods)</span><br><span class="line"></span><br><span class="line">julia&gt; B.A</span><br><span class="line">A</span><br><span class="line"></span><br><span class="line">julia&gt; B.A.foo</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">3</span> methods)</span><br><span class="line"></span><br><span class="line">julia&gt; B.A.bar</span><br><span class="line">bar (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br><span class="line"></span><br><span class="line">julia&gt; B.bar</span><br><span class="line">ERROR: <span class="built_in">UndefVarError</span>: bar not defined</span><br><span class="line">Stacktrace:</span><br><span class="line"> [<span class="number">1</span>] top-level scope</span><br><span class="line">   @ REPL[<span class="number">7</span>]:<span class="number">1</span></span><br></pre></td></tr></table></figure><h3 id="我想定義自己的方法，但是會跟其他的套件衝突">我想定義自己的方法，但是會跟其他的套件衝突</h3><p>常常發生的問題就是，開發中會用到某 <code>A</code> 套件，而自己定義的函式中有跟 <code>A</code> 套件衝突的部份。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">using</span> A</span><br></pre></td></tr></table></figure><p>例如，<code>A</code> 套件中匯出了 <code>foo</code> 函式，而自己開發的套件也定義了同樣的函式名稱。這時候就會發生衝突，也就是出現類似以下的錯誤：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ERROR: error <span class="keyword">in</span> method definition: <span class="keyword">function</span> A.foo must be explicitly imported to be extended</span><br></pre></td></tr></table></figure><p>這時候就需要明確地延伸定義，也就是修改或是增加以下程式碼：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> A: foo</span><br></pre></td></tr></table></figure><p>如此一來，就可以定義自己的 <code>foo</code> 了。</p><h3 id="不想要-import">不想要 import</h3><p>會有基於一些緣故不想要匯入 <code>A</code> 套件的功能。這時候很單純，那就是用以上 <code>using A</code> 的方式而已。</p><p>為了跟 <code>A</code> 套件的功能區別，可以在 <code>B</code> 套件中，指定要呼叫的套件。</p><p>在 src/B.jl 中，</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> B</span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> A</span><br><span class="line"></span><br><span class="line">foo(::<span class="built_in">Number</span>) = <span class="number">5</span></span><br><span class="line"></span><br><span class="line">println(A.foo(<span class="number">4</span>))</span><br><span class="line">println(B.foo(<span class="number">4</span>))</span><br><span class="line"></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>載入 <code>B</code> 套件時會有</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">using</span> B</span><br><span class="line"><span class="number">4</span></span><br><span class="line"><span class="number">5</span></span><br></pre></td></tr></table></figure><h3 id="讓一個套件去補充其他套件的功能">讓一個套件去補充其他套件的功能</h3><p>像我前一陣子的工作是將 <code>scatter</code> 跟 <code>gather</code> 搬到 <code>NNlib</code> 套件下。</p><p>主要當然是把 cpu 運算的部份寫在 <code>NNlib</code> 套件中，但是會有 cuda 運算的部份。然而，cuda 運算的部份則是寫在 <code>NNlibCUDA</code> 套件下，<code>NNlibCUDA</code> 套件則是 <code>NNlib</code> 套件的一個依賴套件。</p><p>這時候 <code>NNlibCUDA</code> 套件的角色就是去延伸 <code>NNlib</code> 套件下，<code>scatter</code> 與 <code>gather</code> 的 cuda 版本，所以這時候我會在 <code>NNlibCUDA</code> 套件中寫：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> NNlib.scatter(::CuArray, ...)</span><br><span class="line">    ...</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> NNlib.gather(::CuArray, ...)</span><br><span class="line">    ...</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>如此，在載入 <code>NNlibCUDA</code> 套件時，就會自動去延伸<code>scatter</code> 與 <code>gather</code> 的方法了。</p><h2 id="結論">結論</h2><p>這邊整理了一些關於命名空間跟一些基本的模組概念，沒有特別實驗或是在開發套件的朋友可能會一團混亂。</p><p>這時候就真的有需要一篇文章來澄清這些行為了呢！</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/05/22/namespace-in-julia/</id>
    <link href="https://yuehhua.github.io/blog/2021/05/22/namespace-in-julia/"/>
    <published>2021-05-21T16:37:40.000Z</published>
    <summary>
      <![CDATA[<p>基本上，我們知道 Julia 的命名空間的概念不是很強，命名空間的概念是由模組（module）所建構的。</p>
<p>介紹模組前先要介紹幾個比較基本的語法：<code>using</code>、<code>import</code> 跟 <code>include</code>。</p>]]>
    </summary>
    <title>Julia 的命名空間</title>
    <updated>2021-05-22T01:39:25.746Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>最近有遇到業界的工程師對 Julia 有點好奇，提了一些問題。</p><p>在 Python 到 Julia 的轉換路上，常常不知道原本在 Python 用慣的套件，在 Julia 中要去哪裡找？</p><span id="more"></span><h2 id="Python-的效能優化套件">Python 的效能優化套件</h2><p>例如，在 Python 都用 numba 來提升效能，那麼 Julia 有相對應的套件可以用嗎？</p><p>簡單地回答是「Julia 除了解決 two language problem 以外，他也是直接有 numba 的效能，內建 numpy 跟一部分 scipy」。</p><p>也就是，「Julia = numpy + part of scipy + numba」。</p><p>比較複雜的回答則是，Julia 的重點擺在他強大的編譯器跟語言設計上，因為語言設計的緣故，所以他可以在 jit 蒐集各種型別的資訊。</p><p>以往動態語言的效能不高，最大的問題在於一個變數一直要到執行時期才有辦法決定他的型別，這導致了編譯器無法事先對他做最佳化，這我們也稱為 type unstable。然而，Julia 的突破就在於這點，他的語言設計及有效的型別推斷，讓他被編譯成 LLVM IR 的時候擁有跟 C 這類靜態語言一樣充足的型別資訊，所以他可以有靜態語言的效能，有完整型別資訊的 LLVM IR 編譯出來的機器碼，就跟用 C 寫沒什麼兩樣了。</p><p>另一邊，numba 的本身也是利用編譯最佳化的技術讓效能可以上去，這個本身可以被視為半個編譯器，但是他本身也會有所限制。像是他不能處理巢狀結構的最佳化，當有陣列中含有其他陣列的時候就沒有辦法。相對 Julia 本身就是語言編譯器，所以他本來就可以對這些巢狀結構做最佳化，並且 Julia 的型別本身直接對應 C 的 struct，甚至 alignment 也是一致的，所以也就是 C 的效能了。總結，Julia 編譯器對陣列的行為最佳化產出的成果就是 numba 本身。</p><p>那這點不只用在陣列上，歐洲有新創公司在做資料庫引擎，他們利用 Julia 加上他們自家開發的套件，把 Julia 編譯器當成他們引擎的最佳化器，那他們的資料庫引擎就有等同於 C 寫出來的一樣，他們甚至將機器學習套件結合到他們的資料庫中，就等同於可以在資料端訓練模型的引擎。</p><h2 id="Python-與-Julia-相對應的套件">Python 與 Julia 相對應的套件</h2><p>既然有這樣的疑問，所以我整理了一系列 Python 套件與 Julia 套件的對應表。</p><h3 id="numpy-numba-Julia">numpy + numba -&gt; Julia</h3><p>numpy 是 Python 底下的矩陣運算加速套件，其最重要的特色就是他底下使用了 C 實作套件，所以當你使用了 numpy 就等於是使用了 C 的陣列，以及其速度。對於陣列以外的資料結構，則會使用 numba 來做加速。</p><p>Julia 在語言設計上也支援陣列，並且在型別的結構上有跟 C struct 有一樣的 alignment。所以使用 Julia 本來就是 Python 中的 numpy + numba + cython。</p><p>你不用在 Python 中寫 C-like 的語法啦！</p><h3 id="scipy">scipy</h3><p>scipy 是 Python 底下相當知名的科學運算套件，最重要的特色就是他直接整合 numpy，所以科學運算就有了 C 陣列的速度。但由於 scipy 包山包海，沒有一個套件可以直接對應 scipy，不過 Julia 中有對於不同的功能直接對應的套件。以下列出這些套件：</p><ul><li>線性代數 Linear algebra (scipy.linalg): Julia 內建標準函式庫 <a href="https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/"><code>LinearAlgebra</code></a></li><li>稀疏矩陣 Sparse arrays (scipy.sparse.csgraph): Julia 內建標準函式庫 <a href="https://docs.julialang.org/en/v1/stdlib/SparseArrays/"><code>SparseArrays</code></a> 以及 <a href="https://docs.julialang.org/en/v1/stdlib/SuiteSparse/"><code>SuiteSparse</code></a></li><li>特徵分解套件 ARPACK: Julia 官方直接支援的 <a href="https://julialinearalgebra.github.io/Arpack.jl/stable/"><code>Arpack.jl</code></a></li><li>特殊函式 Special functions (scipy.special): <a href="https://github.com/JuliaMath/SpecialFunctions.jl"><code>SpecialFunctions.jl</code></a></li><li>快速傅立葉轉換 Fourier Transforms (scipy.fft): <a href="https://github.com/JuliaMath/FFTW.jl"><code>FFTW.jl</code></a></li><li>最佳化 Optimization (scipy.optimize): <a href="https://jump.dev/"><code>JuMP</code></a></li><li>數值積分 Integration (scipy.integrate)<ul><li>一維的積分 <a href="https://github.com/JuliaMath/QuadGK.jl"><code>QuadGK.jl</code></a></li><li>高維度的積分 <a href="https://github.com/JuliaMath/HCubature.jl"><code>HCubature.jl</code></a> 或是 <a href="https://github.com/pabloferz/NIntegration.jl"><code>NIntegration.jl</code></a></li><li><a href="https://github.com/JuliaMath/Calculus.jl"><code>Calculus.jl</code></a></li><li><a href="https://github.com/hwborchers/NumericalMath.jl"><code>NumericalMath.jl</code></a></li><li>教學可以參考<a href="https://juliahub.com/docs/CalculusWithJulia/AZHbv/0.0.5/">這篇文章</a></li><li><a href="https://github.com/JuliaApproximation">github org JuliaApproximation</a></li></ul></li><li>內插 Interpolation (scipy.interpolate): <a href="https://github.com/JuliaMath/Interpolations.jl"><code>Interpolations.jl</code></a></li><li>統計 Statistics (scipy.stats): <a href="https://github.com/JuliaStats/Distributions.jl"><code>Distributions.jl</code></a></li><li>訊號處理 Signal Processing (scipy.signal)<ul><li><a href="https://github.com/JuliaDSP/DSP.jl"><code>DSP.jl</code></a></li><li><a href="https://github.com/haberdashPI/SignalOperators.jl"><code>SignalOperators.jl</code></a></li><li>教學可以參考<a href="https://juliahub.com/docs/SignalAnalysis/7Vz2N/0.4.0/">這裡</a></li><li><a href="https://github.com/JuliaDSP/Wavelets.jl"><code>Wavelets.jl</code></a></li><li><a href="https://github.com/JuliaDSP/Deconvolution.jl"><code>Deconvolution.jl</code></a></li><li><a href="https://github.com/JuliaDSP">github org JuliaDSP</a></li></ul></li><li>空間資料結構 Spatial data structures and algorithms (scipy.spatial): <a href="https://github.com/KristofferC/NearestNeighbors.jl"><code>NearestNeighbors.jl</code></a></li><li>影像處理 Multidimensional image processing (scipy.ndimage): <a href="https://juliaimages.org/stable/">JuliaImages</a></li></ul><h3 id="matplotlib">matplotlib</h3><p>繪圖套件可以參考以下：</p><ul><li><a href="https://github.com/JuliaPlots/Plots.jl"><code>Plots.jl</code></a></li><li><a href="https://github.com/GiovineItalia/Gadfly.jl"><code>Gadfly.jl</code></a></li><li>GPU 繪圖套件 <a href="https://github.com/JuliaPlots/Makie.jl"><code>Makie.jl</code></a></li></ul><h3 id="sympy">sympy</h3><p><a href="https://github.com/JuliaSymbolics/Symbolics.jl"><code>Symbolics.jl</code></a> 是近期推出相當熱門的符號操作套件，他支援的現代的快速電腦代數系統，足以媲美 MATLAB。</p><h3 id="pandas">pandas</h3><p><a href="https://github.com/JuliaData/DataFrames.jl"><code>DataFrames.jl</code></a> 提供了表格類資料的資料結構與運算，實作直接是 Julia 陣列，運算的部份支援絕大多數 pandas 的運算，以及支援類資料庫操作。讀寫檔的操作可以使用 <a href="https://github.com/JuliaData/CSV.jl"><code>CSV.jl</code></a> 來讀寫 csv, tsv 類檔案。<a href="https://github.com/JuliaData/Tables.jl"><code>Tables.jl</code></a> 是以上套件與資料庫銜接的介面，可以搭配 <a href="https://github.com/JuliaData/TableOperations.jl"><code>TableOperations.jl</code></a> 的串流運算，可以串到 <a href="https://github.com/JuliaDatabases/ODBC.jl"><code>ODBC.jl</code></a>、<a href="https://github.com/invenia/LibPQ.jl"><code>LibPQ.jl</code></a>、<a href="https://github.com/JuliaDatabases/MySQL.jl"><code>MySQL.jl</code></a>、<a href="https://github.com/JuliaDatabases/SQLite.jl"><code>SQLite.jl</code></a> 和 <a href="https://github.com/JuliaDatabases/Hive.jl"><code>Hive.jl</code></a> 等等資料庫。</p><h3 id="statsmodels">statsmodels</h3><ul><li><a href="https://github.com/JuliaStats/HypothesisTests.jl"><code>HypothesisTests.jl</code></a></li><li><a href="https://github.com/JuliaStats/GLM.jl"><code>GLM.jl</code></a></li><li><a href="https://github.com/JuliaStats/MixedModels.jl"><code>MixedModels.jl</code></a></li><li><a href="https://github.com/JuliaStats/TimeSeries.jl"><code>TimeSeries.jl</code></a></li></ul><h3 id="scikit-learn">scikit-learn</h3><p><a href="https://github.com/alan-turing-institute/MLJ.jl"><code>MLJ.jl</code></a> 提供了超過 150 種經典機器學習模型，包含了知名的 libsvm、xgboost、scikit-learn 等等套件，這個套件是由知名的 Alan Turing Institute 的團隊所維護。</p><h3 id="Deep-learning">Deep learning</h3><p>在 Python 有兩大知名深度學習套件：pytorch 及 tensorflow，Julia 則有 <a href="https://github.com/FluxML/Flux.jl"><code>Flux.jl</code></a> 和 <a href="https://github.com/denizyuret/Knet.jl"><code>Knet.jl</code></a>。</p><h2 id="使用-Julia-的好處">使用 Julia 的好處</h2><p>對比 Python 現有的套件與生態系，Julia 可能都有對應的套件可以使用。不過使用 Julia 有什麼特別的優勢嗎？可能是 code 可以寫得更好維運？統一風格？更好閱讀或更精簡？Python 用上述函式庫有時候就是各自一套 DSL，像是在寫多種不同語言的感覺。</p><p>Julia 主要解決所謂的 two language problem 是指，開發的時候需要一個好寫好改的語言，可以快速開發，快速做驗證。在產品上線的時候需要效能，但往往需要另外一個語言的重新實作，但是用 Julia 就可以直接在同一個語言直接開發，並且逐步調整效能，不用重寫。</p><p>使用 Julia 在程式碼風格上統一，在開發期間所用的語言就是上線的語言，不會有要上線的語言要將 python/matlab/R 轉換成 C/C++ 這種狀況發生。更有甚者，我個人認為 Julia 在語言設計上，可以讓工程師在寫 code 的時候，code 寫得更為精簡。</p><p>相對，DSL 的部分就不會是因為不同的函式庫而有有不同 DSL，而是因為有不同的應用場景 (統計、ML、DL)，因為不同領域的人有不同的習慣或是使用情境去設計適合他們的 DSL。</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/04/19/corresponding-packages-in-julia-and-python/</id>
    <link href="https://yuehhua.github.io/blog/2021/04/19/corresponding-packages-in-julia-and-python/"/>
    <published>2021-04-19T03:16:56.000Z</published>
    <summary>
      <![CDATA[<p>最近有遇到業界的工程師對 Julia 有點好奇，提了一些問題。</p>
<p>在 Python 到 Julia 的轉換路上，常常不知道原本在 Python 用慣的套件，在 Julia 中要去哪裡找？</p>]]>
    </summary>
    <title>Python 與 Julia 相對應的套件</title>
    <updated>2021-04-19T03:49:27.840Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>常常開發者會需要在，使用者使用不同的語言版本或是套件版本，做不同的處置，有可能是安裝不同的函式庫，或是設定不同的參數。這時候要在程式中自動取得目前的語言版本或是特定套件的版本就很重要。Julia 語言本身就有內建版本字串可以使用，它可以用來比較版本的差異或是大小。</p><span id="more"></span><h2 id="Julia-語言版本">Julia 語言版本</h2><p>如果要取得目前 Julia 語言版本相當地簡單，有個全域變數 <code>VERSION</code>，它直接提供給你目前的語言版本資訊。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="literal">VERSION</span></span><br><span class="line"><span class="string">v&quot;1.6.0&quot;</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="literal">VERSION</span> ≥ <span class="string">v&quot;1.5.0&quot;</span></span><br><span class="line"><span class="literal">true</span></span><br></pre></td></tr></table></figure><h2 id="套件版本">套件版本</h2><p>目前官方並沒有提供一個方便查詢套件版本的方式給大家。像 python 有 <code>__version__</code> 可以使用。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">import</span> numpy</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>numpy.__version__</span><br><span class="line"><span class="string">&#x27;1.20.0&#x27;</span></span><br></pre></td></tr></table></figure><p>目前在 Julia 不依賴套件的方法是到 <code>Pkg.dependencies()</code> 去找尋，他會回傳給你目前所有套件的相依樹（dependency tree），key 是每個套件的 UUID，而 value 則是其相依的套件資訊。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; Pkg.dependencies()</span><br><span class="line"><span class="built_in">Dict</span>&#123;Base.UUID, Pkg.Types.PackageInfo&#125; with <span class="number">584</span> entries:</span><br><span class="line">  UUID(<span class="string">&quot;fb77eaff-e24c-56d4-86b1-d163f2edb164&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;Sundials_jll&quot;</span>, <span class="string">v&quot;5.2.0+1&quot;</span>, <span class="string">&quot;013ff4504fc1d475aa80c63b455b6b3a58767db2&quot;</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">true</span>, noth…</span><br><span class="line">  UUID(<span class="string">&quot;4d4711f2-db25-561a-b6b3-d35e7d4047d3&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;MatrixMarket&quot;</span>, <span class="string">v&quot;0.3.1&quot;</span>, <span class="string">&quot;54d39ccb57d29aefa666418bca8ca5598ebd8225&quot;</span>, <span class="literal">true</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">true</span>, nothing…</span><br><span class="line">  UUID(<span class="string">&quot;708ec375-b3d6-5a57-a7ce-8257bf98657a&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;Gumbo&quot;</span>, <span class="string">v&quot;0.8.0&quot;</span>, <span class="string">&quot;e711d08d896018037d6ff0ad4ebe675ca67119d4&quot;</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">true</span>, <span class="literal">nothing</span>, noth…</span><br><span class="line">  UUID(<span class="string">&quot;9bbee03b-0db5-5f46-924f-b5c9c21b8c60&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;NaiveBayes&quot;</span>, <span class="string">v&quot;0.4.0&quot;</span>, <span class="string">&quot;296d27a455ae074d3cb27f7edeff8e6532865f87&quot;</span>, <span class="literal">true</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">true</span>, <span class="literal">nothing</span>, …</span><br><span class="line">  UUID(<span class="string">&quot;c73af94c-d91f-53ed-93a7-00f77d67a9d7&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;ImageMagick_jll&quot;</span>, <span class="string">v&quot;6.9.10-12+3&quot;</span>, <span class="string">&quot;1c0a2295cca535fabaf2029062912591e9b61987&quot;</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, tru…</span><br><span class="line">  UUID(<span class="string">&quot;b99e7846-7c00-51b0-8f62-c81ae34c0232&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;BinaryProvider&quot;</span>, <span class="string">v&quot;0.5.10&quot;</span>, <span class="string">&quot;ecdec412a9abc8db54c0efc5548c64dfce072058&quot;</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">true</span>, not…</span><br><span class="line">  UUID(<span class="string">&quot;cc61e674-0454-545c-8b26-ed2c68acab7a&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;Xorg_libxkbfile_jll&quot;</span>, <span class="string">v&quot;1.1.0+4&quot;</span>, <span class="string">&quot;926af861744212db0eb001d9e40b5d16292080b2&quot;</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, tru…</span><br><span class="line">  UUID(<span class="string">&quot;112f6efa-9a02-5b7d-90c0-432ed331239a&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;VegaLite&quot;</span>, <span class="string">v&quot;2.4.1&quot;</span>, <span class="string">&quot;eb937ff65666c83f6c4db40d07d2fecfedeaff7e&quot;</span>, <span class="literal">true</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">true</span>, <span class="literal">nothing</span>, no…</span><br><span class="line">  UUID(<span class="string">&quot;7876af07-990d-54b4-ab0e-23690620f79a&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;Example&quot;</span>, <span class="string">v&quot;0.5.3&quot;</span>, <span class="string">&quot;46e44e869b4d90b96bd8ed1fdcf32244fddfb6cc&quot;</span>, <span class="literal">true</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">true</span>, <span class="literal">nothing</span>, not…</span><br><span class="line">  UUID(<span class="string">&quot;c84ed2f1-dad5-54f0-aa8e-dbefe2724439&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;Ratios&quot;</span>, <span class="string">v&quot;0.4.0&quot;</span>, <span class="string">&quot;37d210f612d70f3f7d57d488cb3b6eff56ad4e41&quot;</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">true</span>, <span class="literal">nothing</span>, not…</span><br><span class="line">  UUID(<span class="string">&quot;88cd18e8-d9cc-4ea6-8889-5259c0d15c8b&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;ConsoleProgressMonitor&quot;</span>, <span class="string">v&quot;0.1.2&quot;</span>, <span class="string">&quot;3ab7b2136722890b9af903859afcf457fa3059e8&quot;</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, tr…</span><br><span class="line">  UUID(<span class="string">&quot;37e2e46d-f89d-539d-b4ee-838fcccc9c8e&quot;</span>) =&gt; PackageInfo(<span class="string">&quot;LinearAlgebra&quot;</span>, <span class="literal">nothing</span>, <span class="literal">nothing</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">true</span>, <span class="literal">nothing</span>, <span class="literal">nothing</span>, <span class="string">&quot;/usr/share/julia/stdli…</span></span><br><span class="line"><span class="string">  UUID(&quot;31c24e10</span>-a181-<span class="number">5473</span>-b8eb-<span class="number">7969</span><span class="string">acd0382f&quot;) =&gt; PackageInfo(&quot;Distributions</span><span class="string">&quot;, v&quot;0</span><span class="number">.23</span><span class="number">.8</span><span class="string">&quot;, &quot;9c41285c57c6e0d73a21ed4b65f6eec34805f937</span><span class="string">&quot;, true, false, false, false, true, nothi…</span></span><br><span class="line"><span class="string">  UUID(&quot;1bc83da4</span>-<span class="number">3</span>b8d-<span class="number">516</span>f-aca4-<span class="number">4</span><span class="string">fe02f6d838f&quot;) =&gt; PackageInfo(&quot;SafeTestsets</span><span class="string">&quot;, v&quot;0</span><span class="number">.0</span><span class="number">.1</span><span class="string">&quot;, &quot;36ebc5622c82eb9324005cc75e7e2cc51181d181</span><span class="string">&quot;, false, false, false, false, true, nothin…</span></span><br><span class="line"><span class="string">  UUID(&quot;42fd0dbc</span>-a981-<span class="number">5370</span>-<span class="number">80f2</span>-<span class="string">aaf504508153&quot;) =&gt; PackageInfo(&quot;IterativeSolvers</span><span class="string">&quot;, v&quot;0</span><span class="number">.8</span><span class="number">.5</span><span class="string">&quot;, &quot;704eee044a41b0e7e8417f7dd2a6b6b5361afd5f</span><span class="string">&quot;, false, false, false, false, true, no…</span></span><br><span class="line"><span class="string">  UUID(&quot;01680d73</span>-<span class="number">4</span>ee2-<span class="number">5</span>a08-a1aa-<span class="number">533608</span><span class="string">c188bb&quot;) =&gt; PackageInfo(&quot;GenericSVD</span><span class="string">&quot;, v&quot;0</span><span class="number">.3</span><span class="number">.0</span><span class="string">&quot;, &quot;62909c3eda8a25b5673a367d1ad2392ebb265211</span><span class="string">&quot;, false, false, false, false, true, nothing,…</span></span><br><span class="line"><span class="string">  UUID(&quot;9a3f8284</span>-a2c9-<span class="number">5f02</span>-<span class="number">9</span>a11-<span class="number">845980</span><span class="string">a1fd5c&quot;) =&gt; PackageInfo(&quot;Random</span><span class="string">&quot;, nothing, nothing, true, false, false, false, true, nothing, nothing, &quot;</span>/usr/share/julia/stdlib/v1<span class="number">.6</span>/R…</span><br><span class="line">  ...</span><br></pre></td></tr></table></figure><p>這種方法會比較辛苦一點，在當中找到特定的套件版本。</p><p>如果是用套件的方法則是，安裝 PkgVersion 這個套件，並且使用 <code>PkgVersion.Version</code> 這個函式來取得已載入的套件版本資訊。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">using</span> PkgVersion</span><br><span class="line"></span><br><span class="line">julia&gt; <span class="keyword">using</span> DataFrames</span><br><span class="line"></span><br><span class="line">julia&gt; PkgVersion.Version(DataFrames)</span><br><span class="line"><span class="string">v&quot;0.21.8&quot;</span></span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/04/04/julia-package-version/</id>
    <link href="https://yuehhua.github.io/blog/2021/04/04/julia-package-version/"/>
    <published>2021-04-03T17:20:56.000Z</published>
    <summary>
      <![CDATA[<p>常常開發者會需要在，使用者使用不同的語言版本或是套件版本，做不同的處置，有可能是安裝不同的函式庫，或是設定不同的參數。這時候要在程式中自動取得目前的語言版本或是特定套件的版本就很重要。Julia 語言本身就有內建版本字串可以使用，它可以用來比較版本的差異或是大小。</p>]]>
    </summary>
    <title>Julia 的版本與套件版本</title>
    <updated>2021-04-03T17:20:52.054Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<!-- toc --><p>在 v1.6 版中，Julia 有大幅度的效能提昇，效能提昇的部份著重在於預編譯（precompilation）以及編譯的效能改進，而 v1.6 版將成為下一個長期支援（long-term support, LTS）的版本。</p><p>根據<a href="https://julialang.org/blog/2021/03/julia-1.6-highlights/">官方部落格</a>，本次版本更新引進了眾多新的技術，包含 parallel precompilation、消除重複編譯、降低編譯器的 latency、加速二進位檔案的載入，以及改善 stacktrace 的格式等等重大的功能。那我們就來詳細看看有哪些更新吧！</p><span id="more"></span><h2 id="重要功能">重要功能</h2><h3 id="平行預編譯">平行預編譯</h3><p>使用者在 using/import 某些套件的時候，總是需要等待長久的預編譯時間，但在 v1.6 版引進了平行預編譯（parallel precompilation）技術來降低套件的載入時間。<code>pkg&gt; precompile</code> 會啟動平行預編譯，並且以深度優先的方式，預編譯其套件下的所有相依套件。只有直接相依的套件（列於 <code>Project.toml</code> 中）會丟出錯誤訊息。平行預編譯會在 manifest 被更新之後自動啟動。平行預編譯也支援多套件同時編譯，它會使用多行程（multi-processed）的方式編譯。Julia 會預設地產生最大 CPU 核心數的預編譯任務並且執行平行預編譯。自動預編譯會記住在特定環境下所發生的錯誤，並且會在環境改變時再次嘗試。自動預編譯可以使用 <code>ctrl-c</code> 中斷，或是設定環境變數 <code>JULIA_PKG_PRECOMPILE_AUTO=0</code> 來關閉。</p><p>在 v1.5 版載入 DifferentialEquations.jl。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">(v1<span class="number">.5</span>) pkg&gt; add DifferentialEquations</span><br><span class="line">...</span><br><span class="line">julia&gt; <span class="meta">@time</span> <span class="keyword">using</span> DifferentialEquations</span><br><span class="line">[ Info: Precompiling DifferentialEquations [<span class="number">0</span>c46a032-eb83-<span class="number">5123</span>-abaf-<span class="number">570</span>d42b7fbaa]</span><br><span class="line">  <span class="number">474.288251</span> seconds …</span><br></pre></td></tr></table></figure><p>在 v1.6 版載入 DifferentialEquations.jl。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">(v1<span class="number">.6</span>) pkg&gt; add DifferentialEquations</span><br><span class="line">...</span><br><span class="line">Precompiling project...</span><br><span class="line">  Progress [========================================&gt;]  <span class="number">112</span>/<span class="number">112</span></span><br><span class="line"><span class="number">112</span> dependencies successfully precompiled <span class="keyword">in</span> <span class="number">72</span> seconds</span><br><span class="line"></span><br><span class="line">julia&gt; <span class="meta">@time</span> <span class="keyword">using</span> DifferentialEquations</span><br><span class="line">  <span class="number">4.995477</span> seconds …</span><br></pre></td></tr></table></figure><p>程式碼取自官方部落格。</p><h3 id="避免重複編譯">避免重複編譯</h3><p>延展性（extensibility）是 Julia 的重要功能之一，你可以對既有的 function 增加新的 method。有的時候，這些更動會讓 Julia 重新編譯程式碼。Julia 會讓「過期」的程式碼被標記，並且編譯新的程式碼。在 v1.6 版中，標記「過期」的程式碼的方式被改進，變得更為精準，如此可以避免重複編譯的問題。</p><h3 id="使用者功能">使用者功能</h3><h4 id="語法">語法</h4><ul><li>Types written with <code>where</code> syntax can now be used to define constructors, e.g.<br><code>(Foo{T} where T)(x) = ...</code>.</li></ul><h5 id="增加新的語法-import-as">增加新的語法 <code>import ... as ...</code></h5><p>新增新語法 <code>import A as B</code>，也包含<code>import A: x as y</code>、<code>import A.x as y</code> 和 <code>using A: x as y</code>，可以對載入的模組跟辨識子重新命名。（#1255）</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">import</span> DataFrames as DF</span><br><span class="line"></span><br><span class="line">julia&gt; <span class="keyword">using</span> DataFrames as DF</span><br><span class="line">ERROR: syntax: invalid syntax <span class="string">&quot;using DataFrames as ...&quot;</span></span><br><span class="line">Stacktrace:</span><br><span class="line"> [<span class="number">1</span>] top-level scope</span><br><span class="line">   @ none:<span class="number">1</span></span><br></pre></td></tr></table></figure><p>注意，<code>using</code> 是不支援 <code>as</code> 的喔！</p><h5 id="可以使用-來指定解構的變數">可以使用 <code>...</code> 來指定解構的變數</h5><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; a, b... = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]</span><br><span class="line"><span class="number">3</span>-element <span class="built_in">Vector</span>&#123;<span class="built_in">Int64</span>&#125;:</span><br><span class="line"> <span class="number">1</span></span><br><span class="line"> <span class="number">2</span></span><br><span class="line"> <span class="number">3</span></span><br><span class="line"></span><br><span class="line">julia&gt; a</span><br><span class="line"><span class="number">1</span></span><br><span class="line"></span><br><span class="line">julia&gt; b</span><br><span class="line"><span class="number">2</span>-element <span class="built_in">Vector</span>&#123;<span class="built_in">Int64</span>&#125;:</span><br><span class="line"> <span class="number">2</span></span><br><span class="line"> <span class="number">3</span></span><br><span class="line"></span><br><span class="line">julia&gt; a, b... = (<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>)</span><br><span class="line">(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)</span><br><span class="line"></span><br><span class="line">julia&gt; b</span><br><span class="line">(<span class="number">2</span>, <span class="number">3</span>)</span><br><span class="line"></span><br><span class="line">julia&gt; a, b, c... = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>]</span><br><span class="line"><span class="number">4</span>-element <span class="built_in">Vector</span>&#123;<span class="built_in">Int64</span>&#125;:</span><br><span class="line"> <span class="number">1</span></span><br><span class="line"> <span class="number">2</span></span><br><span class="line"> <span class="number">3</span></span><br><span class="line"> <span class="number">4</span></span><br><span class="line"></span><br><span class="line">julia&gt; c</span><br><span class="line"><span class="number">2</span>-element <span class="built_in">Vector</span>&#123;<span class="built_in">Int64</span>&#125;:</span><br><span class="line"> <span class="number">3</span></span><br><span class="line"> <span class="number">4</span></span><br></pre></td></tr></table></figure><h4 id="陣列與集合">陣列與集合</h4><h5 id="支援-init-關鍵字參數">支援 <code>init</code> 關鍵字參數</h5><p><code>sum</code>、<code>prod</code>、<code>maximum</code>、<code>minimum</code>，以及 <code>count</code> 現在支援 <code>init</code> 關鍵字參數。（#36188, #35839, #37461）</p><h5 id="集合容器支援更多運算子">集合容器支援更多運算子</h5><p>集合容器現在也支援 <code>∉(collection)</code>、<code>∋(item)</code>、<code>∌(item)</code> 這些方法。（#38475）</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="number">1</span> ∉ [<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>]</span><br><span class="line"><span class="literal">true</span></span><br><span class="line"></span><br><span class="line">julia&gt; [<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>] ∋ <span class="number">1</span></span><br><span class="line"><span class="literal">false</span></span><br><span class="line"></span><br><span class="line">julia&gt; [<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>] ∌ <span class="number">1</span></span><br><span class="line"><span class="literal">true</span></span><br></pre></td></tr></table></figure><h5 id="新的-NamedTuple-建構子">新的 <code>NamedTuple</code> 建構子</h5><p><code>NamedTuple</code> 有新的建構子，可以用 <code>NamedTuple(iterator)</code> 的方式來支援從 key-value 配對的集合容器中建構 named tuple。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; d = <span class="built_in">Dict</span>(:a =&gt; <span class="number">1</span>, :b =&gt; <span class="number">2</span>)</span><br><span class="line"><span class="built_in">Dict</span>&#123;<span class="built_in">Symbol</span>, <span class="built_in">Int64</span>&#125; with <span class="number">2</span> entries:</span><br><span class="line">  :a =&gt; <span class="number">1</span></span><br><span class="line">  :b =&gt; <span class="number">2</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="built_in">NamedTuple</span>(d)</span><br><span class="line">(a = <span class="number">1</span>, b = <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">julia&gt; a = [:a =&gt; <span class="number">1</span>, :b =&gt; <span class="number">2</span>]</span><br><span class="line"><span class="number">2</span>-element <span class="built_in">Vector</span>&#123;<span class="built_in">Pair</span>&#123;<span class="built_in">Symbol</span>, <span class="built_in">Int64</span>&#125;&#125;:</span><br><span class="line"> :a =&gt; <span class="number">1</span></span><br><span class="line"> :b =&gt; <span class="number">2</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="built_in">NamedTuple</span>(a)</span><br><span class="line">(a = <span class="number">1</span>, b = <span class="number">2</span>)</span><br></pre></td></tr></table></figure><h5 id="點運算子可以被用於高階函式">點運算子可以被用於高階函式</h5><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; map(.*, collect(<span class="number">1</span>:<span class="number">5</span>), collect(<span class="number">6</span>:<span class="number">10</span>))</span><br><span class="line"><span class="number">5</span>-element <span class="built_in">Vector</span>&#123;<span class="built_in">Int64</span>&#125;:</span><br><span class="line">  <span class="number">6</span></span><br><span class="line"> <span class="number">14</span></span><br><span class="line"> <span class="number">24</span></span><br><span class="line"> <span class="number">36</span></span><br><span class="line"> <span class="number">50</span></span><br></pre></td></tr></table></figure><h5 id="Range-支援非整數型別"><code>Range</code> 支援非整數型別</h5><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="number">1.0</span>:<span class="number">0.1</span>:<span class="number">10.0</span></span><br><span class="line"><span class="number">1.0</span>:<span class="number">0.1</span>:<span class="number">10.0</span></span><br><span class="line"></span><br><span class="line">julia&gt; typeof(<span class="number">1.0</span>:<span class="number">0.1</span>:<span class="number">10.0</span>)</span><br><span class="line"><span class="built_in">StepRangeLen</span>&#123;<span class="built_in">Float64</span>, Base.TwicePrecision&#123;<span class="built_in">Float64</span>&#125;, Base.TwicePrecision&#123;<span class="built_in">Float64</span>&#125;&#125;</span><br><span class="line"></span><br><span class="line">julia&gt; <span class="number">1.0</span>:<span class="number">10.0</span></span><br><span class="line"><span class="number">1.0</span>:<span class="number">1.0</span>:<span class="number">10.0</span></span><br><span class="line"></span><br><span class="line">julia&gt; typeof(<span class="number">1.0</span>:<span class="number">10.0</span>)</span><br><span class="line"><span class="built_in">StepRangeLen</span>&#123;<span class="built_in">Float64</span>, Base.TwicePrecision&#123;<span class="built_in">Float64</span>&#125;, Base.TwicePrecision&#123;<span class="built_in">Float64</span>&#125;&#125;</span><br></pre></td></tr></table></figure><p>要指定 <code>x:y</code> 以前都需要是整數型別 <code>&lt;: Integer</code> 才行，現在 <code>LinRange</code>、<code>StepRange</code> 和 <code>StepRangeLen</code> 都支援非整數型別。（#32439）</p><h4 id="訊息與呈現">訊息與呈現</h4><h5 id="code-XXX-的格式更新"><code>@code_XXX</code> 的格式更新</h5><p><code>@code_llvm</code> 及 <code>@code_native</code> 變成彩色的了！</p><p><img src="/images/code_native_1.6.png" alt=""></p><h5 id="稀疏矩陣的顯示格式更新">稀疏矩陣的顯示格式更新</h5><p>稀疏矩陣的顯示變得更直覺了！他自動隱藏非零值。（#33821）</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; sprand(<span class="number">4</span>, <span class="number">4</span>, <span class="number">0.5</span>)</span><br><span class="line"><span class="number">4</span>×<span class="number">4</span> SparseMatrixCSC&#123;<span class="built_in">Float64</span>, <span class="built_in">Int64</span>&#125; with <span class="number">9</span> stored entries:</span><br><span class="line"> <span class="number">0.883381</span>  <span class="number">0.990356</span>   ⋅         ⋅ </span><br><span class="line"> <span class="number">0.344935</span>  <span class="number">0.238646</span>   ⋅        <span class="number">0.218795</span></span><br><span class="line"> <span class="number">0.583395</span>   ⋅        <span class="number">0.674894</span>   ⋅ </span><br><span class="line"> <span class="number">0.892346</span>   ⋅         ⋅        <span class="number">0.53169</span></span><br></pre></td></tr></table></figure><h5 id="UUID-用裝置亂數作為亂數產生器">UUID 用裝置亂數作為亂數產生器</h5><p>變更 <code>uuid1</code> 和 <code>uuid4</code> 去使用 <code>Random.RandomDevice()</code> 作為預設的亂數產生器。（#35872）</p><h3 id="開發者功能">開發者功能</h3><h4 id="開發">開發</h4><p>以後不再有 home project 的概念了！執行 <code>julia --project=dir</code> 等同於執行 <code>julia</code>、<code>pkg&gt; activate $dir</code> 以及 <code>julia --project</code> 一系列命令。<code>julia --project</code> 等同於指定了 <code>dir = Base.current_project()</code>。（#36434）</p><p>編譯與型別推斷現在可以在模組中被啟用或是關閉，使用 <code>Base.Experimental.@compiler_options</code> 可以達到。（#37041）</p><h4 id="二進位檔與函式庫">二進位檔與函式庫</h4><p><code>Pkg.Artifacts</code> 模組目前可以被作為一個獨立的套件（<code>Artifacts</code>）使用，當然 <code>Pkg.Artifacts</code> 也可以。（#37320）</p><p><code>Pkg.BinaryPlatforms</code> 被移動至 <code>Base</code> 成為 <code>Base.BinaryPlatforms</code>。（#37320）</p><p>如果要延遲下載 artifacts，<code>LazyArtifacts</code> 一定要被列在相依套件中。（#37844）</p><h4 id="測試">測試</h4><ul><li><code>@testset</code> 支援新的選項 <code>verbose</code> 來呈現測試結果。（#33755）</li></ul><h4 id="效能調校">效能調校</h4><h5 id="字串支援-view">字串支援 view</h5><p>現在所有字串（<code>AbstractString</code>）都支援 <code>view</code> 囉！ 也包含 <code>@view</code> 以及 <code>@views</code>，他們會回傳 <code>SubString</code>。（#35879）</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; s = <span class="string">&quot;ABCDabcd&quot;</span></span><br><span class="line"><span class="string">&quot;ABCDabcd&quot;</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="meta">@view</span> s[<span class="number">2</span>:<span class="number">4</span>]</span><br><span class="line"><span class="string">&quot;BCD&quot;</span></span><br><span class="line"></span><br><span class="line">julia&gt; typeof(<span class="meta">@view</span> s[<span class="number">2</span>:<span class="number">4</span>])</span><br><span class="line"><span class="built_in">SubString</span>&#123;<span class="built_in">String</span>&#125;</span><br></pre></td></tr></table></figure><h5 id="time-增加編譯時間比例"><code>@time</code> 增加編譯時間比例</h5><p>在執行 <code>@time</code> 時，增加了顯示時間中有多少比例的編譯時間（compile time），<code>@timev</code> 則有更詳盡的資料（#37678）。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; A = rand(<span class="number">5</span>, <span class="number">5</span>)</span><br><span class="line"><span class="number">5</span>×<span class="number">5</span> <span class="built_in">Matrix</span>&#123;<span class="built_in">Float64</span>&#125;:</span><br><span class="line"> <span class="number">0.457416</span>  <span class="number">0.437818</span>   <span class="number">0.562112</span>  <span class="number">0.406917</span>  <span class="number">0.447958</span></span><br><span class="line"> <span class="number">0.332568</span>  <span class="number">0.947091</span>   <span class="number">0.936427</span>  <span class="number">0.514941</span>  <span class="number">0.692013</span></span><br><span class="line"> <span class="number">0.590303</span>  <span class="number">0.0198501</span>  <span class="number">0.729961</span>  <span class="number">0.603581</span>  <span class="number">0.333894</span></span><br><span class="line"> <span class="number">0.380095</span>  <span class="number">0.879258</span>   <span class="number">0.957336</span>  <span class="number">0.640208</span>  <span class="number">0.744337</span></span><br><span class="line"> <span class="number">0.313589</span>  <span class="number">0.866007</span>   <span class="number">0.207502</span>  <span class="number">0.480253</span>  <span class="number">0.700147</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="meta">@time</span> A*A</span><br><span class="line">  <span class="number">0.493280</span> seconds (<span class="number">2.37</span> M allocations: <span class="number">127.468</span> MiB, <span class="number">7.62</span>% gc time, <span class="number">97.77</span>% compilation time)</span><br><span class="line"><span class="number">5</span>×<span class="number">5</span> <span class="built_in">Matrix</span>&#123;<span class="built_in">Float64</span>&#125;:</span><br><span class="line"> <span class="number">0.981792</span>  <span class="number">1.3718</span>   <span class="number">1.55993</span>  <span class="number">1.22651</span>  <span class="number">1.31208</span></span><br><span class="line"> <span class="number">1.4326</span>    <span class="number">2.11323</span>  <span class="number">2.39394</span>  <span class="number">1.85024</span>  <span class="number">1.98484</span></span><br><span class="line"> <span class="number">1.04164</span>   <span class="number">1.11159</span>  <span class="number">1.53036</span>  <span class="number">1.23779</span>  <span class="number">1.20494</span></span><br><span class="line"> <span class="number">1.50815</span>   <span class="number">2.22566</span>  <span class="number">2.50318</span>  <span class="number">1.9526</span>   <span class="number">2.09605</span></span><br><span class="line"> <span class="number">0.956036</span>  <span class="number">1.9902</span>   <span class="number">1.74374</span>  <span class="number">1.3425</span>   <span class="number">1.65672</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="meta">@time</span> A*A</span><br><span class="line">  <span class="number">0.000007</span> seconds (<span class="number">1</span> allocation: <span class="number">288</span> bytes)</span><br><span class="line"><span class="number">5</span>×<span class="number">5</span> <span class="built_in">Matrix</span>&#123;<span class="built_in">Float64</span>&#125;:</span><br><span class="line"> <span class="number">0.981792</span>  <span class="number">1.3718</span>   <span class="number">1.55993</span>  <span class="number">1.22651</span>  <span class="number">1.31208</span></span><br><span class="line"> <span class="number">1.4326</span>    <span class="number">2.11323</span>  <span class="number">2.39394</span>  <span class="number">1.85024</span>  <span class="number">1.98484</span></span><br><span class="line"> <span class="number">1.04164</span>   <span class="number">1.11159</span>  <span class="number">1.53036</span>  <span class="number">1.23779</span>  <span class="number">1.20494</span></span><br><span class="line"> <span class="number">1.50815</span>   <span class="number">2.22566</span>  <span class="number">2.50318</span>  <span class="number">1.9526</span>   <span class="number">2.09605</span></span><br><span class="line"> <span class="number">0.956036</span>  <span class="number">1.9902</span>   <span class="number">1.74374</span>  <span class="number">1.3425</span>   <span class="number">1.65672</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="meta">@timev</span> A*A</span><br><span class="line">  <span class="number">0.000044</span> seconds (<span class="number">1</span> allocation: <span class="number">288</span> bytes)</span><br><span class="line">elapsed time (ns): <span class="number">44371</span></span><br><span class="line">bytes allocated:   <span class="number">288</span></span><br><span class="line">pool allocs:       <span class="number">1</span></span><br><span class="line"><span class="number">5</span>×<span class="number">5</span> <span class="built_in">Matrix</span>&#123;<span class="built_in">Float64</span>&#125;:</span><br><span class="line"> <span class="number">0.981792</span>  <span class="number">1.3718</span>   <span class="number">1.55993</span>  <span class="number">1.22651</span>  <span class="number">1.31208</span></span><br><span class="line"> <span class="number">1.4326</span>    <span class="number">2.11323</span>  <span class="number">2.39394</span>  <span class="number">1.85024</span>  <span class="number">1.98484</span></span><br><span class="line"> <span class="number">1.04164</span>   <span class="number">1.11159</span>  <span class="number">1.53036</span>  <span class="number">1.23779</span>  <span class="number">1.20494</span></span><br><span class="line"> <span class="number">1.50815</span>   <span class="number">2.22566</span>  <span class="number">2.50318</span>  <span class="number">1.9526</span>   <span class="number">2.09605</span></span><br><span class="line"> <span class="number">0.956036</span>  <span class="number">1.9902</span>   <span class="number">1.74374</span>  <span class="number">1.3425</span>   <span class="number">1.65672</span></span><br></pre></td></tr></table></figure><ul><li>編譯器最佳化的常數傳遞（constant propagation）支援關鍵字參數（keyword arguments）。（#35976）</li></ul><h2 id="新功能">新功能</h2><h3 id="新增標準函式庫">新增標準函式庫</h3><p>在 v1.6 中，新增了兩個標準函式庫：TOML、Downloads。TOML 可以被用來解析 <code>.toml</code> 檔案。Downloads 提供了跨平台、多協定、行程內的下載功能，並使用 libcurl。它取代了原先的 <code>Base.download</code>，並提供 <code>Downloads.download</code> 介面。</p><h3 id="陣列與其他集合">陣列與其他集合</h3><p>新功能 <code>spdiagm([m, n,] v::AbstractVector)</code> 支援由 <code>v</code> 作為對角線來生成稀疏矩陣的對角矩陣，其呼叫 <code>spdiagm([m, n,] 0 =&gt; v)</code>，與稠密矩陣的 <code>diagm</code> 有對等的功能。（#37684）</p><p>新增 <code>Iterators.map</code>，也新增了 <code>Iterators.map(f, iterators...)</code> 的語法，簡化了 <code>(f(args...) for args in zip(iterators...))</code>。（#34352）</p><p>新功能 <code>insorted</code> 來確定一個集合容器中的元素是否是已經排序的。（#37490）</p><h3 id="數值計算">數值計算</h3><p>現在 <code>isapprox(x,y)</code> 支援 <code>norm</code> 這個關鍵字參數，來計算兩者的範數（norm）是否接近，也支援非陣列的 <code>x</code> 跟 <code>y</code> 參數。（#35883）</p><p>新功能 <code>LinearAlgebra.BLAS.get_num_threads()</code> 可以取得 BLAS 的執行緒數量。（#36360）</p><h4 id="平行運算">平行運算</h4><p>新功能 <code>Base.Threads.foreach(f, channel::Channel)</code> 支援多執行緒的 <code>Channel</code> 消耗。（#34543）</p><h4 id="其他">其他</h4><p>新增 <code>parse(::Type{UUID}, ::AbstractString)</code> 方法。</p><h2 id="新支援">新支援</h2><h3 id="陣列與其他集合-2">陣列與其他集合</h3><p>現在 <code>append!(vector, collections...)</code> 及 <code>prepend!(vector, collections...)</code> 方法都支援多個集合容器（collections）。（#36227）</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; a = rand(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line">julia&gt; b = [rand(<span class="number">10</span>), rand(<span class="number">20</span>)]</span><br><span class="line"><span class="number">2</span>-element <span class="built_in">Vector</span>&#123;<span class="built_in">Vector</span>&#123;<span class="built_in">Float64</span>&#125;&#125;:</span><br><span class="line"> [<span class="number">0.4274732922161779</span>, <span class="number">0.10937373891763369</span>, <span class="number">0.5654187553795427</span>, <span class="number">0.9906034331313402</span>, <span class="number">0.013972810993100104</span>, <span class="number">0.9124867642867496</span>, <span class="number">0.7026800717485269</span>, <span class="number">0.6919261624138788</span>, <span class="number">0.6637048817292697</span>, <span class="number">0.6751652383396913</span>]</span><br><span class="line"> [<span class="number">0.2195233748657055</span>, <span class="number">0.8611811964575287</span>, <span class="number">0.5207507597979009</span>, <span class="number">0.8922624660959817</span>, <span class="number">0.6598412164100307</span>, <span class="number">0.5197210219304949</span>, <span class="number">0.6657337471786067</span>, <span class="number">0.20595020263413644</span>, <span class="number">0.9792308729299666</span>, <span class="number">0.20457512725986682</span>, <span class="number">0.3964379369245947</span>, <span class="number">0.9492425568657055</span>, <span class="number">0.4298200055489003</span>, <span class="number">0.38595130501514974</span>, <span class="number">0.9106291942539788</span>, <span class="number">0.9979619358373388</span>, <span class="number">0.05452976209666782</span>, <span class="number">0.7036395889179883</span>, <span class="number">0.5909806544881551</span>, <span class="number">0.26667970632080373</span>]</span><br><span class="line"></span><br><span class="line">julia&gt; append!(a, b...)</span><br><span class="line"><span class="number">40</span>-element <span class="built_in">Vector</span>&#123;<span class="built_in">Float64</span>&#125;:</span><br><span class="line"> <span class="number">0.5841916683652206</span></span><br><span class="line"> <span class="number">0.054243862919656216</span></span><br><span class="line"> <span class="number">0.5576101120027053</span></span><br><span class="line"> <span class="number">0.3870928566144738</span></span><br><span class="line"> <span class="number">0.1998130659845283</span></span><br><span class="line"> ...</span><br></pre></td></tr></table></figure><p>轉置（<code>adjoint!(::*Triangular)</code>、<code>transpose!(::*Triangular)</code>）一個上（下）三角矩陣 <code>*Triangular</code> 會回傳相反的三角矩陣。套件中含有方法，像是 <code>Adjoint{&lt;:Any,&lt;:LowerTriangular{&lt;:Any,&lt;:OwnMatrixType}}</code> 需要被改為 <code>UpperTriangular{&lt;:Any,&lt;:Adjoint{&lt;:Any,&lt;:OwnMatrixType}}</code>。（#38168）</p><p><code>unique(f, itr; seen=Set{T}())</code> 現在容許你宣告容器的型別。（#36280）</p><h3 id="I-O">I/O</h3><p><code>redirect_*</code> 函式現在接受 <code>devnull</code> 來拋棄所有輸出的資料，或是作為一個空的輸入來源。（#36146）</p><p><code>redirect_*</code> 函式現在可以呼叫 <code>IOContext</code> 物件。（#36688）</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/04/04/julia-v1-6-release/</id>
    <link href="https://yuehhua.github.io/blog/2021/04/04/julia-v1-6-release/"/>
    <published>2021-04-03T17:04:33.000Z</published>
    <summary>
      <![CDATA[<!-- toc -->
<p>在 v1.6 版中，Julia 有大幅度的效能提昇，效能提昇的部份著重在於預編譯（precompilation）以及編譯的效能改進，而 v1.6 版將成為下一個長期支援（long-term support, LTS）的版本。</p>
<p>根據<a href="https://julialang.org/blog/2021/03/julia-1.6-highlights/">官方部落格</a>，本次版本更新引進了眾多新的技術，包含 parallel precompilation、消除重複編譯、降低編譯器的 latency、加速二進位檔案的載入，以及改善 stacktrace 的格式等等重大的功能。那我們就來詳細看看有哪些更新吧！</p>]]>
    </summary>
    <title>Julia v1.6 釋出！新功能介紹！</title>
    <updated>2026-09-02T04:02:26.116Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<a data-fancybox data-src="/images/covers/Nyvq2juw4_o-unsplash.jpg"><img src="/images/covers/Nyvq2juw4_o-unsplash.jpg" alt="" /></a><!-- toc --><p>Julia 作為一個新興的語言，他有眾多的優點，他不僅執行快速，而且像 python 一樣，是動態語言非常容易上手好寫。Julia 本身的套件管理系統也具有足夠高的再現性（reproducible），並且自動安裝內含編譯過的函式庫檔案。作為一個泛用性以及開源的程式語言，這些特色帶來許多優點。</p><p>隨著今日科學社群不斷的擴大，科學計算與數值計算相關的軟體也不斷的發展，Julia 作為一個以科學計算為目的的語言，不僅融合了現代的科學計算工具、新穎的演算法、優異的性能，以及平易近人的語法。由於 Julia 優異的語法設計，搭配多重分派以及型別系統，讓獨到的即時編譯（just-in-time compilation）變得自然，型別推斷讓 Julia 的速度得以提升。</p><span id="more"></span><h2 id="現代化">現代化</h2><p>科學計算有長遠的歷史。在歷史悠久的軟體當中很難整合現代的功能，例如 GPU 或 TPU 支援，有的甚至連平行處理都可能沒有。Julia 語言挾著年輕的優勢，在建立微分方程套件時，也整合了 CUDA 的運算。語言的可組合性讓各式各樣的數值計算方法以及模型，可以輕鬆的支援 GPU 以及 TPU 的運算。在同樣的編譯器架構下，相同的原始碼可以被編譯為不同硬體的版本。</p><p>優秀的套件管理系統也是近代才有的產物，他可以確保套件的安裝與移除是完整的，並且套件不會有遺失的狀況。Python 的 Anaconda 也是優秀的套件管理系統。Julia 背後支援的 BinaryBuilder.jl，可以整合套件中需要使用到的動態函式庫，以及一些編譯好的執行檔。因此，目前 Julia 的套件，像是 CUDA.jl，所需要的函式庫，例如 CUDA 函式庫，就可以藉由 Julia 的套件管理系統安裝到。使用 CUDA.jl 時，他會自動地而且惰性地（lazy）安裝相對應的 CUDA 函式庫。</p><h2 id="機器學習">機器學習</h2><p>Python 是目前最大的機器學習語言，他擁有 TensorFlow 以及 PyTorch 兩大深度學習框架，分別由 Google 及 Facebook 維護。然而 Julia 也在深度學習套件上有著不輸 Python 的特色。深度學習框架的一個核心引擎是自動微分，我們訓練模型都需要倒傳遞演算法（backpropagation），倒傳遞演算法計算的則是模型的微分式，面對各式各樣不同的深度學習模型，我們不可能為每一個深度學習模型量身訂製一套他們自己的微分式，所以我們勢必要讓電腦知道怎麼自動推論模型的微分式。Zygote.jl 就是在 Julia 上非常知名的自動微分推論引擎，在開發者積極的開發下，Julia 的自動微分推論引擎已經成爲語言的第一支援，由於語言本身支援的自動微分引擎可以微分任何東西。如此徹底的實現了 LeCun 講的可微分程式設計（differentiable programming）。如此，這樣子的系統在機器學習領域佔有一席之地。</p><p>Flux.jl 是在 Julia 上使用 Zygote.jl 作為自動微分引擎的深度學習框架，其中的影像辨識及自然語言處理模型都已經使用這個自動微分引擎自動推論。Flux.jl 是個百分之百純 Julia 寫成的深度學習框架，它支援高階的抽象，以及低階的 API，也就是，要像 Keras 那樣一層一層定義網路架構，或是自己從底層寫起，定義 loss function、定義運算，甚至是梯度或是 normalization 都是可行的。套件裡的函式都可以直接跟語言相容，所以 Flux.jl 讓開發者有非常大的自由度以及彈性可以自由發揮。本身支援 CUDA，但不依賴 CUDA C 函式庫，由 Julia 社群提供的 CUDA 編譯器，可以直接將 Julia 的原始碼編譯為虛擬組合語言並且送至 GPU 執行，所以可以利用 Julia 語言本身的編譯能力最佳化 CUDA 的執行效率。</p><p>不只深度學習，在經典的機器學習套件，Julia 有 MLJ 這個由英國的 The Alan Turing Institute 所開發及維護的機器學習套件，目前所支援的模型數在一百五十個以上，足以覆蓋一般商業及工程的應用場景。MLJ 也支援 scikit-learn 套件中的模型在 Julia 使用，</p><p>Turing.jl 是 Julia 中支援機率程式設計（probabilistic programming）的知名套件。不只可以自己用機率搭建機器學習模型，還可以訓練機率性深度學習網路，或稱貝氏深度學習（Bayesian deep learning）。目前此套件也跟 Flux 以及 MLJ 整合，可以結合各方所長，打造更加穩固而可信的模型與系統。</p><h2 id="資料科學">資料科學</h2><p>有了充足的機器學習基礎，資料科學家的得力工具更是不可或缺。</p><p>DataFrames.jl 提供了對應於 pandas 的功能，能夠操作表格類（tabular）的資料，並搭配 Statistics 或 StatsBase 提供多樣的統計功能，可以方便地對資料做抽樣、分割、選取欄位，甚至是樞紐分析。如果需要處理時間序列相關的資料，只要搭配 Julia 語言本身的 Dates 及 TimeZones，便可以方便地在 DataFrame 物件中操作時間序列資料。</p><p>資料的讀取則由不同的套件負責。CSV.jl 支援 .csv、.tsv 等等相關檔案的讀取，Excel 檔案則由 ExcelFiles.jl 或是 XLSX.jl 負責。不同的讀檔都可以得到 DataFrame 物件，處理完之後儲存成各自的檔案格式中。</p><p>Gadfly.jl 支援非常優秀的繪圖功能，不僅有 garmmar of graphics 的語法設計，並且繪圖類似於 R 的 ggplot2。Plots.jl 支援眾多的繪圖引擎後端，包含 GR、plotly、pyplot、UnicodePlots 等等繪圖引擎。可以繪製的圖形種類眾多，搭配上 StatsPlots.jl 或是 GraphPlot.jl，更可以支援 graph 物件的繪製。</p><p>CSV.jl 也跟資料庫整合地非常好，有 Tables.jl 作為介面，並且可以將資料流導向 SQLite、MySQL 或是 PostgresQL 等等資料庫系統。如果希望在資料流水線上對資料做處理，TableOperations.jl 可以提供相關的功能，在資料流過時做即時地處理。</p><h2 id="微分方程">微分方程</h2><p>Julia 也有號稱地表最強大的微分方程套件 DifferentialEquations.jl，支援多種微分方程的計算，包含常微分方程（ordinary differential equations, ODEs）、偏微分方程（partial differential equations, PDEs）、隨機微分方程（Stochastic ordinary differential equations, SDEs）、微分代數方程（Differential algebraic equations, DAEs）等等。同時比較了不同語言的微分方程套件，包含 MATLAB, R, Julia, Python, C, Mathematica, Maple 和 Fortran，Julia 的 DifferentialEquations.jl 有全方位優異的表現。</p><h2 id="科學機器學習">科學機器學習</h2><p>由於近年來深度學習及機器學習的興起，Julia 也整合了經典微分方程及深度學習的計算，基於神經微分方程（neural ODE），將所有種類的微分方程以及深度學習模型做了整合，則有了科學機器學習（scientific machine learning, SciML）的新領域。此領域以及相關的套件工具是其他語言社群所沒有的，這同時也彰顯了 Julia 一個非常重要的語言特性：可組合性的威力。</p><p>科學機器學習是結合機器學習或深度學習與經典的微分方程的方法。由於目前科學探索還有部分領域，還有未知的部份是尚未可以用微分方程求解的，所以這部分可以先用深度學習或是機器學習模型加以取代，待日後研究更進一步。如此，整合機器學習或是深度學習的科學計算方法，成為了科學機器學習的主軸，並且以神經微分方程為核心出發，攻克各個科學的未知領域。</p><h2 id="作業研究及最佳化">作業研究及最佳化</h2><p>JuMP.jl 包含眾多作業研究及最佳化方法的套件，裡頭支援的方法包含一般的線性規劃（linear programming）、混和整數規劃（mixed-integer programming）、二階錐規劃（second-order conic programming）、半定性規劃（semidefinite programming）以及非線性規劃（nonlinear programming）等等。更有 Changhyun Kwon 教授幫這個套件寫書，介紹作業研究這個領域，並且書上的範例為 Julia 程式碼。</p><h2 id="Julia-將成為未來科學計算與人工智慧的計算引擎">Julia 將成為未來科學計算與人工智慧的計算引擎</h2><p>以上述的科學計算與機器學習套件為基礎，在 Julia 這個可組合性極佳的語言底下，各個套件可以發揮其 1+1 &gt; 2 的能力，不同套件之間可以無縫地整合，不如其他語言的套件之間會有不同的界面或是隔閡存在。在極具彈性的語法跟極佳的效能下，能夠發揮硬體最大的極限。可以想見，Julia 將成為未來科學計算與人工智慧的計算引擎！</p><p>除了上述跟學術或是理論相關的套件以外，Julia 也有非常優秀的 MVC 架構的網站框架 – Genie.jl，有 routing 機制，頁面呈現有模板語言（template language），模型與資料庫有物件關係對映（object relational mapping，ORM），可以寫 RESTful API 或是大型網站。在強大的計算模型的基礎之上，也可以提供網頁的應用程式。</p><p>目前已經有非常多世界頂尖大學以及研究所在教授 Julia，可以參考<a href="https://julialang.org/learning/">官網頁面</a>最底下。在自動控制與最佳化理論領域相當知名的 Stephen Boyd 教授，與 Lieven Vandenberghe 教授，所共同撰寫的 Introduction to Applied Linear Algebra – Vectors, Matrices, and Least Squares，更是將範例程式碼從 MATLAB 轉成 Julia。目前正在從人才端補足 Julia 程式設計師不足的狀態。</p><p>目前 Julia 語言已經穩定，而相關套件也正在趨於完善，想必未來能帶給這個世界更加精彩的作品！</p><!-- <script>window.onload = function(){$.fancybox.open([{src  : '/images/covers/Nyvq2juw4_o-unsplash.jpg'}], {loop : false});};</script> -->]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/03/28/the-future-of-julialang/</id>
    <link href="https://yuehhua.github.io/blog/2021/03/28/the-future-of-julialang/"/>
    <published>2021-03-28T14:51:51.000Z</published>
    <summary>
      <![CDATA[<a data-fancybox data-src="/images/covers/Nyvq2juw4_o-unsplash.jpg">
	<img src="/images/covers/Nyvq2juw4_o-unsplash.jpg" alt="" />
</a>
<!-- toc -->
<p>Julia 作為一個新興的語言，他有眾多的優點，他不僅執行快速，而且像 python 一樣，是動態語言非常容易上手好寫。Julia 本身的套件管理系統也具有足夠高的再現性（reproducible），並且自動安裝內含編譯過的函式庫檔案。作為一個泛用性以及開源的程式語言，這些特色帶來許多優點。</p>
<p>隨著今日科學社群不斷的擴大，科學計算與數值計算相關的軟體也不斷的發展，Julia 作為一個以科學計算為目的的語言，不僅融合了現代的科學計算工具、新穎的演算法、優異的性能，以及平易近人的語法。由於 Julia 優異的語法設計，搭配多重分派以及型別系統，讓獨到的即時編譯（just-in-time compilation）變得自然，型別推斷讓 Julia 的速度得以提升。</p>]]>
    </summary>
    <title>Julia 語言的未來性</title>
    <updated>2026-09-02T04:02:26.115Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>對於 Julia 比較不熟悉的使用者或開發者，要怎麼定函式的參數型別是一個大學問。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> average(xs)</span><br><span class="line">    <span class="keyword">return</span> sum(xs)/length(xs)</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>例如以上的 <code>average</code> 函式，<code>xs</code> 要定成什麼樣的型別比較好？</p><p>可能有人會以他所測試的情境去定：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; xs = rand(<span class="number">10</span>)</span><br><span class="line"><span class="number">10</span>-element <span class="built_in">Array</span>&#123;<span class="built_in">Float64</span>,<span class="number">1</span>&#125;:</span><br><span class="line"> <span class="number">0.8261912048684596</span></span><br><span class="line"> <span class="number">0.4466692353358077</span></span><br><span class="line"> <span class="number">0.6337754306737924</span></span><br><span class="line"> <span class="number">0.1297961522759261</span></span><br><span class="line"> <span class="number">0.4699412442087936</span></span><br><span class="line"> <span class="number">0.6194816490253636</span></span><br><span class="line"> <span class="number">0.8258926319092839</span></span><br><span class="line"> <span class="number">0.05094839501664228</span></span><br><span class="line"> <span class="number">0.21008570113108194</span></span><br><span class="line"> <span class="number">0.16250331333741275</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="keyword">function</span> average(xs::<span class="built_in">Array</span>&#123;<span class="built_in">Float64</span>,<span class="number">1</span>&#125;)</span><br><span class="line">           <span class="keyword">return</span> sum(xs)/length(xs)</span><br><span class="line">       <span class="keyword">end</span></span><br><span class="line">average (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br><span class="line"></span><br><span class="line">julia&gt; average(xs)</span><br><span class="line"><span class="number">0.4375284957782564</span></span><br></pre></td></tr></table></figure><span id="more"></span><p>這樣當然是沒有錯，但是會過於狹隘。這樣定出來只有一維矩陣可以適用，而且裡頭的元素還必須是 <code>Float64</code> 型別。</p><h2 id="思考廣義化">思考廣義化</h2><p>我們能不能讓所有的陣列都適用？那就可以改成這樣：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> average(xs::<span class="built_in">AbstractArray</span>&#123;<span class="built_in">Float64</span>&#125;)</span><br><span class="line">    <span class="keyword">return</span> sum(xs)/length(xs)</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>可是這樣又限制了元素的型別，像是 <code>Float32</code> 或是無理數 <code>Irrational</code> 就不適用。</p><p>如果我們要將他廣義化到所有的整數跟浮點數都適用，也支援無理數。</p><p>那麼我們可以考慮支援實數 <code>Real</code>，可以寫成以下的樣子：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> average(xs::<span class="built_in">AbstractArray</span>&#123;&lt;:<span class="built_in">Real</span>&#125;)</span><br><span class="line">    <span class="keyword">return</span> sum(xs)/length(xs)</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>或是也可以考慮將他參數化：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> average(xs::<span class="built_in">AbstractArray</span>&#123;T&#125;) <span class="keyword">where</span> &#123;T&lt;:<span class="built_in">Real</span>&#125;</span><br><span class="line">    <span class="keyword">return</span> sum(xs)/length(xs)</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>這兩種寫法所編譯出來的 method instance 是一樣的。</p><p>這兩種寫法差異在於，如果將他參數化，開發者有機會將參數型別 <code>T</code> 取出來使用。</p><h2 id="建議">建議</h2><p>為了避免大家寫出來的函式太過於狹義，所以在這邊給出一些建議。</p><p>如果要支援的型別是所有整數，那麼可以考慮使用 <code>Integer</code>，它可以支援 <code>Bool</code>、<code>Int64</code>、<code>UInt8</code> 之類的型別。</p><p>如果要支援的型別是所有的整數以及浮點數等等的，那麼可以考慮使用 <code>Real</code>，它可以支援 <code>Float64</code>、<code>Irrational</code> 等等的型別。</p><p>如果還想要支援複數 <code>Complex</code>，那麼就直接使用數字 <code>Number</code> 吧！</p><h2 id="思考點">思考點</h2><p>那至於要支援什麼樣的型別以及他的範疇，這是個很好的問題。</p><p>那就要問在你的函式當中所用到的函式支援哪些型別？</p><p>例如在 <code>average</code> 中有 <code>sum</code> 以及 <code>length</code> 函式。</p><p><code>sum</code> 支援包含 <code>AbstractArray</code>、iterable，甚至是 <code>AbstractRange</code>。</p><p><code>length</code> 則支援所有的陣列 <code>AbstractArray</code>、集合 <code>Set</code>、字典 <code>Dict</code>、所有字串 <code>AbstractString</code> 等等的。</p><p>接下來要思考 <code>average</code> 所要提供的功能是什麼？他的語義是什麼？</p><p>就字面上的意義而言，他要提供的是「某個集合體的平均」。這時候就可以去定義要支援什麼樣的集合體，以及支援集合體中的元素範疇是什麼。</p><p>最後就可以決定這個函式的型別參數應該是什麼了。</p><h2 id="自定義型別">自定義型別</h2><p>如果有人想要自行設計自己的型別，並且這個型別支援 <code>sum</code> 及 <code>length</code>，那理論上，這個型別就自動支援 <code>average</code>。</p><p>要讓其他人去自行定義型別，並且自動支援 <code>average</code>，為了避免將這個函式綁得太死，那就乾脆不定義型別。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> average(xs)</span><br><span class="line">    <span class="keyword">return</span> sum(xs)/length(xs)</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>這樣是可以的。</p><p>有沒有發現，與其加一堆型別將函式綁死（加法設計），不如把型別拿掉還來的更好（減法設計）。</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/03/19/use-of-numerical-type-in-parametric-functions-in-julia/</id>
    <link href="https://yuehhua.github.io/blog/2021/03/19/use-of-numerical-type-in-parametric-functions-in-julia/"/>
    <published>2021-03-19T06:21:30.000Z</published>
    <summary>
      <![CDATA[<p>對於 Julia 比較不熟悉的使用者或開發者，要怎麼定函式的參數型別是一個大學問。</p>
<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> average(xs)</span><br><span class="line">    <span class="keyword">return</span> sum(xs)/length(xs)</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure>
<p>例如以上的 <code>average</code> 函式，<code>xs</code> 要定成什麼樣的型別比較好？</p>
<p>可能有人會以他所測試的情境去定：</p>
<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; xs = rand(<span class="number">10</span>)</span><br><span class="line"><span class="number">10</span>-element <span class="built_in">Array</span>&#123;<span class="built_in">Float64</span>,<span class="number">1</span>&#125;:</span><br><span class="line"> <span class="number">0.8261912048684596</span></span><br><span class="line"> <span class="number">0.4466692353358077</span></span><br><span class="line"> <span class="number">0.6337754306737924</span></span><br><span class="line"> <span class="number">0.1297961522759261</span></span><br><span class="line"> <span class="number">0.4699412442087936</span></span><br><span class="line"> <span class="number">0.6194816490253636</span></span><br><span class="line"> <span class="number">0.8258926319092839</span></span><br><span class="line"> <span class="number">0.05094839501664228</span></span><br><span class="line"> <span class="number">0.21008570113108194</span></span><br><span class="line"> <span class="number">0.16250331333741275</span></span><br><span class="line"></span><br><span class="line">julia&gt; <span class="keyword">function</span> average(xs::<span class="built_in">Array</span>&#123;<span class="built_in">Float64</span>,<span class="number">1</span>&#125;)</span><br><span class="line">           <span class="keyword">return</span> sum(xs)/length(xs)</span><br><span class="line">       <span class="keyword">end</span></span><br><span class="line">average (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br><span class="line"></span><br><span class="line">julia&gt; average(xs)</span><br><span class="line"><span class="number">0.4375284957782564</span></span><br></pre></td></tr></table></figure>]]>
    </summary>
    <title>在 Julia 的 parametric methods 使用數值型別（numerical type）</title>
    <updated>2021-03-28T05:33:46.442Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> Foo</span><br><span class="line"></span><br><span class="line"><span class="comment"># Some code here</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> __init__()</span><br><span class="line">    <span class="comment"># Some code here too</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>是否曾經疑惑過寫在 module 中的程式碼會在何時被載入呢？</p><span id="more"></span><p>事實上，解答如下囉！</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> Foo</span><br><span class="line"></span><br><span class="line">println(<span class="string">&quot;code here will be printed when you build this module&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> __init__()</span><br><span class="line">    println(<span class="string">&quot;code here will be printed when you using this module&quot;</span>)</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/01/14/julia-module-code-loading/</id>
    <link href="https://yuehhua.github.io/blog/2021/01/14/julia-module-code-loading/"/>
    <published>2021-01-14T03:50:26.000Z</published>
    <summary>
      <![CDATA[<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">module</span> Foo</span><br><span class="line"></span><br><span class="line"><span class="comment"># Some code here</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> __init__()</span><br><span class="line">    <span class="comment"># Some code here too</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure>
<p>是否曾經疑惑過寫在 module 中的程式碼會在何時被載入呢？</p>]]>
    </summary>
    <title>Julia冷知識-你知道模組中的程式碼是何時被執行的嗎</title>
    <updated>2021-01-14T03:50:26.514Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>依函式分派（dispatch on function）算是在 Julia 語言中相當常見的一個技巧，它依賴 Julia 的多重分派機制（multiple dispatch），可以依據不同的函式有不一樣的行為。</p><h2 id="舉例">舉例</h2><p>在資料分析或是資料庫分析中，常常會需要對資料欄位進行聚合運算，像是加總的 <code>sum</code>、平均的 <code>avg</code> 或是計數的 <code>count</code>。他們都是用同一個欄位的資料，聚合成一個值輸出。當我們需要將資料相加時，我們會寫出以下的程式碼：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">a = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>]</span><br><span class="line">sum(a)</span><br></pre></td></tr></table></figure><p>這看起來很直觀，但往往在資料庫的設計當中，只會設計一些常用到的聚合函式（aggregate function）。</p><p>那麼有沒有一個方式可以得到一個比較廣義的聚合函式呢？</p><span id="more"></span><p>假設我們想要定一個函式叫作 <code>aggregate</code>，其實 <code>sum</code> 就是利用加法（<code>+</code>）來做聚合，所以我們可以寫成這樣：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> aggregate(op, data)</span><br><span class="line">    y = data[<span class="number">1</span>]</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">2</span>:length(data)</span><br><span class="line">        y = op(y, data[i])</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">    y</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>如此一來，下面兩者的結果會一樣。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">aggregate(+, a) == sum(a)</span><br></pre></td></tr></table></figure><p>那如果我們需要一個將所有資料相乘（<code>*</code>）的聚合方式，那我們只需要改寫成以下的方式。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">aggregate(*, a) == prod(a)</span><br></pre></td></tr></table></figure><p>這樣感覺超棒的！</p><p>不過這是一般函數式程式設計的寫法，這跟 <code>reduce(*, data)</code> 沒什麼兩樣。</p><h2 id="用分派來處理特例">用分派來處理特例</h2><p>接著，再來實作一個簡單的 <code>aggregate(count, data)</code>，如果你直接呼叫 <code>aggregate(count, a)</code> 是會出錯的。</p><p>然而 <code>count</code> 的計算其實是需要重新實作的，所以就不能再走上面的方式了。</p><p>要依據參數的不同，執行不同的方法就是多型（polymorphism）的真諦。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> aggregate(op::typeof(count), data)</span><br><span class="line">    y = <span class="number">1</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">2</span>:length(data)</span><br><span class="line">        y += <span class="number">1</span></span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">    y</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>或是直接取資料的長度也可以。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">aggregate(op::typeof(count), data) = length(data)</span><br></pre></td></tr></table></figure><h2 id="統計常用函式">統計常用函式</h2><p>這時候如果我們要實作的是一些統計上常用的函式，像是平均、中位數或眾數，就遇到困難了。這邊示範平均的聚合函式，如果像以下的方式寫會發生錯誤：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">aggregate(mean, a) != mean(a)</span><br></pre></td></tr></table></figure><p>因為在這樣的計算之下，它會變成第一項先跟第二項取平均，再跟第三項取平均，再跟第四項取平均，以此類推。</p><p>這時候就要將 <code>mean</code> 的實作分開定義。</p><p>由於 <code>mean</code> 的行為可以想成是先將資料加總，然後除以資料的數量，所以我們可以計算 <code>aggregate(+, data)</code> 及 <code>aggregate(count, data)</code>，並且將他們兩者相除。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> aggregate(op::typeof(mean), data)</span><br><span class="line">    aggregate(+, data) / aggregate(count, data)</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>如此一來，就可以依據不同的函式名稱來做分派了！</p><h2 id="原理">原理</h2><p>由於在 Julia 中萬物都是物件，即使是函式也如同物件一樣是有型別的，可以取 <code>typeof</code>，而函式 <code>foo</code> 的型別就是 <code>typeof(foo)</code>。</p><p>因此，可以將函式 <code>foo</code> 視為實體，函式型別 <code>typeof(foo)</code> 視為型別。</p><p>利用一般的多重分派就可以達成 <code>aggregate(op::typeof(mean), data)</code> 囉！</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/01/09/dispatch-on-function/</id>
    <link href="https://yuehhua.github.io/blog/2021/01/09/dispatch-on-function/"/>
    <published>2021-01-09T03:51:45.000Z</published>
    <summary>
      <![CDATA[<p>依函式分派（dispatch on function）算是在 Julia 語言中相當常見的一個技巧，它依賴 Julia 的多重分派機制（multiple dispatch），可以依據不同的函式有不一樣的行為。</p>
<h2 id="舉例">舉例</h2>
<p>在資料分析或是資料庫分析中，常常會需要對資料欄位進行聚合運算，像是加總的 <code>sum</code>、平均的 <code>avg</code> 或是計數的 <code>count</code>。他們都是用同一個欄位的資料，聚合成一個值輸出。當我們需要將資料相加時，我們會寫出以下的程式碼：</p>
<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">a = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>]</span><br><span class="line">sum(a)</span><br></pre></td></tr></table></figure>
<p>這看起來很直觀，但往往在資料庫的設計當中，只會設計一些常用到的聚合函式（aggregate function）。</p>
<p>那麼有沒有一個方式可以得到一個比較廣義的聚合函式呢？</p>]]>
    </summary>
    <title>依函式分派（dispatch on function）</title>
    <updated>2021-01-09T03:52:59.820Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>依型別分派（dispatch on types）算是在 Julia 語言中相當常見的一個技巧，它依賴 Julia 的多重分派機制（multiple dispatch），可以依據不同的型別有不一樣的行為。</p><p>依據不同的型別有不同的行為，而不是實體。直觀上看起來會有點像傳統物件導向當中的 class method，不過在 Julia 當中還有更多用途。</p><span id="more"></span><h2 id="Convert">Convert</h2><p>在 Julia 的 Base 中有許多應用到這樣技巧的例子，這邊就舉 <code>convert</code> 為例。</p><p><code>convert</code> 是一個轉換函式，它可以將特定物件轉換成特定的型別，所以物件跟型別就分別是它的參數。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">convert(<span class="built_in">Char</span>, <span class="number">10</span>)</span><br></pre></td></tr></table></figure><p>這樣可以將 <code>10</code> 轉換成一個字元的型別，就會變成 <code>'\n'</code>。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">convert(<span class="built_in">Array</span>&#123;<span class="built_in">Float64</span>&#125;, <span class="built_in">Any</span>[<span class="number">1</span> <span class="number">2</span> <span class="number">3</span>; <span class="number">4</span> <span class="number">5</span> <span class="number">6</span>])</span><br></pre></td></tr></table></figure><p>或是一個將裝有 <code>Any</code> 型別元素的矩陣，轉成 <code>Float64</code> 型別元素的矩陣。</p><p>以上的實作大概會類似：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> convert(T::<span class="built_in">Type</span>&#123;<span class="built_in">Char</span>&#125;, val)</span><br><span class="line">    T(val)</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>基本上會試圖呼叫該型別的建構子，而第一個參數上也會加上 <code>Type{...}</code> 的型別。</p><h2 id="Read">Read</h2><p>或是我們也可以在讀取二進制資料當中發現這樣的模式。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">io = <span class="built_in">IOBuffer</span>(<span class="string">&quot;JuliaLang is the best.&quot;</span>)</span><br><span class="line">read(io, <span class="built_in">Char</span>)</span><br></pre></td></tr></table></figure><p>在讀取 <code>IOBuffer</code> 的二進制資料當中，可以將資料解析成 <code>Char</code> 的型別。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">read(io, <span class="built_in">String</span>)</span><br></pre></td></tr></table></figure><p>或是解析成 <code>String</code> 的型別。</p><p>在這邊我們看到的都是將型別作為參數給進函式中，函式可以藉由得到的型別做不同的事情。</p><p>其中一個目的是依據型別做分派（dispatch），也就是不同的型別會對應到不同的方法實作上。</p><p><code>read(io, Char)</code> 跟 <code>read(io, String)</code> 的實作方式是截然不同的，畢竟要解析成不同的型別，方法會是不同的。</p><p>也有可能會像是 <code>convert</code> 一樣，再度利用給進來的參數。由於 Julia 的型別本身也是一個物件，呼叫型別本身也等同於呼叫型別的建構子，所以我們可以看到在 <code>convert(T::Type{Char}, val)</code> 中，呼叫 <code>T</code> 作為建構子的方式來轉換物件的型別。</p><h2 id="用在哪裡？">用在哪裡？</h2><p>這樣的技術可以被用在哪些場景呢？</p><p>通常需要傳型別到其它函式，可以用來呼叫其建構子，而函式則提供一個統一的介面，可以適用於創造物件的場景。</p><p>以下就來示範有不同種飲料被製作出來的過程吧！</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract type</span> Beverage <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> MilkTea &lt;: Beverage <span class="keyword">end</span></span><br><span class="line"><span class="keyword">struct</span> GreenTea &lt;: Beverage <span class="keyword">end</span></span><br><span class="line"><span class="keyword">struct</span> BlackTea &lt;: Beverage <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">abstract type</span> Topping <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> TapiocaBall &lt;: Topping <span class="keyword">end</span></span><br><span class="line"><span class="keyword">struct</span> Pudding &lt;: Topping <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> BubbleMilkTea &lt;: Beverage <span class="keyword">end</span></span><br><span class="line"><span class="keyword">struct</span> PuddingMilkTea &lt;: Beverage <span class="keyword">end</span></span><br><span class="line"><span class="keyword">struct</span> BubbleGreenTea &lt;: Beverage <span class="keyword">end</span></span><br><span class="line"><span class="keyword">struct</span> BubbleBlackTea &lt;: Beverage <span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>這邊定義了奶茶、綠茶及紅茶幾種飲料，然後還可以對飲料加料，加料之後的飲料就會變成其他種的飲料。</p><p>接下來就可以來決定加什麼料會變成什麼樣的飲料。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mix(::<span class="built_in">Type</span>&#123;MilkTea&#125;, ::<span class="built_in">Type</span>&#123;TapiocaBall&#125;) = BubbleMilkTea()</span><br></pre></td></tr></table></figure><p>像是把奶茶跟波霸加在一起，就變成了波霸奶茶。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mix(::<span class="built_in">Type</span>&#123;MilkTea&#125;, ::<span class="built_in">Type</span>&#123;Pudding&#125;) = PuddingMilkTea()</span><br></pre></td></tr></table></figure><p>如果把奶茶跟布丁加在一起就變成布丁奶茶囉~~</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mix(::<span class="built_in">Type</span>&#123;GreenTea&#125;, ::<span class="built_in">Type</span>&#123;TapiocaBall&#125;) = BubbleGreenTea()</span><br><span class="line">mix(::<span class="built_in">Type</span>&#123;BlackTea&#125;, ::<span class="built_in">Type</span>&#123;TapiocaBall&#125;) = BubbleBlackTea()</span><br></pre></td></tr></table></figure><p>我們還有賣波霸綠茶跟波霸紅茶喔！</p><p>但是有些組合沒有在菜單上，因為老闆覺得沒有在菜單上的組合喝起來很噁心，所以不打算提供，像是布丁加綠茶這種組合。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; mix(GreenTea, Pudding)</span><br><span class="line">ERROR: <span class="built_in">MethodError</span>: no method matching mix(::<span class="built_in">Type</span>&#123;GreenTea&#125;, ::<span class="built_in">Type</span>&#123;Pudding&#125;)</span><br><span class="line">Closest candidates are:</span><br><span class="line">  mix(::<span class="built_in">Type</span>&#123;MilkTea&#125;, ::<span class="built_in">Type</span>&#123;Pudding&#125;) at REPL[<span class="number">13</span>]:<span class="number">1</span></span><br><span class="line">  mix(::<span class="built_in">Type</span>&#123;GreenTea&#125;, ::<span class="built_in">Type</span>&#123;TapiocaBall&#125;) at REPL[<span class="number">14</span>]:<span class="number">1</span></span><br></pre></td></tr></table></figure><p>在這邊 <code>mix</code> 就提供了一個統一的介面來混合飲料跟加料的部份。</p><p>提供這樣單一的物件創造介面就類似於物件導向中的 factory method pattern。</p><h2 id="依參數型別分派（2021-5-24-補充）">依參數型別分派（2021.5.24 補充）</h2><p>如果有個參數化型別 <code>Foo</code>，它帶有一個型別參數 <code>K</code>。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; <span class="keyword">struct</span> Foo&#123;K&#125; <span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>如果有個函式 <code>foo</code> 想依據不同 <code>K</code> 分派，例如，當 <code>K=1</code> 時，可以回傳一個 <code>&quot;BOOM!&quot;</code>，否則就回傳 <code>K</code> 自己。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; foo(::Foo&#123;K&#125;) <span class="keyword">where</span> K = K</span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">1</span> method)</span><br><span class="line"></span><br><span class="line">julia&gt; foo(::Foo&#123;<span class="number">1</span>&#125;) = <span class="string">&quot;BOOM!&quot;</span></span><br><span class="line">foo (generic <span class="keyword">function</span> with <span class="number">2</span> methods)</span><br></pre></td></tr></table></figure><p>這樣會發現我們也可以依據 <code>K</code> 的值分派到不同的函式。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">julia&gt; foo(Foo&#123;<span class="number">1</span>&#125;())</span><br><span class="line"><span class="string">&quot;BOOM!&quot;</span></span><br><span class="line"></span><br><span class="line">julia&gt; foo(Foo&#123;<span class="number">2</span>&#125;())</span><br><span class="line"><span class="number">2</span></span><br></pre></td></tr></table></figure><h2 id="總結">總結</h2><p>我們可以發現到使用多重分派所帶來的一些好處。如果是在單一分派（single dispatch），也就是一般物件導向的語言中，他只能依據第一個參數做分派。然而，多重分派就可以考慮參數型別的排列組合去做分派，當然參數是型別也是可行的。</p><p>類似這樣的機制，也可以對應到在物件導向中的 strategy pattern，strategy pattern 是根據不同的演算法種類來做分派的，我們可以寫成像這樣：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sort(BubbleSort, xs)</span><br><span class="line">sort(Heapsort, xs)</span><br></pre></td></tr></table></figure><p>如此一來，就是一個完整的 strategy pattern 了。</p><p>最後，這邊介紹了如何利用多重分派的機制，來依據不同的型別做分派，並且做到不同的應用。</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2021/01/07/dispatch-on-types/</id>
    <link href="https://yuehhua.github.io/blog/2021/01/07/dispatch-on-types/"/>
    <published>2021-01-07T15:43:49.000Z</published>
    <summary>
      <![CDATA[<p>依型別分派（dispatch on types）算是在 Julia 語言中相當常見的一個技巧，它依賴 Julia 的多重分派機制（multiple dispatch），可以依據不同的型別有不一樣的行為。</p>
<p>依據不同的型別有不同的行為，而不是實體。直觀上看起來會有點像傳統物件導向當中的 class method，不過在 Julia 當中還有更多用途。</p>]]>
    </summary>
    <title>依型別分派（dispatch on types）</title>
    <updated>2021-05-24T15:13:56.572Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">using</span> Random</span><br><span class="line">Random.default_rng()</span><br></pre></td></tr></table></figure><p>Ref. <a href="https://discourse.julialang.org/t/how-to-get-the-current-random-seed/31640/3">How to get the current “random” seed?</a></p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2020/11/09/get-random-seed-in-julia/</id>
    <link href="https://yuehhua.github.io/blog/2020/11/09/get-random-seed-in-julia/"/>
    <published>2020-11-09T15:52:17.000Z</published>
    <summary>
      <![CDATA[<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td>]]>
    </summary>
    <title>在 Julia 取得目前的 random seed</title>
    <updated>2020-11-09T15:54:19.011Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<h2 id="安裝-Julia">安裝 Julia</h2><p>首先先確保電腦上已經有安裝 Julia 語言，沒有安裝的話可以到<a href="https://julialang.org/downloads/">官網</a>下載安裝。</p><span id="more"></span><h2 id="設定環境變數">設定環境變數</h2><p>在 Windows 環境下要將 Julia 的執行檔位置設定到環境變數 PATH 下，可以參考<a href="https://julialang.org/downloads/platform/#adding_julia_to_path_on_windows_10">這邊</a>。一般執行檔的路徑會在 <code>C:\Users\你的使用者帳號\AppData\Local\Programs\Julia 1.5.2\bin</code> 下。</p><p>我自己是 Linux 系統，所以我會建立一個捷徑到 <code>/usr/bin</code> 下。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ln</span> -s /opt/julia-1.5.2/bin/julia /usr/bin/</span><br></pre></td></tr></table></figure><h2 id="在-VS-code-上安裝-extensions">在 VS code 上安裝 extensions</h2><p>正式進到安裝 VS code extensions 的環節了。主要要安裝的是這個 Julia language support。</p><p><img src="/images/julia-ext.png" alt=""></p><p>然後這個 Markdown Julia 可以幫你在 Julia 程式碼含有 markdown 的地方標色。</p><p><img src="/images/julia-markdown.png" alt=""></p><p>Julia Formatter 可以幫你的程式碼變整齊漂亮。</p><p><img src="/images/julia-formatter.png" alt=""></p><p>裝完之後應該是可以用了。</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2020/10/31/vscode-with-julia/</id>
    <link href="https://yuehhua.github.io/blog/2020/10/31/vscode-with-julia/"/>
    <published>2020-10-31T14:52:57.000Z</published>
    <summary>
      <![CDATA[<h2 id="安裝-Julia">安裝 Julia</h2>
<p>首先先確保電腦上已經有安裝 Julia 語言，沒有安裝的話可以到<a href="https://julialang.org/downloads/">官網</a>下載安裝。</p>]]>
    </summary>
    <title>如何在 VS code 上設定 Julia</title>
    <updated>2026-09-02T04:02:26.112Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>基本上在 Julia 上跑多執行緒不太困難，在環境中先設定好執行緒的數量，或是在執行 Julia 時增加執行緒數目。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">julia --threads 4</span><br></pre></td></tr></table></figure><span id="more"></span><p>如果既有的程式碼是 for 迴圈，基本上不難改。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Threads.@threads for i = 1:1000_000</span><br><span class="line">    do something()</span><br><span class="line">end</span><br></pre></td></tr></table></figure><p>但是終究會遇到要存取同一個物件的時候，這個時候就會有 race condition。</p><p>要避免 race condition 的方式就是使用 lock。</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">results = []</span><br><span class="line">splock = Threads.SpinLock()</span><br><span class="line"></span><br><span class="line">Threads.<span class="meta">@threads</span> <span class="keyword">for</span> i = <span class="number">1</span>:<span class="number">1000_000</span></span><br><span class="line">    y = do_something()</span><br><span class="line"></span><br><span class="line">    lock(splock)</span><br><span class="line">    <span class="keyword">try</span></span><br><span class="line">        push!(results, y)</span><br><span class="line">    <span class="keyword">finally</span></span><br><span class="line">        unlock(splock)</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在迴圈中計算 <code>do_something</code>，我們想要把計算結果儲存下來，我們將他儲存在 <code>results</code> 中。<br>這時候我們必須用一個 lock 來把要存取的資源鎖住，一開始會產生一個 <code>SpinLock</code>，當程式執行到 <code>lock(splock)</code> 的時候，如果這個 lock 可以被取用，那這個執行緒就會拿這個 lock 並且進到後續的程式區塊中。如果前面有人拿了 lock，那目前這個想拿 lock 的執行緒就得等到 lock 被釋放才可以。<br>當程式執行完，<code>unlock(splock)</code> 會將 lock 給釋放掉，這個時候其他的執行緒就可以拿這個 lock 進到程式區塊中。<br>如此可以保證每次操作 <code>results</code> 物件的只能有一個執行緒，可以避免 race condition。</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2020/10/19/use-threads-lock-in-julia/</id>
    <link href="https://yuehhua.github.io/blog/2020/10/19/use-threads-lock-in-julia/"/>
    <published>2020-10-19T02:27:25.000Z</published>
    <summary>
      <![CDATA[<p>基本上在 Julia 上跑多執行緒不太困難，在環境中先設定好執行緒的數量，或是在執行 Julia 時增加執行緒數目。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">julia --threads 4</span><br></pre></td></tr></table></figure>]]>
    </summary>
    <title>在 Julia 使用多執行緒跑平行運算 - threads 及 lock 的使用</title>
    <updated>2020-10-19T02:34:12.711Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>在 Julia 中存取物件的欄位的時候，設計者會想要對於存取的過程中加上一些檢查，這個想法是來自於傳統物件導向 getter/setter 的概念。</p><p>例如，在自己設計的物件當中有兩個矩陣，這兩個矩陣可以讓使用者隨意更新，但是需要保證這兩個矩陣的維度是一致的。這個時候就需要在使用者更新矩陣的時候加入檢查，以確保兩個矩陣之間的維度是一致的，如果檢查不通過，可能會跳例外或者是不讓矩陣被更新。</p><span id="more"></span><p>那如果要在 Julia 中，存取物件時加入檢查的程式碼，要怎麼辦呢？</p><p>Julia 提供了兩個 setter 來提供設定物件的欄位：<code>setproperty!</code> 跟 <code>setfield!</code></p><p><code>setfield!</code> 是屬於內部的 API，這個不能覆寫，所以我們要用的是 <code>setproperty!</code>。</p><p><code>setproperty!</code> 的 API 可以藉由查詢文件得知：</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">setproperty!(value, name::<span class="built_in">Symbol</span>, x)</span><br></pre></td></tr></table></figure><p>也就是當你在呼叫 <code>a.b = c</code> 其實就會去呼叫 <code>setproperty!(a, :b, c)</code>。</p><p>依據上述的例子，我們可以示範以下程式碼：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">mutable struct Foo</span><br><span class="line">    A::Matrix</span><br><span class="line">    B::Matrix</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">function setproperty!(obj::Foo, name::Symbol, x)</span><br><span class="line">    if name == :A</span><br><span class="line">        if size(obj.B) == size(x)</span><br><span class="line">            setfield!(obj, name, x)</span><br><span class="line">        else</span><br><span class="line">            throw(DimensionMismatch())</span><br><span class="line">        end</span><br><span class="line">    elseif name == :B</span><br><span class="line">        if size(obj.A) == size(x)</span><br><span class="line">            setfield!(obj, name, x)</span><br><span class="line">        else</span><br><span class="line">            throw(DimensionMismatch())</span><br><span class="line">        end</span><br><span class="line">    else</span><br><span class="line">        setfield!(obj, name, x)</span><br><span class="line">    end</span><br><span class="line">end</span><br></pre></td></tr></table></figure><p>這邊有幾點需要特別注意，第一是語言中的 <code>setproperty!</code> 第一個參數是 <code>Any</code> 型別，所以第一個參數一定要指定自己的型別是什麼，不然會跟語言本身的衝突。</p><p>第二個參數吃進來的是 <code>Symbol</code> 型別，這個也要指定，不然會發生 ambiguous 的狀況。</p><p>第三個參數為了廣義，所以是 <code>Any</code> 型別。</p><p>函式裡頭要區分開不同的欄位，這邊用 if-else 處理。想要用多重分派的機制處理的也是可以，但會比較麻煩，而且用到 <code>Val()</code> 會有效能降低的現象。</p><p>通過檢查後，要真正設定物件欄位，這邊用 <code>setfield!(obj, name, x)</code> 是比較好的作法。如果呼叫 <code>obj.A = x</code>，則會去呼叫 <code>setproperty!(obj, :A, x)</code>，就會變成無限遞迴呼叫了，所以 <code>=</code> 跟 <code>setproperty!</code> 在這邊都沒辦法用。</p><p>最後，我們把要檢查的欄位都處理好之後，我們不想要動到其他的欄位設定的行為，那就讓其他的欄位都用 <code>setfield!(obj, name, x)</code> 處理掉吧！</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2020/10/12/julia-setproperty-setfield/</id>
    <link href="https://yuehhua.github.io/blog/2020/10/12/julia-setproperty-setfield/"/>
    <published>2020-10-12T03:50:07.000Z</published>
    <summary>
      <![CDATA[<p>在 Julia 中存取物件的欄位的時候，設計者會想要對於存取的過程中加上一些檢查，這個想法是來自於傳統物件導向 getter/setter 的概念。</p>
<p>例如，在自己設計的物件當中有兩個矩陣，這兩個矩陣可以讓使用者隨意更新，但是需要保證這兩個矩陣的維度是一致的。這個時候就需要在使用者更新矩陣的時候加入檢查，以確保兩個矩陣之間的維度是一致的，如果檢查不通過，可能會跳例外或者是不讓矩陣被更新。</p>]]>
    </summary>
    <title>在 Julia 對設定物件欄位增加檢查 - setproperty 與 setfield</title>
    <updated>2020-10-12T03:52:42.354Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="Statistics" scheme="https://yuehhua.github.io/blog/categories/Statistics/"/>
    <content>
      <![CDATA[<p>Maximum likelihood estimation is an essential approach to estimate parameters in statistics. It requires statistical assumptions on error pattern. I will introduce this technique with really simple statistical model - linear regression.</p><span id="more"></span><p>We usually want to infer the relationship between input and output. They can be cause and effect of a physical phenomena or some indirect relationship in social science. We always want to realize the truth about our interest. Statistical tools are the tools to help you. The relationship between input and output are formulated as a mathematical function as follow:</p><p>$$<br>y = f(x)<br>$$</p><p>A linear model is assumed in linear regression. The relationship between $x$ and $y$ is assumed to be linear and $w$ and $b$ are introduced as unknown parameters into the model. $w$ denotes the extent of $x$ contributing to $y$ while $b$ denotes an inherent bias in $y$.</p><p>$$<br>y = wx + b<br>$$</p><p>On the other side, data are collected in pair of $(x^i, y^i)$. The superscript $n$ denotes the index for each sample.</p><p>$$<br>\mathcal{D} = {(x^1, y^1), (x^2, y^2), \cdots, (x^n, y^n)}<br>$$</p><p>The maximum likelihood estimation starts from the likelihood function. A likelihood function quantified the likelihood of data generation from the model we specified. That is, how likely the sample $(x_i, y_i)$ are generated from the model. All parameters are reduced into $\theta$. Precisely, $\mathcal{L}(\theta \mid \mathcal{D})$ represents the likelihood of model with parameter $\theta$ given data $\mathcal{D}$. Notably, data is fixed here. Thus, we want the most likely model that fits our samples. The model with maximum likelihood is estimated.</p><p>$$<br>\begin{aligned}<br>\mathcal{L}(\theta \mid \mathcal{D}) &amp;= f(\mathcal{D} \mid \theta) \\<br>&amp;= p((x^1, y^1), (x^2, y^2), \cdots, (x^n, y^n) \mid \theta)<br>\end{aligned}<br>$$</p><p>A probability distribution is used to estimate the likelihood of model $\theta$. The interpretation here is the probability of data generation from the model $\theta$.</p><p>$$<br>\begin{aligned}<br>\mathcal{L}(\theta \mid \mathcal{D}) &amp;= p((x^1, y^1), (x^2, y^2), \cdots, (x^n, y^n) \mid \theta) \\<br>&amp;= p((x^1, y^1) \mid \theta) \cdot p((x^2, y^2) \mid \theta) \cdots p((x^n, y^n) \mid \theta)<br>\end{aligned}<br>$$</p><p>It is formed from the joint probability distributions. A critical statistical assumption is introduced here. Samples $(x^i, y^i)$ are generated <em>independently</em> such that the joint probability can be split into multiplication of probabilities. Further, samples are generated from the same population/model $\theta$. So, we call that data are <em>independently, identically distributed</em>, or <em>iid</em>, generated from some model.</p><p>$$<br>\begin{aligned}<br>\mathcal{L}(\theta \mid \mathcal{D}) &amp;= p((x^1, y^1) \mid \theta) \cdot p((x^2, y^2) \mid \theta) \cdots p((x^n, y^n) \mid \theta) \\<br>&amp;= \prod_{i=1}^n p((x^i, y^i) \mid \theta)<br>\end{aligned}<br>$$</p><p>Normal distribution is used as error pattern in linear regression model. A linear regression model always infers the mean value of $y$ given $x$. The uncertainty of $y$ can be described by normal distribution. We add an error term after the linear regression model.</p><p>$$<br>y = wx + b + \epsilon<br>$$</p><p>$$<br>\epsilon = y - wx - b = \mathcal{N}(z \mid \mu = 0, \sigma^2)<br>$$</p><p>Or we can rewrite it into</p><p>$$<br>\epsilon = \mathcal{N}(y - wx - b \mid \mu = 0, \sigma^2)<br>$$</p><p>where $\mathcal{N}(x \mid \mu, \sigma^2) = \frac{1}{\sigma \sqrt{2 \pi}} exp(-\frac{1}{2} (\frac{x-\mu}{\sigma})^2)$.</p><p>Likelihood function would be</p><p>$$<br>\begin{aligned}<br>\mathcal{L}(\theta \mid \mathcal{D}) &amp;= \prod_{i=1}^n p((x^i, y^i) \mid \theta) \\<br>&amp;= \prod_{i=1}^n \mathcal{N}(y^i - wx^i - b \mid \mu = 0, \sigma^2)<br>\end{aligned}<br>$$.</p><p>Negative log likelihood would be</p><p>$$<br>\begin{aligned}<br>\mathcal{l}(\theta \mid \mathcal{D}) &amp;= - ln \mathcal{L}(\theta \mid \mathcal{D}) \\<br>&amp;= - ln \prod_{i=1}^n \mathcal{N}(y^i - wx^i - b \mid \mu = 0, \sigma^2) \\<br>&amp;= - \sum_{i=1}^n ln \mathcal{N}(y^i - wx^i - b \mid \mu = 0, \sigma^2) \\<br>&amp;= - \sum_{i=1}^n - \frac{1}{2} (\frac{y^i - wx^i - b - 0}{\sigma})^2 - ln(\sigma \sqrt{2 \pi}) \\<br>&amp;= \sum_{i=1}^n \frac{1}{2} (\frac{y^i - wx^i - b}{\sigma})^2 + ln(\sigma) + ln(\sqrt{2 \pi})<br>\end{aligned}<br>$$</p><p>The primal goal is to maximize likelihood function $\arg\max_{\theta} \mathcal{L}(\theta \mid \mathcal{D})$, while we have to minimize the negative log likelihood (NLL) function</p><p>$$<br>\arg\min_{\theta} \mathcal{l}(\theta \mid \mathcal{D})<br>$$.</p><p>To solve this problem, we need to calculate the first-order derivative of NLL. The minimum value happens while $\frac{\partial \mathcal{l}}{\partial w} = 0$ and $\frac{\partial \mathcal{l}}{\partial b} = 0$ are satisfied.</p><p>$$<br>\begin{aligned}<br>\frac{\partial \mathcal{l}}{\partial w} &amp;= \frac{\partial}{\partial w} \sum_{i=1}^n \frac{1}{2} (\frac{y^i - wx^i - b}{\sigma})^2 + ln(\sigma) + ln(\sqrt{2 \pi}) \\<br>&amp;= \sum_{i=1}^n \frac{y^i - wx^i - b}{\sigma} \cdot \frac{\partial}{\partial w} \frac{y^i - wx^i - b}{\sigma} \\<br>&amp;= \sum_{i=1}^n \frac{y^i - wx^i - b}{\sigma} \frac{-x^i}{\sigma} \\<br>&amp;= \frac{-1}{\sigma^2} \sum_{i=1}^n x^i (y^i - wx^i - b) \\<br>&amp;= 0<br>\end{aligned}<br>$$</p><p>$$<br>\begin{aligned}<br>\frac{-1}{\sigma^2} \sum_{i=1}^n x^i (y^i - wx^i - b) &amp;= 0 \\<br>\sum_{i=1}^n x^i (y^i - wx^i - b) &amp;= 0 \\<br>\sum_{i=1}^n{x^i y^i} - w \sum_{i=1}^n{(x^i)^2} - b \sum_{i=1}^n{x^i} &amp;= 0<br>\end{aligned}<br>$$</p><p>The same way we can have</p><p>$$<br>\sum_{i=1}^n{y^i} - w \sum_{i=1}^n{x^i} - b = 0<br>$$</p><p>derived from $\frac{\partial \mathcal{l}}{\partial b} = 0$.</p><p>Finally, we can estimate the parameters from the following two equations:</p><p>$$<br>\begin{cases}<br>(\sum_{i=1}^n{(x^i)^2}) w + (\sum_{i=1}^n{x^i}) b = \sum_{i=1}^n{x^i y^i} \\<br>(\sum_{i=1}^n{x^i}) w + b = \sum_{i=1}^n{y^i}<br>\end{cases}<br>$$</p><p>$$<br>\begin{cases}<br>w = ? \\<br>b = ?<br>\end{cases}<br>$$</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2020/10/12/linear-regression-with-mle/</id>
    <link href="https://yuehhua.github.io/blog/2020/10/12/linear-regression-with-mle/"/>
    <published>2020-10-11T17:20:57.000Z</published>
    <summary>
      <![CDATA[<p>Maximum likelihood estimation is an essential approach to estimate parameters in statistics. It requires statistical assumptions on error pattern. I will introduce this technique with really simple statistical model - linear regression.</p>]]>
    </summary>
    <title>Linear Regression with Maximum Likelihood Estimation</title>
    <updated>2020-10-12T08:39:03.657Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Believe。Think。Soul" scheme="https://yuehhua.github.io/blog/categories/My-Style/Believe%E3%80%82Think%E3%80%82Soul/"/>
    <content>
      <![CDATA[<p>這幾年，隨著接觸的東西變多，知道的東西變多，個性上也有點變化。</p><p>約莫四五年前，碩班時期接觸到一些很棒的網路技術文章，當時線上課程也非常熱門，很多優秀的大學紛紛把他們的上課內容做成教材釋出。也因為這樣，我自己其實從這些網路資源受惠非常多。當時也是自己在發展自學能力的輝煌時期。</p><span id="more"></span><p>也因為接觸開源文化，所以對於「分享」很有憧憬。覺得能夠分享自己的經驗的人很厲害，除了自己有些東西可以告訴別人，也有這個意願跟熱忱可以將自己所學回饋給社會的感覺。</p><p>後來畢業之後在研發替代役的過程中，一邊練習自己的溝通跟演講技術，一邊弄社群跟開一些小型的短期課程，還成為工研院的機器學習講師。過程當中也很開心可以真正可以把自己身上的東西跟大家分享，有的學員是私下來問我的看法或是建議。</p><p>漸漸地，隨著接觸的東西跟知道的東西變多，會開始知道有些作法或是想法上是有瑕疵或是問題的。一部份也是受到研替時的老闆的影響，老闆是個急性子，也不斷感受到壓力，久了之後心中也對有問題的方法莫名升起一種煩躁感。</p><p>煩躁感的出現，加上有能力表達，也有足夠的知識，變得開始會對身邊的人給建議。</p><p>有可能是談話中朋友表達他的某個想法，我會脫口而出這樣的想法背後可能會有什麼潛在的問題，抑或是我覺得這樣的想法好不好。話題範圍從我的專業領域到日常的電視廣告，只要是我有求證過或是我知道的，很多都會直接給出分析的結果。</p><p>目前正在博士的訓練路途上，博士的訓練是希望有獨立的分析跟研究能力，所以這樣能夠有批判性思考是很重要的能力。</p><p>這樣的分析似乎會困擾我身邊的人，畢竟不是每個人都需要「被建議」，他們或許覺得自己的作法很好，不然就是他就是想要這樣做。雖然我不太介意他是否會採納我的建議，但就是會講出口。有些時候講出口的剎那，對方會有種被否定或是攻擊的感覺，無論我的語氣是用「我覺得」或是「我建議」這種比較不強烈的。</p><p>大多數時候我是覺得我在發表自己的意見，對方也可以有自己的意見，我覺得這樣很公平。不過這些意見有時候是衝突，甚至相反的，有些人就會覺得被否定。的確，被否定的感覺很難受，意見被否定乃至於延伸到人格被否定，有些人是會失去自信的。</p><p>很多文章跟書本都告訴人不要主動給建議，建議只有當別人問的時候才給。或許該學著睜一隻眼閉一隻眼，即便是身邊再親的人也不要輕易給建議。</p><p>事情搞砸就是他的事，與我無關。</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2020/10/12/from-sharing-to-suggestions/</id>
    <link href="https://yuehhua.github.io/blog/2020/10/12/from-sharing-to-suggestions/"/>
    <published>2020-10-11T16:29:36.000Z</published>
    <summary>
      <![CDATA[<p>這幾年，隨著接觸的東西變多，知道的東西變多，個性上也有點變化。</p>
<p>約莫四五年前，碩班時期接觸到一些很棒的網路技術文章，當時線上課程也非常熱門，很多優秀的大學紛紛把他們的上課內容做成教材釋出。也因為這樣，我自己其實從這些網路資源受惠非常多。當時也是自己在發展自學能力的輝煌時期。</p>]]>
    </summary>
    <title>從分享到建議</title>
    <updated>2020-10-11T16:34:30.496Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <category term="My Style" scheme="https://yuehhua.github.io/blog/categories/My-Style/"/>
    <category term="Computer Science" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/"/>
    <category term="Julialang" scheme="https://yuehhua.github.io/blog/categories/My-Style/Computer-Science/Julialang/"/>
    <content>
      <![CDATA[<p>這個問題在官方文件中並沒有詳細記載，所以覺得值得紀錄一下。</p><p>查閱 <code>@async</code> 的文件會講說，他會用一個 <code>Task</code> 把後面的表達式包裝起來，並且將他掛到排程器的佇列（queue）中。意思就是將表達式包裝成一個任務，並放到佇列中等待 CPU 核心的資源來執行他。</p><span id="more"></span><p>然而通常會搭配 <code>@sync</code> 來使用，<code>@sync</code> 的文件中提到，他會等到後面的 <code>@async</code>、<code>@spawn</code>、<code>@spawnat</code> 及 <code>@distributed</code> 都執行完畢。</p><p>使用情境比較像是（修改自<a href="https://stackoverflow.com/questions/37287020/how-and-when-to-use-async-and-sync-in-julia">這篇 stackoverflow</a>）</p><figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@sync</span> <span class="keyword">for</span> (idx, pid) <span class="keyword">in</span> enumerate(workers())</span><br><span class="line">    <span class="meta">@async</span> a[idx] = remotecall_fetch(do_something, pid, <span class="number">2</span>)</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p><code>@sync</code> 會等待這個 block 中的 <code>@async</code> 都執行結束才結束，<code>@async</code> 可以讓你指派一些非同步處理的任務，像是多執行緒或是多行程的平行運算。</p><p><code>@sync</code> 就比較像 python 當中的 <code>join()</code>。</p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2020/09/06/how-to-use-async-sync-in-julia/</id>
    <link href="https://yuehhua.github.io/blog/2020/09/06/how-to-use-async-sync-in-julia/"/>
    <published>2020-09-06T09:43:04.000Z</published>
    <summary>
      <![CDATA[<p>這個問題在官方文件中並沒有詳細記載，所以覺得值得紀錄一下。</p>
<p>查閱 <code>@async</code> 的文件會講說，他會用一個 <code>Task</code> 把後面的表達式包裝起來，並且將他掛到排程器的佇列（queue）中。意思就是將表達式包裝成一個任務，並放到佇列中等待 CPU 核心的資源來執行他。</p>]]>
    </summary>
    <title>在 Julia 怎麼用 async 跟 sync</title>
    <updated>2020-10-11T16:36:42.590Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yueh-Hua Tu</name>
    </author>
    <content>
      <![CDATA[<p>之前在 Linux 上測試麥克風，發現錄製的時候總會把背景雜訊給錄進去，會在有人講話的同時聽到雜音。</p><p>我用的是 OBS 來做桌面錄製，所以自然想用 OBS 來做音訊的降噪。在 OBS 裡有噪音閥及噪音抑制，似乎噪音閥的效果比較明顯，但是講話聲音背後仍有雜音。</p><p>這時候在網路上找了一下，發現可以用系統 pulseaudio 的驅動來做降噪，只是要特別設定開啟，預設是不會開啟的。試了之後效果超好，在這邊紀錄一下。</p><h2 id="步驟">步驟</h2><p>首先，編輯以下檔案</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo nano /etc/pulse/default.pa</span><br></pre></td></tr></table></figure><p>把以下這行加到檔案中，建議可以加到有個 Echo Cancellation 的地方：</p><p>load-module module-echo-cancel</p><p>重載 PulseAudio (pulseaudio -k) 就可以囉！</p><p>Ref: <a href="https://askubuntu.com/questions/18958/realtime-noise-removal-with-pulseaudio">https://askubuntu.com/questions/18958/realtime-noise-removal-with-pulseaudio</a></p>]]>
    </content>
    <id>https://yuehhua.github.io/blog/2020/09/06/linux-system-noise-cancellation/</id>
    <link href="https://yuehhua.github.io/blog/2020/09/06/linux-system-noise-cancellation/"/>
    <published>2020-09-06T09:22:33.000Z</published>
    <summary>
      <![CDATA[<p>之前在 Linux 上測試麥克風，發現錄製的時候總會把背景雜訊給錄進去，會在有人講話的同時聽到雜音。</p>
<p>我用的是 OBS 來做桌面錄製，所以自然想用 OBS 來做音訊的降噪。在 OBS 裡有噪音閥及噪音抑制，似乎噪音閥的效果比較明顯，但是講話聲音背後仍有雜音。<]]>
    </summary>
    <title>Linux 系統降噪</title>
    <updated>2020-09-06T09:23:17.999Z</updated>
  </entry>
</feed>
