RSS

月別アーカイブ: 12月 2021

Julia の勉強:自作パッケージ HtmlTable の紹介

概要

自作パッケージ (公式ではなく野良ですが) を作ったのでご紹介します。

なお、ソースは GitHub にアップロードしたのでダウンロード可能です。

このパッケージは、Matrix、DataFrame または CSV ファイルから HTML を生成します。

HTML は関数の出力として取得できるので、ファイル保存してブラウザに表示できます。

コンソールアプリでは、大きめの行列を表示すると見やすくありませんが、ブラウザで表示することでぐっと見やすくなります。

行列や表題行のない CSV データにはカラム名を追加できます。

また、行番号を追加して表示できます。

GitHub の URL は https://github.com/makandat/julia です。

使い方

GitHub から HtmlTable の内容をローカルのフォルダにそのままコピーします。

julia を対話モードで起動し、パッケージモードで activate した後、add コマンドを使って CSV, DataFrames, Tables パッケージをインストールします。

$ cd HtmlTable
$ julia
julia> ]
pkg> activate .
pkg> add CSV
pkg> add DataFrames
pkg> Tables

テストプログラムを実行して動作確認します。

$ cd HtmlTable
$ julia test/matrix.jl
$ julia dataframe.jl
$ julia csv.jl
$ julia rownum.jl

サンプルは上のテストプログラムのソースを参照してください。

エクスポート関数

function fromMatrix(mat::Matrix, columns::Vector; title=”HTML Table”, rownum=false)

fromMatrix() は行列 mat を元に HTML を生成します。

引数

  • mat: 入力行列
  • columns: 列名のベクトル
  • title=”HTML Table”: HTML のタイトル (option)
  • rownum=false: 行番号を列1に追加するかどうか。デフォルトは追加しない。(option)

戻り値

生成した HTML (::String)。

function fromDataFrame(df::DataFrame; title=”HTML Table”, rownum=false)

fromDataFrame() は DataFrame df を元に HTML を生成します。

引数

  • df: 入力の DataFrame
  • title=”HTML Table”: HTML のタイトル (option)
  • rownum=false: 行番号を列1に追加するかどうか。デフォルトは追加しない。(option)

戻り値

生成した HTML (::String)。

function fromCSV(path::String; header=true, delimter=”,”, stripQuote=true, title=”HTML Table”, rownum=false)

fromCSV() は path で指定される CSV ファイルを読み込んで HTML を生成します。

引数

  • path: CSV ファイルのパス名
  • header=true: CSV ファイルの先頭行を表題行とみなすかどうか。(option)
  • delimiter=”,”: カラムの区切り文字 (option)
  • stripQuote=true: データが引用符で囲まれているとき、その引用符を取り去るかどうか。(option)
  • title=”HTML Table”: HTML のタイトル (option)
  • rownum=false: 行番号を列1に追加するかどうか。デフォルトは追加しない。(option)

戻り値

生成した HTML (::String)。

カスタマイズ

スタイルシート

フィールド css を変更すれば、HTML のスタイルを変更できます。このフィールドはエクスポートされていないので、HtmlTable.css としてアクセスします。

HTML の内容

HTML の内容は HTMLFMT を変更する必要がありますが、このフィールドは const なのでソースを直接変更する必要があります。

 
コメントする

投稿者: : 2021/12/30 投稿先 Julia

 

タグ: , ,

Julia の勉強:DataFrame

DataFrame はオンメモリのデータベーステーブルあるいはワークシートのような機能を提供するパッケージです。

インストールですが、Julia のパッケージモードで add DataFrames としてもいいですが、確率・統計統合パッケージの StatsKit にも含まれているので、 StatsKit がインストールされていれば改めてインストールする必要はありません。
(注意) パッケージ名は DataFrames複数形なので注意。

構築

ベクトルやスカラーからも構築できますが、行列から構築することが多いと思われます。下に簡単なを示します。DataFrame コンストラクタの2番目の引数 :auto は列名をデフォルトで名づけるという意味です。

その場合、列名は “Column1”, “Column2”, … などとなります。

using DataFrames

payments = [
29801 "2020-01-07" "101" 20_180 "RayPay";
29802 "2020-01-09" "101" 42_352 "Anazon";
29803 "2020-01-11" "201" 25_811 "TEPKO";
29804 "2020-01-21" "301" 38_190 "Zip Insurance";
29805 "2020-01-26" "101" 67_553 "Biza Card";
29806 "2020-02-06" "101" 12_493 "Anazon";
29807 "2020-02-13" "522" 85_005 "Kz Denki"
]

df = DataFrame(payments, :auto)

@show df

テーブルの列名を付ける場合は、次のようにシンボルのベクトルで指定します。

using DataFrames

payments = [
29801 "2020-01-07" "101" 20_180 "RayPay";
29802 "2020-01-09" "101" 42_352 "Anazon";
29803 "2020-01-11" "201" 25_811 "TEPKO";
29804 "2020-01-21" "301" 38_190 "Zip Insurance";
29805 "2020-01-26" "101" 67_553 "Biza Card";
29806 "2020-02-06" "101" 12_493 "Anazon";
29807 "2020-02-13" "522" 85_005 "Kz Denki"
]

df = DataFrame(payments, [:ID, :DATE, :CODE, :AMOUNT, :INFO])

@show df

列名は日本語でも付けることができます。

using DataFrames

payments = [
29801 "2020-01-07" "101" 20_180 "RayPay";
29802 "2020-01-09" "101" 42_352 "Anazon";
29803 "2020-01-11" "201" 25_811 "TEPKO";
29804 "2020-01-21" "301" 38_190 "Zip 保険";
29805 "2020-01-26" "101" 67_553 "Biza カード";
29806 "2020-02-06" "101" 12_493 "Anazon";
29807 "2020-02-13" "522" 85_005 "Kz 電機"
]

df = DataFrame(payments, [:ID, :日付, :コード, :金額, :備考])

@show df

実行例

df = 7×5 DataFrame
 Row │ ID     日付        コード  金額   備考
     │ Any    Any         Any     Any    Any
─────┼───────────────────────────────────────────────
   1 │ 29801  2020-01-07  101     20180  RayPay
   2 │ 29802  2020-01-09  101     42352  Anazon
   3 │ 29803  2020-01-11  201     25811  TEPKO
   4 │ 29804  2020-01-21  301     38190  Zip 保険
   5 │ 29805  2020-01-26  101     67553  Biza カード
   6 │ 29806  2020-02-06  101     12493  Anazon
   7 │ 29807  2020-02-13  522     85005  Kz 電機

