Julia言語 を導入し人生を N ≥ 1 歩進める(2024 年 12 月 版)

# 本日は

アドベントカレンダーの季節がやってまいりました．

この記事は プログラミング言語 Julia のアドベントカレンダー $N=1$ 日目の記事です．

https://qiita.com/advent-calendar/2024/julia

投稿者を募集しています．The Julia Programming Languageに関する内容なら何でもどうぞ
過去のカレンダーはこちら：

[Julia Advent Calendar 2023](https://qiita.com/advent-calendar/2023/julia)
[Julia Advent Calendar 2022](https://qiita.com/advent-calendar/2022/julia)
[Julia Advent Calendar 2021](https://qiita.com/advent-calendar/2021/julia)
[Julia Advent Calendar 2020](https://qiita.com/advent-calendar/2020/julia)
[Julia Advent Calendar 2019](https://qiita.com/advent-calendar/2019/julialang)
[Julia Advent Calendar 2018](https://qiita.com/advent-calendar/2018/julialang)
[Julia Advent Calendar 2017](https://qiita.com/advent-calendar/2017/julialang)
[Julia Advent Calendar 2016](https://qiita.com/advent-calendar/2016/julialang)
[Julia Advent Calendar 2015](https://qiita.com/advent-calendar/2015/julialang)
[Julia Advent Calendar 2014](https://qiita.com/advent-calendar/2014/julialang)


## Julia について

プログラミング言語の一つです．Ruby, Python など動的型付け言語の性質を持つ一方，JIT コンパイルで動作をするため C/C++/Fortran/Rust などの静的型付け言語に匹敵するパフォーマンスを（ちゃんと書けば）出すことができる言語です．JIT コンパイルには [LLVM](https://llvm.org/) が使われています．

## インストール

とりあえず手元のマシンに導入してみましょう．この記事をいわゆるパソコンと呼ばれるものでみているのであれば大抵の環境で動きます．

### 細かく考えてしまう人向け

もう少し詳しく知りたい場合は下記の Supported platforms の Tier 1 という箇所を見てください．その環境であれば導入できるはずです．

https://julialang.org/downloads/#supported_platforms

Tier 2 でも ARMv8 (64-bit) 環境であればラズベリーパイ3,4,5 で 64bitの Raspberry Pi OS を入れれば動作します．

### juliaup を利用したインストール

Julia の公式ドキュメントを眺めてみましょう．

https://julialang.org/downloads/#install_julia

macOS, Linux 環境であれば下記のコマンドが見えるでしょう．

```sh
$ curl -fsSL https://install.julialang.org | sh
```

Windows 環境では下記のコマンドが見えるはずです．

```powershell
PS> winget install julia -s msstore
```

これらのコマンドは [Juliaup](https://github.com/JuliaLang/juliaup) というツールを用いて Julia をインストールする方法です．今ではこれが公式の手順の一つになっています．もう一つの選択肢は直接ダウンロードページからバイナリを導入することです．以下では juliaup を使う方法を前提とします．

コマンド実行後にいろいろ聞かれますが，デフォルトのコンフィグレーションで問題ないです．ひたすら Yes の意味で `Y` を押したり，次に進む意味でエンターキーをひたすら押しておけばなんとかなります．

ターミナル(Windows では PowerShell)で `julia` と入力してみましょう．実行できなければ一旦ターミナルを閉じてもう一度ターミナルを開けば `julia` のパスが通ってるはずです．

#### 少し細かい話

- `curl -fsSL https://install.julialang.org | sh -s -- --yes` のようにすることで非対話形式でJuliaのインストールがを進めることができます．Dockerのイメージのビルド，シェルスクリプトでインストール手順を作りたい場合は使ってみると良いかもしれません．
- WSL2 で利用したい方は Linux 環境でのインストールと同様の手順でインストールしてください．
- PowerShell で文字化けが発生する場合は下記の Qiita の記事が参考になります．

https://qiita.com/tiro_sx/items/c98d4ca620562ebd9f5a

- 過去に別の方法で Julia を入れてたが数年ぶりに使いたくなった場合は一旦古い Julia をアンインストールしてください．
- 特に理由がなければ Julia の最新安定版（Current stable release）を使い続けるようにしてください．現時点では `v1.11.1` が最新ですが，将来 `v1.12.0` 系が出た場合は `juliaup update` というコマンドを使って使う Julia を `v1.12.0` を使うようにしてください．Juliaup を導入しておけばコマンド一発で新しい Julia を導入することができます．
- また `apt-get install ...` のようにパッケージマネージャでJuliaを入れることは非推奨になっています．古いものが入ってたり壊れてたりするようです．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/350ca7a4-0cb5-8af2-0b82-507da3c1f7a7.png)

- (保守的なシステムを構築する場合など）特定の理由で固定したJuliaのバージョンで運用したい場合は LTS である Julia `1.10` 系を利用します．これにはバグ修正，パフォーマンス改善などのパッチが定期的に追加されます．初めてJuliaを使う方は最新安定版を使っていきましょう．そっちの方が明らかにクォリティオブライフが充実します．

## REPL を使う

Julia をインストールした後 `julia` とターミナルで入力すれば Python のように対話環境としての [REPL](https://docs.julialang.org/en/v1/stdlib/REPL/) が立ち上がります．

```shell-session
$ julia

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.11.1 (2024-10-16)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |


julia>
```

### 初めてのパッケージの導入

パッケージマネージャーが標準として付属しており REPL 内で

```julia
julia> using Pkg; Pkg.add("LatticeQCD")
```

を入力しエンターキーを押して実行するとパッケージを導入することができます．これは GitHub リポジトリ [akio-tomiya/LatticeQCD.jl](https://github.com/akio-tomiya/LatticeQCD.jl) に管理されている Julia パッケージに対応します（国産パッケージはいくら紹介してもいいですからね）．続けて下記を入力し実行します．

```julia
julia> Pkg.test("LatticeQCD")
```

これによりソフトウェアテストが実行され，プログラム作成者が期待している動作がインストールされた環境で動作するかをチェックすることができます．しばらく時間がかかりますが，手元の環境では次のような結果が得られます．

```julia
Test Summary: | Pass  Total     Time
LatticeQCD.jl |   11     11  3m44.8s
     Testing LatticeQCD tests passed

julia>
```

### あなたはいくつかの奇跡に遭遇しました．

`tests passed` と書いてあるので「このパッケージは手元のマシンで動かせそう」ということがわかります．凄くないですか？というのもこの手の類のソフトウェアは

- ソースコードの入手(どこにあるのかわからない，Gitって何？)
- インストールのために準備するもの（依存関係の解決に苦しむ）
- コンパイルが必要な言語であればビルドが通らない
    - そもそもコンパイルをするためのコマンドが書いてない
    - 大抵一発で通らない
        - README に書いてある通りに動いたらそのソフトウェアを作った人はすごい人
    - ビルドは通ったけれど共有ライブラリが見当たらない関係で実行時エラーが起きる
    - ソースコードのどの部分に対応するのかわからない

という心理的に辛いことを強いられるケースが多いのに，上記の例ではわずか二行で多くの困難な壁をたやすく乗り越え奇跡的に我々ユーザに機能を提供してくれます．

#### 奇跡は当然であってほしい（奇跡のトリック）

私はリオールの町でワインが噴き出てる町で奇跡の技を起こす司教様ではありませんし，リバウンドをする賢者の石劣化版を持つ司教様でもありません．

これには Julia のパッケージマネージャー, その裏で Julia 以外の外部ライブラリをビルド・管理する [BinaryBuilder.jl](https://github.com/JuliaPackaging/BinaryBuilder.jl)，[JuliaPackaging/Yggdrasil](https://github.com/JuliaPackaging/Yggdrasil) が縁の下の力持ちになっています．

[JuliaCI/PkgTemplates.jl](https://github.com/JuliaCI/PkgTemplates.jl)，最近では [JuliaBesties/BestieTemplate.jl](https://github.com/JuliaBesties/BestieTemplate.jl) , といったパッケージを作るテンプレートが用意されており，それに従ってコードを書けば，ソフトウェアを専門にしない方でも一定のクォリティを保ったままプロの専門職としてのソフトウェア開発者が行うワークフローに相当する開発プロセスを回すことができます．

例えば https://github.com/julia-actions というGitHub オーガニゼーション（組織）があるように, そこで管理されているワークフローファイルを利用すればコードの変更，プルリクエストを作った際に自動テストが実行されパッケージのビルド・テストの実行，（次回以降のCIの時間の削減のため）依存関係のキャッシュといったことができるようになります．以下のYAMLは https://github.com/julia-actions/cache の README.md から抜粋したものです．

```yml:.github/workflows/CI.yml
name: CI

on: [push, pull_request]

# needed to allow julia-actions/cache to delete old caches that it has created
permissions:
  actions: write
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: julia-actions/setup-julia@v2
    - uses: julia-actions/cache@v2
    - uses: julia-actions/julia-buildpkg@v1
    - uses: julia-actions/julia-runtest@v1
```

まともな企業・組織であれば当然やっているだろう自動テスト，CI/CD といったノウハウ・開発手法が科学技術計算の文脈でも利用することができるのです，（読者が数値計算の結果を根拠に理論の正当性・新規性を主張する立場であれば職位を問わず結果が正確なものであるために努力を惜しんではいけないのです．）

## 今の Julia

簡単にパッケージをインストールできるようになったとはいえ，ソフトウェア構築しメンテナンス・運用・他の人に利用してもらうようにするのは裁縫をするために糸を針の穴に何回も連続で通すぐらいに難しいことです．その難しさをなるべく回避してくれるように整うようになってきました．また，開発体験，利便性も向上しました．

### TTFL/TTFX 問題の軽減

Julia 1.9 から [package image](https://docs.julialang.org/en/v1/devdocs/pkgimg/) と言う仕組みが導入されパッケージの初回読み込み，関数の初回実行の時間が大幅に軽減されました．Julia は JIT コンパイル方式で動作するために，初回のコンパイルコストが数秒から数十秒単位でかかっていました．いわゆる TTFL(time to first load), TTFX (time to first execution) 問題がありました．昔 Julia を触ってたけれどパッケージのロードの遅さで諦めてた人は下記を試してください．

```julia
julia> using Plots; p = plot(sin); display(p)
```

以前ためされてた時に比べて大幅に待ち時間が短縮されたと思います．これで初回のロード・実行に時間がかかる問題(TTFL, TTFX)を概ね軽減することができました．また，https://github.com/JuliaLang/PrecompileTools.jl　などで関数の TTFX を軽減することもできます．

### Pluto Notebook による再現性のあるノートブック環境・デモの構築を可能にする

Jupyter Notebook は Python, R などでよく使われる対話環境の一つですが，Julia にはリアクティブノートブックである Pluto と呼ばれる対話環境を持っています．Pluto で作られたノートブックは Julia のソースコードとして実行できる他，パッケージの依存関係などのメタ情報を TOML フォーマットで格納するため，同じ Julia のバージョン，Pluto のバージョンであれば別のマシンで同様の環境を構築することができます．プログラミング言語 Rust の文脈で言えば Cargo.toml と Cargo.lock の情報が一枚のノートブックに入っていると思ってください．ナイーブな Jupyter Notebook の運用ではノートブックの実行前に全ての環境が整っていることが前提としているので再現性を確保するのはとても難しいです．ですが，Pluto ではそれが簡単にできるのです．

#### Example

例えばTCI(tensor cross interpolation) に基づいたテンソルネットワークの手法を研究するグループ [tensor4all](https://tensor4all.org/) でのJuliaを使ったデモコードは Pluto を使っています．

以前は JupyterBook を使っていました．

https://github.com/tensor4all/T4AJuliaTutorials

https://tensor4all.org/T4AJuliaTutorials/ipynbs/index.html

ですが，エンドユーザに使ってもらうためのチュートリアル資料を動かすための環境構築のコストがエンドユーザにとって高い（Julia に加えて Python, Python との連携のためのパッケージの相性のコントロールが難しかった）ので Pluto Notebook へ乗り換えることにしました．Pluto を使った版は以下のページになります．

https://github.com/tensor4all/T4APlutoExamples

https://tensor4all.org/T4APlutoExamples/pluto_notebooks/

こちらを使うとユーザは Julia のインストール，Pluto.jl パッケージを追加してもらえれば最低限の準備を整えることができます．

```julia
julia> using Pkg; Pkg.add("Pluto")
```

特にエラーが起きなければ下記を実行することで特定のノートブックに必要な環境構築・実行がすぐにできます：

```julia
# 以下のソースコードを Julia の REPL に貼り付ける
using Pkg; Pkg.activate(temp=true); Pkg.add("Pluto")
BASE_URL = "https://raw.githubusercontent.com/tensor4all/T4APlutoExamples/refs/heads/main/pluto_notebooks/"
notebook = "quantics1d.jl"
url = joinpath(BASE_URL, notebook)
using Pluto; Pluto.run(notebook=download(url))
```

下記のような図が出たら実行できていると思って良いでしょう．この例は複雑に振動する関数 $f$ に対する QTT representation を構築する例です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/63bb6530-4ab0-84c2-bdd0-cded96cf9c79.png)

Pluto に乗り換えたおかげで開発者が行う環境構築の手順とエンドユーザがするそれを同一にすることができとても楽になりました．なんでこんなに詳しいかって？自分がノートブック・デモを作る土台を構築したからです．JupyterBookに関するエラーに苦しむことから解放されメンテナンスのための工数は大幅に削減できました．

## JET.jl, Aqua.jl によるコードのクォリティの維持が可能

パッケージ開発時においてうっかり気を抜くと

- 不要なパッケージをインストールしたままになっている
- `oldfunction` を消したけれど `export oldfunction` にしたコードがまだ残っていた
- `type piracies` を引き起こすメソッドを定義しちゃった
- General レジストリ登録済みパッケージの更新・登録時に `[compat]` の欄の要件を満たしてなかった

という事案が発生します．そういったうっかりしたことを防ぐためのパッケージとして [JuliaTesting/Aqua.jl](https://github.com/JuliaTesting/Aqua.jl) があります．

https://github.com/JuliaTesting/Aqua.jl

`YourPackage` を開発してる人はとりあえず下記を試してみましょう．

```julia
using YourPackage
using Aqua
Aqua.test_all(YourPackage)
```

また，うっかりしてると

- 型不安定な実装をしてしまい実行パフォーマンスを悪くしてしまった．
- テストは通ったけれどテストでカバーしきれてない箇所で `UndefVarError` （変数の未定義によるエラー）が出ちゃった．（潜在的なバグ）

といった経験もします．そんな時は静的解析を可能にする [aviatesk/JET.jl](https://github.com/aviatesk/JET.jl) を使ってみましょう．

https://github.com/aviatesk/JET.jl

https://discourse.julialang.org/t/ann-jet-jl-the-next-generation-of-code-checker-for-julia/58913

また，メモリアロケーションの検知は

https://github.com/JuliaLang/AllocCheck.jl

が有用です．

## Julia の未来の話

Julia 1.12 またはそれ以降の未来の話をしましょう. `juliac` というコンパイラドライバが開発されています．平たく言えば `gcc` コマンドのように Julia のコード・パッケージを事前にコンパイルし実行形式・共有ライブラリを作ることができる仕組みです．

↓のYouTubeなどをみてください．
https://www.youtube.com/watch?v=R0DEG-ddBZA

PackageCompiler.jl は現時点で動作するパッケージではありますが，ビルドの時間・得られるバイナリサイズが巨大なので改善が望まれていました．juliac はPackageCompilerに比べ高速にビルドができ，`--trim` オプションという experimental な機能を使うことでバイナリのサイズを小さくすることができます．（が，ここ数日の動きだと色々混乱があります．

また，実行バイナリを数MBまで縮められると謳っていますが，厳密には `libjulia.dylib` にも依存しているので配布する際には配布先のマシンにも Julia が入っている必要があります（少なくともこの記事が出た時点では）．それを考慮するとやや誇張な表現です．まぁ nightly なので．．．色々ブレるのは仕方がないことです．

実際に動かす例は↓に作っています．

注意: nightly なので不安定なので常に動作できるかは保証できません．

https://github.com/terasakisatoshi/libcalcpi_juliac

https://github.com/AtelierArith/CarbonNowCLI.jl

## さいごに

色々話しましたが，今日のアドベントカレンダーの目標としましては皆さんのマシンに Juliaup を入れてもらうことです．具体的な話は 2 日以降の方が解説してくれるでしょう．まだまだカレンダーは空いているのでみなさんの投稿をお待ちしております．