Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/sparse/conversions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,15 @@
end
end

## ROCSparseVector to ROCVector
ROCVector(x::ROCSparseVector{T}) where {T} = ROCVector{T}(x)

Check warning on line 205 in src/sparse/conversions.jl

View check run for this annotation

Codecov / codecov/patch

src/sparse/conversions.jl#L205

Added line #L205 was not covered by tests

function ROCVector{T}(sv::ROCSparseVector{T}) where {T}
n = length(sv)
dv = AMDGPU.zeros(T, n)
scatter!(dv, sv, 'O')

Check warning on line 210 in src/sparse/conversions.jl

View check run for this annotation

Codecov / codecov/patch

src/sparse/conversions.jl#L207-L210

Added lines #L207 - L210 were not covered by tests
end

## CSR to BSR and vice-versa

for (fname,elty) in ((:rocsparse_scsr2bsr, :Float32),
Expand Down Expand Up @@ -400,7 +409,7 @@
end
end

function Base.copyto!(dest::Array{T, 2}, src::AbstractROCSparseMatrix{T}) where T
function Base.copyto!(dest::Matrix{T}, src::AbstractROCSparseMatrix{T}) where T
copyto!(dest, ROCMatrix{T}(src))
end

Expand Down
115 changes: 115 additions & 0 deletions src/sparse/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,128 @@

## API functions

function sparsetodense(A::Union{ROCSparseMatrixCSC{T},ROCSparseMatrixCSR{T},ROCSparseMatrixCOO{T}}, index::SparseChar,
algo::rocsparse_sparse_to_dense_alg=rocsparse_sparse_to_dense_alg_default) where {T}
m,n = size(A)
B = ROCMatrix{T}(undef, m, n)
desc_sparse = ROCSparseMatrixDescriptor(A, index)
desc_dense = ROCDenseMatrixDescriptor(B)

function bufferSize()
out = Ref{Csize_t}()
rocsparse_sparse_to_dense(handle(), desc_sparse, desc_dense, algo, out, C_NULL)
return out[]
end

buffer_size = Ref{Csize_t}()
with_workspace(bufferSize) do buffer
buffer_size[] = sizeof(buffer)
rocsparse_sparse_to_dense(handle(), desc_sparse, desc_dense, algo, buffer_size, buffer)
end
return B
end

function densetosparse(A::ROCMatrix{T}, fmt::Symbol, index::SparseChar,
algo::rocsparse_dense_to_sparse_alg=rocsparse_dense_to_sparse_alg_default) where {T}
m,n = size(A)
local rowPtr, colPtr, desc_sparse, B

Check warning on line 29 in src/sparse/generic.jl

View check run for this annotation

Codecov / codecov/patch

src/sparse/generic.jl#L29

Added line #L29 was not covered by tests
if fmt == :coo
desc_sparse = ROCSparseMatrixDescriptor(ROCSparseMatrixCOO, T, Cint, m, n, index)
elseif fmt == :csr
rowPtr = ROCVector{Cint}(undef, m+1)
desc_sparse = ROCSparseMatrixDescriptor(ROCSparseMatrixCSR, rowPtr, T, Cint, m, n, index)
elseif fmt == :csc
colPtr = ROCVector{Cint}(undef, n+1)
desc_sparse = ROCSparseMatrixDescriptor(ROCSparseMatrixCSC, colPtr, T, Cint, m, n, index)
else
error("Format :$fmt not available, use :csc, :csr or :coo.")

Check warning on line 39 in src/sparse/generic.jl

View check run for this annotation

Codecov / codecov/patch

src/sparse/generic.jl#L39

Added line #L39 was not covered by tests
end
desc_dense = ROCDenseMatrixDescriptor(A)

function bufferSize()
out = Ref{Csize_t}()
rocsparse_dense_to_sparse(handle(), desc_dense, desc_sparse, algo, out, C_NULL)
return out[]
end

buffer_size = Ref{Csize_t}()
with_workspace(bufferSize) do buffer
buffer_size[] = sizeof(buffer)
# Analysis
rocsparse_dense_to_sparse(handle(), desc_dense, desc_sparse, algo, C_NULL, buffer)
nnzB = Ref{Int64}()
rocsparse_spmat_get_size(desc_sparse, Ref{Int64}(), Ref{Int64}(), nnzB)
if fmt == :coo
rowInd = ROCVector{Cint}(undef, nnzB[])
colInd = ROCVector{Cint}(undef, nnzB[])
nzVal = ROCVector{T}(undef, nnzB[])
B = ROCSparseMatrixCOO{T, Cint}(rowInd, colInd, nzVal, (m,n))
rocsparse_coo_set_pointers(desc_sparse, B.rowInd, B.colInd, B.nzVal)
elseif fmt == :csr
colVal = ROCVector{Cint}(undef, nnzB[])
nzVal = ROCVector{T}(undef, nnzB[])
B = ROCSparseMatrixCSR{T, Cint}(rowPtr, colVal, nzVal, (m,n))
rocsparse_csr_set_pointers(desc_sparse, B.rowPtr, B.colVal, B.nzVal)
elseif fmt == :csc
rowVal = ROCVector{Cint}(undef, nnzB[])
nzVal = ROCVector{T}(undef, nnzB[])
B = ROCSparseMatrixCSC{T, Cint}(colPtr, rowVal, nzVal, (m,n))
rocsparse_csc_set_pointers(desc_sparse, B.colPtr, B.rowVal, B.nzVal)
else
error("Format :$fmt not available, use :csc, :csr or :coo.")

Check warning on line 73 in src/sparse/generic.jl

View check run for this annotation

Codecov / codecov/patch

src/sparse/generic.jl#L73

Added line #L73 was not covered by tests
end
rocsparse_dense_to_sparse(handle(), desc_dense, desc_sparse, algo, buffer_size, buffer)
end
return B
end

function gather!(X::ROCSparseVector, Y::ROCVector, index::SparseChar)
descX = ROCSparseVectorDescriptor(X, index)
descY = ROCDenseVectorDescriptor(Y)
rocsparse_gather(handle(), descY, descX)
X
end

function scatter!(Y::ROCVector, X::ROCSparseVector, index::SparseChar)
descX = ROCSparseVectorDescriptor(X, index)
descY = ROCDenseVectorDescriptor(Y)
rocsparse_scatter(handle(), descX, descY)
return Y
end

function axpby!(alpha::Number, X::ROCSparseVector{T}, beta::Number, Y::ROCVector{T}, index::SparseChar) where {T}
descX = ROCSparseVectorDescriptor(X, index)
descY = ROCDenseVectorDescriptor(Y)
rocsparse_axpby(handle(), Ref{T}(alpha), descX, Ref{T}(beta), descY)
return Y
end

function rot!(X::ROCSparseVector{T}, Y::ROCVector{T}, c::Number, s::Number, index::SparseChar) where {T}
descX = ROCSparseVectorDescriptor(X, index)
descY = ROCDenseVectorDescriptor(Y)
rocsparse_rot(handle(), Ref{T}(c), Ref{T}(s), descX, descY)
return X, Y
end

function vv!(transx::SparseChar, X::ROCSparseVector{T}, Y::DenseROCVector{T}, index::SparseChar) where {T}
descX = ROCSparseVectorDescriptor(X, index)
descY = ROCDenseVectorDescriptor(Y)
result = Ref{T}()

function bufferSize()
out = Ref{Csize_t}()
rocsparse_spvv(handle(), transx, descX, descY, result, T, out, C_NULL)
return out[]
end

buffer_size = Ref{Csize_t}()
with_workspace(bufferSize) do buffer
buffer_size[] = sizeof(buffer)
rocsparse_spvv(handle(), transx, descX, descY, result, T, buffer_size, buffer)
end
return result[]
end

function mv!(
transa::SparseChar, alpha::Number, A::Union{ROCSparseMatrixCSR{T}, ROCSparseMatrixCSC{T}, ROCSparseMatrixCOO{T}},
X::DenseROCVector{T}, beta::Number, Y::DenseROCVector{T}, index::SparseChar,
Expand Down
54 changes: 39 additions & 15 deletions src/sparse/helpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,33 @@
mutable struct ROCSparseMatrixDescriptor
handle::rocsparse_spmat_descr

function ROCSparseMatrixDescriptor(A::ROCSparseMatrixCOO, IndexBase::Char; transposed::Bool=false)
desc_ref = Ref{rocsparse_spmat_descr}()
if transposed
rocsparse_create_coo_descr(

Check warning on line 110 in src/sparse/helpers.jl

View check run for this annotation

Codecov / codecov/patch

src/sparse/helpers.jl#L110

Added line #L110 was not covered by tests
desc_ref, reverse(size(A))..., nnz(A),
A.colInd, A.rowInd, nonzeros(A),
eltype(A.colInd), IndexBase, eltype(nonzeros(A))
)
else
rocsparse_create_coo_descr(
desc_ref, size(A)..., nnz(A),
A.rowInd, A.colInd, nonzeros(A),
eltype(A.rowInd), IndexBase, eltype(nonzeros(A))
)
end
obj = new(desc_ref[])
return finalizer(rocsparse_destroy_spmat_descr, obj)
end

function ROCSparseMatrixDescriptor(::Type{ROCSparseMatrixCOO}, Tv::DataType, Ti::DataType, m::Integer, n::Integer, IndexBase::Char)
desc_ref = Ref{rocsparse_spmat_descr}()
rocsparse_create_coo_descr(desc_ref, m, n, Ti(0), C_NULL, C_NULL, C_NULL, Ti, IndexBase, Tv)
obj = new(desc_ref[])
finalizer(rocsparse_destroy_spmat_descr, obj)
return obj
end

function ROCSparseMatrixDescriptor(A::ROCSparseMatrixCSR, IndexBase::Char; transposed::Bool=false)
desc_ref = Ref{rocsparse_spmat_descr}()
if transposed
Expand All @@ -121,6 +148,14 @@
return finalizer(rocsparse_destroy_spmat_descr, obj)
end

function ROCSparseMatrixDescriptor(::Type{ROCSparseMatrixCSR}, rowPtr::ROCVector, Tv::DataType, Ti::DataType, m::Integer, n::Integer, IndexBase::Char)
desc_ref = Ref{rocsparse_spmat_descr}()
rocsparse_create_csr_descr(desc_ref, m, n, Ti(0), rowPtr, C_NULL, C_NULL, Ti, Ti, IndexBase, Tv)
obj = new(desc_ref[])
finalizer(rocsparse_destroy_spmat_descr, obj)
return obj
end

function ROCSparseMatrixDescriptor(A::ROCSparseMatrixCSC, IndexBase::Char; transposed::Bool=false)
desc_ref = Ref{rocsparse_spmat_descr}()
if transposed
Expand All @@ -138,23 +173,12 @@
return finalizer(rocsparse_destroy_spmat_descr, obj)
end

function ROCSparseMatrixDescriptor(A::ROCSparseMatrixCOO, IndexBase::Char; transposed::Bool=false)
function ROCSparseMatrixDescriptor(::Type{ROCSparseMatrixCSC}, colPtr::ROCVector, Tv::DataType, Ti::DataType, m::Integer, n::Integer, IndexBase::Char)
desc_ref = Ref{rocsparse_spmat_descr}()
if transposed
rocsparse_create_coo_descr(
desc_ref, reverse(size(A))..., nnz(A),
A.colInd, A.rowInd, nonzeros(A),
eltype(A.colInd), IndexBase, eltype(nonzeros(A))
)
else
rocsparse_create_coo_descr(
desc_ref, size(A)..., nnz(A),
A.rowInd, A.colInd, nonzeros(A),
eltype(A.rowInd), IndexBase, eltype(nonzeros(A))
)
end
rocsparse_create_csc_descr(desc_ref, m, n, Ti(0), colPtr, C_NULL, C_NULL, Ti, Ti, IndexBase, Tv)
obj = new(desc_ref[])
return finalizer(rocsparse_destroy_spmat_descr, obj)
finalizer(rocsparse_destroy_spmat_descr, obj)
return obj
end
end

Expand Down
6 changes: 6 additions & 0 deletions src/sparse/interfaces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
mm!(transa, transb, alpha, A, B, beta, C, 'O')
end

LinearAlgebra.dot(x::ROCSparseVector{T}, y::DenseROCVector{T}) where {T <: BlasReal} = vv!('N', x, y, 'O')
LinearAlgebra.dot(x::DenseROCVector{T}, y::ROCSparseVector{T}) where {T <: BlasReal} = dot(y, x)

Check warning on line 26 in src/sparse/interfaces.jl

View check run for this annotation

Codecov / codecov/patch

src/sparse/interfaces.jl#L25-L26

Added lines #L25 - L26 were not covered by tests

LinearAlgebra.dot(x::ROCSparseVector{T}, y::DenseROCVector{T}) where {T <: BlasComplex} = vv!('C', x, y, 'O')
LinearAlgebra.dot(x::DenseROCVector{T}, y::ROCSparseVector{T}) where {T <: BlasComplex} = conj(dot(y,x))

Check warning on line 29 in src/sparse/interfaces.jl

View check run for this annotation

Codecov / codecov/patch

src/sparse/interfaces.jl#L28-L29

Added lines #L28 - L29 were not covered by tests

# legacy methods with final MulAddMul argument
LinearAlgebra.generic_matvecmul!(C::ROCVector{T}, tA::AbstractChar, A::ROCSparseMatrix{T}, B::DenseROCVector{T}, _add::MulAddMul) where T <: BlasFloat =
LinearAlgebra.generic_matvecmul!(C, tA, A, B, _add.alpha, _add.beta)
Expand Down
92 changes: 92 additions & 0 deletions test/rocsparse/generic.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,95 @@
fmt = Dict(ROCSparseMatrixCSC => :csc,
ROCSparseMatrixCSR => :csr,
ROCSparseMatrixCOO => :coo)

for SparseMatrixType in [ROCSparseMatrixCSC, ROCSparseMatrixCSR, ROCSparseMatrixCOO]
@testset "$SparseMatrixType -- densetosparse algo=$algo" for algo in [rocSPARSE.rocsparse_dense_to_sparse_alg_default]
@testset "densetosparse $T" for T in [Float32, Float64, ComplexF32, ComplexF64]
A_sparse = sprand(T, 10, 20, 0.5)
A_dense = Matrix{T}(A_sparse)
dA_dense = ROCMatrix{T}(A_dense)
dA_sparse = rocSPARSE.densetosparse(dA_dense, fmt[SparseMatrixType], 'O', algo)
@test A_sparse ≈ collect(dA_sparse)
end
end
@testset "$SparseMatrixType -- sparsetodense algo=$algo" for algo in [rocSPARSE.rocsparse_sparse_to_dense_alg_default]
@testset "sparsetodense $T" for T in [Float32, Float64, ComplexF32, ComplexF64]
A_dense = rand(T, 10, 20)
A_sparse = sparse(A_dense)
dA_sparse = SparseMatrixType(A_sparse)
dA_dense = rocSPARSE.sparsetodense(dA_sparse, 'O', algo)
@test A_dense ≈ collect(dA_dense)
end
end
end

@testset "gather! $T" for T in [Float32, Float64, ComplexF32, ComplexF64]
X = sprand(T, 20, 0.5)
dX = ROCSparseVector{T}(X)
Y = rand(T, 20)
dY = ROCVector{T}(Y)
rocSPARSE.gather!(dX, dY, 'O')
Z = copy(X)
for i = 1:nnz(X)
Z[X.nzind[i]] = Y[X.nzind[i]]
end
@test Z ≈ sparse(collect(dX))
end

@testset "scatter! $T" for T in [Float32, Float64, ComplexF32, ComplexF64]
X = sprand(T, 20, 0.5)
dX = ROCSparseVector{T}(X)
Y = rand(T, 20)
dY = ROCVector{T}(Y)
rocSPARSE.scatter!(dY, dX, 'O')
Z = copy(Y)
for i = 1:nnz(X)
Z[X.nzind[i]] = X.nzval[i]
end
@test Z ≈ collect(dY)
end

@testset "axpby! $T" for T in [Float32, Float64, ComplexF32, ComplexF64]
X = sprand(T, 20, 0.5)
dX = ROCSparseVector{T}(X)
Y = rand(T, 20)
dY = ROCVector{T}(Y)
alpha = rand(T)
beta = rand(T)
rocSPARSE.axpby!(alpha, dX, beta, dY, 'O')
@test alpha * X + beta * Y ≈ collect(dY)
end

@testset "rot! $T" for T in [Float32, Float64, ComplexF32, ComplexF64]
X = sprand(T, 20, 0.5)
dX = ROCSparseVector{T}(X)
Y = rand(T, 20)
dY = ROCVector{T}(Y)
c = rand(T)
s = rand(T)
rocSPARSE.rot!(dX, dY, c, s, 'O')
W = copy(X)
Z = copy(Y)
for i = 1:nnz(X)
W[X.nzind[i]] = c * X.nzval[i] + s * Y[X.nzind[i]]
Z[X.nzind[i]] = -s * X.nzval[i] + c * Y[X.nzind[i]]
end
@test W ≈ collect(dX)
@test Z ≈ collect(dY)
end

@testset "vv! $T" for T in [Float32, Float64, ComplexF32, ComplexF64]
for (transx, opx) in [('N', identity), ('C', conj)]
T <: Real && transx == 'C' && continue
X = sprand(T, 20, 0.5)
dX = ROCSparseVector{T}(X)
Y = rand(T, 20)
dY = ROCVector{T}(Y)
result = rocSPARSE.vv!(transx, dX, dY, 'O')
@test sum(opx(X[i]) * Y[i] for i=1:20) ≈ result
end
end

@testset "generic mv!" for T in (Float32, Float64, ComplexF32, ComplexF64)
A = sprand(T, 10, 10, 0.1)
x = rand(T, 10)
Expand Down