M.Hiroi's Home Page
http://www.geocities.jp/m_hiroi/

Julia Language Programming

Julia の基礎知識

[ Home | Light | Julia ]

●Julia のデータ型

Julia のデータ型は階層構造 (木構造) になっていて、ルートのデータ型が Any になります。型の名前は先頭が英大文字になります。すべての型は Any を継承していると考えてください。

型は抽象型と具象型の二種類があり、実際のデータ (値) に対応するのが具象型で、抽象型は値を生成することはできません。木構造でいえば、「葉」に相当する型が具象型、それ以外の「節」に相当する型が抽象型となります。抽象型を継承して新しい型を作ることはできますが、逆に具象型を継承して新しい型を作ることはできません。

値の型は関数 typeof() や isa() で、上位の型は関数 super() で、下位の型 (サブタイプ) は関数 subtypes() で調べることができます。また、Type1 <: Type2 で Type1 が Type2 のサブタイプか調べることもできます。

julia> typeof(12345)
Int32

julia> typeof(1.2345)
Float64

julia> isa(1, Int32)
true

julia> isa(1, Float64)
false

julia> subtypes(Number)
2-element Array{Any,1}:
 Complex{T<:Real}
 Real

julia> subtypes(Real)
4-element Array{Any,1}:
 AbstractFloat
 Integer
 Irrational{sym}
 Rational{T<:Integer}

julia> super(Int32)
Signed

julia> super(Signed)
Integer

julia> Int32 <: Number
true

julia> Int32 <: Any
true

●基本的なデータ型

●基本的な演算子

●基本的なデータ構造

●範囲オブジェクト

●制御構造

●関数

julia> foo(x) = x^2
foo (generic function with 1 method)

julia> foo(x, y) = x^2 + y^2
foo (generic function with 2 methods)

julia> foo(x, y, z) = x^2 + y^2 + z^2
foo (generic function with 3 methods)

julia> foo(3)
9

julia> foo(3, 4)
25

julia> foo(3, 4, 5)
50

julia> bar(x::Int) = println("bar:Int")
bar (generic function with 1 method)

julia> bar(x::Float64) = println("bar:Float64")
bar (generic function with 2 methods)

julia> bar(1)
bar:Int

julia> bar(1.2345)
bar:Float64

julia> baz(x::Int, y::Int) = println("baz, Int, Int")
baz (generic function with 1 method)

julia> baz(x::Int, y::Float64) = println("baz, Int, Float")
baz (generic function with 2 methods)

julia> baz(x::Float64, y::Float64) = println("baz, Float, Float")
baz (generic function with 3 methods)]

julia> baz(1, 2)
baz, Int, Int

julia> baz(1, 0.1)
baz, Int, Float

julia> baz(1.1, 1.2)
baz, Float, Float

julia> baz(1.1, 1)
ERROR: MethodError: `baz` has no method matching baz(::Float64, ::Int32)
Closest candidates are:
  baz(::Int32, ::Int32)
  baz(::Float64, ::Float64)

●変数

function foo(n)
    for x in 1:n
        print(x)
    end
    print(x)      # 大域変数にアクセスする
end
julia> x = 100
100

julia> foo(5)
12345100
function bar(n)
    local x
    for x in 1:n  # local で宣言した局所変数 x を使用する
        print(x)
    end
    print(x)      # 局所変数 x をアクセス
end

function baz()
    global x      # global がないと x は局所変数になる
    x = 100       # 大域変数の値を書き換えたいときは global が必要になる
end
julia> bar(5)
123455

julia> x = 0
0

julia> baz()
100

julia> x
100
julia> x, y = 1, 2            # 大域変数
(1,2)

julia> let x = 10, y = 20     # (A)
       let x = 100, y = 200   # (B)
       println(x, y)          # (B) の x, y を表示
       end                    # (B) で定義した変数の有効範囲はここまで
       println(x, y)          # (A) の x, y を表示
       end                    # (A) で定義した変数の有効範囲はここまで
100200
1020

julia> println(x,y)           # 大域変数を表示
12

●データ型の定義

