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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ docs/site/
LocalPreferences.toml
benchmarks/results.txt
/Manifest.toml
*.cov
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/SuiteSparseGraphBLAS.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export ColMajor, RowMajor, storageorder #reexports from StorageOrders
include("abstracts.jl")
include("libutils.jl")

include("lib/LibGraphBLAS_gen.jl")
include("../lib/LibGraphBLAS_gen.jl")
using .LibGraphBLAS

include("operators/libgbops.jl")
Expand Down
14 changes: 14 additions & 0 deletions src/abstractgbarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -811,4 +811,18 @@ function setfill(A::AbstractGBArray, x) # aliasing form.
B = similar(A; fill=x)
B.p = A.p
return B
end

getfill(A::AbstractGBArray) = A.fill
getfill(A::LinearAlgebra.AdjOrTrans{<:Any, <:AbstractGBArray}) = parent(A).fill

function Base.:(==)(A::GBArrayOrTranspose, B::GBArrayOrTranspose)
A === B && return true
size(A) == size(B) || return false
getfill(A) == getfill(B) || return false
nnz(A) == nnz(B) || return false
C = emul(A, B, ==)
nnz(C) == nnz(A) || return false
nnz(C) == 0 && return true
return reduce(∧, C, dims=:, init=true)
end
6 changes: 5 additions & 1 deletion src/libutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@ macro wraperror(code)
throw(BoundsError())
elseif info == LibGraphBLAS.GrB_PANIC
throw(PANIC)
elseif info == LibGraphBLAS.GrB_INVALID_OBJECT
throw(ErrorException("Invalid Object"))
elseif info == LibGraphBLAS.GrB_EMPTY_OBJECT
throw(ErrorException("Empty Object"))
else
throw(ErrorException("Unreachable Reached."))
throw(ErrorException("Unknown GraphBLAS Exception."))
end
end
end
Expand Down
17 changes: 5 additions & 12 deletions src/operations/operationutils.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
inferunarytype(::Type{T}, f::F) where {T, F<:Base.Callable} = Base._return_type(f, Tuple{T})
inferunarytype(::Type{X}, op::TypedUnaryOperator) where X = ztype(op)
inferunarytype(::Type{X}, op::TypedUnaryOperator{F, X}) where {F, X} = ztype(op)

inferbinarytype(::Type{T}, ::Type{U}, f::F) where {T, U, F<:Base.Callable} = Base._return_type(f, Tuple{T, U})
# Overload for `first`, which will give Vector{T} normally:
inferbinarytype(::Type{T}, ::Type{U}, f::typeof(first)) where {T, U} = T
inferbinarytype(::Type{T}, ::Type{U}, op::AbstractMonoid) where {T, U} = inferbinarytype(T, U, op.binaryop.fn)
inferbinarytype(::Type{T}, ::Type{U}, op::AbstractMonoid) where {T, U} = inferbinarytype(T, U, op.fn)
#semirings are technically binary so we'll just overload that
inferbinarytype(::Type{T}, ::Type{U}, op::Tuple) where {T, U} = inferbinarytype(T, U, semiring(op, T, U))
inferbinarytype(::Type{T}, ::Type{U}, op::TypedSemiring) where {T, U} = inferbinarytype(T, U, op.mulop)
Expand Down Expand Up @@ -37,7 +37,7 @@ Base.parent(C::Complement) = C.parent
Structural(A::T) where {T<:GBArrayOrTranspose}= Structural{T}(A)
Base.parent(C::Structural) = C.parent

_handlemask!(desc, mask::Nothing) = C_NULL
_handlemask!(desc, ::Nothing) = C_NULL
_handlemask!(desc, mask::AbstractGBArray) = mask
function _handlemask!(desc, mask)
while !(mask isa AbstractGBArray)
Expand All @@ -51,6 +51,8 @@ function _handlemask!(desc, mask)
desc.structural_mask = true
elseif mask isa Ptr
return C_NULL
else
throw(ArgumentError("Mask type not recognized."))
end
end
return mask
Expand All @@ -63,15 +65,6 @@ _handleaccum(op::Function, t) = binaryop(op, t, t)
_handleaccum(op::Function, tleft, tright) = binaryop(op, tleft, tright)
_handleaccum(op::TypedBinaryOperator, x...) = op

