
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
12 / 43juliaコマンドで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 … elseBool型のみ
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