行列からでなくベクトルやスカラーからも構築できます。

DataFrame の要素を参照する場合の様々な方法とともに、その例を示します。

using DataFrames

# ベクトルから作成
df0 = DataFrame(A=[1, 2, 3, 4], B=[-1, -2, -3, -4], C=[0, 5, 9, 3])
@show df0

# スカラーから作成
df1 = DataFrame(x=1, y=2, z=3)
@show df1

# df1 に行を追加
push!(df1, [3, 4, 5])

# df1 に他の DataFrame を追加
df2 = DataFrame(x=[-1, -2], y=[-2, -3], z=[-3, -4])
append!(df1, df2)
@show df1

# 最初と最後の行
@show first(df1)
@show last(df1)

# 2番目の行と2番目の列 (: は「すべて」を表す。:の代わりに!でもよい)
@show df1[2, :]
@show df1[:, 2]

# 行2、列2の成分
@show df1[2, 2]

# 座標(1,1)と座標(3,2)の矩形成分
@show df1[1:3, 1:2]

CSV ファイルから構築する

外部のファイルからCSV形式データを読み込んで DataFrame を構築する例を示します。その場合、 CSV パッケージが必要になります。

using CSV
using DataFrames

# CSV の先頭行がヘッダの場合
df0 = DataFrame(CSV.File("./payments.csv"))
@show df0
# CSV の先頭行がデータの場合
df1 = DataFrame(CSV.File("./payments0.csv", header=false))
# 列名はデフォルトで Column1, Column2 .. となるので、必要なら変更できる。
cols = names(df1)
@show cols
rename!(df1, cols[1] => :ID, cols[2] => :DATE, cols[3] => :CODE, cols[4] => :AMOUNT, cols[5] => :INFO)
@show df1

DataFrame から配列への変換

LinearAlgebra など他のパッケージを使用する場合、データを配列に変換したいときがあります。そのような場合は、Tables パッケージを利用すると簡単に変換できます。

using DataFrames
using Tables

# DataFrame df を行列 M に変換する。
df = DataFrame(A=1:4, B=5:8)
M = Tables.matrix(df)
@show M

実行例

M = [1 5; 2 6; 3 7; 4 8]

並べ替え (ソート)

ある列をキーとしてデータを並べ替えたいことがよくあります。そのような場合には sort!() 関数が使えます。

using DataFrames

payments = [
29801 "2020-01-07" "101" 20_180 "RayPay";
29802 "2020-01-09" "101" 42_352 "Anazon";
29803 "2020-01-11" "201" 25_811 "TEPKO";
29804 "2020-01-21" "301" 38_190 "Zip Insurance";
29805 "2020-01-26" "101" 67_553 "Biza Card";
29806 "2020-02-06" "101" 12_493 "Anazon";
29807 "2020-02-13" "522" 85_005 "Kz Denki"
]

df = DataFrame(payments, [:ID, :DATE, :CODE, :AMOUNT, :INFO])
@show df

# 金額で並べ替え
sort!(df, :AMOUNT)
@show df

# 金額(降順)で並べ替え
sort!(df, :AMOUNT, rev=true)
@show df

集計

ある列のデータの合計や平均を求めたいときがあります。個別に計算することもできますが、describe() 関数を使うと、一度にデータの概要を知ることができます。

using DataFrames
using Statistics

payments = [
29801 "2020-01-07" "101" 20_180 "RayPay";
29802 "2020-01-09" "101" 42_352 "Anazon";
29803 "2020-01-11" "201" 25_811 "TEPKO";
29804 "2020-01-21" "301" 38_190 "Zip Insurance";
29805 "2020-01-26" "101" 67_553 "Biza Card";
29806 "2020-02-06" "101" 12_493 "Anazon";
29807 "2020-02-13" "522" 85_005 "Kz Denki"
]

df = DataFrame(payments, [:ID, :DATE, :CODE, :AMOUNT, :INFO])
@show df

# このデータの概要
@show describe(df)
# 平均金額
@show mean(df.AMOUNT)
# 合計金額
@show combine(df, :AMOUNT .=> sum)

実行例

df = 7×5 DataFrame
 Row │ ID     DATE        CODE  AMOUNT  INFO
     │ Any    Any         Any   Any     Any
─────┼────────────────────────────────────────────────
   1 │ 29801  2020-01-07  101   20180   RayPay
   2 │ 29802  2020-01-09  101   42352   Anazon
   3 │ 29803  2020-01-11  201   25811   TEPKO
   4 │ 29804  2020-01-21  301   38190   Zip Insurance
   5 │ 29805  2020-01-26  101   67553   Biza Card
   6 │ 29806  2020-02-06  101   12493   Anazon
   7 │ 29807  2020-02-13  522   85005   Kz Denki
describe(df) = 5×7 DataFrame
 Row │ variable  mean     min         median   max            nmissing  eltype
     │ Symbol    Union…   Any         Union…   Any            Int64     DataType
─────┼───────────────────────────────────────────────────────────────────────────
   1 │ ID        29804.0  29801       29804.0  29807                 0  Any
   2 │ DATE               2020-01-07           2020-02-13            0  Any
   3 │ CODE               101                  522                   0  Any
   4 │ AMOUNT    41654.9  12493       38190.0  85005                 0  Any
   5 │ INFO               Anazon               Zip Insurance         0  Any
mean(df.AMOUNT) = 41654.857142857145
combine(df, :AMOUNT .=> sum) = 1×1 DataFrame
 Row │ AMOUNT_sum
     │ Int64
─────┼────────────
   1 │     291584
 
コメントする

投稿者: : 2021/12/28 投稿先 Julia

 

タグ: ,

Julia の勉強:構造体

構造体

Julia では構造体という用語を使うかどうか知りませんが、C 言語の struct に近いものがあります。ただし、struct は変更不可です。つまり要素の値も要素の追加や変更もできません。

struct Point
  x
  y
end

x, y の型の指定もできます。(正確には型ヒント)

struct Point
  x::Float64
  y::Float64
end

次の例は struct 変数が変更できないことを確認しています。

なお、struct の初期化にはコンストラクタを使います。Python のクラスのインスタンス化のように struct の名前をコンストラクタ名にします。

julia> struct Point
         x
         y
       end