function _kwargtoc(desc, x)
x.second === nothing && return C_NULL
if x.first === :mask
return _handlemask!(desc, x.second)
end
return x.second
end


"""
xtype(op::GrBOp)::DataType

Expand Down
12 changes: 9 additions & 3 deletions src/operations/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ function reduce!(
op = typedmonoid(op, eltype(w))
accum = _handleaccum(accum, eltype(w))
@wraperror LibGraphBLAS.GrB_Matrix_reduce_Monoid(
Ptr{LibGraphBLAS.GrB_Vector}(gbpointer(w)), mask, accum, op, gbpointer(parent(A)), desc
Ptr{LibGraphBLAS.GrB_Vector}(
gbpointer(w)), gbpointer(mask), accum, op, gbpointer(parent(A)), desc
)
return w
end
Expand All @@ -26,9 +27,13 @@ function Base.reduce(
desc = _handledescriptor(desc; in1=A)
mask = _handlemask!(desc, mask)
if typeout === nothing
typeout = eltype(A)
typeout = inferbinarytype(eltype(A), eltype(A), op)
end
if typeout != eltype(A)
throw(ArgumentError(
"The SuiteSparse:GraphBLAS reduce function only supports monoids where T x T -> T.
Please pass a function whose output type matches both input types."))
end

if dims == 2
w = similar(A, typeout, size(A, 1))
reduce!(op, w, A; desc, accum, mask)
Expand All @@ -52,6 +57,7 @@ function Base.reduce(
end
accum = _handleaccum(accum, typeout)
@wraperror LibGraphBLAS.GrB_Matrix_reduce_Monoid_Scalar(c, accum, op, gbpointer(parent(A)), desc)
c[] === nothing && return getfill(A)
return c[]
end
end
Expand Down
7 changes: 6 additions & 1 deletion src/operators/monoids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ end
typedmonoid(op::TypedMonoid, x...) = op

# We default to no available monoid.
defaultmonoid(f::F, ::Type{T}) where {F<:Base.Callable, T} = nothing
defaultmonoid(f::F, ::Type{T}) where {F<:Base.Callable, T} = throw(
ArgumentError("Function $f does not have a default monoid.
You must either extend defaultmonoid(::$F, ::Type{T}) =
Monoid($f, <identity> [, <terminal>]) or pass the struct
Monoid($f, <identity>, [, <terminal>]) to the operation.")
)

# Use defaultmonoid when available. User should verify that this results in the correct monoid.
typedmonoid(f::F, ::Type{T}) where {F<:Base.Callable, T} = typedmonoid(defaultmonoid(f, T), T)
Expand Down
4 changes: 3 additions & 1 deletion src/scalar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ for T ∈ valid_vec
@eval begin
function Base.getindex(value::GBScalar{$T})
x = Ref{$T}()
@wraperror LibGraphBLAS.$func(x, value)
info = LibGraphBLAS.$func(x, value)
info == LibGraphBLAS.GrB_NO_VALUE && return nothing
@wraperror info
return x[]
end
end
Expand Down
3 changes: 2 additions & 1 deletion src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ function _monoidnew!(op::TypedMonoid{F, Z, T}) where {F, Z, T}
if op.terminal === nothing
@wraperror LibGraphBLAS.GrB_Monoid_new_UDT(opref, op.binaryop, Ref(op.identity))
else
@wraperror LibGraphBLAS.GrB_Monoid_terminal_new_UDT(opref, op.binaryop, Ref(op.identity), Ref(op.terminal))
@wraperror LibGraphBLAS.GxB_Monoid_terminal_new_UDT(opref, op.binaryop, Ref(op.identity), Ref(op.terminal))
end
op.p = opref[]
end
Expand Down Expand Up @@ -294,6 +294,7 @@ end
# However, if one (for some reason) wraps another AbstractGBArray
# this should be overloaded.
gbpointer(A::AbstractGBArray) = A.p[]
gbpointer(A::Ptr) = A

# We need to do this at runtime. This should perhaps be `RuntimeOrder`, but that trait should likely be removed.
# This should ideally work out fine. a GBMatrix or GBVector won't have
Expand Down
2 changes: 1 addition & 1 deletion test/issues.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
A = GBMatrix([1,1,2,2,3,4,4,5,6,7,7,7], [2,4,5,7,6,1,3,6,3,3,4,5], [1:12...])
B = GBVector([3, 4, 5, 6, 7], [3, 4, 5, 6, 7])
x = subassign!(A, B', 3, :);
@test_broken x == GBVector([3,4,5,6,7], [3,4,5,6,7])'
x == GBVector([3,4,5,6,7], [3,4,5,6,7])'
@test A[3, 3] == 3
B = GBVector([1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7])
@test subassign!(A, B', 3, :; mask=B') == B'
Expand Down
26 changes: 26 additions & 0 deletions test/operations/operationutils.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using SuiteSparseGraphBLAS: inferunarytype, inferbinarytype,
Complement, Structural, _handlemask!, _handleaccum, _promotefill
@testset "operationutils.jl" begin
@testset "Unary inference" begin
@test inferunarytype(ComplexF64, imag) === Float64
@test inferunarytype(ComplexF64, SuiteSparseGraphBLAS.unaryop(real, ComplexF64)) ===
Float64
end
@testset "Binary inference" begin
@test inferbinarytype(ComplexF64, Float32, first) === ComplexF64
@test inferbinarytype(ComplexF64, Float32, SuiteSparseGraphBLAS.second) === Float32
f = (x, y) -> x + y
@test inferbinarytype(ComplexF64, Int32, f) === ComplexF64
@test inferbinarytype(Float64, Float64, (+, SuiteSparseGraphBLAS.pair)) ==
Float64
end
@testset "Masking" begin
v = GBVector([1,3,5], [true, false, true])
d = Descriptor()
@test (mask = _handlemask!(d, ~~~v); d.complement_mask && mask isa GBVector)
d = Descriptor()
@test (mask = _handlemask!(d, ~~Structural(v));
!d.complement_mask && d.structural_mask && mask isa GBVector)
end
end

26 changes: 23 additions & 3 deletions test/operations/reduce.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
using SuiteSparseGraphBLAS: Structural
@testset "reduce" begin
@testset "Reduction of Vec -> Scalar" begin
v = GBVector(Int128.(1:10))
@testset "Reduction of Vec" begin
v = GBVector(Int128.(1:10)) # test UDTs here.
@test reduce(+, v) == 55
@test reduce(*, v) == 3628800
@test reduce(+, v, dims=1) == 55
@test reduce(+, v, dims=1) == GBVector([1], Int128[55])
@test reduce(+, v, dims=2) == v
@test reduce(Monoid((x, y) -> x + y, zero), v) == 55
f = (x, y) -> x * y
SuiteSparseGraphBLAS.defaultmonoid(::typeof(f), ::Type{T}) where {T<:Any} = Monoid(f, one, zero)
@test reduce(f, v) == 3628800
end
@testset "Reduction of Matrices" begin
M = GBMatrix([[1,2] [3,4]]) # UDTs are pretty well tested above.
@test reduce(+, M) == 10
@test reduce(+, M, dims=1) == GBVector([3,7])
@test reduce(+, M, dims=2) == GBVector([4, 6])
@test reduce(+, M, dims=1; mask = GBVector([1], [true], nrows = 2)) ==
GBVector([1], [3], nrows = 2)
@test reduce(+, M, dims=2; mask = ~GBVector([1], [true], nrows = 2)) ==
GBVector([2], [6], nrows = 2)

@test reduce(+, M, dims=2; mask=Structural(GBVector([1], [false], nrows = 2))) ==
GBVector([1], [4], nrows = 2)
@test reduce(+, M, dims=2; mask=GBVector([1], [false], nrows = 2)) ==
GBVector{Int64}(2)
end
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ println("$(SuiteSparseGraphBLAS.get_lib())")
include_test("operations/transpose.jl")
include_test("operations/broadcasting.jl")
include_test("operations/concat.jl")
include_test("operations/operationutils.jl")
include_test("chainrules/chainrulesutils.jl")
include_test("chainrules/mulrules.jl")
include_test("chainrules/ewiserules.jl")
Expand Down