M.Hiroi's Home Page

Julia Language Programming

お気楽 Julia プログラミング超入門

[ Home | Light | Julia ]

Julia の基礎知識

●内包表記とジェネレータ式

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

julia> [x * x for x = a]
5-element Array{Int64,1}:
  1
  4
  9
 16
 25

julia> [(x, x * x) for x = a]
5-element Array{Tuple{Int64,Int64},1}:
 (1, 1)
 (2, 4)
 (3, 9)
 (4, 16)
 (5, 25)

julia> [x * x for x = a if x % 2 == 0]
2-element Array{Int64,1}:
  4
 16

julia> [x + y for x = 1 : 3, y = 10 : 13]
3×4 Array{Int64,2}:
 11  12  13  14
 12  13  14  15
 13  14  15  16

julia> [x + y for x = 1 : 3 for y = 10 : 13]
12-element Array{Int64,1}:
 11
 12
 13
 14
 12
 13
 14
 15
 13
 14
 15
 16

julia> [x + y for x = 1 : 3, y = 10 : 13 if (x + y) % 2 == 0 ]
6-element Array{Int64,1}:
 12
 12
 14
 14
 14
 16
julia> a
5-element Array{Int64,1}:
 1
 2
 3
 4
 5

julia> b = (x * x for x = a)
Base.Generator{Vector{Int64}, var"#19#20"}(var"#19#20"(), [1, 2, 3, 4, 5])

julia> for x in b
       println(x)
       end
1
4
9
16
25

julia> collect(b)
5-element Array{Int64,1}:
  1
  4
  9
 16
 25

julia> k = ["foo", "bar", "baz"]
3-element Array{String,1}:
 "foo"
 "bar"
 "baz"

julia> v = [10, 20, 30]
3-element Array{Int64,1}:
 10
 20
 30

julia> d = Dict(key => val for (key, val) = zip(k, v))
Dict{String,Int64} with 3 entries:
  "bar" => 20
  "baz" => 30
  "foo" => 10

julia> Set(x * x for x = 1 : 10)
Set{Int64} with 10 elements:
  64
  4
  16
  49
  25
  36
  81
  9
  1
  100

●データ型の定義

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

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

julia> typeof(x)
Foo

julia> x.a
1

julia> x.b
1.23456

julia> x.a = 10
ERROR: setfield! immutable struct of type Foo cannot be changed

julia> mutable struct Bar
       a::Int
       b::Float64
       end

julia> y = Bar(100, 123.456)
Bar(100, 123.456)

julia> typeof(y)
Bar

julia> y.a
100

julia> y.a = 200
200

julia> y
Bar(200, 123.456)
julia> struct Foo1
       a::Int
       Foo1(x) = x > 0 ? new(x) : new(-x)
       end

julia> foo1 = Foo1(10)
Foo1(10)

julia> foo2 = Foo1(-10)
Foo1(10)
julia> Foo2 = Union{Int, Nothing}
Union{Nothing, Int64}

julia> Int <: Foo2
true

julia> Nothing <: Foo2
true

julia> struct Baz
       x::Foo2
       end

julia> Baz(123)
Baz(123)

julia> Baz(nothing)
Baz(nothing)

●型パラメータ

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

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

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

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

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

julia> foo(x)
123

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

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

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

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

●ファイル入出力

open("test.txt", "r") do fin
    for s = eachline(fin)
        println(s)
    end
end
julia> open("test.txt", "w") do fout
       for i = 1 : 5
       write(fout, "hello, Julia!\n")
       end
       end

julia> open("test.txt") do fin
       for line = eachline(fin)
       println(line)
       end
       end
hello, Julia!
hello, Julia!
hello, Julia!
hello, Julia!
hello, Julia!

julia> fin = open("test.txt")
IOStream(<file test.txt>)

julia> read(fin, String)
"hello, Julia!\nhello, Julia!\nhello, Julia!\nhello, Julia!\nhello, Julia!\n"

julia> close(fin)

