rtx-backend-metal: GPU index_select / index_add via one-hot CSR SpMM
Override the Backend trait's host-round-trip defaults: gather is S @ X with S the [E x N] one-hot selection CSR; scatter-add is the adjoint S^T @ X, whose CSR is built directly by counting sort so duplicate indices land in one row and the spmm kernel (one thread per output element) accumulates them without atomics. CSR matrices are cached per thread keyed by the exact index list + dims, so a static graph topology (GNN message passing) builds each matrix once. Host fallback on degenerate shapes or any sparse-pipeline failure. 13 new parity tests vs CPU reference: duplicates, unreferenced rows, D=1/2/3, 15k x 5k x 64 gather/scatter, cache reuse, adjoint roundtrip. Verified on-device that the SpMM path (not the fallback) serves all 13. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
2e23d0f4c6
commit
9297976929
@@ -388,6 +388,23 @@ impl Backend for MetalBackend {
|
||||
ops::conv::avg_pool2d(&input, kernel_size, stride, padding, count_include_pad)
|
||||
}
|
||||
|
||||
// ==================== Index Operations ====================
|
||||
|
||||
fn index_select<const D: usize>(
|
||||
tensor: Self::TensorPrimitive<D>,
|
||||
indices: &[usize],
|
||||
) -> Self::TensorPrimitive<D> {
|
||||
ops::index::index_select(&tensor, indices)
|
||||
}
|
||||
|
||||
fn index_add<const D: usize>(
|
||||
tensor: Self::TensorPrimitive<D>,
|
||||
indices: &[usize],
|
||||
num_rows: usize,
|
||||
) -> Self::TensorPrimitive<D> {
|
||||
ops::index::index_add(&tensor, indices, num_rows)
|
||||
}
|
||||
|
||||
// ==================== Device Management ====================
|
||||
|
||||
fn device<const D: usize>(tensor: &Self::TensorPrimitive<D>) -> Self::Device {
|
||||
|
||||
Reference in New Issue
Block a user