julia> p = Point(0.0, 2.0)
Point(0.0, 2.0)
julia> p.x
0.0
julia> p.y
2.0
julia> p.x = 1.0
ERROR: setfield!: immutable struct of type Point cannot be changed
Stacktrace:
 [1] setproperty!(x::Point, f::Symbol, v::Float64)
   @ Base .\Base.jl:43
 [2] top-level scope
   @ REPL[14]:1

変更が必要なら mutable struct を使います。

struct は不変なので静的メモリに割り当てられます。mutable struct はヒープに割り当てられます。

julia> mutable struct MutPoint
         x
         y
       end
julia> mp = MutPoint(0.0, 2.0)
MutPoint(0.0, 2.0)
julia> mp.x = 1.0
1.0
julia> mp
MutPoint(1.0, 2.0)

ジェネリック型の struct も可能です。その場合は struct Name{T} のように宣言します。

julia> struct I64Point{int64}
         x::Int64
         y::Int64
       end
julia> ip = I64Point{Int64}(0, 1)
I64Point{Int64}(0, 1)
julia> ip.x
0
julia> ip.y
1

共用体

C 言語に union キーワードというのがあって共用体を定義できますがが、Julia の場合は先頭が大文字の Union であり、C の union とはニュアンスが異なります。

Union は特殊な型を作るためのキーワードで次のように使います。

julia> IntOrString = Union{Int,AbstractString}
Union{Int64, AbstractString}
julia> 1::IntOrString
1
julia> "Hello"::IntOrString
"Hello"
# 整数でも文字列でもない場合はエラーになる。
julia> 1.0::IntOrString
ERROR: TypeError: in typeassert, expected Union{Int64, AbstractString}, got a value of type Float64
Stacktrace:
 [1] top-level scope
   @ REPL[33]:1

次のように変数 u は整数 0 で初期化していますが、後から文字列を代入できます。

julia> u = 0::IntOrString
0
julia> u = "Hello"
"Hello"
 
コメントする

投稿者: : 2021/12/26 投稿先 Julia

 

タグ: ,

Julia の勉強:確率・統計パッケージ StatsKit

StatsKit は確立・統計に関連するパッケージをまとめた統合パッケージです。StatsKit をインストールすれば次のパッケージが同時にインストールされます。よって、確立・統計に関する処理を行う場合、StatsKit をインストールすれば必要なパッケージが手に入るということになります。

Bootstrap の使用例

このリストの先頭の Bootstrap を使用してみます。この Bootstrap は StatsKit パッケージの子パッケージなので using StatsKit.Bootstrap とする必要があります。

using StatsKit.Bootstrap
using Statistics

# 平均が 0 で標準偏差が 1 の正規分布に従う乱数 100 からなる配列
some_data = randn(100)
n_boot = 1000
# std は標準偏差を求める Statistics の関数
bs1 = bootstrap(std, some_data, BasicSampling(n_boot))
bs2 = bootstrap(std, some_data, BalancedSampling(n_boot))
println(bs1)
println(bs2)

実行例

$ julia .\bootstrap.jl
Bootstrap Sampling
  Estimates:
     Var │ Estimate  Bias         StdError
         │ Float64   Float64      Float64
    ─────┼──────────────────────────────────
       1 │  1.04718  -0.00586388  0.0700483
  Sampling: BasicSampling
  Samples:  1000
  Data:     Vector{Float64}: { 100 }

Bootstrap Sampling
  Estimates:
     Var │ Estimate  Bias         StdError
         │ Float64   Float64      Float64
    ─────┼──────────────────────────────────
       1 │  1.04718  -0.00742811  0.0703431
  Sampling: BalancedSampling
  Samples:  1000
  Data:     Vector{Float64}: { 100 }

StatsBase の使用例

StatsKit に含まれるパッケージのうち、最も基礎的なパッケージが StatsBase です。幾何平均を StatsBase と定義に基づいて計算してみます。

using StatsKit.StatsBase

# 幾何平均を StatsBase を使って計算
a = [1, 3, 7]
gm0 =  geomean(a)
# 幾何平均を定義に基づいて計算
gm1 = (a[1] * a[2] * a[3]) ^ (1.0/3.0)
@show gm0, gm1
println(isapprox(gm0, gm1))

実行結果

$ julia statsbase.jl
(gm0, gm1) = (2.7589241763811208, 2.7589241763811203)
true
 
コメントする

投稿者: : 2021/12/26 投稿先 Julia

 

タグ: ,

Julia の勉強:データを補間する

Interpolations パッケージを使うとデータを補間することができます。

ドキュメントに書いてある通り、次のようにしてインストールします。(パッケージモードで add Interpolations を実行しても同じです)

julia> using Pkg
julia> Pkg.add("Interpolations")

線形補間の使用例

次のサンプルは単純な線形補間で与えられたデータ (ベクトル A) の成分間を保管してグラフを描くものです。

using Interpolations
using Plots

xs = range(0, 10, step=1)
A = [0.1, 1.8, 2.2, 2.6, 5.1, 4.2, 5.9, 7.5, 8.8, 9.0, 9.9]

println("LinearInterpolation")
itp = LinearInterpolation(xs, A)
y1 = Float64[]
x1 = range(0.0, 10.0, step=0.02)

for x = x1
  append!(y1, itp(x))
end

plot(x1, y1, show=true, w=2)

print("> ")
read(stdin, Char)

B-スプライン曲線で補間する

描画ソフトなどでよく見かけるB-スプライン曲線での補間を行ってみます。

次のサンプルは Interpolations のドキュメントに出ていたサンプルを少し改造およびコメントを英語から日本語にしてしてグラフを表示するものです。

using Interpolations, Plots

println("Start Interpolations and Plot")
# 補間範囲の最小値と最大値
a = 1.0
b = 10.0
# 補間区間を決める
x = a:1.0:b
# x と y の長さは同じで要素は昇順であること。
# length(x) == length(y)
y = @. cos(x^2 / 9.0) # 補間対象の点のY座標を生成
# データから線形と3次スプライン関数を生成する。
itp_linear = LinearInterpolation(x, y)
itp_cubic = CubicSplineInterpolation(x, y)
# 補間関数が破壊型 plot! で正しく動くようにするため
f_linear(x) = itp_linear(x)
f_cubic(x) = itp_cubic(x)
# Plots の表示パラメータ
width, height = 720, 480 # ウィンドウサイズ (なくても動作する)
x_new = a:0.1:b # 曲線を滑らかにするための設定 (3次スプライン補間で必要)