julia> fin = open("test.txt")
IOStream(<file test.txt>)

julia> readlines(fin)
5-element Vector{String}:
 "hello, Julia!"
 "hello, Julia!"
 "hello, Julia!"
 "hello, Julia!"
 "hello, Julia!"

julia> close(fin)

リスト : コマンドライン引数の表示 (test.jl)

println(ARGS)
$ julia test.jl abc def ghi
["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> foo() = println("foo!")
foo (generic function with 1 method)

julia> bar() = (println("bar!"); throw("Global Exit!!"))
bar (generic function with 1 method)

julia> baz() = println("baz!")
baz (generic function with 1 method)

julia> test() = (foo(); bar(); baz())
test (generic function with 1 method)

julia> try
       test()
       catch err
       println(err)
       end
foo!
bar!
Global Exit!!

●モジュール

julia> module Foo
       a, b, c, d = 1, 2, 3, 4
       export a, b
       end
Main.Foo

julia> Foo.a
1

julia> Foo.b
2

julia> Foo.c
3

julia> Foo.d
4

julia> using .Foo

julia> a
1

julia> b
2

julia> c
ERROR: UndefVarError: c not defined

julia> import .Foo.c

julia> c
3
julia> c = 10
ERROR: cannot assign variable Foo.c from module Main
リスト : モジュールの簡単な使用例 (test_mod.jl)

module Foo
    a = 1
    set_a(x) = global a = x
    function show_a()
        println("Foo.a = $a")
        println("Foo.Bar.a = $(Bar.a)")
        println("Foo.Bar.Baz.a = $(Bar.Baz.a)")
    end

    module Bar 
        a = 10
        set_a(x) = global a = x
        import ..Foo             # 一つ外側のモジュール Foo をインポート
        function show_a()
            println("Foo.a = $(Foo.a)")
            println("Foo.Bar.a = $a")
            println("Foo.Bar.Baz.a = $(Baz.a)")
        end

        module Baz
            a = 100
            set_a(x) = global a = x
            import ..Bar
            import ...Foo        # 二つ外側のモジュール Foo をインポート
            function show_a()
                println("Foo.a = $(Foo.a)")
                println("Foo.Bar.a = $(Bar.a)")
                println("Foo.Bar.Baz.a = $a")
            end
        end
    end
end
julia> include("test_mod.jl")
Main.Foo

julia> Foo.Bar.Baz.show_a()
Foo.a = 1
Foo.Bar.a = 10
Foo.Bar.Baz.a = 100

julia> Foo.set_a(123)
123

julia> Foo.Bar.Baz.show_a()
Foo.a = 123
Foo.Bar.a = 10
Foo.Bar.Baz.a = 100

●イテレータ

julia> struct Fibo
       end

julia> Base.iterate(::Fibo, state=(0, 1)) =
       if state[1] < 0
       nothing
       else
       (state[1], (state[2], state[1] + state[2]))
       end

julia> for x = Fibo()
       print(x, " ")
       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 2971215073 4807526976 7778742049 
12586269025 20365011074 32951280099 53316291173 86267571272 139583862445 225851433717 365435296162 
591286729879 956722026041 1548008755920 2504730781961 4052739537881 6557470319842 10610209857723 
17167680177565 27777890035288 44945570212853 72723460248141 117669030460994 190392490709135 308061521170129 
498454011879264 806515533049393 1304969544928657 2111485077978050 3416454622906707 5527939700884757 
8944394323791464 14472334024676221 23416728348467685 37889062373143906 61305790721611591 99194853094755497 
160500643816367088 259695496911122585 420196140727489673 679891637638612258 1100087778366101931 
1779979416004714189 2880067194370816120 4660046610375530309 7540113804746346429

julia> Base.length(::Fibo) = 93

julia> collect(Fibo())
93-element Vector{Any}:
                   0
                   1
                   1
                   2
                   3
                   5
                   8
                  13
                  21
                  34
                  55
                  89
                 144
                 233
                   ⋮
   23416728348467685
   37889062373143906
   61305790721611591
   99194853094755497
  160500643816367088
  259695496911122585
  420196140727489673
  679891637638612258
 1100087778366101931
 1779979416004714189
 2880067194370816120
 4660046610375530309
 7540113804746346429
julia> for x = Iterators.enumerate(11 : 15)
       print(x, " ")
       end
(1, 11) (2, 12) (3, 13) (4, 14) (5, 15)
julia> for x = Iterators.zip(1 : 5, 11 : 15)
       print(x, " ")
       end
(1, 11) (2, 12) (3, 13) (4, 14) (5, 15)
julia> collect(Iterators.take(Fibo(), 10))
10-element Vector{Any}:
  0
  1
  1
  2
  3
  5
  8
 13
 21
 34

julia> collect(Iterators.take(Iterators.drop(Fibo(), 10), 5))
5-element Vector{Any}:
  55
  89
 144
 233
 377

julia> collect(Iterators.take(Iterators.cycle(1 : 4), 10))
10-element Vector{Int64}:
 1
 2
 3
 4
 1
 2
 3
 4
 1
 2

julia> collect(Iterators.take(Iterators.repeated(0), 5))
5-element Vector{Int64}:
 0
 0
 0
 0
 0

julia> collect(Iterators.product(1 : 3, 4 : 6))
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 4)  (1, 5)  (1, 6)
 (2, 4)  (2, 5)  (2, 6)
 (3, 4)  (3, 5)  (3, 6)

