5  Julia 文法クイックスタート

このページでは、次のいくつかのステップで登場する Julia の文法を素早く紹介する。すべてを暗記する必要はない。目標は、コードに出てきたときにこれらのパターンを認識し、読めるようにすることである。

5.1 このページの目的

これは完全な Julia チュートリアルではない。Step 1 と Step 2 で登場する文法のみを扱う。struct、モジュール、パフォーマンス最適化などの高度なトピックは後のステップで扱う。

5.2 変数と式

Julia のコードは左から右に読む:

x = 3
beta = 1 / T
L = 8
  • = は変数に値を代入する
  • 変数を式の中で使える
  • 変数名は大文字・小文字を区別する

5.3 関数と戻り値

関数は入力を受け取り、計算を行い、出力を返す:

function initialize_spins(L)
    return rand(Int8[-1, 1], L, L)
end
  • function 名前(引数) ... end で関数を定義する
  • return で出力を明示する
  • Julia では最後の式も自動的に返されるが、初学者には return を書いた方が分かりやすい

関数はこのように呼び出す:

spins = initialize_spins(8)

5.4 配列・行列・インデックス

配列は多くの値をまとめて格納する:

A = [1, 2, 3]           # 1次元配列
B = [1 2; 3 4]          # 2次元配列(行列)
C = rand(Int8[-1, 1], 4, 4)  # 4x4 行列
  • 2次元配列は表や行列のようなものである
  • A[i] で i 番目の要素を取得(1次元)
  • A[i, j] で i 行 j 列の要素を取得(2次元)
  • 重要: Julia は 1-based インデックス(配列は 1 から始まる、0 からではない)

便利な関数:

size(A)        # A の次元
length(A)      # 要素の総数
eltype(A)      # 要素の型(例: Int8, Float64)

5.5 ループと範囲

for ループはコードを繰り返す:

for i in 1:L
    # i を使って何かする
end
  • 1:L は 1 から L までの範囲を作る
  • ループをネストしたり、まとめたりできる:
for i in 1:L, j in 1:L
    # i と j を使って何かする
end

5.6 登場する型

Julia には型があるが、どこにでも書く必要はない:

x = 3          # Int
y = 3.0        # Float64
z = Int8(3)    # Int8

この講義で登場する主な型:

  • Int: 整数(通常64ビット)
  • Int8: 小さな整数(8ビット、メモリ節約)
  • Float64: 浮動小数点数
  • Bool: true または false

型アノテーション(L::Int など)は「これは整数であるべき」という意味である。読めれば十分で、まだどこにでも書く必要はない。

5.7 変更操作、foo!copy

一部の関数は配列をその場で変更する:

function flip_first!(spins)
    spins[1, 1] *= -1
    return nothing
end

spins = [1 1; 1 1]
flip_first!(spins)
# spins は [-1 1; 1 1] になる
ノート

Julia では、引数を変更する可能性がある関数の名前の末尾に ! をつける慣習がある。これは強制ではなく慣習だが、広く守られている。! がついている関数を見たら「引数が書き換わるかもしれない」と意識せよ。

  • 配列は mutable(変更可能): 関数内での変更は元の配列に影響する
  • 別のコピーが必要な場合は copy(x) を使う:
original = [1, 2, 3]
duplicate = copy(original)
modify!(duplicate)
# original は変更されない

5.8 更新演算子

よくある更新操作の省略記法:

x += 1    # x = x + 1 と同じ
e -= 5    # e = e - 5 と同じ
spins[i, j] *= -1  # spins[i, j] = spins[i, j] * -1 と同じ

5.9 using とパッケージ

パッケージのコードを使うには:

using Pkg
using BenchmarkTools
using Plots
  • using パッケージ名 でパッケージを読み込む
  • パッケージは呼び出せる関数を提供する
  • プロジェクト環境(Step 0 で作成)が利用可能なパッケージを制御する

5.10 今は無視してよいもの

以下はまだ理解する必要がない:

  • struct(Step 4 で扱う)
  • module とパッケージ開発(後で扱う)
  • 多重ディスパッチの詳細
  • パフォーマンス最適化の詳細(Step 5 で扱う)
  • . によるブロードキャスト(この講義では明示的には使わない)

5.11 ミニ・コードリーディング確認

以下を読んで、何をしているか説明せよ:

function count_ones(A)
    n = 0
    for i in 1:size(A, 1), j in 1:size(A, 2)
        if A[i, j] == 1
            n += 1
        end
    end
    return n
end

そして以下の質問に答えよ:

  1. size(A, 1) は何を返すか?
  2. なぜループの中で n を変更しているのか?
  3. すべて 1 で埋められた 3x3 行列に対して count_ones を呼び出すとどうなるか?

5.12 次のステップ

これで Step 1 に進む準備ができた。Step 1 では、2次元イジング格子を初期化する関数を作成する。