Add direct constructors for sparse arrays#684
Add direct constructors for sparse arrays#684nHackel wants to merge 4 commits intoJuliaGPU:masterfrom
Conversation
|
Your PR requires formatting changes to meet the project's style guidelines. Click here to view the suggested changes.diff --git a/lib/JLArrays/src/JLArrays.jl b/lib/JLArrays/src/JLArrays.jl
index 3bd3571..b76a237 100644
--- a/lib/JLArrays/src/JLArrays.jl
+++ b/lib/JLArrays/src/JLArrays.jl
@@ -150,7 +150,7 @@ mutable struct JLSparseMatrixCSC{Tv, Ti} <: GPUArrays.AbstractGPUSparseMatrixCSC
new{Tv, Ti}(colPtr, rowVal, nzVal, dims, length(nzVal))
end
end
-function GPUSparseMatrixCSC(colPtr::JLArray{Ti, 1}, rowVal::JLArray{Ti, 1}, nzVal::JLArray{Tv, 1}, dims::NTuple{2,<:Integer}) where {Tv, Ti <: Integer}
+function GPUSparseMatrixCSC(colPtr::JLArray{Ti, 1}, rowVal::JLArray{Ti, 1}, nzVal::JLArray{Tv, 1}, dims::NTuple{2, <:Integer}) where {Tv, Ti <: Integer}
return JLSparseMatrixCSC(colPtr, rowVal, nzVal, dims)
end
function JLSparseMatrixCSC(colPtr::JLArray{Ti, 1}, rowVal::JLArray{Ti, 1}, nzVal::JLArray{Tv, 1}, dims::NTuple{2,<:Integer}) where {Tv, Ti <: Integer}
@@ -184,7 +184,7 @@ end
function JLSparseMatrixCSR(rowPtr::JLArray{Ti, 1}, colVal::JLArray{Ti, 1}, nzVal::JLArray{Tv, 1}, dims::NTuple{2,<:Integer}) where {Tv, Ti <: Integer}
return JLSparseMatrixCSR{Tv, Ti}(rowPtr, colVal, nzVal, dims)
end
-function GPUSparseMatrixCSR(rowPtr::JLArray{Ti, 1}, colVal::JLArray{Ti, 1}, nzVal::JLArray{Tv, 1}, dims::NTuple{2,<:Integer}) where {Tv, Ti <: Integer}
+function GPUSparseMatrixCSR(rowPtr::JLArray{Ti, 1}, colVal::JLArray{Ti, 1}, nzVal::JLArray{Tv, 1}, dims::NTuple{2, <:Integer}) where {Tv, Ti <: Integer}
return JLSparseMatrixCSR(rowPtr, colVal, nzVal, dims)
end
function SparseArrays.SparseMatrixCSC(x::JLSparseMatrixCSR)
diff --git a/test/testsuite/sparse.jl b/test/testsuite/sparse.jl
index 146801e..ecfee75 100644
--- a/test/testsuite/sparse.jl
+++ b/test/testsuite/sparse.jl
@@ -154,11 +154,11 @@ end
# Helper function to derive direct matrix formats:
# Create colptr, rowval, nzval for m x n matrix with 3 values per column
-function csc_vectors(m::Int, n::Int, ::Type{ET}; I::Type{<:Integer}=Int32) where {ET}
+function csc_vectors(m::Int, n::Int, ::Type{ET}; I::Type{<:Integer} = Int32) where {ET}
# Fixed, deterministic 3 nnz per column; random nz values
colptr = Vector{I}(undef, n + 1)
rowval = Vector{I}()
- nzval = Vector{ET}()
+ nzval = Vector{ET}()
colptr[1] = I(1)
nnz_acc = 0
@@ -172,29 +172,29 @@ function csc_vectors(m::Int, n::Int, ::Type{ET}; I::Type{<:Integer}=Int32) where
end
return colptr, rowval, nzval
end
-function csr_vectors(m::Int, n::Int, ::Type{ET}; I::Type{<:Integer}=Int32) where {ET}
+function csr_vectors(m::Int, n::Int, ::Type{ET}; I::Type{<:Integer} = Int32) where {ET}
# Build CSC for (n, m), then interpret as CSR for (m, n)
- colptr_nm, rowval_nm, nzval_nm = csc_vectors(n, m, ET; I=I)
+ colptr_nm, rowval_nm, nzval_nm = csc_vectors(n, m, ET; I = I)
rowptr = colptr_nm
colind = rowval_nm
- nzval = nzval_nm
+ nzval = nzval_nm
return rowptr, colind, nzval
end
# Construct appropriate sparse arrays
-function construct_sparse_matrix(AT::Type{<:GPUArrays.AbstractGPUSparseMatrixCSC}, ::Type{ET}, m::Int, n::Int; I::Type{<:Integer}=Int32) where {ET}
- colptr, rowval, nzval = csc_vectors(m, n, ET; I=I)
+function construct_sparse_matrix(AT::Type{<:GPUArrays.AbstractGPUSparseMatrixCSC}, ::Type{ET}, m::Int, n::Int; I::Type{<:Integer} = Int32) where {ET}
+ colptr, rowval, nzval = csc_vectors(m, n, ET; I = I)
dense_AT = GPUArrays.dense_array_type(AT)
d_colptr = dense_AT(colptr)
d_rowval = dense_AT(rowval)
- d_nzval = dense_AT(nzval)
+ d_nzval = dense_AT(nzval)
return GPUSparseMatrixCSC(d_colptr, d_rowval, d_nzval, (m, n))
end
-function construct_sparse_matrix(AT::Type{<:GPUArrays.AbstractGPUSparseMatrixCSR}, ::Type{ET}, m::Int, n::Int; I::Type{<:Integer}=Int32) where {ET}
- rowptr, colind, nzval = csr_vectors(m, n, ET; I=I)
+function construct_sparse_matrix(AT::Type{<:GPUArrays.AbstractGPUSparseMatrixCSR}, ::Type{ET}, m::Int, n::Int; I::Type{<:Integer} = Int32) where {ET}
+ rowptr, colind, nzval = csr_vectors(m, n, ET; I = I)
dense_AT = GPUArrays.dense_array_type(AT)
d_rowptr = dense_AT(rowptr)
d_colind = dense_AT(colind)
- d_nzval = dense_AT(nzval)
+ d_nzval = dense_AT(nzval)
return GPUSparseMatrixCSR(d_rowptr, d_colind, d_nzval, (m, n))
end
function direct_vector_construction(AT::Type{<:GPUArrays.AbstractGPUSparseMatrix}, eltypes)
@@ -205,6 +205,7 @@ function direct_vector_construction(AT::Type{<:GPUArrays.AbstractGPUSparseMatrix
@test x isa AT{ET}
@test size(x) == (m, n)
end
+ return
end
function direct_vector_construction(AT, eltypes)
# NOP |
General GPUSparseMatrix defaults to COO, which defaults to sparse
7f75c5e to
2301530
Compare
|
Sorry for neglecting this, I'll try to take a look today |
|
So one question I have is whether COO is really the best default format, or whether we should allow users/developers to set the format somehow with a |
|
@kshyatt that's a good question. From a user perspective, I think a changeable default matrix would make using the default constructor difficult unless the user can overwrite the default. Otherwise since the inputs are interpreted differently between the formats, a user would need to check the default format and construct the appropriate inputs. At which point they could also just call the appropriate "direct" constructor anyways. So maybe we have a default of: function GPUSparseMatrix(args...; kwargs..., format = :coo)
if format == :coo
GPUSparseMatrixCOO(args...; kwargs...)
elseif format == :csc
# ...
else
throw(ArgumentError("Unexpected format specifier $format"))
end
end
# Optionally in this setting CUDA could overwrite like this
GPUSparseMatrix(i::CuVector, args...; kwargs..., format = :csc) = ...or with a default option from a backend via a function: function GPUSparseMatrix(gpu::GPUArray, args...; kwargs..., format = default_sparse_format(typeof(GPU)))
if format == :coo
GPUSparseMatrixCOO(args...; kwargs...)
elseif format == :csc
# ...
else
throw(ArgumentError("Unexpected format specifier $format"))
end
endor we just drop the |
|
I think |
|
Should a default constructor always expect COO/normal function GPUSparseMatrix(I, J, V; format = default_sparse_format(I))
if format == :coo
GPUSparseMatrixCOO(I, J, V)
elseif format == :csc
# calculate colptr and use in function call
GPUSparseMatrixCSC(...)
elseif format == :csr
# calculate rowptr and use in function call
GPUSparseMatrixCSR(...)
# ...
end
endor should it just pass along arguments as in the version in my previous comment? I think CUDA has a similar interface for |
|
Well I guess we could also pass a |
|
I can do that, my main worry/question is what we should do with the inputs for the default setting. If we just pass along the arguments, a user can run into this issue: colptr = ...
rowval = ...
vals = ...
GPUSparseMatrix(colptr, rowval, vals; format = :csc) # result should be as expected by user
# Would most likely result in transpose of desired matrix
# Since CSR expects arguments (rowptr, colval, vals)
# In this case the user chose that, in the case of a backend specific default, the user doesn't necessarily
# know the default backend
GPUSparseMatrix(colptr, rowval, vals; format = :csr)If we always expect arguments to be in COO format, we could try to compute the approriate indices: GPUSparseMatrix(I, J, V; format = default_sparse_format(I)) = GPUSparseMatrix(format, I, J, V)
GPUSparseMatrix(format::Symbol, args...) = GPUSparseMatrix(Val(format), args...)
function GPUSparseMatrix(::Val{:csc}, I, J, V)
colptr = # based on I
return GPUSparseMatrixCSC(colptr, J, V)
end
function GPUSparseMatrix(::Val{:csr}, I, J, V)
rowptr = # based on J
return GPUSparseMatrixCSC(rowptr, I, V)
endor we drop the GPUSparseMatrix and just provde |
|
I agree users could be tricked here... but on the other hand at some point they have to use the constructor responsibly. It's also the case that they can inadvertently create a transposed matrix with |
|
Maybe the default could indeed be COO but then if the user passes a |
|
Then etc? |
|
That sounds like a good middle-ground between the options! I'll try that out as soon as I can |
This PR adds direct constructors for the sparse matrix types defined in GPUArrays.jl or rather adds a function for backends to generically define methods for, see also #677.
Changes:
There currently is no COO and BSR implementation for JLArrays. I could add one as well, at least for the BSR I'd need to take a look at the format first or adapt from maybe CUDA.jl