Repository navigation
Conversation
|
|
||
| A sparse array can't share the `AbstractGPUArray` supertype — that is a `DenseArray`, | ||
| whereas a sparse array must be an `AbstractSparseArray` — so GPUArrays keeps a parallel | ||
| sparse hierarchy with its own generic functionality. Integrating a back-end has three |
There was a problem hiding this comment.
Weird phrasing here, let me think a bit about how to make this more natural
| | `AbstractGPUSparseMatrixCSR{Tv,Ti}` | `rowPtr`, `colVal`, `nzVal`, `dims`, `nnz` | | ||
| | `AbstractGPUSparseMatrixCOO{Tv,Ti}` | `rowInd`, `colInd`, `nzVal`, `dims`, `nnz` | | ||
|
|
||
| The pointer/index/value arrays are the back-end's own dense vector type. Provide only the |
There was a problem hiding this comment.
Should we give an example (e.g. CuVector for CUDA)
|
|
||
| ### Interface to implement | ||
|
|
||
| * **Constructors** — from component arrays (`MyCSR(rowPtr, colVal, nzVal, dims)`), |
There was a problem hiding this comment.
What about to/from dense arrays?
| JLArray(x::JLSparseVector) = JLArray(collect(SparseVector(x))) | ||
| JLArray(x::JLSparseMatrixCSC) = JLArray(collect(SparseMatrixCSC(x))) | ||
| JLArray(x::JLSparseMatrixCSR) = JLArray(collect(SparseMatrixCSC(x))) | ||
| JLArray(x::JLSparseVector) = GPUArrays.to_dense(x) |
There was a problem hiding this comment.
should we make this an eval block?
| SparseArrays.SparseMatrixCSC(x::AbstractGPUSparseMatrixCSC) = SparseMatrixCSC(size(x)..., Array(SparseArrays.getcolptr(x)), Array(SparseArrays.rowvals(x)), Array(SparseArrays.nonzeros(x))) | ||
|
|
||
| function check_sparse_target(::Type{ST}, ::Type{Tv}, ::Type{Ti}) where {ST,Tv,Ti} | ||
| Tv isa Type && Ti isa Type || |
There was a problem hiding this comment.
This looks really funky to me. Shouldn't Ti also check it's a <: Integer?
|
|
||
| function check_sparse_target(::Type{ST}, ::Type{Tv}, ::Type{Ti}) where {ST,Tv,Ti} | ||
| Tv isa Type && Ti isa Type || | ||
| throw(ArgumentError("sparse target type $ST must specify value and index eltypes")) |
There was a problem hiding this comment.
Should we include Tv and Ti in the error message?
| @kernel function densify_vector_kernel!(out, iPtr, nzVal) | ||
| k = @index(Global, Linear) | ||
| if k <= length(nzVal) | ||
| @inbounds out[iPtr[k]] = nzVal[k] |
There was a problem hiding this comment.
it's funny how Claude made this a one liner here but not above
|
Yeah this hasn't passed my personal sniff test yet, hence draft, but thanks for the review. FWIW, the initial motivation was Metal support + SpMV/SpMM (which happens to be easier to express in COO), with the rest following out of it. The API simplification, replacing *_array_type / dense_array_type / sparse_array_type with something like |
|
Ah I can eff off until it's ready if you prefer, sorry! |
|
I'd love to review this one too once it's ready! |
|
Note to self: add a |
|
Can we resurrect this? |
|
This is exciting!!! |
GPUArrays now implements the sparse formats itself: GPUSparseVector and GPUSparseMatrixCSR/CSC/COO are immutable structs parametrized on the dense vectors that store their indices and values. Generic code allocates results with similar() on the buffers it already has, so the trait hooks (dense_array_type, sparse_array_type, csc_type, csr_type, coo_type, _sptranspose, _spadjoint) are gone, and a back-end needs no sparse-specific code: it can alias the types for its storage and add a transfer policy for its adaptor. The same struct is used on the device, replacing the GPUSparseDevice* types and the per-back-end adapt rules. The formats are canonical, as in SparseArrays (COO in row-major order). Constructors check host metadata only; check_structure verifies the invariants on the device. similar, copy, copyto!, zero and adapt follow SparseArrays and Adapt semantics: copies and conversions never share buffers, and adapting to a storage type keeps the format and types. Conversions between all formats run on the device (generic_regroup for CSR <-> CSC, generic_expand/generic_compress for CSR <-> COO). Broadcasting and reductions are ported to the new types. Broadcasting no longer reuses the input's pointer buffer for its output, and handles matrices without rows or columns. AbstractGPUSparseMatrixCSR/CSC/COO remain as deprecated aliases of the concrete types for downstream dispatch. JLArrays keeps only aliases, constructors on them, and host versions of sortperm, accumulate! and findall. The testsuite builds its inputs from dense buffers and covers every format for every back-end.
Dense GPU arrays convert to every sparse format on the device, through findall in column-major order (or on the dense transpose for row-major formats), and sparse(A; fmt) selects the format like CUDA.jl and AMDGPU.jl do. copy(transpose(A)), copy(adjoint(A)) and permutedims produce the same format by regrouping, and the format constructors accept transposed operands. findnz returns the coordinates in column-major order like SparseArrays, for every format.
sparse(I, J, V, m, n, combine; fmt) and sparsevec(I, V, n, combine) on GPU vectors sort packed coordinate keys, combine the values of repeated coordinates with a per-run fold (reduce_by_key), and compress. As in SparseArrays, repeated entries are folded in input order, with + by default (| for Bool) and explicit zeros kept, so that a call gives the same result on every back-end. Because the device sort need not be stable, a second sort on keys that are unique per entry restores the input order, unless the order cannot change the result (+ and * on integers, max, min, |, &). spdiagm builds on the same path.
The sparse redesign removes the back-end hooks and changes the sparse types, which is breaking for back-ends and for JLArrays' sparse types.
…lidation [only tests]
4e20de2 to
099665d
Compare
Breaking v13 redesign: GPUArrays owns immutable sparse vectors, CSR, CSC and row-major
COO, portable operations, high-level vendor integration and algorithm selection.
Backends supply storage/runtime and native executors, so future portable operations
and algorithm choices stay central.
Compressed pointers and coordinates have separate storage/index widths. Raw
constructors borrow; structural mutation is preflighted. Duplicate combination
preserves order; custom combiners must be associative but need not commute.
See the interface contract for the API and unsupported cases.
Coordinated CUDA, AMDGPU, oneAPI, Metal and OpenCL branches preserve vendor solves,
factorizations, BSR and batching where supported. oneAPI has explicit handle,
queue, buffer and prepared-operation lifetimes.
Metal integration is in JuliaGPU/Metal.jl#982.
The handoff records exact tested revisions and limits;
the performance report records timings and temporary memory. Metal was spot-tested
only. NVIDIA dense-allocation churn also reproduces on the v12 baseline and remains
unresolved.
Not release-ready: final coordinated CI, oneAPI artifact audit/publication, compatible
releases and registered resolution remain gates. The single TEMP CI commit pins the
unreleased stack and explicitly develops dependencies on Julia 1.10.