julia> for x = Iterators.product(1 : 3, 4 : 6)
       print(x, " ")
       end
(1, 4) (2, 4) (3, 4) (1, 5) (2, 5) (3, 5) (1, 6) (2, 6) (3, 6)
julia> collect(Iterators.flatten(Iterators.product(1 : 3, 4 : 6)))
18-element Vector{Int64}:
 1
 4
 2
 4
 3
 4
 1
 5
 2
 5
 3
 5
 1
 6
 2
 6
 3
 6

julia> collect(Iterators.partition(1 : 10, 3))
4-element Vector{UnitRange{Int64}}:
 1:3
 4:6
 7:9
 10:10

julia> collect(Iterators.partition(collect(1 : 10), 3))
4-element Vector{SubArray{Int64, 1, Vector{Int64}, Tuple{UnitRange{Int64}}, true}}:
 [1, 2, 3]
 [4, 5, 6]
 [7, 8, 9]
 [10]

julia> collect(Iterators.filter(isodd, 1 : 10))
5-element Vector{Int64}:
 1
 3
 5
 7
 9

julia> for x = Iterators.reverse(1 : 10)
       print(x, " ")
       end
10 9 8 7 6 5 4 3 2 1

julia> collect(Iterators.take(Iterators.rest(Fibo(), (55, 89)), 10))
10-element Vector{Any}:
   55
   89
  144
  233
  377
  610
  987
 1597
 2584
 4181
julia> a = 1 : 5
1:5

julia> for x = a
       if x == 3 break end
       println(x)
       end
1
2

julia> collect(a)
5-element Vector{Int64}:
 1
 2
 3
 4
 5

julia> b = Iterators.Stateful(a)
Base.Iterators.Stateful{UnitRange{Int64},Union{Nothing, Tuple{Int64,Int64}}}(1:5, (1, 1), 0)

julia> for x = b
       if x == 3 break end
       println(x)
       end
1
2

julia> collect(b)
2-element Vector{Int64}:
 4
 5

julia> isempty(b)
true

簡単なプログラム

●経路の探索


      図 : 経路図
リスト : 経路の探索 (keiro.jl)

#=
 A = 1, B = 2, C = 3, D = 4, 
 E = 5, F = 6, G = 7
=#

# 隣接リスト (配列の配列)
adjacent = [
    [2, 3],
    [1, 3, 4],
    [1, 2, 5],
    [2, 5, 6],
    [3, 4, 7],
    [4],
    [5]
]

