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
8 changes: 6 additions & 2 deletions src/abstractgbarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ function Base.copy(A::M) where {M<:AbstractGBArray}
M(_copyGrBMat(A.p), A.fill)
end

function Base.Matrix(A::GBArrayOrTranspose)
function Base.Matrix(A::AbstractGBArray)
format = sparsitystatus(A)
if format === Dense()
T = unsafeunpack!(A, Dense())
Expand All @@ -195,7 +195,7 @@ function Base.Matrix(A::GBArrayOrTranspose)
return M
end

function Base.Vector(A::GBVectorOrTranspose)
function Base.Vector(A::AbstractGBVector)
format = sparsitystatus(A)
if format === Dense()
T = unsafeunpack!(A, Dense())
Expand All @@ -213,6 +213,10 @@ function Base.Vector(A::GBVectorOrTranspose)
return M
end

# The unpacking above needs an AbstractGBArray, so materialize the transpose first.
Base.Matrix(A::Transpose{<:Any, <:AbstractGBArray}) = Matrix(copy(A))
Base.Vector(A::Transpose{<:Any, <:AbstractGBVector}) = Vector(parent(A))

function SparseArrays.SparseMatrixCSC(A::GBArrayOrTranspose)
T = copy(A) # avoid changing sparsity of A and destroying it.
return unsafeunpack!(T, SparseMatrixCSC; attachfinalizer = true)
Expand Down
38 changes: 38 additions & 0 deletions src/operations/mul.jl
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,44 @@ function Base.:*(
return @_densepack B (*(A, B, op; mask, accum, desc))
end

# Dense outputs: C = α * A * B + β * C, so that mul! callers (Arpack, KrylovKit, ...) run in
# GraphBLAS rather than the generic LinearAlgebra fallback. See #125.
# pack needs a DenseArray: alias contiguous views (e.g. Arpack's views into workd), copy others.
_asdense(B::DenseVecOrMat) = B
_asdense(B::Transpose) = transpose(_asdense(parent(B)))
function _asdense(B::StridedVecOrMat)
contiguous = stride(B, 1) == 1 && (B isa AbstractVector || stride(B, 2) == size(B, 1))
return contiguous ? unsafe_wrap(Array, pointer(B), size(B)) : copy(B)
end

function _densemul!(C, A, B, α, β)
size(A, 2) == size(B, 1) || throw(DimensionMismatch("size(A, 2) != size(B, 1)"))
size(A, 1) == size(C, 1) || throw(DimensionMismatch("size(A, 1) != size(C, 1)"))
size(B, 2) == size(C, 2) || throw(DimensionMismatch("size(B, 2) != size(C, 2)"))
T = GC.@preserve B A * pack(_asdense(B))
R = unsafeunpack!(T, Dense())
try
R′ = reshape(R, size(C))
iszero(β) ? (C .= α .* R′) : (C .= α .* R′ .+ β .* C)
finally
_jlfree(R)
end
return C
end

const _GBVecMatOrTrans = Union{GBMatrixOrTranspose, GBVectorOrTranspose}

for (TC, TB) in (
(:StridedVector, :(StridedVector{<:valid_union})),
(:StridedMatrix, :(Union{StridedVecOrMat{<:valid_union}, Transpose{<:Any, <:StridedVecOrMat{<:valid_union}}})),
)
@eval begin
LinearAlgebra.mul!(C::$TC, A::_GBVecMatOrTrans, B::$TB, α::Number, β::Number) =
_densemul!(C, A, B, α, β)
LinearAlgebra.mul!(C::$TC, A::_GBVecMatOrTrans, B::$TB) = _densemul!(C, A, B, true, false)
end
end

function Base.:*((⊕)::Monoid, (⊗)::Function)
return function(A::GBArrayOrTranspose, B::GBArrayOrTranspose; mask=nothing, accum=nothing, desc=nothing)
*(A, B, (⊕, ⊗); mask, accum, desc)
Expand Down
3 changes: 3 additions & 0 deletions test/gbarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
# #104: non-default fill shows up in show
@test !occursin("fill value", sprint(show, MIME"text/plain"(), A))
@test occursin("fill value: 17", sprint(show, MIME"text/plain"(), setfill(A, 17)))
A = GBMatrix(sprand(ComplexF64, 5, 4, 0.5))
@test Matrix(A') == Matrix(A)'
@test Matrix(transpose(A)) == transpose(Matrix(A))
end
@testset "sparse" begin
#Construction and indexing correct for sparse matrices
Expand Down
11 changes: 11 additions & 0 deletions test/operations/mul.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,15 @@
@test m' * n == Matrix(m)' * Vector(n)
@test n' * m == Vector(n)' * Matrix(m)
@test n' * n == GBVector([Vector(n)' * Vector(n)])

# mul! into dense outputs runs in GraphBLAS (#125)
S = sprand(ComplexF64, 20, 15, 0.3)
A = GBMatrix(S)
x, X, y, Y = rand(ComplexF64, 15), rand(ComplexF64, 15, 3), rand(ComplexF64, 20), rand(ComplexF64, 20, 3)
@test mul!(copy(y), A, x) ≈ S * x
@test mul!(copy(y), A, x, 2, 3) ≈ 2 * S * x + 3 * y
@test mul!(copy(Y), A, X) ≈ S * X
@test mul!(copy(Y), A, X, 2, 3) ≈ 2 * S * X + 3 * Y
@test mul!(zeros(ComplexF64, 15), A', y) ≈ S' * y
@test mul!(view(zeros(ComplexF64, 25), 3:22), A, view([x; x], 16:30)) ≈ S * x
end
Loading