internal の設計

設計目標

immut と mutable は同じ前提条件(正方性、範囲、形状の適合性)を検査し、それらを同じように報告しなければなりません。internal は各検査の実装を 1 つだけ持つことで、2 つのパッケージが食い違わないようにしつつ、ヘルパーを下流のコードには公開しません。

数学的背景

各ガードは、エラーの設計 で述べた定義域の特性判定です。dom⁡(tr⁡)={A:r=c}\operatorname{dom}(\operatorname{tr}) = \{A : r = c\}、dom⁡(⋅)={(A,B):cA=rB}\operatorname{dom}(\cdot) = \{(A, B) : c_A = r_B\} などです。判定を全域関数 χ:X→Unit+E\chi : X \to \mathrm{Unit} + E として一度だけ書けば、部分演算の両方の形式が得られます。

checked(x)=χ(x)> ⁣ ⁣> ⁣ ⁣=(_↦Ok(f(x))),unchecked(x)={f(x)χ(x)=Ok(())abortotherwise.\mathtt{checked}(x) = \chi(x) \mathbin{>\!\!>\!\!=} (\_ \mapsto \mathrm{Ok}(f(x))), \qquad \mathtt{unchecked}(x) = \begin{cases} f(x) & \chi(x) = \mathrm{Ok}(()) \\ \text{abort} & \text{otherwise.} \end{cases}

中断するガードを検査付きのガードから導出する(ensure_x は ensure_x_checked に対してマッチする)ことで、両者は構成上あらゆる入力で一致します。

設計上の判断

internal パッケージ

MoonBit の internal パッケージ規則により、Luna-Flow/linear-algebra/internal をインポートできるのはこのモジュールのパッケージに限られます。そのためヘルパーは自由に変更でき、その効果は公開メソッドの側で規定されます。

MatrixShape とは別の HasShape

@algebra.MatrixShape も同じメソッドを持ちますが、algebra は実験的であり、具体的なパッケージはそれに依存すべきではありません。HasShape はガードに、immut と mutable がローカルに実装する境界を与えます。この重複は、安定した具体的パッケージを実験的な層から独立させておくための代償です。

列より先に行

ensure_index_in_bounds はまず行を、次に列を、それぞれ自身の次元に対して検査します。代わりに平坦なオフセット rc′+cr c' + c を rc′rc' と比較すると、次の行にはみ出す列インデックスを受け入れてしまいます。

正しさと不変条件

  • ensure_x(m) が中断するのは、ensure_x_checked(m) が Err を返すとき、かつそのときに限ります。
  • 各検査付きガードは、API ページ に挙げたエラーの種類を固定のメッセージとともに返します。
  • すべてのガードは O(1)O(1) で実行され、shape しか呼び出しません。

却下した代替案

  • 各パッケージで検査を重複させる。 0.4 系より前は、これが原因で範囲外の扱いが食い違っていました。
  • 公開ヘルパー。 下流のコードが依存する API になってしまいます。

境界

internal は形状とインデックスだけを検査します。算術、ストレージ、値に依存する検査(特異性、データが空であること、収束)は含みません。