Chapter 19. サイズを伴う永続化行列

次元情報 (つまり列の数や行の数) が付属した永続化行列を サイズを伴う行列 (matrix-with-size) と呼びます。 観型 VT が与えられたとき、観型 VT の要素を M 列と N 行含むサイズを伴う行列の型は mtrxszref(VT, M, N) です。 本質的に、この型の値は3つの型 arrayref(VT, N), size_t(M), size_t(N) を構成要素とするボックス化レコードです。 サイズを伴う永続化行列に関する様々な関数のインターフェイスを prelude/SATS/matrixref.sats に見つけることができます。

次の関数はサイズを伴う行列を生成するのに一般的に使用されます:

fun{a:t0p} mtrxszref_make_elt (m: size_t, n: size_t, x0: a): mtrxref (a) // end of [mtrxszref_make_elt]

2つのサイズ m, n と要素 x0 が与えられたとき、 mtrxszref_make_elt はそれぞれの行列セルが与えられた要素 x0 で初期化された次元 m, n のサイズを伴う行列を返します。

行列セルの内容物にアクセスしたり更新したりするために、 次の2つの関数 mtrxszref_get_atmtrxszref_set_at を使うことができます:

fun{a:t0p} mtrxszref_get_at (M: mtrxszref(a), i: size_t, j: size_t): (a) fun{a:t0p} mtrxszref_set_at (M: mtrxszref(a), i: size_t, j: size_t, x: a): void

サイズを伴う行列 M と2つのインデックス i, j と値 v が与えられたとき、mtrxszref_get_at(M, i, j)mtrxszref_set_at(M, i, j, v) はそれぞれ M[i,j]M[i,j] := v のように書くことができます。 mtrxszref_get_at もしくは mtrxszref_set_at が呼び出されると実行時に行列の範囲検査が行なわれ、行列の範囲外アクセスを検出すると例外 MatrixSubscriptExn が発生することに注意してください。

簡単な例として、次のコードは与えられたサイズを伴う行列の中身の転置行列を取る関数を実装しています:

// extern fun{a:t0p} mtrxszref_transpose (M: mtrxszref(a)): void // implement{a} mtrxszref_transpose (M) = let // val n = M.nrow() // val ((*void*)) = assertloc (M.nrow() = M.ncol()) // fun loop ( i: size_t, j: size_t ) : void = if j < n then let val x = M[i,j] val () = M[i,j] := M[j,i] val () = M[j,i] := x in loop(i, succ(j)) end else let val i1 = succ (i) in if i1 < n then loop(i1, succ(i1)) else () end // end of [if] // in if n > 0 then loop(i2sz(0), i2sz(1)) else () end // end of [mtrxszref_transpose]

サイズを伴う配列と同様に、サイズを伴う行列は依存型行列よりも簡単にプログラミングできます。 けれども、後者はコンパイル時にエラーを効果的に検出することができず、実行時のコード実行で検出します。 ATS でプログラミングする際、サイズを伴う行列からはじめて、その恩恵が明確になった後で行列に置き換えるのは妥当でしょう。

この章で紹介したコードの全体は オンライン から入手できます。