julia script.jl
で即実行julia
コマンドで対話的実行$ cat script.jl
println("hello, world")
$ julia script.jl
hello, world
$ julia -q
julia> A = randn(3, 3)
3×3 Matrix{Float64}:
-0.378213 1.17271 0.646551
-0.318493 -0.25825 0.121042
0.822649 1.50609 1.01108
julia> A'A # 行列積
3×3 Matrix{Float64}:
0.921234 0.877702 0.548677
0.877702 3.71027 2.24974
0.548677 2.24974 1.45496
julia>
end
までがブロック2x
やA'B
などの数学記法σ
などユニコード変数をサポート
# 1次元配列(Vector)は要素の型付き
typeof([1, 2, 3]) #> Vector{Int64}
typeof([1.0, 2.0, 3.0]) #> Vector{Float64}
# マクロによるコードの書き換え
x = 1
@assert x > 0
@assert x < 0 #! ERROR: AssertionError: x < 0
# if … end のブロック
if x > 0
println("x is positive")
end
# ユニコード変数
μ, σ = -0.3, 1.2
x = μ + randn() * σ # 正規分布 N(μ, σ^2)
isless
関数が要素の型に応じて特殊化@inbounds
は境界チェックを省略
quicksort(xs) = quicksort!(copy(xs))
quicksort!(xs) = quicksort!(xs, 1, length(xs))
function quicksort!(xs, lo, hi)
if lo < hi
p = partition!(xs, lo, hi)
quicksort!(xs, lo, p - 1)
quicksort!(xs, p + 1, hi)
end
return xs
end
function partition!(xs, lo, hi)
pivot = div(lo + hi, 2)
pvalue = xs[pivot]
xs[pivot], xs[hi] = xs[hi], xs[pivot]
j = lo
@inbounds for i in lo:hi-1
if isless(xs[i], pvalue)
xs[i], xs[j] = xs[j], xs[i]
j += 1
end
end
xs[j], xs[hi] = xs[hi], xs[j]
return j
end
Array{T, n}
型run
やeachline
で実行ccall
でCの関数を実行
# 外部コマンドの実行
for path in eachline(`find . -name '*.txt'`)
# gzip <"$path" >"$path.gz"
run(pipeline(path, `gzip`, "$(path).gz"))
end
# C関数の呼出し
ccall(:sin, Cdouble, (Cdouble,), 1.0)
# Pythonの使用
using PyCall
optimize = pyimport("scipy.optimize")
optimize.brentq(x -> x^2 - 2, 0, 2) # x^2 = 2 の解
Julia | Python | |
---|---|---|
easy.txt | 257.3 ㍉秒 | 52.4 ㍉秒 |
hard.txt | 5.1 秒 | 438.2 秒 |
# Julia版の数独ソルバー
function solve(puzzle)
next(i, j) = i < 9 ? (i + 1, j) : (1, j + 1)
function solved(sol, i, j)
if j > 9
return true
elseif sol[i,j] > 0
return solved(sol, next(i, j)...)
end
m, n = (i - 1) ÷ 3, (j - 1) ÷ 3
for k in 1:9
if all(sol[i,j] != k for i in 1:9) &&
all(sol[i,j] != k for j in 1:9) &&
all(sol[i,j] != k for j in 3n+1:3n+3,
i in 3m+1:3m+3)
sol[i,j] = k
solved(sol, next(i, j)...) && return true
end
end
sol[i,j] = 0
return false
end
sol = copy(puzzle)
return solved(sol, 1, 1) ? sol : nothing
end
julia
コマンドでREPLを起動
exit()
で終了julia>
Juliaモード(Del
キー)help?>
ヘルプモード(?
キー)shell>
シェルモード(;
キー)pkg>
パッケージ管理モード(]
キー)nothing
は意味のない値
println
関数の返り値などNone
に相当missing
は「値がない」ことを表す値
# 数値
42 # 整数
3.14 # 浮動小数点数(小数表記)
6.02e+23 # 浮動小数点数(指数表記)
1.2 - 0.9im # 複素数
2//3 # 有理数
# 真偽値
true
false
# Nothing
nothing
# 欠損値
missing
[ … ]
で配列作成
begin
: 最初の要素end
: 最後の要素ndims | 次元 |
size | サイズ |
length | 要素数 |
zeros | ゼロ初期化配列 |
copy | 複製配列 |
sum | 総和 |
minimum | 最小値 |
vcat | 縦結合 |
hcat | 横結合 |
fill! | 全要素設定 |
push! | 要素追加 |
pop! | 要素削除 |
sort! | 整列 |
# 1次元配列(ベクトル)
[1, 2, 3]
# 2次元配列(行列)
[1.0 2.0 3.0
0.0 4.0 5.0
0.0 0.0 6.0]
# 要素の参照
x = [10, 20, 30]
x[1] #> 10
x[3] #> 30
x[begin] #> 10
x[end] #> 30
x[end-1] #> 20
Vector{T}
のT
がパラメタVector{T}
はArray{T, 1}
の別名Matrix{T}
はArray{T, 2}
の別名Any
型
# 配列は要素の型を持つ
typeof([0]) #> Vector{Int64}
typeof([0.0]) #> Vector{Float64}
# 要素の型を返すeltype関数
eltype([0]) #> Int64
eltype([0.0]) #> Float64
# 空の配列
Float64[] # 浮動小数点数の1次元配列
[] # Any[] と同じ
# 名前無しタプル
t = ("Albert Einstein", 1879)
t[1] #> "Albert Einstein"
t[2] #> 1879
# 名前付きタプル
t = (name = "Albert Einstein", birth = 1879)
t.name #> "Albert Einstein"
t.birth #> 1879
t[1] #> "Albert Einstein"
t[2] #> 1879
# 最大値とその位置を返すfindmax関数
findmax([3.9, 5.2, 2.1, 4.0]) #> (5.2, 2)
/
は浮動小数点数を返すので注意÷
と%
を使うdiv
とrem
と同じ!
: 否定|
: 論理和&
: 論理積2 + 3
も+(2, 3)
も同じ
# 四則演算
2 + 3 #> 5
2 - 3 #> -1
2 * 3 #> 6
2 / 3 #> 0.6666666666666666
# 商と剰余
9 ÷ 2 #> 4 = div(9, 2)
9 % 2 #> 1 = rem(9, 2)
# 論理演算
!true #> false
true | false #> true
true & false #> false
# 畳み込み演算
foldl(+, [1, 2, 3], init = 0) #> 6
if … elseif … else
Bool
型のみ
false
かtrue
のみが有効0
や""
は使えないので注意x && y
は「x
が真 iff y
を評価」x || y
は「x
が偽 iff y
を評価」
# 条件分岐
if x == 0
println("x is zero.")
elseif x > 0
println("x is positive.")
else
println("x is negative.")
end
# 条件演算子
println(x < 0 ? "negative" : "nonnegative")
# 短絡評価
x > 0 && x < 10 # 0 < x < 10 と同じ
x < 0 || x > 10
start:stop
は範囲オブジェクト
start:step:stop
で間隔を変更できるstep
を負の値にすれば逆順for
やwhile
ブロック内ではbreak
とcontinue
が使える
break
: ループを抜けるcontinue
: ループの残りを飛ばす
# 範囲
1:9 # 1, 2, …, 9
1:2:9 # 1, 3, …, 9
# for文
for i in 1:9
println(i)
end
# 2重ループ
for j in 1:9, i in 1:9
println(i, j)
end
# while文
while true
println("yes")
end
for
のin
は=
や∈
でもOKfunction
を使う定義return
は省略可能
x -> x + 1
と書くと無名関数
# 1行定義
iseven(n) = n % 2 == 0
# 標準的な定義
function collatz(n::Integer)
steps = 0
while n != 1
if iseven(n)
n = n ÷ 2
else
n = 3n + 1
end
steps += 1
end
return steps
end
mutable struct
に変えると可変な構造体
# 2次元極座標の構造体型
struct PolarCoords
# フィールド
r::Float64 # radius
φ::Float64 # angle
# ユーザ定義コンストラクタ(オブジェクトを作る関数)
function PolarCoords(r, φ)
r ≥ 0 || error("radius must be non-negative")
0 ≤ φ < 2π || error("angle must be in [0, 2π)")
return new(r, φ)
end
end
# PolarCoordsオブジェクトの作成
p = PolarCoords(1.0, 2π/3)
p.r, p.φ #> (1.0, 2.0943951023931953)
T
がパラメータT
はどんな型にもなれるComplex{T}
Array{T, n}
Dict{K, V}
# 2次元極座標の構造体型(パラメトリック版)
struct PolarCoords{T}
# フィールド
r::T # radius
φ::T # angle
# ユーザ定義コンストラクタ(オブジェクトを作る関数)
function PolarCoords(r::T, φ::T) where T
r ≥ 0 || error("radius must be non-negative")
0 ≤ φ < 2π || error("angle must be in [0, 2π)")
return new{T}(r, φ)
end
PolarCoords(r, φ) = PolarCoords(promote(r, φ)...)
end
# PolarCoordsオブジェクトの作成
p = PolarCoords(1//2, 2//3)
Any
抽象型
Integer # 抽象型
Int64 # 具象型
UInt8 # 具象型
Float64 # 具象型
# 階層関係
Int64 <: Integer #> true
UInt8 <: Integer #> true
Float64 <: Integer #> false
42 isa Int64 #> true
42 isa Integer #> true
0.5 isa Float64 #> true
0.5 isa Integer #> false
Number
抽象型以下の階層f
には3つのメソッドがある*
関数さえも)
# 関数fに3つのメソッドを定義
f(x::Int64) = "Int64"
f(x::Float64) = "Float64"
f(x::Integer) = "Integer"
# 関数呼出し
f(42) #> "Int64"
f(0.5) #> "Float64"
f(true) #> "Integer"
f('a') #! MethodError
# Int * Intメソッドが呼び出される
2 * 3 #> 6
# Int * Vector{Int}メソッドが呼び出される
2 * [4, 5, 6] #> [8, 10, 12]
Base
の関数を拡張するときはBase.{関数名}
で定義
# 極座標の回転(新しい関数の定義)
rotate(p::PolarCoords, θ::Real) =
PolarCoords(p.r, mod(p.φ + θ, 2π))
# 極座標のスカラ倍(関数の拡張)
Base.:*(α::Real, p::PolarCoords) =
PolarCoords(α * p.r, p.φ)
Base.:*(p::PolarCoords, α::Real) = α * p
# 極座標の和(練習問題)
Base.:+(p1::PolarCoords,
p2::PolarCoords) = …
*
などの演算子のときはBase.:*
のようにコロンが必要だが、それ以外のときは必要ない
問題:fit
関数を新しいデータ型MyData
に拡張したい
# Python
class Model:
def fit(self, data):
…
fit
関数の実装を書き換える
def fit(self, data):
if isinstance(data, MyData):
…
# Julia
struct Model … end
function fit(mod::Model, data) … end
fit
関数に新しいメソッドを加える
function fit(mod::Model, data::MyData)
…
end
~/.julia
以下にファイルを配置]
キーを押下するとパッケージ管理モードに移行
status
: 状態を表示add
: パッケージを追加remove
: パッケージを削除
(@v1.6) pkg> status
Status `~/.julia/environments/v1.6/Project.toml`
[6e4b80f9] BenchmarkTools v1.1.1
[944b1d66] CodecZlib v0.7.0
[31c24e10] Distributions v0.25.11
…
ペアで使われる2つのパッケージ管理ファイル:
Project.toml
)Manifest.toml
)~/.julia/environments/v1.6/{Project, Manifest}.toml
がデフォルト(ユーザ固有)activate .
コマンドを実行して環境を有効化julia --project
でJuliaを実行 ORJULIA_PROJECT
環境変数を@.
に設定\sigma
の直後にTabキーを押すと、σ
に変換される≈
はisapprox
関数の別名)
julia> \sigma # ← ここでTabキーを押下
julia> σ # ← このようになる
julia> 1.0 ≈ 1.00000001 # isapprox
true
\div | ÷ |
\approx | ≈ |
\equiv | ≡ |
\in | ∈ |
\notin | ∉ |
\subseteq | ⊆ |
\cap | ∩ |
\cup | ∪ |
isless
関数呼出し
isless
関数は型に応じてディスパッチ
function partition!(xs, lo, hi)
pivot = div(lo + hi, 2)
pvalue = xs[pivot]
xs[pivot], xs[hi] = xs[hi], xs[pivot]
j = lo
@inbounds for i in lo:hi-1
if isless(xs[i], pvalue)
xs[i], xs[j] = xs[j], xs[i]
j += 1
end
end
xs[j], xs[hi] = xs[hi], xs[j]
return j
end
# 型推論結果を表示
code_typed(
partition!,
(Vector{Float32}, Int, Int),
optimize = false)
julia -t4
で4スレッドを起動Task
型)というコルーチンを並列実行できるThreads
モジュール
@spawn
: 並列実行タスクを起動@sync
: タスクを同期@threads
: forループを並列化
using .Threads: @threads, @spawn
# fooとbarを並列実行
@sync begin
@spawn foo()
@spawn bar()
end
# for文を並列実行
@threads for i in 1:100
baz(i)
end