diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f76956d2..5fd2b69e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,8 +56,7 @@ jobs: Pkg.develop(PackageSpec(path = pwd())) Pkg.add(name = "Aqua", version = "0.8") using Aqua, SuiteSparseGraphBLAS - # ambiguities: ~190 pre-existing. - Aqua.test_all(SuiteSparseGraphBLAS; ambiguities = false)' + Aqua.test_all(SuiteSparseGraphBLAS)' docs: name: Documentation runs-on: ubuntu-latest diff --git a/src/abstractgbarray.jl b/src/abstractgbarray.jl index 2ffa7447..4033d697 100644 --- a/src/abstractgbarray.jl +++ b/src/abstractgbarray.jl @@ -287,6 +287,7 @@ Base.reshape( dims::Tuple{Union{Integer, Base.OneTo}, Vararg{Union{Integer, Base.OneTo}}}; bycol = true ) = reshape(A, dims...; bycol) +Base.reshape(A::AbstractGBMatrix, dims::Tuple{Integer, Vararg{Integer}}; bycol = true) = reshape(A, map(Int, dims)...; bycol) function Base.reshape(A::AbstractGBMatrix, ::Colon; bycol = true) out = similar(A, length(A)) @@ -526,7 +527,7 @@ for T ∈ valid_vec end func = Symbol(prefix, :_Matrix_assign_, suffix(T)) @eval begin - function _assign(C::AbstractGBMatrix{$T}, x, I, ni, J, nj, mask, accum, desc) + function _assign(C::AbstractGBMatrix{$T}, x::$T, I, ni, J, nj, mask, accum, desc) @wraperror LibGraphBLAS.$func(C, mask, accum, x, I, ni, J, nj, desc) return x end @@ -852,7 +853,7 @@ for T ∈ valid_vec # Getindex functions func = Symbol(prefix, :_Matrix_extractElement_, suffix(T)) @eval begin - function Base.getindex(v::GBVector{$T}, i::Integer) + function Base.getindex(v::AbstractGBVector{$T}, i::Integer) x = Ref{$T}() result = LibGraphBLAS.$func(x, v, LibGraphBLAS.GrB_Index(decrement!(i)), 0) if result == LibGraphBLAS.GrB_SUCCESS @@ -934,7 +935,7 @@ function Base.setindex!(v::AbstractGBVector{T}, x, i::Integer) where {T} return LibGraphBLAS.GrB_Matrix_setElement_UDT(v, Ref(x), LibGraphBLAS.GrB_Index(decrement!(i)), 0) end -function Base.getindex(v::GBVector{T}, i::Integer) where {T} +function Base.getindex(v::AbstractGBVector{T}, i::Integer) where {T} x = Ref{T}() result = LibGraphBLAS.GrB_Matrix_extractElement_UDT(x, v, LibGraphBLAS.GrB_Index(decrement!(i)), 0) if result == LibGraphBLAS.GrB_SUCCESS @@ -973,6 +974,8 @@ function SparseArrays.nonzeroinds(v::GBVector{T}) where {T} return increment!(I) end +build!(v::AbstractGBVector{T}, I::Vector{<:Integer}, X::AbstractVector; combine = +) where T = + invoke(build!, Tuple{AbstractGBVector{T}, AbstractVector{<:Integer}, AbstractVector}, v, I, X; combine) function build!(v::AbstractGBVector{T}, I::Vector{<:Integer}, x::T2) where {T, T2} _canbeoutput(v) || throw(ShallowException()) nnz(v) == 0 || throw(OutputNotEmptyError("Cannot build vector with existing elements")) @@ -1066,22 +1069,21 @@ function Base.getindex( return x end -function Base.getindex( - u::AbstractGBVector, I; - mask = nothing, accum = nothing, desc = nothing -) - return extract(u, I; mask, accum, desc) -end function Base.getindex(u::AbstractGBVector, ::Colon; mask = nothing, accum = nothing, desc = nothing) return extract(u, :) end -function Base.getindex( - u::AbstractGBVector, i::Union{Vector, UnitRange, StepRange}; - mask = nothing, accum = nothing, desc = nothing -) - return extract(u, i; mask, accum, desc) +# Typed rather than a catch-all, so these don't clash with SparseArrays' AbstractSparseVector methods. +for IT in (:AbstractVector, :AbstractUnitRange) + @eval function Base.getindex(u::AbstractGBVector, I::$IT; mask = nothing, accum = nothing, desc = nothing) + return extract(u, I; mask, accum, desc) + end +end +for IT in (:(AbstractVector{Bool}), :(AbstractUnitRange{Bool})) # logical indexing + @eval function Base.getindex(u::AbstractGBVector, I::$IT; mask = nothing, accum = nothing, desc = nothing) + return extract(u, findall(I); mask, accum, desc) + end end diff --git a/src/convert.jl b/src/convert.jl index 896edd54..923dce8e 100644 --- a/src/convert.jl +++ b/src/convert.jl @@ -36,3 +36,5 @@ end # TODO: Implement this? Base.convert(::Type{M}, ::AbstractGBArray; fill = nothing) where {M<:AbstractGBShallowArray} = throw(ArgumentError("Cannot convert into a shallow array.")) +Base.convert(::Type{M}, ::AbstractGBVector; fill = nothing) where {M<:AbstractGBShallowArray{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any, 1}} = + throw(ArgumentError("Cannot convert into a shallow array.")) diff --git a/src/iterator.jl b/src/iterator.jl index 6835fea3..bd014600 100644 --- a/src/iterator.jl +++ b/src/iterator.jl @@ -284,7 +284,10 @@ function Base.iterate(I::VectorIterator) end Base.iterate(I::VectorIterator, ::Nothing) = inext(I) -Base.getindex(A::AbstractArray, I::GxBIterator) = getindex(A, getrow(I), getcol(I)) -Base.getindex(A::AbstractArray, v::VectorIterator) = getindex(A, v.iterator) -Base.setindex!(A::AbstractArray, x, I::GxBIterator) = setindex!(A, x, getrow(I), getcol(I)) -Base.setindex!(A::AbstractArray, x, v::VectorIterator) = setindex!(A, x, v.iterator) \ No newline at end of file +# Index a matrix at an iterator's position. Restricted to GraphBLAS and dense matrices to avoid +# ambiguities with SparseArrays' getindex methods. +const _IterIndexable = Union{AbstractGBMatrix, DenseMatrix} +Base.getindex(A::_IterIndexable, I::GxBIterator) = getindex(A, getrow(I), getcol(I)) +Base.getindex(A::_IterIndexable, v::VectorIterator) = getindex(A, v.iterator) +Base.setindex!(A::_IterIndexable, x, I::GxBIterator) = setindex!(A, x, getrow(I), getcol(I)) +Base.setindex!(A::_IterIndexable, x, v::VectorIterator) = setindex!(A, x, v.iterator) \ No newline at end of file diff --git a/src/operations/concat.jl b/src/operations/concat.jl index 8bfd128d..e18cdf0e 100644 --- a/src/operations/concat.jl +++ b/src/operations/concat.jl @@ -37,6 +37,6 @@ vcat!(C, A::GBArrayOrTranspose...) = cat!(C, collect(A)) Base.vcat(A::GBArrayOrTranspose...) = cat(collect(A)) hcat!(C, A::GBArrayOrTranspose...) = cat!(C, permutedims(collect(A))) -Base.hcat(A::GBArrayOrTranspose...) = cat(permutedims(collect(A))) +Base.hcat(A::GBArrayOrTranspose, B::GBArrayOrTranspose...) = cat(permutedims(collect((A, B...)))) # TODO split. I don't necessarily see a great need for split though. We have indexing/slicing. \ No newline at end of file diff --git a/src/operations/ewise.jl b/src/operations/ewise.jl index a2a57e1f..09522072 100644 --- a/src/operations/ewise.jl +++ b/src/operations/ewise.jl @@ -422,12 +422,12 @@ eunion( ) = eunion(A, getfill(A), B, getfill(B), op; mask, accum, desc) eunion( - A::GBArrayOrTranspose, α, B::GBArrayOrTranspose, op::Function = +; + A::GBArrayOrTranspose, α::Number, B::GBArrayOrTranspose, op::Function = +; mask = nothing, accum = nothing, desc = nothing ) = eunion(A, α, B, getfill(B), op; mask, accum, desc) eunion( - A::GBArrayOrTranspose, B::GBArrayOrTranspose, β, op::Function = +; + A::GBArrayOrTranspose, B::GBArrayOrTranspose, β::Number, op::Function = +; mask = nothing, accum = nothing, desc = nothing ) = eunion(A, getfill(A), B, β, op; mask, accum, desc) @@ -442,12 +442,12 @@ eunion!( ) = eunion!(C, A, getfill(A), B, getfill(B), op; mask, accum, desc) eunion!( - C::GBVecOrMat, A::GBArrayOrTranspose, α, B::GBArrayOrTranspose, op::Function = +; + C::GBVecOrMat, A::GBArrayOrTranspose, α::Number, B::GBArrayOrTranspose, op::Function = +; mask = nothing, accum = nothing, desc = nothing ) = eunion!(C, A, α, B, getfill(B), op; mask, accum, desc) eunion!( - C::GBVecOrMat, A::GBArrayOrTranspose, B::GBArrayOrTranspose, β, op::Function = +; + C::GBVecOrMat, A::GBArrayOrTranspose, B::GBArrayOrTranspose, β::Number, op::Function = +; mask = nothing, accum = nothing, desc = nothing ) = eunion!(C, A, getfill(A), B, β, op; mask, accum, desc) diff --git a/src/operations/map.jl b/src/operations/map.jl index f33fc454..2f6e9166 100644 --- a/src/operations/map.jl +++ b/src/operations/map.jl @@ -69,6 +69,9 @@ function apply!( end return C end +# Neither of the 3-arg forms applies when both are arrays and the first can't be an output. +apply!(op, ::GBArrayOrTranspose, ::GBArrayOrTranspose; mask = nothing, accum = nothing, desc = nothing) = + throw(ArgumentError("apply! needs a non-transposed output array; for two arrays use `eadd` or `emul`.")) function apply!( op, A::GBArrayOrTranspose, x; mask = nothing, accum = nothing, desc = nothing @@ -142,11 +145,6 @@ function Base.map!(f, A::GBArrayOrTranspose; mask = nothing, accum = nothing, de apply!(f, A, A; mask, accum, desc) end -Base.:*(x, u::GBArrayOrTranspose; mask = nothing, accum = nothing, desc = nothing) = - apply(*, x, u; mask, accum, desc) -Base.:*(u::GBArrayOrTranspose, x; mask = nothing, accum = nothing, desc = nothing) = - apply(*, u, x; mask, accum, desc) - Base.:*(x::Number, u::GBArrayOrTranspose; mask = nothing, accum = nothing, desc = nothing) = apply(*, x, u; mask, accum, desc) Base.:*(u::GBArrayOrTranspose, x::Number; mask = nothing, accum = nothing, desc = nothing) = diff --git a/src/operations/mul.jl b/src/operations/mul.jl index cd8b97fa..91f04ce9 100644 --- a/src/operations/mul.jl +++ b/src/operations/mul.jl @@ -1,3 +1,6 @@ +# A semiring given as a (⊕, ⊗) tuple or a TypedSemiring. Typed so 3-arg `*` can't clash with A * B * C. +const SemiringSpec = Union{Tuple, TypedSemiring} + function LinearAlgebra.mul!( C::GBVecOrMat, A::GBArrayOrTranspose, @@ -86,7 +89,7 @@ The operator syntax `A * B` can be used when the default semiring is desired, an function Base.:*( A::GBArrayOrTranspose, B::GBArrayOrTranspose, - op = (+, *); + op::SemiringSpec = (+, *); mask = nothing, accum = nothing, desc = nothing @@ -108,7 +111,7 @@ end function Base.:*( A::VecMatOrTrans, B::GBArrayOrTranspose, - op = (+, *); + op::SemiringSpec = (+, *); mask = nothing, accum = nothing, desc = nothing @@ -119,7 +122,7 @@ end function Base.:*( A::GBArrayOrTranspose, B::VecMatOrTrans, - op = (+, *); + op::SemiringSpec = (+, *); mask = nothing, accum = nothing, desc = nothing @@ -142,11 +145,17 @@ function Base.:*(v::Transpose{<:Real, <:AbstractGBVector{T, F, O} where O} where u::AbstractGBVector{T, F, O} where {T, F, O}) *(v, u, (+, *)) end +# Dense matrix times a GraphBLAS vector also matches SparseArrays' triangular/adjoint * sparse vector methods. +Base.:*(A::DenseMatrix, v::AbstractGBVector) = *(A, v, (+, *)) +Base.:*(A::Transpose{<:Any, <:DenseMatrix}, v::AbstractGBVector) = *(A, v, (+, *)) +Base.:*(A::Transpose{<:Real, <:DenseMatrix}, v::AbstractGBVector) = *(A, v, (+, *)) +# u' * x for real dense x, also matched by LinearAlgebra's dot-product method. +Base.:*(v::Transpose{<:Real, <:AbstractGBVector}, u::DenseVector{<:Real}) = *(v, u, (+, *)) function Base.:*( A::Transpose{<:T, <:DenseVecOrMat}, B::GBArrayOrTranspose, - op = (+, *); + op::SemiringSpec = (+, *); mask = nothing, accum = nothing, desc = nothing @@ -157,7 +166,7 @@ end function Base.:*( A::GBArrayOrTranspose, B::Transpose{<:T, <:DenseVecOrMat}, - op = (+, *); + op::SemiringSpec = (+, *); mask = nothing, accum = nothing, desc = nothing @@ -226,12 +235,12 @@ function LinearAlgebra.mul!(C::GBVecOrMat, A::G, D::Diagonal, op = (+, *); mask SuiteSparseGraphBLAS.AbstractGBArray{T, F, O, 2} where {T, F, O}}} return mul!(C, A, G(D), op; mask, accum, desc) end -function Base.:*(D::Diagonal, A::G, op = (+, *); mask = nothing, accum = nothing, desc = nothing) where +function Base.:*(D::Diagonal, A::G, op::SemiringSpec = (+, *); mask = nothing, accum = nothing, desc = nothing) where {G <: Union{Transpose{T, <:SuiteSparseGraphBLAS.AbstractGBArray{T1, F, O}} where {T, T1, F, O}, SuiteSparseGraphBLAS.AbstractGBArray{T, F, O, 2} where {T, F, O}}} return *(G(D), A, op; mask, accum, desc) end -function Base.:*(A::G, D::Diagonal, op = (+, *); mask = nothing, accum = nothing, desc = nothing) where +function Base.:*(A::G, D::Diagonal, op::SemiringSpec = (+, *); mask = nothing, accum = nothing, desc = nothing) where {G <: Union{Transpose{T, <:SuiteSparseGraphBLAS.AbstractGBArray{T1, F, O}} where {T, T1, F, O}, SuiteSparseGraphBLAS.AbstractGBArray{T, F, O, 2} where {T, F, O}}} return *(A, G(D), op; mask, accum, desc) diff --git a/src/operations/operationutils.jl b/src/operations/operationutils.jl index 7a05dfe4..c926762d 100644 --- a/src/operations/operationutils.jl +++ b/src/operations/operationutils.jl @@ -122,6 +122,9 @@ _promotefill(x, ::AbstractGBArray{<:Any, Nothing}, op) = nothing _promotefill(::AbstractGBArray{<:Any, Nothing}, ::AbstractGBArray{<:Any, <:Any}, op) = nothing _promotefill(::AbstractGBArray{<:Any, <:Any}, ::AbstractGBArray{<:Any, Nothing}, op) = nothing +_promotefill(::AbstractGBArray{<:Any, Missing}, ::AbstractGBArray{<:Any, Nothing}, op) = missing +_promotefill(::AbstractGBArray{<:Any, Nothing}, ::AbstractGBArray{<:Any, Missing}, op) = missing + _promotefill(x, op) = x function _promotefill(x::AbstractGBArray{<:Any, T}, y::AbstractGBArray{<:Any, U}, op) where {T, U} diff --git a/src/operators/monoids.jl b/src/operators/monoids.jl index ef224843..41e980d7 100644 --- a/src/operators/monoids.jl +++ b/src/operators/monoids.jl @@ -40,6 +40,7 @@ function typedmonoid(m::Monoid{F, I, Term}, ::Type{T}) where {F, I, Term, T} end typedmonoid(op::TypedMonoid, x...) = op +typedmonoid(op::TypedMonoid, ::Type) = op # We default to no available monoid. defaultmonoid(f::F, ::Type{T}) where {F, T} = throw( diff --git a/src/operators/selectops.jl b/src/operators/selectops.jl index 121fec30..7dc140f1 100644 --- a/src/operators/selectops.jl +++ b/src/operators/selectops.jl @@ -119,16 +119,16 @@ function rowleq end function rowgt end const COLLEQ = TypedIndexUnaryOperator{typeof(colleq), Any, Any, Bool}( true, false, "GrB_COLLEQ", LibGraphBLAS.GrB_IndexUnaryOp(),colleq) -indexunaryop(::typeof(colleq), ::Any, ::Any) = COLLEQ +indexunaryop(::typeof(colleq), ::Type, ::Type) = COLLEQ const COLGT = TypedIndexUnaryOperator{typeof(colgt), Any, Any, Bool}( true, false, "GrB_OFFDIAG", LibGraphBLAS.GrB_IndexUnaryOp(),colgt) -indexunaryop(::typeof(colgt), ::Any, ::Any) = COLGT +indexunaryop(::typeof(colgt), ::Type, ::Type) = COLGT const ROWLEQ = TypedIndexUnaryOperator{typeof(rowleq), Any, Any, Bool}( true, false, "GrB_OFFDIAG", LibGraphBLAS.GrB_IndexUnaryOp(),rowleq) -indexunaryop(::typeof(rowleq), ::Any, ::Any) = ROWLEQ +indexunaryop(::typeof(rowleq), ::Type, ::Type) = ROWLEQ const ROWGT = TypedIndexUnaryOperator{typeof(rowgt), Any, Any, Bool}( true, false, "GrB_OFFDIAG", LibGraphBLAS.GrB_IndexUnaryOp(),rowgt) -indexunaryop(::typeof(rowgt), ::Any, ::Any) = ROWGT +indexunaryop(::typeof(rowgt), ::Type, ::Type) = ROWGT cardinal_vec = filter(x-> x ∉ [ComplexF64, ComplexF32], valid_vec) @@ -219,7 +219,7 @@ for F ∈ [ rowgt ] @eval isindexop(::typeof($F)) = true - @eval SuiteSparseGraphBLAS.inferbinarytype(::Any, ::Any, ::typeof($F)) = Bool + @eval SuiteSparseGraphBLAS.inferbinarytype(::Type, ::Type, ::typeof($F)) = Bool end end diff --git a/src/shallowtypes.jl b/src/shallowtypes.jl index 32b8541d..d5ffacba 100644 --- a/src/shallowtypes.jl +++ b/src/shallowtypes.jl @@ -100,8 +100,8 @@ reshape!(::AbstractGBShallowArray, dims...; kwargs...) = throw(ShallowException( reshape!(::AbstractGBShallowArray, n; kwargs...) = throw(ShallowException()) Base.deleteat!(::GBShallowMatrix, i, j) = throw(ShallowException()) Base.deleteat!(::GBShallowVector, i) = throw(ShallowException()) -Base.resize!(::GBShallowMatrix, nrows, ncols) = throw(ShallowException()) -Base.resize!(::GBShallowVector, nrows) = throw(ShallowException()) +Base.resize!(::GBShallowMatrix, nrows::Integer, ncols::Integer) = throw(ShallowException()) +Base.resize!(::GBShallowVector, nrows::Integer) = throw(ShallowException()) build!(::GBShallowMatrix{T}, I::AbstractVector, J::AbstractVector, x::T) where T = throw(ShallowException()) LinearAlgebra.Diagonal(v::GBShallowVector) = Diagonal(copy(v)) diff --git a/src/solvers/cholmod.jl b/src/solvers/cholmod.jl index 24781b90..47570a13 100644 --- a/src/solvers/cholmod.jl +++ b/src/solvers/cholmod.jl @@ -237,7 +237,7 @@ end (\)(L::FactorComponent, B::Adjoint{<:Any,<:AbstractGBMatrix}) = L \ copy(B) (\)(L::FactorComponent, B::Transpose{<:Any,<:AbstractGBMatrix}) = L \ copy(B) -\(adjL::Adjoint{<:Any,<:FactorComponent}, B::Union{VecOrMat,AbstractGBArray}) = (L = adjL.parent; adjoint(L)\B) +\(adjL::Adjoint{<:Any,<:FactorComponent}, B::AbstractGBArray) = (L = adjL.parent; adjoint(L)\B) # VecOrMat is SparseArrays' (\)(L::Factor, B::S) where {S<:AbstractGBMatrix} = S(spsolve(CHOLMOD_A, L, CHOLMOD.Sparse(B, 0))) (\)(L::Factor, B::Adjoint{<:Any,<:AbstractGBMatrix}) = L \ copy(B) (\)(L::Factor, B::Transpose{<:Any,<:AbstractGBMatrix}) = L \ copy(B) diff --git a/test/gbarray.jl b/test/gbarray.jl index 5bfe9f9b..253a8366 100644 --- a/test/gbarray.jl +++ b/test/gbarray.jl @@ -71,6 +71,19 @@ @test Vector(GBVector([1, 3], 2.0, 4)) == [2.0, 0, 2, 0] @test Vector(GBVector((3,), 1.0)) == ones(3) @test Matrix(GBMatrix((2, 2), 1.0)) == ones(2, 2) + @test SuiteSparseGraphBLAS.pack([1.0, 2.0, 3.0])[2] == 2.0 # scalar index on a shallow vector + w = GBVector([1.0, 0, 3]) + @test Vector(w[[true, false, true]]) == [1.0, 3.0] # logical indexing + sh = SuiteSparseGraphBLAS.pack([1.0, 2.0]) + @test_throws SuiteSparseGraphBLAS.ShallowException resize!(sh, 3) + @test_throws SuiteSparseGraphBLAS.ShallowException resize!(SuiteSparseGraphBLAS.pack([1.0 2; 3 4]), 3, 3) + @test_throws ArgumentError convert(typeof(sh), w) + b = SuiteSparseGraphBLAS.build!(GBVector{Float64}(3), [1, 3], [1.0, 2.0]) + @test Vector(b) == [1.0, 0, 2.0] + @test size(reshape(GBMatrix([1.0 2; 3 4]), (Int32(4), Int32(1)))) == (4, 1) + mon = SuiteSparseGraphBLAS.Monoids.typedmonoid(+, Float64) + @test SuiteSparseGraphBLAS.Monoids.typedmonoid(mon, Float64) === mon + @test SuiteSparseGraphBLAS.IndexUnaryOps.indexunaryop(SuiteSparseGraphBLAS.IndexUnaryOps.colleq, Float64, Float64) isa SuiteSparseGraphBLAS.TypedIndexUnaryOperator end end @@ -155,5 +168,8 @@ @test isempty(gather(SuiteSparseGraphBLAS.iteratecols(H, 5))) @test gather(SuiteSparseGraphBLAS.iteratecols(H, 2:900, SuiteSparseGraphBLAS.IndicesIterator())) == [((1, 2), 1.0), ((7, 2), 2.0), ((3, 900), 3.0)] + Hs = H[1:10, 1:3]; D = Matrix(Hs); vals = [] + for it in SuiteSparseGraphBLAS.iteratecols(Hs, 2, SuiteSparseGraphBLAS.IteratorIterator()); push!(vals, D[it]); end + @test vals == [1.0, 2.0] # index a dense matrix at the iterator's position end end diff --git a/test/operations/ewise.jl b/test/operations/ewise.jl index 18a33ecd..1eb035d4 100644 --- a/test/operations/ewise.jl +++ b/test/operations/ewise.jl @@ -8,4 +8,11 @@ #emul correctness @test emul(m, n, ^)[3, 2] == m[3,2] ^ n[3,2] @test eltype(m .== n) == Bool + + # eunion shortcut forms with a scalar fill for one side + E = GBMatrix([1.0 2; 3 4]); E2 = GBMatrix([1, 2], [1, 2], [10.0, 20.0], 2, 2) + @test Matrix(eunion(E, 0.0, E2, +)) == Matrix(eunion(E, getfill(E), E2, getfill(E2), +)) + @test Matrix(eunion(E, E2, 0.0, +)) == Matrix(E) + Matrix(E2) + @test Matrix(eunion!(similar(E), E, 0.0, E2, +)) == Matrix(E) + Matrix(E2) + @test Matrix(eunion!(similar(E), E, E2, 0.0, +)) == Matrix(E) + Matrix(E2) end diff --git a/test/operations/map.jl b/test/operations/map.jl index 6744b496..c04ba3f1 100644 --- a/test/operations/map.jl +++ b/test/operations/map.jl @@ -10,4 +10,5 @@ # Julia will map over the entire array, rather than just nnz. # so just test [1,1] @test map((x) -> 1.5, n)[nonzero...] == map((x) -> 1.5, m)[nonzero...] + @test_throws ArgumentError apply!(+, transpose(n), n) end diff --git a/test/operations/mul.jl b/test/operations/mul.jl index 3bef20d9..9feb20de 100644 --- a/test/operations/mul.jl +++ b/test/operations/mul.jl @@ -32,4 +32,14 @@ @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 + + # previously ambiguous products + R = GBMatrix([1.0 2; 3 4]); r = [3.0, 4.0] + @test (GBVector([1.0, 2.0])' * r)[1, 1] == 11.0 + @test R * sparse(r) ≈ [11.0, 25.0] + @test R * view([0.0, 3, 4], 2:3) ≈ [11.0, 25.0] + M = [1.0 2; 3 4]; g = GBVector([1.0, 1.0]) + @test Vector(M * g) == M * [1.0, 1.0] + @test Vector(transpose(M) * g) == transpose(M) * [1.0, 1.0] + @test Vector(transpose(ComplexF64.(M)) * GBVector(ComplexF64[1, 1])) == transpose(M) * [1.0, 1.0] end diff --git a/test/operations/operationutils.jl b/test/operations/operationutils.jl index 418100df..f19a6e76 100644 --- a/test/operations/operationutils.jl +++ b/test/operations/operationutils.jl @@ -22,5 +22,8 @@ end @test (mask = _handlemask!(d, ~~Structural(v)); !d.complement_mask && d.structural_mask && mask isa GBVector) end + @test SuiteSparseGraphBLAS.inferbinarytype(Float64, Float64, triu) == Bool + gm, gn = GBMatrix([1.0 2]; fill = missing), GBMatrix([1.0 2]; fill = nothing) + @test SuiteSparseGraphBLAS._promotefill(gm, gn, +) === missing + @test SuiteSparseGraphBLAS._promotefill(gn, gm, +) === missing end - \ No newline at end of file