julia> type Foo
       a::Int
       b::Float64
       end

julia> x = Foo(1, 1.23456)
Foo(1,1.23456)

julia> x.a
1

julia> x.a = 10
10

julia> x
Foo(10,1.23456)
julia> immutable Foo
       a
       Foo(x) = x > 0 ? new(x) : new(-x)
       end

julia> foo = Foo(10)
Foo(10)

julia> bar = Foo(-10)
Foo(10)
julia> Foo = Union{Int, Void}
Union{Int32,Void}

julia> Int <: Foo
true

julia> Void <: Foo
true

julia> type Baz
       x::Foo
       end

julia> Baz(123)
Baz(123)

julia> Baz(nothing)
Baz(nothing)

●型パラメータ

julia> type Foo{T}
       x::T
       end

julia> Foo{Int}(123)
Foo{Int32}(123)

julia> Foo{Float64}(1.2345)
Foo{Float64}(1.2345)
julia> foo{T}(a::Foo{T}) = a.x
foo (generic function with 1 method)

julia> x = Foo{Int}(123)
Foo{Int32}(123)

julia> y = Foo{Float64}(1.2345)
Foo{Float64}(1.2345)

julia> foo(x)
123

julia> foo(y)
1.2345
julia> type Bar{T <: Integer}
       x::T
       end

julia> Bar{Int}(123)
Bar{Int32}(123)

julia> Bar{Int64}(123)
Bar{Int64}(123)

julia> Bar{Float64}(1.23)
ERROR: TypeError: Bar: in T, expected T<:Integer, got Type{Float64}

●ファイル入出力

open("test.txt", "r") do fin
    for s in eachline(fin)
        print(s)
    end
end
C>julia test.jl abc def ghi
UTF8String["abc","def","ghi"]

●例外処理

julia> try
       error("oops!")
       catch err
       print(err)
       finally
       print("finish!!")
       end
ErrorException("oops!")finish!!
julia> try
       throw("oops")
       catch err
       println(err)
       end
oops

julia> try
       throw(ErrorException("oops"))
       catch err
       println(err)
       end
ErrorException("oops")

●ベクトルと行列

julia> a = [1 2 3; 4 5 6]
2x3 Array{Int32,2}:
 1  2  3
 4  5  6

julia> b = [3 2 1; 6 5 4]
2x3 Array{Int32,2}:
 3  2  1
 6  5  4

julia> a + b
2x3 Array{Int32,2}:
  4   4   4
 10  10  10

julia> a - b
2x3 Array{Int32,2}:
 -2  0  2
 -2  0  2

julia> a * 10
2x3 Array{Int32,2}:
 10  20  30
 40  50  60

julia> b + 5
2x3 Array{Int32,2}:
  8   7  6
 11  10  9

julia> a .* b
2x3 Array{Int32,2}:
  3   4   3
 24  25  24

julia> a ./ b
2x3 Array{Float64,2}:
 0.333333  1.0  3.0
 0.666667  1.0  1.5
julia> b'
3x2 Array{Int32,2}:
 3  6
 2  5
 1  4

julia> a * b'
2x2 Array{Int32,2}:
 10  28
 28  73

julia> f = [big(1) big(1); big(1) big(0)]
2x2 Array{BigInt,2}:
 1  1
 1  0

julia> f ^ 100
2x2 Array{BigInt,2}:
 573147844013817084101  354224848179261915075
 354224848179261915075  218922995834555169026

julia> c =[2 3; 1 2]
2x2 Array{Int32,2}:
 2  3
 1  2

julia> inv(c)
2x2 Array{Float64,2}:
  2.0  -3.0
 -1.0   2.0

julia> c * inv(c)
2x2 Array{Float64,2}:
 1.0  0.0
 0.0  1.0

julia> det(c)
1.0

julia> rank(c)
2
julia> trace(c)
4

julia> diag(c)
2-element Array{Int32,1}:
 2
 2

julia> diagm([1,2,3])
3x3 Array{Int32,2}:
 1  0  0
 0  2  0
 0  0  3

julia> v = [1,2,3]
3-element Array{Int32,1}:
 1
 2
 3