# 散布図 (点の描画)
scatter(x, y, markersize=7,label="Data points")
# 線形補間グラフ
plot!(f_linear, x_new, w=3,label="Linear interpolation")
# 3次スプライン補間のグラフ
plot!(f_cubic, x_new, linestyle=:dash, w=3, label="Cubic Spline interpolation")
# ウィンドウサイズを設定
plot!(size = (width, height))
# 凡例の表示とウィンドウ表示の指定
plot!(legend = :bottomleft, show=true)

print("> ")
read(stdin, Char)
 
コメントする

投稿者: : 2021/12/25 投稿先 Julia

 

タグ: ,

Julia の勉強:数値積分

QuadGK パッケージを使うと簡単に関数の定積分を求めることができます。

このパッケージには3つの関数しかないので使い方は簡単です。主に使うのは次の関数です。

quadgk(f, a,b,c...; rtol=sqrt(eps), atol=0, maxevals=10^7, order=7, norm=norm)
  • f は積分を行う関数です。
  • a, b は積分を行う範囲です。c 以降は追加の範囲 (b~c, c~d, …) です。関数 f の変化の激しい区間は幅を狭めることでより正確な値を得ることができます。
  • 残りは省略可能ですが、rtol は相対誤差の許容値、atol は絶対誤差の許容値です。
  • maxevals は f の評価最大値です。
  • order は積分公式の最大次数です。
  • norm が指定されると E <= max(atol, rtol*norm(I)) を満たします。ただし、E は最大誤差です。

この関数の戻り値は積分値 I と最大誤差 E のペア (タプル) になります。

使用例

julia> using QuadGK
julia> f(x) = 1
f (generic function with 1 method)
julia> quadgk(f, 0, 1)
(1.0, 0.0)
julia> f(x) = x
f (generic function with 1 method)
julia> quadgk(f, 0, 1)
(0.5, 0.0)
julia> f(x) = x^2
f (generic function with 1 method)
julia> quadgk(f, 0, 1)
(0.3333333333333333, 5.551115123125783e-17)

楕円積分の例

QuadGK を使って特殊関数である楕円積分のグラフを描いてみます。

# 楕円積分
using QuadGK
using Plots

println("Start ..")
xs = Float64[]
ys = Float64[]

for m = range(-5, 0.9, step=0.01)
    f(x) = 1 / sqrt(1 - m*sin(x)^2)
    I, E = quadgk(f, 0, pi/2)
    append!(xs, m)
    append!(ys, I)
end

plot(xs, ys, show=true, framestyle=:origin, w=2)

print("> ")
read(stdin, Char)
 
コメントする

投稿者: : 2021/12/24 投稿先 Julia

 

タグ: ,

Julia の勉強:特殊関数

特殊関数は SpecialFunctions パッケージをインストールすることで利用できます。

pkg> add SpecialFunctions

このパッケージに含まれる特殊関数は

です。

ガンマ関数

ガンマ関数は階乗 n! を複素数に拡張した関数です。SpecialFunctions では派生型の関数がいくつかサポートされていますが、基本の gamma() 関数を試してみました。

変数は複素数が可能ですが、グラフにしやすい正の実数変数で計算してみました。

# ガンマ関数
using SpecialFunctions
using Plots

xs = Float64[]
ys = Float64[]

for x = range(0.04, 6, step=0.001)
    try
        y = gamma(x)
        #@show x, y
        append!(xs, x)
        append!(ys, y)
    catch
        println("Error on ", x)
    end
end

println("Plot start ..")
plot(xs, ys, show=true, framestyle=:origin, w=2)

print("> ")
read(stdin, Char)

指数積分および三角積分

指数積分は指数関数を含む関数の積分、三角積分は正弦や余弦を含む関数の積分ですが、これらは初等関数の組み合わせで表すことができずに特殊関数となります。

下のプログラムは指数積分関数のサンプルです。

# 指数積分関数 Ei(z)
using SpecialFunctions
using Plots

println("Start plot ..")
plot(range(-5, 5, step=0.1), expinti, show=true, framestyle=:origin, w=2)

print("> ")
read(stdin, Char)

誤差関数

誤差関数は確率論、統計などに使われる特殊関数です。誤差関数にはいくつかのバラエティがありますが、下のプログラムは基本的な誤差関数 erf() です。

# 誤差関数
using SpecialFunctions
using Plots

println("Start plot ..")
plot(range(-3, 3, step=0.01), erf, show=true, framestyle=:origin)

print("> ")
read(stdin, Char)

エアリー 関数

エアリー関数はイギリスの天文学者エアリーにちなんで名づけられた関数で、エアリーの微分方程式の解になります。

# エアリー関数
using SpecialFunctions
using Plots

println("Start plot ..")
plot(range(-15.0, 5.0, step=0.01), airyai, show=true, framestyle=:origin, w=2)

print("> ")
read(stdin, Char)

ベッセル関数

ベッセル関数は電磁気学などでよく使われる特殊関数で変種がたくさんあります。ここでは 0 と 1 次第一種ベッセル関数を使ってみます。

# ベッセル関数 J0(x)
using SpecialFunctions
using Plots

println("Start plot ..")
plot(range(-20.0, 20.0, step=0.02), [besselj0, besselj1], show=true, framestyle=:origin, w=2)

print("> ")
read(stdin, Char)

楕円積分

振り子運動などに関係する特殊関数です。ある関数を積分した時に得られる関数です。

# 楕円積分
using SpecialFunctions
using Plots

println("Start plot ..")
plot(range(-5.0, 0.9, step=0.01), ellipk, show=true, framestyle=:origin, w=2)

print("> ")
read(stdin, Char)

ゼータ関数

数論や力学で使用される関数でいくつもの変種がありますが、一番歴史のあるのはリーマンゼータ関数だそうです。

ここでは、そのリーマンゼータ関数を使用してみます。

# リーマンゼータ関数
using SpecialFunctions
using Plots

println("Start plot ..")
plot(range(-1.0, 4.0, step=0.01), zeta, show=true, framestyle=:origin, w=2)

print("> ")
read(stdin, Char)
 
コメントする

投稿者: : 2021/12/23 投稿先 Julia

 

タグ: ,

Julia の勉強:線形代数 (いろいろな行列)

単位行列 (Identity Matrix) など

単位行列は対角成分が 1 で、それ以外はすべて 0 の行列です。