# 深さ優先探索
function dfs(goal, xs)
    if xs[end] == goal
        println(xs)
    else
        for p = adjacent[xs[end]]
            if p in xs; continue; end
            push!(xs, p)
            dfs(goal, xs)
            pop!(xs)
        end
    end
end

# 幅優先探索
function bfs(start, goal)
    que = Array{Int,1}[[1]]
    while length(que) > 0
        xs = popfirst!(que)
        if xs[end] == goal
            println(xs)
        else
            for p = adjacent[xs[end]]
                if p in xs; continue; end
                ys = copy(xs)
                push!(ys, p)
                push!(que, ys)
            end
        end
    end
end

# 反復進化

function ids(start, goal)
    function dfs(xs, limit)
        if length(xs) == limit
            if xs[end] == goal
                println(xs)
            end
        else
            for p = adjacent[xs[end]]
                if p in xs; continue; end
                push!(xs, p)
                dfs(xs, limit)
                pop!(xs)
            end
        end
    end

    for limit = 1 : length(adjacent)
      println("----- $limit -----")
      dfs([1], limit)
    end
end

println("----- dfs -----")
dfs(6, [1])
println("----- bfs -----")
bfs(1, 6)
println("----- ids -----")
ids(1, 6)
$ julia keiro.jl
----- dfs -----
[1, 2, 3, 5, 4, 6]
[1, 2, 4, 6]
[1, 3, 2, 4, 6]
[1, 3, 5, 4, 6]
----- bfs -----
[1, 2, 4, 6]
[1, 3, 2, 4, 6]
[1, 3, 5, 4, 6]
[1, 2, 3, 5, 4, 6]
----- ids -----
----- 1 -----
----- 2 -----
----- 3 -----
----- 4 -----
[1, 2, 4, 6]
----- 5 -----
[1, 3, 2, 4, 6]
[1, 3, 5, 4, 6]
----- 6 -----
[1, 2, 3, 5, 4, 6]
----- 7 -----

●ナンバープレース

リスト : ナンバープレースの解法 (numplace.jl)

function check(board, x, y, n)
    # 縦横のチェック
    for i = 1 : 9
        if board[x, i] == n || board[i, y] == n
            return false
        end
    end
    # 枠のチェック
    x1 = div(x - 1, 3) * 3 + 1
    y1 = div(y - 1, 3) * 3 + 1
    for i = 0 : 2, j = 0 : 2
        if board[x1 + i, y1 + j] == n
            return false
        end
    end
    true
end

function solver(board, x, y)
    if y == 10
        println(board)
    elseif x == 10
        solver(board, 1, y + 1)
    elseif board[x, y] != 0
        solver(board, x + 1, y)
    else
        for n = 1 : 9
            if !check(board, x, y, n); continue; end
            board[x, y] = n
            solver(board, x + 1, y)
            board[x, y] = 0
        end
    end
end

# 問題 (出典: 数独 - Wikipedia の問題例)
q00 = [
    5 3 0  0 7 0  0 0 0;
    6 0 0  1 9 5  0 0 0;
    0 9 8  0 0 0  0 6 0;

    8 0 0  0 6 0  0 0 3;
    4 0 0  8 0 3  0 0 1;
    7 0 0  0 2 0  0 0 6;

    0 6 0  0 0 0  2 8 0;
    0 0 0  4 1 9  0 0 5;
    0 0 0  0 8 0  0 7 9
]

println(q00)
println("--------")
@time solver(copy(q00), 1, 1)
println("--------")
$ julia numplace.jl
[5 3 0 0 7 0 0 0 0;
 6 0 0 1 9 5 0 0 0;
 0 9 8 0 0 0 0 6 0;
 8 0 0 0 6 0 0 0 3;
 4 0 0 8 0 3 0 0 1;
 7 0 0 0 2 0 0 0 6;
 0 6 0 0 0 0 2 8 0;
 0 0 0 4 1 9 0 0 5;
 0 0 0 0 8 0 0 7 9]