julia> w = [4,5,6]
3-element Array{Int32,1}:
 4
 5
 6

julia> norm(v)
3.7416573867739413

julia> norm(w)
8.774964387392123

julia> v' * w
1-element Array{Int32,1}:
 32
julia> c = reshape(1:9, 3, 3)
3x3 Array{Int32,2}:
 1  4  7
 2  5  8
 3  6  9

julia> for x in a
       print(x)
       end
123456789

julia> reshape(c, 9)
9-element Array{Int32,1}:
 1
 2
 3
 4
 5
 6
 7
 8
 9

julia> reshape(c, 1, 9)
1x9 Array{Int32,2}:
 1  2  3  4  5  6  7  8  9

julia> vcat(a, b)
4x3 Array{Int32,2}:
 1  2  3
 4  5  6
 3  2  1
 6  5  4

julia> hcat(a, b)
2x6 Array{Int32,2}:
 1  2  3  3  2  1
 4  5  6  6  5  4

●イテレータ

julia> immutable Fibo
       end

julia> Base.start(::Fibo) = (0, 1)
start (generic function with 49 methods)

julia> Base.next(::Fibo, state) = (state[1], (state[2], state[1] + state[2]))
next (generic function with 62 methods)

julia> Base.done(::Fibo, state) = state[1] < 0
done (generic function with 51 methods)

julia> for x in Fibo()
       print(x), print(" ")
       end
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711
28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578
5702887 9227465 14930352 24157817 39088169 63245986 102334155 165580141 267914296
433494437 701408733 1134903170 1836311903
julia> collect(Fibo())
47-element Array{Any,1}:
          0
          1
          1
          2
          3
          5
          8
         13
         21
         34
          ⋮⋮
   24157817
   39088169
   63245986
  102334155
  165580141
  267914296
  433494437
  701408733
 1134903170
 1836311903

●モジュール

julia> module Foo
       a = 10
       export foo
       foo(x) = a * x
       end
Foo

julia> module Bar
       a = 100
       export bar
       bar(x) = a + x
       end
Bar

julia> Foo.a
10

julia> Foo.foo(10)
100

julia> Bar.a
100

julia> Bar.bar(5)
105

julia> import Foo.foo

julia> foo(100)
1000

julia> importall Bar

julia> bar(10)
110

●Expr 型と Symbol 型

julia> :((1 + 2) * (3 - 4))
:((1 + 2) * (3 - 4))

julia> typeof(:((1 + 2) * (3 - 4)))
Expr

julia> dump(:((1 + 2) * (3 - 4)))
Expr
  head: Symbol call
  args: Array(Any,(3,))
    1: Symbol *
    2: Expr
      head: Symbol call
      args: Array(Any,(3,))
        1: Symbol +
        2: Int32 1
        3: Int32 2
      typ: Any
    3: Expr
      head: Symbol call
      args: Array(Any,(3,))
        1: Symbol -
        2: Int32 3
        3: Int32 4
      typ: Any
  typ: Any
julia> a = :foo
:foo

julia> b = Symbol("foo")
:foo

julia> a === b
true

julia> "foo" === "foo"
false

julia> Meta.show_sexpr(:((1 + 2) * (3 - 4)))
(:call, :*, (:call, :+, 1, 2), (:call, :-, 3, 4))

julia> eval(:((1 + 2) * (3 - 4)))
-3

julia> x = 100
100

julia> :(x + 200)
:(x + 200)

julia> :($x + 200)
:(100 + 200)

julia> eval(:(x + 200))
300

julia> x = 10
10

julia> eval(:(x + 200))
210

●マクロ

julia> macro m_square(x)
       :($x * $x)
       end

julia> @m_square(100)
10000

julia> a = 20
20

julia> @m_square(a)
400

julia> x = 123
123

julia> @m_square(x * 2) # 123 * 2 * 123 * 2
60516

julia> foo(x) = (println("foo!"); x)
foo (generic function with 1 method)

julia> @m_square(foo(10))
foo!
foo!
100
julia> macro add10(x)
       :($x += 10)
       end