成分がすべてゼロ (zeros()関数を利用) やすべて任意の値 (fill()関数を利用) である行列も簡単に作れます。

乱数行列

Julia では単なる乱数だけでなく、行列の成分が乱数である乱数行列を rand() 関数で簡単に作れます。

ベクトルの回転行列

ベクトルに行列をかけると別のベクトルに変換できます。その中で幾何学的に意味を持たせたベクトルを回転するための回転ベクトルがあります。

転置行列 (Transpose Matrix)

正方行列の対角線で要素の上下を入れ替えた行列のことを転置行列と言います。

Julia では LinearAlgebra.Transpose () 関数で求めることができます。

逆行列 (Inverse Matrix)

元の行列とその逆行列を掛けると単位行列になるような行列のこと。逆行列を持つ正方行列を特に正則行列と言います。逆行列を持つ正方行列を正則行列と言います。

逆行列は、Julia では Base.inv() 関数で求めることができます。

置換行列 (Permutation Matrix)

各行各列にひとつだけ 1 を持ち、残りはすべて 0 であるような行列。この置換行列を他の行列に掛けると要素の置換が起きます。

対角行列 (Diagonal Matrix)

対角成分以外はすべて 0 であるような正方行列を対角行列と言います。

対称行列 (Symmetric Matrix)

対角要素を挟んで要素が対称になっている正方行列を対称行列と言います。

交代行列 (Alternating Matrix)

元の行列の転置行列が元の行列の -1 倍であるような正方行列を交代行列と言います。

直行行列 (Orthogonal Matrix)

元の行列の転置行列が元の行列の逆行列が等しくなるような正方行列を直交行列と言います。回転行列や置換行列は直交行列でもあります。

余因子行列 (Cofactor Matrix)

正方行列のある行 i と列 j を取り除いた小行列の行列式を並べた行列を余因子行列と言います。

三角行列 (Triangular Matrix)

対角成分の上側の要素、あるいは下側の要素がすべて 0 であるような正方行列を三角行列と言います。上側がすべて 0 の場合が下三角行列、下側がすべて 0 である行列が上三角行列と言います。

エルミート行列 (Hermitian Matrix)

エルミート行列とは、元の複素正方行列を複素共役にし、さらに転置した行列が元の行列に等しいような行列のことです。(実数行列である) 対称行列はエルミート行列でもあります。

随伴行列 (Adjugate Matrix)

随伴行列とは複素行列を転置し、複素共役を取った行列です。

ユニタリー行列 (Unitary Matrix)

ユニタリー行列とは、元の複素正方行列を複素共役にし、さらに転置した行列が、元の行列の逆行列に等しくなるような行列のことです。(実数行列である) 直行行列はユニタリー行列でもあります。

いろいろな行列を作る野良パッケージを作ってみました。わかりやすいように関数には日本語の名前を付けてあります。

module Matrixes
using LinearAlgebra

# ゼロ行列
function ゼロ行列(行数, 列数)
    return zeros(行数, 列数)
end

# 単位行列
function 単位行列(行列数)
    E = zeros(行列数, 行列数) + I(行列数)
    return E
end

# 同一値行列
function 同一値行列(値, 行数, 列数)
    サイズ = (行数, 列数)
    fill(値, サイズ)
end

# 浮動小数点乱数行列
function 乱数行列(行数, 列数; 倍率=1.0)
    R = rand(行数, 列数)
    if 倍率 != 1.0
        R = 倍率 * R
    end
    return R
end

# 整数乱数行列
function 整数乱数行列(範囲, 行数, 列数)
    rand(範囲, 行数, 列数)
end

# 対角行列
function 対角行列(ベクトル)
    diagm(ベクトル)
end

# 回転(2次元)
function 回転行列2(角度; ラジアン=true)
    theta = 角度
    if ! ラジアン
        theta = 角度 / 180.0 * π
    end
    return [cos(theta) -sin(theta); sin(theta) cos(theta)]
end

# 回転(3次元)
function 回転行列3(角度; 回転軸='x', ラジアン=true)
    theta = 角度
    if ! ラジアン
        theta = 角度 / 180.0 * π
    end
    if 回転軸 == 'x'
        return [1.0 0.0 0.0; 0.0 cos(theta) -sin(theta); 0.0 sin(theta) cos(theta) ]
    elseif 回転軸 == 'y'
        return [cos(theta) 0.0 sin(theta); 0.0 1.0 0.0; -sin(theta) 0.0 cos(theta)]
    elseif 回転軸 == 'z'
        return [cos(theta) -sin(theta) 0.0; sin(theta) cos[theta] 0.0; 0.0 0.0 1.0]
    else
        throw("回転軸指定エラー")
    end
end

# 拡大・縮小・反転(2次元)= 2次元の対角行列
function 拡大縮小2(対角成分)
    A = zeros(2, 2)
    A[1, 1] = 対角成分[1]
    A[2, 2] = 対角成分[2]
    return A
end

# 拡大・縮小・反転(3次元)= 3次元の対角行列
function 拡大縮小3(対角成分)
    A = zeros(3, 3)
    A[1, 1] = 対角成分[1]
    A[2, 2] = 対角成分[2]
    A[3, 3] = 対角成分[3]
    return A
end

# 平行移動(2次元)
function 平行移動2(移動成分)
    A = zeros(2, 3)
    A[1, 3] = 移動成分[1]
    A[2, 3] = 移動成分[2]
    return A
end

# 平行移動(3次元)
function 平行移動3(移動成分)
    A = zeros(3, 4)
    A[1, 4] = 移動成分[1]
    A[2, 4] = 移動成分[2]
    A[3, 4] = 移動成分[3]
    return A
end

# 行列式
function 行列式(正方行列)
    det(正方行列)
end

# 階数(ランク)
function 階数(正方行列)
    rank(正方行列)
end

function ランク(正方行列)
    rank(正方行列)
end

# トレース
function トレース(正方行列)
    tr(正方行列)
end

# 固有値
function 固有値(正方行列)
    f = eigen(正方行列)
    f.values  # ベクトルの一要素が固有値
end

# 転置行列
function 転置行列(正方行列)
    Transpose(正方行列)
end

# 対称行列
function 対称行列(正方行列; 下側=false)
    if 下側
        Symmetric(正方行列, :L)
    else
        Symmetric(正方行列)
    end
end

# 直交行列 : 回転行列や置換行列は直交行列の一種