--------
[5 3 4 6 7 8 9 1 2;
 6 7 2 1 9 5 3 4 8;
 1 9 8 3 4 2 5 6 7;
 8 5 9 7 6 1 4 2 3;
 4 2 6 8 5 3 7 9 1;
 7 1 3 9 2 4 8 5 6;
 9 6 1 5 3 7 2 8 4;
 2 8 7 4 1 9 6 3 5;
 3 4 5 2 8 6 1 7 9]
  0.078586 seconds (45.60 k allocations: 2.915 MiB, 87.88% compilation time)
--------

●小町算

1 から 9 までの数字を順番に並べ、間に + と - を補って 100 になる式を作ってください。ただし、1 の前に - 符号はつけないものとします。

例:1 + 2 + 3 - 4 + 5 + 6 + 78 + 9 = 100
リスト : 小町算 (komachi.jl)

# 計算
function calc_expr(nums, ops)
    a = nums[1]
    i = 2
    for op = ops
        a += op == '+' ? nums[i] : -nums[i]
        i += 1
    end
    a
end

# 表示
function print_expr(nums, ops)
    print(nums[1])
    i = 2
    for op = ops
        print(op == '+' ? " + " : " - ")
        print(nums[i])
        i += 1
    end
    println(" = 100")
end

# 小町算の解法
function komachi(n, nums, ops)
    if n == 10
        if calc_expr(nums, ops) == 100
            print_expr(nums, ops)
        end
    else
        for op = ['+', '-']
            push!(ops, op)
            push!(nums, n)
            komachi(n + 1, nums, ops)
            pop!(nums)
            pop!(ops)
        end
        m = nums[end]
        nums[end] = m * 10 + n
        komachi(n + 1, nums, ops)
        nums[end] = m
    end
end

komachi(2, [1], [])
$ julia komachi.jl
1 + 2 + 3 - 4 + 5 + 6 + 78 + 9 = 100
1 + 2 + 34 - 5 + 67 - 8 + 9 = 100
1 + 23 - 4 + 5 + 6 + 78 - 9 = 100
1 + 23 - 4 + 56 + 7 + 8 + 9 = 100
12 + 3 + 4 + 5 - 6 - 7 + 89 = 100
12 + 3 - 4 + 5 + 67 + 8 + 9 = 100
12 - 3 - 4 + 5 - 6 + 7 + 89 = 100
123 + 4 - 5 + 67 - 89 = 100
123 + 45 - 67 + 8 - 9 = 100
123 - 4 - 5 - 6 - 7 + 8 - 9 = 100
123 - 45 - 67 + 89= 100

●ファイルの連結

#
# cat.jl : ファイルの連結
#
#          Copyright (C) 2016-2021 Makoto Hiroi
#

function cat(fin)
    for line = eachline(fin)
        println(line)
    end
end

#
if length(ARGS) == 0
    cat(stdin)
else
    for name = ARGS
        open(name, "r") do fin
            cat(fin)
        end
    end
end

●単語のカウント

#
# wc.jl : 単語のカウント
#
#         Copyright (C) 2016-2021 Makoto Hiroi
#
function wc(fin)
    word = 0
    inword = false
    while !eof(fin)
        c = read(fin, Char)
        if isspace(c)
            inword = false
        elseif !inword
            inword = true
            word += 1
        end
    end
    word
end

if length(ARGS) == 0
    println(wc(stdin))
else
    open(ARGS[1], "r") do fin
        println(wc(fin))
    end
end
julia> split("foo bar baz oops!")
4-element Vector{SubString{String}}:
 "foo"
 "bar"
 "baz"
 "oops!"

●文字列の検索

#
# grep.jl : 文字列の検索
#
#           Copyright (C) 2016-2021 Makoto Hiroi
#
function grep(fin, key)
    for line = eachline(fin)
        if occursin(key, line)
            println(line)
        end
    end
end

if length(ARGS) == 1
    # 検索文字列のみ
    grep(stdin, ARGS[1])
