container との統合

外部ライブラリは、実際の意味に合う能力だけを選んで提供します。接続は一括適合ではなく、内部ストレージを公開する必要もありません。

構造能力の境界を選ぶ

レベル提供する能力参加できる役割
0なし独自 API を使う独立型
1VectorReadOps または MatrixReadOpsmap、変換、転置の入力
2VectorBuildOps または MatrixBuildOpsmap、変換、転置の出力
3対応する read と buildジェネリック変換の入力と出力
4P永続編集辞書検査付き copy-on-replacement 値
4M可変編集辞書検査付き原地更新対象

4P と 4M は所有権モデルで決まる選択肢であり、両方を実装するための段階ではありません。ビューは read と可変編集だけを持ち、build を持たないことが自然です。外部ハンドルは read のみ、生成専用コンテナは build のみでも構いません。

アルゴリズムが要求する能力

アルゴリズム入力の要件出力の要件スカラーの関係
vector_mapVectorReadOps[V1, A]VectorBuildOps[V2, B]A から B へ変更可
matrix_mapMatrixReadOps[M1, A]MatrixBuildOps[M2, B]A から B へ変更可
vector_convertVectorReadOps[V1, T]VectorBuildOps[V2, T]T を保持
matrix_convertMatrixReadOps[M1, T]MatrixBuildOps[M2, T]T を保持
matrix_transposeMatrixReadOps[M1, T]MatrixBuildOps[M2, T]T を保持

read は構築、編集、算術、連続メモリ、安価なランダムアクセスを意味しません。 build は読み戻しを意味しません。編集辞書は resize、insert、delete、疎要素削除を意味しません。

数学能力は独立している

algebra は加算、転置、行列積などを記述し、container は観測と構築を記述します。外部型はそれぞれを独立に選べます。container のみなら代数法則を主張せずデータ変換へ参加でき、algebra のみなら要素を公開せず閉じた数学演算を提供できます。

  • container だけの接続は、スカラーやコンテナの代数法則を主張することなく、データの移動と構造的なアルゴリズムを可能にします。
  • algebra だけの接続は、個々の要素を公開せずに、同じ型に閉じた数学演算を可能にします。
  • 両方を提供すると両系統のジェネリックアルゴリズムに参加できますが、一方を満たしても他方が自動的に満たされるわけではありません。

container 接続のためだけに広いスカラー trait を実装しないでください。数学 trait は、型がその演算と法則を本当に満たす場合だけ追加します。

アダプタの所有者

次の所有順序を優先します。

  1. 型を所有するライブラリが Luna-Flow/linear-algebra/container への依存を自然に受け入れられるなら、そこで操作辞書の factory を公開します。
  2. 双方に直接依存を置きたくない場合は、小さな bridge パッケージが所有します。
  3. Luna-Flow/linear-algebra 本体には、このリポジトリで管理する実装のアダプタだけを置きます。

この方向により、中核パッケージに任意のバックエンド依存が蓄積しません。factory の名前はコンテナと能力を示し、factory はバックエンドが本当に必要とするスカラー制約を持てます。

完全な外部アダプタ例

この例は行優先配列を所有しますが、その意味は操作辞書だけから公開します。転置先には Luna の immutable 行列を使い、実際の異種実装境界を検証します。

///|
struct EcosystemOwnedMatrix[T] {
  rows : Int
  cols : Int
  data : Array[T]
}

///|
fn[T] ecosystem_owned_matrix_read_ops() -> @container.MatrixReadOps[
  EcosystemOwnedMatrix[T],
  T,
] {
  @container.MatrixReadOps::new(matrix => (matrix.rows, matrix.cols), (
    matrix,
    row,
    col,
  ) => {
    guard row >= 0 && row < matrix.rows && col >= 0 && col < matrix.cols else {
      return Err(
        @la_error.LinearAlgebraError::index_out_of_bounds(
          "Matrix index out of bounds",
        ),
      )
    }
    Ok(matrix.data[row * matrix.cols + col])
  })
}

///|
fn[T] ecosystem_owned_matrix_build_ops() -> @container.MatrixBuildOps[
  EcosystemOwnedMatrix[T],
  T,
] {
  @container.MatrixBuildOps::new((rows, cols, initializer) => {
    guard rows >= 0 && cols >= 0 else {
      return Err(
        @la_error.LinearAlgebraError::negative_dimension(
          "Matrix dimensions must be non-negative",
        ),
      )
    }
    Ok({
      rows,
      cols,
      data: Array::makei(rows * cols, index => {
        initializer(index / cols, index % cols)
      }),
    })
  })
}

///|
test "external container adapters preserve actual matrix semantics" {
  let source : EcosystemOwnedMatrix[Int] = (ecosystem_owned_matrix_build_ops().tabulate)(
    2,
    3,
    (row, col) => row * 10 + col,
  ).unwrap()
  let target : @immut.Matrix[Int] = @container.matrix_transpose(
    source,
    ecosystem_owned_matrix_read_ops(),
    @container_adapters.immutable_matrix_build_ops(),
  ).unwrap()
  inspect(target, content="|0, 10|\n|1, 11|\n|2, 12|")
  match (ecosystem_owned_matrix_read_ops().get)(source, -1, 0) {
    Err(error) => inspect(error.is_index_out_of_bounds(), content="true")
    Ok(_) => fail("negative row must fail")
  }
  let degenerate : EcosystemOwnedMatrix[Int] = (ecosystem_owned_matrix_build_ops().tabulate)(
    0,
    3,
    (_, _) => 0,
  ).unwrap()
  debug_inspect((degenerate.rows, degenerate.cols), content="(0, 3)")
}

バックエンドは負の次元、0xN / Nx0、不正座標、所有権規則を自身で保証します。

接続チェックリスト

  • 実際のストレージと所有権に合う辞書だけを選ぶ。
  • 検査付きアクセスと構築で panic しない。
  • 境界 index、空・退化形状、initializer の座標順をテストする。
  • 永続編集では、元の値が変わらないことを確認する。
  • 可変編集では、失敗時に部分的な変更が起きないことを確認する。
  • 対応する両方向で、ジェネリックな map または変換を少なくとも 1 つテストする。
  • remote access、展開、疎行列 materialization などの性能特性を、意味論的な契約を変えずに文書化する。

将来の最適化 kernel 辞書は追加の opt-in 能力であり、read/build の相互運用の前提にしてはいけません。