# 交代行列 (歪対称行列、Alternative Matrix)
function 交代行列(正方行列)
    A = 正方行列
    n = size(A)[1]
    for i = 1:n
        for j = 1:n
            if i > j
                A[i, j] = -A[j, i]
            elseif i == j
                A[i, i] =  0.0
            else
                # A[i, j] = A[i, j]
            end
        end
    end
    return A
end

# 置換行列
function 置換行列(次元)
    A = zeros(次元, 次元)
    for i = 1:次元
        j = 次元 - i + 1
        A[i, j] = 1.0
    end
    return A
end

# 逆行列
function 逆行列(正方行列)
    inv(正方行列)
end

# 余因子行列 2x2 (Adjugate Matrix)
function 余因子行列2(正方行列)
    A = 正方行列
    return [A[2, 2] -A[1, 2]; -A[2, 1] A[1, 2]]
end

# 余因子行列 3x3 (Adjugate Matrix)
function 余因子行列3(正方行列)
    A = 正方行列
    d11 = det(小行列(A, 1, 1))
    d12 = det(小行列(A, 1, 2))
    d13 = det(小行列(A, 1, 3))
    d21 = det(小行列(A, 2, 1))
    d22 = det(小行列(A, 2, 2))
    d23 = det(小行列(A, 2, 3))
    d31 = det(小行列(A, 3, 1))
    d32 = det(小行列(A, 3, 2))
    d33 = det(小行列(A, 3, 3))
    B = [d11 (-d12) d13; (-d21) d22 (-d23); d31 (-d32) d33]
    return B
end

# 小行列
function 小行列(正方行列, 行, 列)
    n = size(正方行列)[1]
    A = Matrix{Float64}(undef, n - 1, n - 1)
    is = 0; js = 0
    for i = 1:n
        if i == 行
            is += 0
        else
            is += 1
        end
        for j = 1:n
            if j == 列
                js += 0
            else
                js += 1
                if i != 行
                    #@show is, js, i, j
                    A[is, js] = 正方行列[i, j]
                end
            end
        end
        js = 0
    end
    return A
end

# 上三角行列
function 上三角行列(正方行列)
    LinearAlgebra.triu(正方行列)
end

# 下三角行列
function 下三角行列(正方行列)
    LinearAlgebra.tril(正方行列)
end

# エルミート行列
function エルミート行列(複素正方行列)
    LinearAlgebra.Hermitian(複素正方行列)
end

# 随伴行列: 複素行列を転置し、複素共役を取った行列 (A*)
function 随伴行列(複素正方行列)
    A = LinearAlgebra.Transpose(複素正方行列)
    return conj(A)
end

# ユニタリー行列
function ユニタリー行列(複素正方行列)
end

end  # end Matrixes

テストプログラム





# Matrixes のテスト
import Pkg
if !isfile("Project.toml")
    println("Project.toml が見つかりません。")
    exit(1)
end
Pkg.activate(".")
import Matrixes

E = Matrixes.単位行列(3)
println("単位行列(3) = ", E)
Z = Matrixes.ゼロ行列(3, 3)
println("ゼロ行列(3, 3) = ", Z)
D = Matrixes.同一値行列(1.0, 3, 3)
println("同一値行列(1.0, 3, 3) = ", D)
R = Matrixes.乱数行列(3, 3, 倍率=100.0)
println("乱数行列(3, 3, 倍率=100.0) = ", R)
R = Matrixes.整数乱数行列(0:9, 3, 3)
println("整数乱数行列(0:9, 3, 3) = ", R)
A = Matrixes.対角行列([10, 5, -4.9])
println("対角行列([10, 5, -4.9] = ", A)
A = Matrixes.回転行列2(30.0, ラジアン=false)
println("回転行列2(30.0, ラジアン=false) = ", A)
A = Matrixes.回転行列3(30.0, 回転軸='x', ラジアン=false)
println("回転行列3(30.0, 回転軸='x', ラジアン=false) = ", A)
A = Matrixes.拡大縮小2([2.0, 0.5])
println("拡大縮小2([2.0, 0.5]) = ", A)
A = Matrixes.拡大縮小3([2.0, 1.0, 0.5])
println("拡大縮小3([2.0, 1.0, 0.5]) = ", A)
A = Matrixes.平行移動2([2.0, -2.0])
println("平行移動2([2.0, -2.0]) = ", A)
A = Matrixes.平行移動3([2.0, 0.0, -2.0])
println("平行移動3([2.0, 0.0, -2.0]) = ", A)
d = Matrixes.行列式([-1 1; 3 3])
println("行列式([-1 1; 3 3]) = ", d)
r = Matrixes.階数([1 2 3; 0 4 4; -1 6 2])
println("階数([1 2 3; 0 4 4; -1 6 2]) = ", r)
r = Matrixes.ランク([1 2 3; 2 4 6; -1 6 2])
println("階数([1 2 3; 2 4 6; -1 6 2]) = ", r)
t = Matrixes.トレース([1 3 3; 0 1 3; -8 -3 1])
println("トレース([1 3 3; 0 1 3; -8 -3 1]) = ", t)
e = Matrixes.固有値([1 3 3; 0 1 3; -8 -3 1])
println("固有値([1 3 3; 0 1 3; -8 -3 1]) = ", e)
T = Matrixes.転置行列([1 3 3; 0 1 3; -8 -3 1])
println("転置行列([1 3 3; 0 1 3; -8 -3 1]) = ", T)
A = Matrixes.対称行列([1 2 3; 4 5 6; 7 8 9])
println("対称行列([1 2 3; 4 5 6; 7 8 9]) = ", A)
A = Matrixes.交代行列([1 2 3; 4 5 6; 7 8 9])
println("交代行列([1 2 3; 4 5 6; 7 8 9]) = ", A)
T = Matrixes.置換行列(3)
println("置換行列(3) = ", T)
A = Matrixes.逆行列([1 0 2; 3 1 3; -2 4 1])
println("逆行列([1 0 2; 3 1 3; -2 4 1]) = ", A)
A = [1 2 3; 4 5 6; 7 8 9]
B = Matrixes.小行列(A, 1, 1)
println("小行列([1 2 3; 4 5 6; 7 8 9], 1, 1) = ", B)
B = Matrixes.小行列(A, 2, 2)
println("小行列([1 2 3; 4 5 6; 7 8 9], 2, 2) = ", B)
B = Matrixes.小行列(A, 3, 1)
println("小行列([1 2 3; 4 5 6; 7 8 9], 3, 1) = ", B)
B = Matrixes.小行列(A, 1, 3)
println("小行列([1 2 3; 4 5 6; 7 8 9], 1, 3) = ", B)
B = Matrixes.余因子行列2([1 2; 3 4])
println("余因子行列2([1 2; 3 4] = ", B)
B = Matrixes.余因子行列3([1 2 4; 4 5 6; 7 8 9])
println("余因子行列2([1 2 4; 4 5 6; 7 8 9] = ", B)
println("上三角行列([1 2 3; 4 5 6; 7 8 9]) = ", Matrixes.上三角行列([1 2 3; 4 5 6; 7 8 9]))
println("下三角行列([1 2 3; 4 5 6; 7 8 9]) = ", Matrixes.下三角行列([1 2 3; 4 5 6; 7 8 9]))
A = [1 0 2+2im 0 3-3im; 0 4 0 5 0; 6-6im 0 7 0 8+8im; 0 9 0 1 0; 2+2im 0 3-3im 0 4]
@show A
println("随伴行列() = ", Matrixes.随伴行列(A))
println("エルミート行列(A) = ", Matrixes.エルミート行列(A))
#println("ユニタリー行列(A) = ", Matrixes.ユニタリー行列(A))