elseif length(ARGS) >= 2
    open(ARGS[2]) do fin
        grep(fin, ARGS[1])
    end
else
    println("usage: julia grep.jl key [filename]")
end
julia> occursin("hello", "hello, Julia!")
true

julia> occursin("julia", "hello, Julia!")
false

●文字の置換

#
# tr.jl : 文字の置換
#
#         Copyright (C) 2016-2021 Makoto Hiroi
#
function tr(fin, s1, s2)
    while !eof(fin)
        c = read(fin, Char)
        n = findfirst(isequal(c), s1)
        if n != nothing
            c = s2[n]
        end
        print(c)
    end
end

if length(ARGS) >= 2
    if length(ARGS[1]) == length(ARGS[2])
        if length(ARGS) == 2
            tr(stdin, ARGS[1], ARGS[2])
        else
            open(ARGS[3], "r") do fin
                tr(fin, ARGS[1], ARGS[2])
            end
        end
    else
        println("第 1 引数と第 2 引数の長さが異なる")
    end
else
    println("usage: julia tr str1 str2 [filename]")
end
julia> a = "abcde"
"abcde"

julia> a[1]
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)

julia> a[5]
'e': ASCII/Unicode U+0065 (category Ll: Letter, lowercase)

julia> a[2:4]
"bcd"
julia> findfirst(isequal('J'), "hello, Julia!")
8

julia> findfirst(isequal('j'), "hello, Julia!")

julia> findfirst("Julia", "hello, Julia!")
8:12

julia> findfirst("JuliA", "hello, Julia!")

●文字列の置換

#
# gres.jl : 文字列の置換
#
#           Copyright (C) 2016-2021 Makoto Hiroi
#
function gres(fin, pat, r)
    for line = eachline(fin)
        println(replace(line, pat => r))
    end
end

if length(ARGS) == 2
    gres(STDIN, ARGS[1], ARGS[2])
elseif length(ARGS) == 3
    open(ARGS[3], "r") do fin
        gres(fin, ARGS[1], ARGS[2])
    end
else
    println("usage: julia gres.jl pattern replace [filename]")
end
julia> replace("foo bar baz foo bar baz oops", "foo" => "FOO")
"FOO bar baz FOO bar baz oops"

julia> replace("foo bar baz foo bar baz oops", "foo" => "FOO", count=1)
"FOO bar baz foo bar baz oops"

●ファイルのコピー

#
# cp.jl : ファイルのコピー
#
#         Copyright (C) 2016-2021 Makoto Hiroi
#

# バイト単位のコピー
function cp(fin, fout)
    while !eof(fin)
        write(fout, read(fin, UInt8))
    end
end

# バッファに読み込む
function cp1(fin, fout)
    local n
    buff = Array{UInt8, 1}(undef, 16)
    while (n = readbytes!(fin, buff)) == 16
        write(fout, buff)
    end
    write(fout, buff[1 : n])
end

if length(ARGS) == 2
    open(ARGS[1], "r") do fin
        open(ARGS[2], "w") do fout
            cp(fin, fout)
        end
    end
else
    println("usage: julia cp.jl src dst")
end

●ファイルのエントロピー

#
# entoropy.jl : ファイルのエントロピーを求める
#
#               Copyright (C) 2016-2021 Makoto Hiroi
#
function entoropy(fin)
    count = zeros(Int, 256)
    while !eof(fin)
        c = read(fin, UInt8)
        count[c + 1] += 1
    end
    total = sum(count)
    e = 0.0
    for x = count
        if x == 0; continue; end
        p = x / total
        e += - p * log(2, p)
    end
    e, e * total / 8
end

if length(ARGS) == 1
    open(ARGS[1], "r") do fin
        println(entoropy(fin))
    end
else
    println("usage: julia entoropy.jl filename")
end

2021/11/27 改訂: Julia のバージョンを 1.6 に変更

Copyright (C) 2016-2021 Makoto Hiroi
All rights reserved.

[ Home | Light | Julia ]