julia> x = 10
10

julia> let y = 20
       @add10(x)    # x += 10 と展開されるので、大域変数 x に 10 を加算
       @add10(y)    # y += 10 と展開されるので、局所変数 y に 10 を加算
       println(x)
       println(y)
       end
20
30

julia> x
20
julia> macro putx(n)
       :(x = $n)
       end

julia> x = 0
0

julia> @putx(100)
100

julia> x
0

julia> let x = 100
       @putx(1000)
       println(x)
       end
100

julia> macroexpand(:(@putx(100)))
:(#4#x = 100)                         # x が #4#x に置き換えられている

julia> macro setf(x, y)
       :($x = $y)                     # マクロの引数 x が変数名でも置換される
       end

julia> a = 10
10

julia> @setf(a, 20)
20

julia> a
10

julia> macroexpand(:(@setf(a, 20)))
:(#11#a = 20)
julia> macro putx(n)
       esc(:(x = $n))
       end

julia> x = 0
0

julia> @putx(100)
100

julia> x
100

julia> let x = 100
       @putx(1000)
       println(x)
       end
1000

julia> macro setf(x, y)
       esc(:($x = $y))
       end

julia> a = 10
10

julia> b = 20
20

julia> @setf(a, b)
20

julia> a
20

julia> b
20

julia> let a = 100, b = 200
       @setf(a, b)
       println(a)
       end
200

●PriorityQueue

julia> pq = Collections.PriorityQueue(ASCIIString, Int)
Base.Collections.PriorityQueue{ASCIIString,Int32,Base.Order.ForwardOrdering} with 0 entries

julia> Collections.enqueue!(pq, "foo", 10)
Base.Collections.PriorityQueue{ASCIIString,Int32,Base.Order.ForwardOrdering} with 1 entry:
  "foo" => 10

julia> Collections.enqueue!(pq, "bar", 20)
Base.Collections.PriorityQueue{ASCIIString,Int32,Base.Order.ForwardOrdering} with 2 entries:
  "foo" => 10
  "bar" => 20

julia> Collections.enqueue!(pq, "baz", 30)
Base.Collections.PriorityQueue{ASCIIString,Int32,Base.Order.ForwardOrdering} with 3 entries:
  "foo" => 10
  "baz" => 30
  "bar" => 20

julia> Collections.enqueue!(pq, "oops", 0)
Base.Collections.PriorityQueue{ASCIIString,Int32,Base.Order.ForwardOrdering} with 4 entries:
  "foo"  => 10
  "baz"  => 30
  "oops" => 0
  "bar"  => 20

julia> length(pq)
4

julia> isempty(pq)
false

julia> Collections.peek(pq)
"oops"=>0

julia> Collections.dequeue!(pq)
"oops"

julia> while !isempty(pq); println(Collections.dequeue!(pq)); end
foo
bar
baz

julia> pq["abc"] = 10
10

julia> pq["def"] = 5
5

julia> pq
Base.Collections.PriorityQueue{ASCIIString,Int32,Base.Order.ForwardOrdering} with 2 entries:
  "def" => 5
  "abc" => 10

julia> Collections.dequeue!(pq)
"def"
julia> a = [4,3,2,1]
4-element Array{Int32,1}:
 4
 3
 2
 1

julia> Collections.heapify!(a)
4-element Array{Int32,1}:
 1
 3
 2
 4

julia> while !isempty(a); println(Collections.heappop!(a)); end
1
2
3
4

julia> for x in [9,8,7,6]; Collections.heappush!(a, x); end

julia> a
4-element Array{Int32,1}:
 6
 7
 8
 9

●do block

julia> xs = [1,2,3,4,5]
5-element Array{Int32,1}:
 1
 2
 3
 4
 5

julia> map(x -> x * x, xs)
5-element Array{Int32,1}:
  1
  4
  9
 16
 25

julia> map(xs) do x
       x * x
       end
5-element Array{Int32,1}:
  1
  4
  9
 16
 25
julia> foldr((x, y) -> x + y, 0, xs)
15

julia> foldr(0, xs) do x, y
       x + y
       end
15
julia> function map2(f, xs, ys)
       zs = []
       for i in 1 : min(length(xs), length(ys))
       push!(zs, f(xs[i], ys[i]))
       end
       zs
       end
map2 (generic function with 1 method)

julia> map2([1,2,3], [4,5,6]) do x, y
       (x, y)
       end
3-element Array{Any,1}:
 (1,4)
 (2,5)
 (3,6)

●特殊な関数

julia> type Foo
       a
       b
       c
       end

julia> function Base.getindex(x::Foo, i::Int)
       if i == 1
       x.a
       elseif i == 2
       x.b
       elseif i == 3
       x.c
       else
       throw(BoundsError(x, i))
       end
       end
getindex (generic function with 120 methods)

julia> x = Foo(1, 2, 3)
Foo(1,2,3)

julia> x[1]
1

julia> x[2]
2

julia> x[3]
3

julia> x[4]
ERROR: BoundsError: attempt to access Foo(1,2,3)
  at index [4]
 in getindex at none:9

julia> function Base.setindex!(x::Foo, v, i::Int)
       if i == 1
       x.a = v
       elseif i == 2
       x.b = v
       elseif i == 3
       x.c = v
       else
       throw(BoundsError(x, i))
       end
       end
setindex! (generic function with 58 methods)

julia> x
Foo(1,2,3)

julia> x[1] = 10
10

julia> x
Foo(10,2,3)

julia> x[3] = 30
30

julia> x
Foo(10,2,30)

julia> Base.endof(x::Foo) = 3
endof (generic function with 18 methods)

julia> x[end]
30

julia> x[end - 1]
2
julia> immutable Foo
       a
       end

julia> call(x::Foo, y) = x.a * y
call (generic function with 1039 methods)

julia> foo10 = Foo(10)
Foo(10)

julia> foo10(5)
50

julia> foo10(123)
1230

julia> foo50 = Foo(50)
Foo(50)

julia> foo50(5)
250

julia> foo50(123)
6150

julia> type Fibo
       a
       b
       end

julia> function call(x::Fibo)
       c = x.a
       x.a = x.b
       x.b += c
       c
       end
call (generic function with 1041 methods)

julia> fibo = Fibo(0, 1)
Fibo(0,1)

julia> for _ in 1:20; println(fibo()); end
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181

●タスク (コルーチン)

julia> function foo()
       for x in 1 : 4
       produce(x)
       end
       5
       end
foo (generic function with 1 method)

julia> co = Task(foo)
Task (runnable) @0x04c624a0

julia> consume(co)
1

julia> consume(co)
2

julia> consume(co)
3

julia> consume(co)
4

julia> istaskdone(co)
false

julia> consume(co)
5

julia> istaskdone(co)
true

julia> consume(co)
5

julia> consume(co)
5
julia> for x in Task(foo)
       println(x)
       end
1
2
3
4

julia> function bar(xs)
       for x in xs
       produce(x)
       end
       end
bar (generic function with 1 method)

julia> co1 = @task bar([1,2,3,4,5])
Task (runnable) @0x0582c010

julia> for x in co1
       println(x)
       end
1
2
3
4
5

●並列プログラミング

C>julia -p 4

julia> nworkers()
4

julia> nprocs()
5
julia> @everywhere include("fibo.jl")    # 二重再帰のフィボナッチ関数

julia> @time fibo(40)
  1.051864 seconds (1.19 k allocations: 40.126 KB)
102334155

julia> r = remotecall(2, fibo, 40)
RemoteRef{Channel{Any}}(2,1,9)

julia> fetch(r)
102334155

julia> @time fibo(40) + fibo(40)
  2.123319 seconds (7 allocations: 208 bytes)
204668310

julia> function test()
       a = remotecall(2, fibo, 40)
       b = remotecall(3, fibo, 40)
       fetch(a) + fetch(b)
       end
test (generic function with 1 method)

julia> @time test()
  1.173763 seconds (3.26 k allocations: 108.768 KB)
204668310

julia> function test1()
       a = remotecall(2, fibo, 40)
       b = remotecall(2, fibo, 40)
       fetch(a) + fetch(b)
       end
test1 (generic function with 1 method)

julia> @time test1()
  2.134433 seconds (91.63 k allocations: 2.256 MB)
204668310
julia> function test2()
       a = @spawn fibo(40)
       b = @spawn fibo(40)
       fetch(a) + fetch(b)
       end
test2 (generic function with 1 method)

julia> @time test2()
  1.168145 seconds (10.66 k allocations: 328.044 KB)
204668310
julia> @time @parallel (+) for _ in 1 : 2; fibo(40); end
  1.057485 seconds (3.34 k allocations: 162.617 KB)
204668310

julia> @time @parallel (+) for _ in 1 : 3; fibo(40); end
  1.200406 seconds (4.23 k allocations: 216.094 KB)
307002465

julia> @time @parallel (+) for _ in 1 : 4; fibo(40); end
  1.214987 seconds (5.26 k allocations: 277.074 KB, 0.42% gc time)
409336620

julia> @time @parallel (+) for _ in 1 : 5; fibo(40); end
  2.094256 seconds (5.17 k allocations: 271.559 KB)
511670775

julia> @time map(fibo, [40, 40, 40, 40])
  4.177310 seconds (68.58 k allocations: 2.350 MB)
4-element Array{Int32,1}:
 102334155
 102334155
 102334155
 102334155

julia> @time pmap(fibo, [40, 40, 40, 40])
  1.328541 seconds (163.85 k allocations: 4.456 MB)
4-element Array{Any,1}:
 102334155
 102334155
 102334155
 102334155

julia> @time pmap(fibo, [40, 40, 40, 40, 40])
  2.105133 seconds (753 allocations: 35.996 KB)
5-element Array{Any,1}:
 102334155
 102334155
 102334155
 102334155
 102334155
julia> @time @sync (@spawn fibo(40); @spawn fibo(40))
  1.132831 seconds (736 allocations: 34.887 KB)
RemoteRef{Channel{Any}}(5,1,50)

julia> @time (@spawn fibo(40); @spawn fibo(40))
  0.009628 seconds (418 allocations: 22.246 KB)
RemoteRef{Channel{Any}}(3,1,54)
julia> @everywhere cnt = 0

julia> @everywhere function test(n)
       for _ in 1 : 10
       global cnt        # ワーカープロセスで実行すると、
                         # そのワーカープロセスの大域変数 cnt にアクセスする
       cnt += n
       println(cnt)
       sleep(n)
       end
       end

julia> r = @spawn test(1); fetch(r)
        From worker 3:  1
        From worker 3:  2
        From worker 3:  3
        From worker 3:  4
        From worker 3:  5
        From worker 3:  6
        From worker 3:  7
        From worker 3:  8
        From worker 3:  9
        From worker 3:  10

julia> cnt
0                        # マスタープロセスの cnt は 0 のまま

julia> a = [1,2,3,4,5]
5-element Array{Int32,1}:
 1
 2
 3
 4
 5

julia> @everywhere test1(a, n, x) = (a[n] = x; println(a))

julia> r = @spawn test1(a, 3, 30); fetch(r)
        From worker 4:  [1,2,30,4,5]    # ワーカープロセスの配列を変更

julia> a                 # マスタープロセスの配列は変更されていない
5-element Array{Int32,1}:
 1
 2
 3
 4
 5

julia> r = @spawn rand(2, 2)
RemoteRef{Channel{Any}}(2,1,5)

julia> a = fetch(r)     # fetch(r) の返り値 (配列) はコピーされる
2x2 Array{Float64,2}:
 0.124082  0.777929
 0.927621  0.245422

julia> a[1,1] = 1.2345  # 配列 a を書き換える
1.2345

julia> a
2x2 Array{Float64,2}:
 1.2345    0.777929
 0.927621  0.245422

julia> fetch(r)         # ワーカープロセスの返り値は元のまま
2x2 Array{Float64,2}:
 0.124082  0.777929
 0.927621  0.245422

Copyright (C) 2016 Makoto Hiroi
All rights reserved.

[ Home | Light | Julia ]