サンプル1 回転行列を使って単位ベクトルを1回転したグラフ

# 回転行列
import Pkg
if !isfile("Project.toml")
    println("Project.toml が見つかりません。")
    exit(1)
end
Pkg.activate(".")
import Matrixes
import Plots

座標x = Float64[]
座標y = Float64[]

for 角度 = 0:360
    xy = Matrixes.回転行列2(角度, ラジアン=false) * [1.0, 0.0]
    append!(座標x, xy[1])
    append!(座標y, xy[2])
end
Plots.gr()
Plots.plot(座標x, 座標y, show=true, framestyle=:origin, aspect_ratio = 1; title = "Rotation Matrix", w = 2)
print("> ")
while true
    yield()
end
サンプル1のグラフ表示
 
コメントする

投稿者: : 2021/12/21 投稿先 Julia

 

タグ: , ,

Julia の勉強:HTTP を利用する

Julia の標準パッケージには Sockets というものがありますが、TCP と UDP しかサポートされてないため、ブラウザをクライアントにすることはできません。(HTTP は TCP の上位プロトコルです)

また、ウェブサービスを利用する場合も HTTP のリクエスト文字列を構築しとレスポンスを解析しなければなりません。

HTTP パッケージを使うと HTTP を容易に利用できます。

そして、HTTP クライアントも HTTP サーバも構築可能です。

ただ、HTTP サーバに関しては HTTP パッケージをバックエンドにした Mux を利用した方が簡単になるので、ここでは HTTP クライアントのみについて勉強します。

HTTP をインストールするには次のようにパッケージモードで add します。

pkg> add HTTP

下の例は HTTP のパッケージ github の README.md に出ていた簡単なサンプルです。

r = HTTP.request("GET", "http://httpbin.org/ip"; verbose=3)
println(r.status)
println(String(r.body))

これを実行すると、下のように表示されます。(ただし、’?’ は具体的な数字が入る)

200
{
  "origin": "1??.1??.121.156"
}

なお、http://httpbin.org は次のようなサイトです。

このサンプルは get() を使ってもっと簡単に書けます。

using HTTP
r = HTTP.get("http://httpbin.org/ip")
println(r.status)
println(String(r.body))

ウェブサービスの多くは JSON を使うので、JSON パッケージをインストールしておいた方がよいです。(JSON3 というパッケージもあります)

pkg> add JSON

JSON パッケージを使って上記のサンプルプログラムを改良してみます。

using HTTP
using JSON
r = HTTP.get("http://httpbin.org/ip")
if r.status == 200
    data = JSON.parse(String(r.body))
    println(data["origin"])
else
    println("エラー: ", r.status)
end

このプログラムを実行すると 1??.1??.121.156 だけが表示されます。

次に POST メソッドを使ってみましょう。

次のサンプルプログラムは、POST メソッドで http://httpbin.org/post へデータを送って応答を表示するものです。

using HTTP
using JSON
const URL = "http://httpbin.org/post"
r = HTTP.post(URL, ["p"=>1080, "name"=>"Beauty and Beast"])
if r.status == 200
    resp = String(r.body)
    println(resp)
    data = JSON.parse(resp)
    println("p: ", data["headers"]["P"])
    println("name: ", data["headers"]["Name"])
else
    println("エラー: ", r.status)
end

このプログラムを実行すると、下のようになりました。送ったデータのエコーは headers の中に含まれていました。

$ julia test3.jl
{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "0",
    "Host": "httpbin.org",
    "Name": "Beauty and Beast",
    "P": "1080",
    "User-Agent": "HTTP.jl/1.7.0",
    "X-Amzn-Trace-Id": "Root=1-61ba6b4e-54c6f1721ca09fde69f521dc"
  },
  "json": null,
  "origin": "131.147.121.156",
  "url": "http://httpbin.org/post"
}

p: 1080
name: Beauty and0Beast
$

 
コメントする

投稿者: : 2021/12/16 投稿先 Julia

 

タグ: ,

Julia の勉強:Julia+Blink で GUI アプリを作る

Julia 単体では基本的にコンソールアプリケーションしか作れませんが、サードパーティのパッケージを使用することにより GUI アプリ (ウィンドウを持つアプリ) を作ることができます。

そのひとつとして WebIO + Blink を使う方法があります。(Gtk や Tk もある)

Blink は WebIO のフロントエンドで Electron を Julia でサポートします。

Electron は Node.js (JavaScript) + HTML + CSS で GUI アプリを構築するためのプラットフォームです。

次のコードを実行すると、ウィンドウが開きそこに Hello Blink! と表示されます。

using Blink
w = Window()
body!(w, "<p style='text-align:center;color:red;'>Hello, Blink!</p>")
println("Started Blink >")
read(stdin, Char)

HTML 表示の確認

次に、ちゃんとした HTML を作ってウィンドウに表示してみます。この例では HTML テーブルを表示してみます。

using Blink

function createTable()
    return """
        <br />
        <table style="margin-top:30px; margin-left: 100px;">
        <thead>
            <tr><th>Row</th><th>A</th><th>B</th><th>C</th><th>D</th></tr>
        </thead>
        <tbody>
            <tr><td>1</td><td>1</td><td>2</td><td>3</td><td>0</td></tr>
            <tr><td>2</td><td>4</td><td>5</td><td>6</td><td>0</td></tr>
            <tr><td>3</td><td>7</td><td>8</td><td>9</td><td>0</td></tr>
        </tbody>
        </table>
    """
