algebra との統合

algebra はベクトル・行列オブジェクト全体の数学能力を表します。外部ライブラリは、演算の意味、閉性、所有権の振る舞いが実際の型に合う trait だけを実装します。

Algebra レベルを選ぶ

ベクトルの trait と行列の trait は、それぞれ別の能力の系統を構成します。

系統Trait前提数学的な約束
形状VectorShapeなしベクトル長を返す
ベクトル 1AdditiveVectorVectorShape + Add + Neg + Sub同じ型で加算・符号反転・減算
ベクトル 2VecMulVectorAdditiveVector + MulMul は要素積/Hadamard 積
形状MatrixShapeなし行列形状を返す
行列 1TransposeMatrixMatrixShape転置が同じ行列型を返す
行列 2AdditiveMatrixTransposeMatrix + Add + Neg + Sub同じ型で行列加算・符号反転・減算
行列 3MatMulMatrixAdditiveMatrix + MulMul は行列積

下流アルゴリズムに必要な最小レベルで止めます。Shape は要素アクセスを意味せず、 TransposeMatrix は行列積を意味しません。AdditiveVector は内積、norm、スカラー作用、要素積を意味しません。

演算子境界

強い trait は MoonBit の演算子を再利用し、Result ではなく Self を返します。実装前に次を確認します。

  • 演算子の既存の意味が trait と一致する。特に MatMulMatrix の Mul は行列積です。
  • 結果が同じ具象型に閉じている。
  • runtime の形状前提と失敗動作が文書化されている。
  • 演算中にバックエンドや所有権モデルを暗黙に切り替えない。

動的な長方形行列では、形状によって積が不正になる場合があります。 MatMulMatrix 自体は検査付きエラーチャネルを定義しません。checked method が必要なバックエンドはそれを保持し、演算子契約が適切な場合だけ trait を実装します。

Algebra と Container は独立

必要なこと使用する層
要素観測・ストレージ変換container の read/build 辞書
同じ型に閉じた数学演算algebra trait
両方対応する trait と辞書を別々に提供

MatrixShape は意味上の形状能力であり、検査付き要素アクセスではありません。 algebra の転置は同じ型を返し、container の転置は別の型を構築できます。

container 接続のためだけに広いスカラー trait を実装しないでください。実際に支える法則と演算に限り Luna-Flow/luna-generic と Luna-Flow/arithmetic を使います。

実装を置く場所

公開演算子と algebra 実装は、通常は具象型を所有するパッケージに置きます。これによりメソッドと trait の解決が予測しやすくなり、型の所有者が演算の意味を決められます。

別の相互運用パッケージが必要な場合は、そのパッケージが所有する wrapper 型を作り、wrapper に algebra trait を実装します。所有していない外部型の演算子の意味を bridge パッケージが安全に再定義できるとは考えないでください。

同じ型に閉じた例

これはスカラーを任意の動的行列に見せかけた例ではなく、意図的に 1x1 行列型です。 1x1 行列では転置は恒等、要素加算は行列加算、唯一の要素同士の積は標準行列積と完全に一致します。固定形状により全演算が同じ型に閉じ、runtime 形状失敗もありません。

///|
struct EcosystemScalarMatrix {
  value : Int
}

///|
impl @algebra.MatrixShape for EcosystemScalarMatrix with fn shape(_) {
  (1, 1)
}

///|
impl @algebra.TransposeMatrix for EcosystemScalarMatrix with fn transpose(self) {
  self
}

///|
impl Add for EcosystemScalarMatrix with fn add(left, right) {
  { value: left.value + right.value, }
}

///|
impl Neg for EcosystemScalarMatrix with fn neg(value) {
  { value: -value.value, }
}

///|
impl Sub for EcosystemScalarMatrix with fn sub(left, right) {
  left + -right
}

///|
impl Mul for EcosystemScalarMatrix with fn mul(left, right) {
  { value: left.value * right.value, }
}

///|
impl @algebra.AdditiveMatrix for EcosystemScalarMatrix

///|
impl @algebra.MatMulMatrix for EcosystemScalarMatrix

///|
fn[M : @algebra.MatMulMatrix] ecosystem_gram(matrix : M) -> M {
  @algebra.TransposeMatrix::transpose(matrix) * matrix
}

///|
test "external algebra type participates by capability" {
  let matrix : EcosystemScalarMatrix = { value: 3, }
  let other : EcosystemScalarMatrix = { value: 4, }
  inspect((matrix + other).value, content="7")
  inspect(@algebra.TransposeMatrix::transpose(matrix).value, content="3")
  inspect(ecosystem_gram(matrix).value, content="9")
}

外部ライブラリは MatrixShape、TransposeMatrix、AdditiveMatrix のどこで止めても構いません。動的行列バックエンドは、この固定形状の前提をコピーせず、互換性のない形状に対する演算子の動作を別途定義する必要があります。

接続チェックリスト

  • 型とアルゴリズムに合う最小 trait を選ぶ。
  • Add / Neg / Sub / Mul の意味が trait と一致することを確認する。
  • 閉性、形状、転置後の形状、型が支える代表的な法則をテストする。
  • runtime 形状前提がある演算子は不正形状の動作もテストする。
  • allocation、共有ストレージ、隠れた mutation を文書化する。
  • 将来の専用能力が定義しない限り、内積、norm、スカラー作用、分解、solver をこれらの trait に含めない。
  • 要素単位の相互運用が必要なら container 辞書を別に追加する。