end

head = """
<html>
<head>
    <meta name="viewport" content="width=800,initial-scale=1">
    <meta charset="utf-8" />
    <title>Table</title>
    <style>
        table, th, td { border-collapse: collapse; border: solid thin gray; }
        th { background-color: azure; padding: 3px; font-weight: bold;}
        td { padding: 3px; width: 50px; text-align: right;}
    </style>
</head>
<body>
"""

foot = """
    <body>
    </html>
"""

html = head * createTable() * foot
w = Window()

body!(w, html)

println("Started Blink >")
read(stdin, Char)

次のようにコードを追加すると、ウィンドウの大きさや位置の指定、ウィンドウの最上位に表示ができるようになります。

size(w, 480, 320)
position(w, 100, 100)
floating(w, true)
body!(w, html)

フォーム

単に計算結果を表示するだけなら、前のサンプルプログラムでもいいですが、データを入力する場合はフォームが必要です。

ここでは、次のようなフォームを持つ Blink アプリを作ってみました。

このアプリは乱数を使ってテスト用の行列を生成するものです。

行列の行数と列数、要素の値の範囲 (整数) を指定して「作成する」ボタンをクリックするとその下にJulia の行列を表示します。

「閉じる」ボタンをクリックすると、このアプリを終了します。

このプログラムは次のようになっています。

using Blink

function html_body()
    htm = """
        <h1>Form test</h1>
        <br />
        <form id="form1">
            <h3>テスト用 行列作成</h3>
            <fieldset><div>行数</div><div><input type="number" id="rows" size="8" value="3" /></div></fieldset>
            <fieldset><div>列数</div><div><input type="number" id="cols" size="8" value="3" /></div></fieldset>
            <fieldset><div>値の範囲</div><div><input type="text" id="range" size="8" value="0:9" /></div></fieldset>
            <fieldset><input type="button" id="button1" value=" 作成する " 
            onclick="Blink.msg('button1Click', form1.rows.value + ',' + form1.cols.value + ',' + form1.range.value)" />&nbsp;
            <input type='button' id="closeButton" value=' 閉じる ' onclick="Blink.msg('closeClick', 'close')" />
            </fieldset>
            <br />
            <p id="result" style="color:magenta;font-size:14pt;"></p>
        </form>
    """
    return htm
end

head = """
<html>
<head>
    <meta name="viewport" content="width=800,initial-scale=1">
    <meta charset="utf-8" />
    <title>Form</title>
    <style>
        table, th, td { border-collapse: collapse; border: solid thin gray; }
        th { background-color: azure; padding: 3px; font-weight: bold;}
        td { padding: 3px; width: 50px; text-align: right;}
        h1 { text-align:center; color:crimson; padding:10px; font-size:1.5em; }
        form { margin-left:10%; }
        fieldset { border-width: 0px; margin: 4px; }
    </style>
</head>
<body>
"""

foot = """
    <p>&nbsp;</p>
    <body>
    </html>
"""

function generateMatrix(args)
    ns = split(args, ",")
    nr = parse(Int32, ns[1])
    nc = parse(Int32, ns[2])
    srg = split(ns[3], ":")
    rg = parse(Int32, srg[1]):parse(Int32,srg[2])
    mat = rand(rg, nr, nc)
    s = "["
    for i = 1:nr
        for j = 1:nc
            s *= string(mat[i, j])
            if j < nc
                s *= " "
            end
        end
        if i < nr
            s *= "; "
        end
    end
    s *= "]"
    return s
end

html = head * html_body() * foot
w = Window(async=false)
body!(w, html, async=false)

handle(w, "button1Click") do arg
    @async begin
        @show arg
        matrix = generateMatrix(arg)
        js(w, Blink.JSString("""document.getElementById('result').innerText = '$matrix';"""))
    end
end

handle(w, "closeClick") do arg
    exit()
end

println("Started Blink >")
#read(stdin, Char)
while true
    yield()
end

画面に表示する HTML は変数 head, 関数 html_body(), foot で定義しています。

JavaScript 側で発生したイベント (ボタンクリック) は下の部分です。

<input type="button" id="button1" value=" 作成する " 
            onclick="Blink.msg('button1Click', form1.rows.value + ',' + form1.cols.value + ',' + form1.range.value)" />
<input type='button' id="closeButton" value=' 閉じる ' onclick="Blink.msg('closeClick', 'close')" />

イベントは JavaScript 側からは Blink.msg(event, message) で送ります。

Julia 側では handle(window, event) で受けます。これを呼び出す前には Window オブジェクトを構築しておかなくてはなりません。ここでパラメータに async=false を指定していますが、これがないと構築動作は非同期になり、構築が完了する前に Window() が終了してしまうそうです。そのため、async = false がないと動作が不安定になる可能性があります。(試しにこの指定なしでやってみましたが、一応動きました)

w = Window(async=false)

次に body!(window, html, async) でウィンドウに HTML を貼り付けます。ここでも async=false を指定していますが、これがないと Window() と同じくウィンドウボディが構築される前に関数が終了してしまうためです。

body!(w, html, async=false)

次の handle(window, event) do arg … が「作成」ボタンのイベントハンドラです。

handle(w, "button1Click") do arg
    @async begin
        @show arg
        matrix = generateMatrix(arg)
        js(w, Blink.JSString("""document.getElementById('result').innerText = '$matrix';"""))
    end
end

ここで @async を使って別のタスクとして実行します。そうしないと、イベントが連続して発生したときの動作が不安定になるし、それ以前にメインタスクに「再入」することになり 1 回しかイベントが動作しません。

「閉じる」ボタンのイベントハンドラには @async がありませんが、この場合、アプリが終了し、1回しかこのイベントが発生しないためです。

handle(w, "closeClick") do arg
    exit()
end

最後には次のような while 文がありますが、これがないとアプリがウィンドウが開くと同時に終了してしまいます。

while ブロックで yield() を実行していますが、これは OS のメッセージポンプを動作させ、待機中に他の処理が行えるようにしています。

while true
    yield()
end

この部分はキー入力待ちにしても同様に動作します。

read(stdin, Char)

 
コメントする

投稿者: : 2021/12/15 投稿先 Julia

 

タグ: , , ,