From 3b6e9d3d635d58bf0411d71bc0ca88fc7c2a412b Mon Sep 17 00:00:00 2001 From: mtfishman <7855256+mtfishman@users.noreply.github.com> Date: Wed, 1 Oct 2025 00:51:06 +0000 Subject: [PATCH 1/3] Format .jl files (Runic) --- Project.toml | 2 +- docs/make.jl | 22 +- docs/make_index.jl | 16 +- docs/make_readme.jl | 16 +- examples/README.jl | 32 +- src/SparseArraysBase.jl | 30 +- src/abstractsparsearray.jl | 246 +++++------ src/abstractsparsearrayinterface.jl | 200 ++++----- src/indexing.jl | 434 ++++++++++---------- src/map.jl | 152 +++---- src/oneelementarray.jl | 278 ++++++------- src/sparsearraydok.jl | 104 ++--- src/sparsearrayinterface.jl | 26 +- src/wrappers.jl | 210 +++++----- test/runtests.jl | 80 ++-- test/test_aqua.jl | 2 +- test/test_basics.jl | 116 +++--- test/test_diagonal.jl | 40 +- test/test_exports.jl | 40 +- test/test_linalg.jl | 74 ++-- test/test_oneelementarray.jl | 198 ++++----- test/test_sparsearraydok.jl | 606 ++++++++++++++-------------- test/test_unstored.jl | 10 +- 23 files changed, 1468 insertions(+), 1466 deletions(-) diff --git a/Project.toml b/Project.toml index f9b1cd4..ef2cee9 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "SparseArraysBase" uuid = "0d5efcca-f356-4864-8770-e1ed8d78f208" authors = ["ITensor developers and contributors"] -version = "0.7.3" +version = "0.7.4" [deps] Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" diff --git a/docs/make.jl b/docs/make.jl index eaa08a3..2d780d5 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -2,23 +2,23 @@ using SparseArraysBase: SparseArraysBase using Documenter: Documenter, DocMeta, deploydocs, makedocs DocMeta.setdocmeta!( - SparseArraysBase, :DocTestSetup, :(using SparseArraysBase); recursive=true + SparseArraysBase, :DocTestSetup, :(using SparseArraysBase); recursive = true ) include("make_index.jl") makedocs(; - modules=[SparseArraysBase], - authors="ITensor developers and contributors", - sitename="SparseArraysBase.jl", - format=Documenter.HTML(; - canonical="https://itensor.github.io/SparseArraysBase.jl", - edit_link="main", - assets=["assets/favicon.ico", "assets/extras.css"], - ), - pages=["Home" => "index.md", "Reference" => "reference.md"], + modules = [SparseArraysBase], + authors = "ITensor developers and contributors", + sitename = "SparseArraysBase.jl", + format = Documenter.HTML(; + canonical = "https://itensor.github.io/SparseArraysBase.jl", + edit_link = "main", + assets = ["assets/favicon.ico", "assets/extras.css"], + ), + pages = ["Home" => "index.md", "Reference" => "reference.md"], ) deploydocs(; - repo="github.com/ITensor/SparseArraysBase.jl", devbranch="main", push_preview=true + repo = "github.com/ITensor/SparseArraysBase.jl", devbranch = "main", push_preview = true ) diff --git a/docs/make_index.jl b/docs/make_index.jl index 2e425e9..8039481 100644 --- a/docs/make_index.jl +++ b/docs/make_index.jl @@ -2,20 +2,20 @@ using Literate: Literate using SparseArraysBase: SparseArraysBase function ccq_logo(content) - include_ccq_logo = """ + include_ccq_logo = """ ```@raw html Flatiron Center for Computational Quantum Physics logo. Flatiron Center for Computational Quantum Physics logo. ``` """ - content = replace(content, "{CCQ_LOGO}" => include_ccq_logo) - return content + content = replace(content, "{CCQ_LOGO}" => include_ccq_logo) + return content end Literate.markdown( - joinpath(pkgdir(SparseArraysBase), "examples", "README.jl"), - joinpath(pkgdir(SparseArraysBase), "docs", "src"); - flavor=Literate.DocumenterFlavor(), - name="index", - postprocess=ccq_logo, + joinpath(pkgdir(SparseArraysBase), "examples", "README.jl"), + joinpath(pkgdir(SparseArraysBase), "docs", "src"); + flavor = Literate.DocumenterFlavor(), + name = "index", + postprocess = ccq_logo, ) diff --git a/docs/make_readme.jl b/docs/make_readme.jl index a7472b2..7537f73 100644 --- a/docs/make_readme.jl +++ b/docs/make_readme.jl @@ -2,20 +2,20 @@ using Literate: Literate using SparseArraysBase: SparseArraysBase function ccq_logo(content) - include_ccq_logo = """ + include_ccq_logo = """ Flatiron Center for Computational Quantum Physics logo. """ - content = replace(content, "{CCQ_LOGO}" => include_ccq_logo) - return content + content = replace(content, "{CCQ_LOGO}" => include_ccq_logo) + return content end Literate.markdown( - joinpath(pkgdir(SparseArraysBase), "examples", "README.jl"), - joinpath(pkgdir(SparseArraysBase)); - flavor=Literate.CommonMarkFlavor(), - name="README", - postprocess=ccq_logo, + joinpath(pkgdir(SparseArraysBase), "examples", "README.jl"), + joinpath(pkgdir(SparseArraysBase)); + flavor = Literate.CommonMarkFlavor(), + name = "README", + postprocess = ccq_logo, ) diff --git a/examples/README.jl b/examples/README.jl index bea4830..fbb85fe 100644 --- a/examples/README.jl +++ b/examples/README.jl @@ -1,5 +1,5 @@ # # SparseArraysBase.jl -# +# # [![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://itensor.github.io/SparseArraysBase.jl/stable/) # [![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://itensor.github.io/SparseArraysBase.jl/dev/) # [![Build Status](https://github.com/ITensor/SparseArraysBase.jl/actions/workflows/Tests.yml/badge.svg?branch=main)](https://github.com/ITensor/SparseArraysBase.jl/actions/workflows/Tests.yml?query=branch%3Amain) @@ -44,19 +44,19 @@ julia> Pkg.add("SparseArraysBase") # ## Examples using SparseArraysBase: - SparseArrayDOK, - SparseMatrixDOK, - SparseVectorDOK, - eachstoredindex, - getstoredindex, - getunstoredindex, - isstored, - setstoredindex!, - setunstoredindex!, - storedlength, - storedpairs, - storedvalues, - zero! + SparseArrayDOK, + SparseMatrixDOK, + SparseVectorDOK, + eachstoredindex, + getstoredindex, + getunstoredindex, + isstored, + setstoredindex!, + setunstoredindex!, + storedlength, + storedpairs, + storedvalues, + zero! using Test: @test, @test_throws a = SparseArrayDOK{Float64}(undef, 2, 2) @@ -127,14 +127,14 @@ b = a[1:2, 2] a = SparseArrayDOK{Float64}(undef, 2, 2) a .= 2 for I in eachindex(a) - @test a[I] == 2 + @test a[I] == 2 end @test storedlength(a) == length(a) a = SparseArrayDOK{Float64}(undef, 2, 2) fill!(a, 2) for I in eachindex(a) - @test a[I] == 2 + @test a[I] == 2 end @test storedlength(a) == length(a) diff --git a/src/SparseArraysBase.jl b/src/SparseArraysBase.jl index c51b99b..5a09d24 100644 --- a/src/SparseArraysBase.jl +++ b/src/SparseArraysBase.jl @@ -1,21 +1,21 @@ module SparseArraysBase export SparseArrayDOK, - SparseMatrixDOK, - SparseVectorDOK, - OneElementArray, - OneElementMatrix, - OneElementVector, - eachstoredindex, - isstored, - oneelement, - sparse, - sparserand, - sparserand!, - sparsezeros, - storedlength, - storedpairs, - storedvalues + SparseMatrixDOK, + SparseVectorDOK, + OneElementArray, + OneElementMatrix, + OneElementVector, + eachstoredindex, + isstored, + oneelement, + sparse, + sparserand, + sparserand!, + sparsezeros, + storedlength, + storedpairs, + storedvalues include("abstractsparsearrayinterface.jl") include("sparsearrayinterface.jl") diff --git a/src/abstractsparsearray.jl b/src/abstractsparsearray.jl index 1c0af04..b6d3ae5 100644 --- a/src/abstractsparsearray.jl +++ b/src/abstractsparsearray.jl @@ -1,6 +1,6 @@ using Dictionaries: AbstractDictionary -abstract type AbstractSparseArray{T,N} <: AbstractArray{T,N} end +abstract type AbstractSparseArray{T, N} <: AbstractArray{T, N} end using DerivableInterfaces: @array_aliases # Define AbstractSparseVector, AnyAbstractSparseArray, etc. @@ -8,43 +8,43 @@ using DerivableInterfaces: @array_aliases using DerivableInterfaces: DerivableInterfaces function DerivableInterfaces.interface(::Type{<:AbstractSparseArray}) - return SparseArrayInterface() + return SparseArrayInterface() end function Base.copy(a::AnyAbstractSparseArray) - return copyto!(similar(a), a) + return copyto!(similar(a), a) end function Base.similar(a::AnyAbstractSparseArray, unstored::Unstored) - return SparseArrayDOK(undef, unstored) + return SparseArrayDOK(undef, unstored) end function Base.similar(a::AnyAbstractSparseArray) - return similar(a, Unstored(unstored(a))) + return similar(a, Unstored(unstored(a))) end function Base.similar(a::AnyAbstractSparseArray, T::Type) - return similar(a, Unstored(unstoredsimilar(unstored(a), T))) + return similar(a, Unstored(unstoredsimilar(unstored(a), T))) end function Base.similar(a::AnyAbstractSparseArray, ax::Tuple) - return similar(a, Unstored(unstoredsimilar(unstored(a), ax))) + return similar(a, Unstored(unstoredsimilar(unstored(a), ax))) end function similar_sparsearray(a::AbstractArray, T::Type, ax::Tuple) - return similar(a, Unstored(unstoredsimilar(unstored(a), T, ax))) + return similar(a, Unstored(unstoredsimilar(unstored(a), T, ax))) end function Base.similar(a::AnyAbstractSparseArray, T::Type, ax::Tuple{Vararg{Int}}) - return similar_sparsearray(a, T, ax) + return similar_sparsearray(a, T, ax) end function Base.similar( - a::AnyAbstractSparseArray, T::Type, ax::Tuple{Integer,Vararg{Integer}} -) - return similar_sparsearray(a, T, ax) + a::AnyAbstractSparseArray, T::Type, ax::Tuple{Integer, Vararg{Integer}} + ) + return similar_sparsearray(a, T, ax) end function Base.similar( - a::AnyAbstractSparseArray, - T::Type, - ax::Tuple{Union{Integer,Base.OneTo},Vararg{Union{Integer,Base.OneTo}}}, -) - return similar_sparsearray(a, T, ax) + a::AnyAbstractSparseArray, + T::Type, + ax::Tuple{Union{Integer, Base.OneTo}, Vararg{Union{Integer, Base.OneTo}}}, + ) + return similar_sparsearray(a, T, ax) end using DerivableInterfaces: @derive @@ -56,29 +56,29 @@ using DerivableInterfaces: @derive using ArrayLayouts: ArrayLayouts using LinearAlgebra: LinearAlgebra -@derive (T=AnyAbstractSparseArray,) begin - Base.getindex(::T, ::Any...) - Base.getindex(::T, ::Int...) - Base.setindex!(::T, ::Any, ::Any...) - Base.setindex!(::T, ::Any, ::Int...) - Base.copy!(::AbstractArray, ::T) - Base.copyto!(::AbstractArray, ::T) - Base.map(::Any, ::T...) - Base.map!(::Any, ::AbstractArray, ::T...) - Base.mapreduce(::Any, ::Any, ::T...; kwargs...) - Base.reduce(::Any, ::T...; kwargs...) - Base.all(::Function, ::T) - Base.all(::T) - Base.iszero(::T) - Base.real(::T) - Base.fill!(::T, ::Any) - DerivableInterfaces.zero!(::T) - Base.zero(::T) - Base.permutedims!(::Any, ::T, ::Any) - Broadcast.BroadcastStyle(::Type{<:T}) - Base.copyto!(::T, ::Broadcast.Broadcasted{Broadcast.DefaultArrayStyle{0}}) - ArrayLayouts.MemoryLayout(::Type{<:T}) - LinearAlgebra.mul!(::AbstractMatrix, ::T, ::T, ::Number, ::Number) +@derive (T = AnyAbstractSparseArray,) begin + Base.getindex(::T, ::Any...) + Base.getindex(::T, ::Int...) + Base.setindex!(::T, ::Any, ::Any...) + Base.setindex!(::T, ::Any, ::Int...) + Base.copy!(::AbstractArray, ::T) + Base.copyto!(::AbstractArray, ::T) + Base.map(::Any, ::T...) + Base.map!(::Any, ::AbstractArray, ::T...) + Base.mapreduce(::Any, ::Any, ::T...; kwargs...) + Base.reduce(::Any, ::T...; kwargs...) + Base.all(::Function, ::T) + Base.all(::T) + Base.iszero(::T) + Base.real(::T) + Base.fill!(::T, ::Any) + DerivableInterfaces.zero!(::T) + Base.zero(::T) + Base.permutedims!(::Any, ::T, ::Any) + Broadcast.BroadcastStyle(::Type{<:T}) + Base.copyto!(::T, ::Broadcast.Broadcasted{Broadcast.DefaultArrayStyle{0}}) + ArrayLayouts.MemoryLayout(::Type{<:T}) + LinearAlgebra.mul!(::AbstractMatrix, ::T, ::T, ::Number, ::Number) end using DerivableInterfaces.Concatenate: concatenate @@ -86,7 +86,7 @@ using DerivableInterfaces.Concatenate: concatenate # is friendlier for invalidations/compile times, see # https://github.com/ITensor/SparseArraysBase.jl/issues/25. function Base._cat(dims, a::AnyAbstractSparseArray...) - return concatenate(dims, a...) + return concatenate(dims, a...) end # TODO: Use `map(WeakPreserving(f), a)` instead. @@ -94,34 +94,34 @@ end # the element type becomes abstract and therefore the zero/unstored # values are not well defined. function map_stored(f, a::AnyAbstractSparseArray) - iszero(storedlength(a)) && return a - kvs = storedpairs(a) - # `collect` to convert to `Vector`, since otherwise - # if it stays as `Dictionary` we might hit issues like - # https://github.com/andyferris/Dictionaries.jl/issues/163. - ks = collect(first.(kvs)) - vs = collect(last.(kvs)) - vs′ = map(f, vs) - a′ = zero!(similar(a, eltype(vs′))) - for (k, v′) in zip(ks, vs′) - a′[k] = v′ - end - return a′ + iszero(storedlength(a)) && return a + kvs = storedpairs(a) + # `collect` to convert to `Vector`, since otherwise + # if it stays as `Dictionary` we might hit issues like + # https://github.com/andyferris/Dictionaries.jl/issues/163. + ks = collect(first.(kvs)) + vs = collect(last.(kvs)) + vs′ = map(f, vs) + a′ = zero!(similar(a, eltype(vs′))) + for (k, v′) in zip(ks, vs′) + a′[k] = v′ + end + return a′ end using Adapt: adapt function Base.print_array(io::IO, a::AnyAbstractSparseArray) - # TODO: Use `map(WeakPreserving(adapt(Array)), a)` instead. - # Currently that has trouble with type unstable maps, since - # the element type becomes abstract and therefore the zero/unstored - # values are not well defined. - a′ = map_stored(adapt(Array), a) - return @invoke Base.print_array(io::typeof(io), a′::AbstractArray{<:Any,ndims(a)}) + # TODO: Use `map(WeakPreserving(adapt(Array)), a)` instead. + # Currently that has trouble with type unstable maps, since + # the element type becomes abstract and therefore the zero/unstored + # values are not well defined. + a′ = map_stored(adapt(Array), a) + return @invoke Base.print_array(io::typeof(io), a′::AbstractArray{<:Any, ndims(a)}) end function Base.replace_in_print_matrix( - a::AnyAbstractSparseVecOrMat, i::Integer, j::Integer, s::AbstractString -) - return isstored(a, i, j) ? s : Base.replace_with_centered_mark(s) + a::AnyAbstractSparseVecOrMat, i::Integer, j::Integer, s::AbstractString + ) + return isstored(a, i, j) ? s : Base.replace_with_centered_mark(s) end # Special-purpose constructors @@ -138,30 +138,30 @@ from the input indices. This constructor does not take ownership of the supplied storage, and will result in an independent container. """ -sparse(::Union{AbstractDict,AbstractDictionary}, dims...) +sparse(::Union{AbstractDict, AbstractDictionary}, dims...) -const AbstractDictOrDictionary = Union{AbstractDict,AbstractDictionary} +const AbstractDictOrDictionary = Union{AbstractDict, AbstractDictionary} # checked constructor from data: use `setindex!` to validate/convert input function sparse(storage::AbstractDictOrDictionary, unstored::AbstractArray) - A = SparseArrayDOK(undef, Unstored(unstored)) - for (i, v) in pairs(storage) - A[i] = v - end - return A + A = SparseArrayDOK(undef, Unstored(unstored)) + for (i, v) in pairs(storage) + A[i] = v + end + return A end function sparse(storage::AbstractDictOrDictionary, ax::Tuple) - return sparse(storage, Zeros{valtype(storage)}(ax)) + return sparse(storage, Zeros{valtype(storage)}(ax)) end function sparse(storage::AbstractDictOrDictionary, dims::Int...) - return sparse(storage, dims) + return sparse(storage, dims) end # Determine the size automatically. function sparse(storage::AbstractDictOrDictionary) - dims = ntuple(Returns(0), length(keytype(storage))) - for I in keys(storage) - dims = map(max, dims, Tuple(I)) - end - return sparse(storage, dims) + dims = ntuple(Returns(0), length(keytype(storage))) + for I in keys(storage) + dims = map(max, dims, Tuple(I)) + end + return sparse(storage, dims) end using Random: Random, AbstractRNG, default_rng @@ -173,14 +173,14 @@ Create an empty size `dims` sparse array. The optional `T` argument specifies the element type, which defaults to `Float64`. """ sparsezeros -function sparsezeros(::Type{T}, unstored::AbstractArray{<:Any,N}) where {T,N} - return SparseArrayDOK{T,N}(undef, Unstored(unstored)) +function sparsezeros(::Type{T}, unstored::AbstractArray{<:Any, N}) where {T, N} + return SparseArrayDOK{T, N}(undef, Unstored(unstored)) end -function sparsezeros(unstored::AbstractArray{T,N}) where {T,N} - return SparseArrayDOK{T,N}(undef, Unstored(unstored)) +function sparsezeros(unstored::AbstractArray{T, N}) where {T, N} + return SparseArrayDOK{T, N}(undef, Unstored(unstored)) end function sparsezeros(::Type{T}, dims::Dims) where {T} - return sparsezeros(T, Zeros{T}(dims)) + return sparsezeros(T, Zeros{T}(dims)) end sparsezeros(::Type{T}, dims::Int...) where {T} = sparsezeros(T, dims) sparsezeros(dims::Dims) = sparsezeros(Float64, dims) @@ -200,26 +200,26 @@ See also [`sparserand!`](@ref). """ sparserand function sparserand(::Type{T}, dims::Dims; kwargs...) where {T} - return sparserand(default_rng(), T, dims; kwargs...) + return sparserand(default_rng(), T, dims; kwargs...) end function sparserand(::Type{T}, dims::Int...; kwargs...) where {T} - return sparserand(T, dims; kwargs...) + return sparserand(T, dims; kwargs...) end sparserand(dims::Dims; kwargs...) = sparserand(default_rng(), Float64, dims; kwargs...) sparserand(dims::Int...; kwargs...) = sparserand(dims; kwargs...) function sparserand(rng::AbstractRNG, dims::Dims; kwargs...) - return sparserand(rng, Float64, dims; kwargs...) + return sparserand(rng, Float64, dims; kwargs...) end function sparserand(rng::AbstractRNG, dims::Int...; kwargs...) - return sparserand(rng, dims; kwargs...) + return sparserand(rng, dims; kwargs...) end function sparserand(rng::AbstractRNG, ::Type{T}, dims::Dims; kwargs...) where {T} - A = SparseArrayDOK{T}(undef, dims) - sparserand!(rng, A; kwargs...) - return A + A = SparseArrayDOK{T}(undef, dims) + sparserand!(rng, A; kwargs...) + return A end function sparserand(rng::AbstractRNG, ::Type{T}, dims::Int...; kwargs...) where {T} - return sparserand(rng, T, dims; kwargs...) + return sparserand(rng, T, dims; kwargs...) end @doc """ @@ -235,14 +235,14 @@ See also [`sparserand`](@ref). sparserand!(A::AbstractArray; kwargs...) = sparserand!(default_rng(), A; kwargs...) function sparserand!( - rng::AbstractRNG, A::AbstractArray; density::Real=0.5, randfun::Function=Random.rand -) - ArrayLayouts.zero!(A) - rand_inds = Random.randsubseq(rng, eachindex(A), density) - rand_entries = randfun(rng, eltype(A), length(rand_inds)) - @inbounds for (I, v) in zip(rand_inds, rand_entries) - A[I] = v - end + rng::AbstractRNG, A::AbstractArray; density::Real = 0.5, randfun::Function = Random.rand + ) + ArrayLayouts.zero!(A) + rand_inds = Random.randsubseq(rng, eachindex(A), density) + rand_entries = randfun(rng, eltype(A), length(rand_inds)) + return @inbounds for (I, v) in zip(rand_inds, rand_entries) + A[I] = v + end end # Catch some cases that aren't getting caught by the current @@ -251,36 +251,36 @@ end # is rewritten. using ArrayLayouts: ArrayLayouts, MemoryLayout using LinearAlgebra: LinearAlgebra, Adjoint -function ArrayLayouts.MemoryLayout(::Type{Transpose{T,P}}) where {T,P<:AbstractSparseMatrix} - return MemoryLayout(P) +function ArrayLayouts.MemoryLayout(::Type{Transpose{T, P}}) where {T, P <: AbstractSparseMatrix} + return MemoryLayout(P) end -function ArrayLayouts.MemoryLayout(::Type{Adjoint{T,P}}) where {T,P<:AbstractSparseMatrix} - return MemoryLayout(P) +function ArrayLayouts.MemoryLayout(::Type{Adjoint{T, P}}) where {T, P <: AbstractSparseMatrix} + return MemoryLayout(P) end function LinearAlgebra.mul!( - dest::AbstractMatrix, - A::Adjoint{<:Any,<:AbstractSparseMatrix}, - B::AbstractSparseMatrix, - α::Number, - β::Number, -) - return ArrayLayouts.mul!(dest, A, B, α, β) + dest::AbstractMatrix, + A::Adjoint{<:Any, <:AbstractSparseMatrix}, + B::AbstractSparseMatrix, + α::Number, + β::Number, + ) + return ArrayLayouts.mul!(dest, A, B, α, β) end function LinearAlgebra.mul!( - dest::AbstractMatrix, - A::AbstractSparseMatrix, - B::Adjoint{<:Any,<:AbstractSparseMatrix}, - α::Number, - β::Number, -) - return ArrayLayouts.mul!(dest, A, B, α, β) + dest::AbstractMatrix, + A::AbstractSparseMatrix, + B::Adjoint{<:Any, <:AbstractSparseMatrix}, + α::Number, + β::Number, + ) + return ArrayLayouts.mul!(dest, A, B, α, β) end function LinearAlgebra.mul!( - dest::AbstractMatrix, - A::Adjoint{<:Any,<:AbstractSparseMatrix}, - B::Adjoint{<:Any,<:AbstractSparseMatrix}, - α::Number, - β::Number, -) - return ArrayLayouts.mul!(dest, A, B, α, β) + dest::AbstractMatrix, + A::Adjoint{<:Any, <:AbstractSparseMatrix}, + B::Adjoint{<:Any, <:AbstractSparseMatrix}, + α::Number, + β::Number, + ) + return ArrayLayouts.mul!(dest, A, B, α, β) end diff --git a/src/abstractsparsearrayinterface.jl b/src/abstractsparsearrayinterface.jl index 6e6c588..3622bff 100644 --- a/src/abstractsparsearrayinterface.jl +++ b/src/abstractsparsearrayinterface.jl @@ -1,6 +1,6 @@ using Base: @_propagate_inbounds_meta using DerivableInterfaces: - DerivableInterfaces, @derive, @interface, AbstractArrayInterface, zero! + DerivableInterfaces, @derive, @interface, AbstractArrayInterface, zero! using FillArrays: Zeros function unstored end @@ -16,8 +16,8 @@ function storedvalues end # Indicates that the array should be interpreted # as the unstored values of a sparse array. -struct Unstored{T,N,P<:AbstractArray{T,N}} <: AbstractArray{T,N} - parent::P +struct Unstored{T, N, P <: AbstractArray{T, N}} <: AbstractArray{T, N} + parent::P end Base.parent(a::Unstored) = a.parent Base.size(a::Unstored) = size(parent(a)) @@ -26,13 +26,13 @@ Base.axes(a::Unstored) = axes(parent(a)) unstored(a::AbstractArray) = Zeros{eltype(a)}(axes(a)) function unstoredsimilar(a::AbstractArray, T::Type, ax::Tuple) - return Zeros{T}(ax) + return Zeros{T}(ax) end function unstoredsimilar(a::AbstractArray, ax::Tuple) - return unstoredsimilar(a, eltype(a), ax) + return unstoredsimilar(a, eltype(a), ax) end function unstoredsimilar(a::AbstractArray, T::Type) - return AbstractArray{T}(a) + return AbstractArray{T}(a) end unstoredsimilar(a::AbstractArray) = a @@ -44,10 +44,10 @@ unstoredsimilar(a::AbstractArray) = a # maybe use `TypeParameterAccessors.unwrap_array_type`. # TODO: Turn into an `@interface` function. function densearray(a::AbstractArray) - # TODO: `set_ndims(unwrap_array_type(a), ndims(a))(a)` - # Maybe define `densetype(a) = set_ndims(unwrap_array_type(a), ndims(a))`. - # Or could use `unspecify_parameters(unwrap_array_type(a))(a)`. - return Array(a) + # TODO: `set_ndims(unwrap_array_type(a), ndims(a))(a)` + # Maybe define `densetype(a) = set_ndims(unwrap_array_type(a), ndims(a))`. + # Or could use `unspecify_parameters(unwrap_array_type(a))(a)`. + return Array(a) end # Minimal interface for `SparseArrayInterface`. @@ -60,24 +60,24 @@ end abstract type AbstractSparseArrayInterface{N} <: AbstractArrayInterface{N} end function DerivableInterfaces.combine_interface_rule( - interface1::AbstractSparseArrayInterface, interface2::AbstractSparseArrayInterface -) - return error("Rule not defined.") + interface1::AbstractSparseArrayInterface, interface2::AbstractSparseArrayInterface + ) + return error("Rule not defined.") end function DerivableInterfaces.combine_interface_rule( - interface1::Interface, interface2::Interface -) where {Interface<:AbstractSparseArrayInterface} - return interface1 + interface1::Interface, interface2::Interface + ) where {Interface <: AbstractSparseArrayInterface} + return interface1 end function DerivableInterfaces.combine_interface_rule( - interface1::AbstractSparseArrayInterface, interface2::AbstractArrayInterface -) - return interface1 + interface1::AbstractSparseArrayInterface, interface2::AbstractArrayInterface + ) + return interface1 end function DerivableInterfaces.combine_interface_rule( - interface1::AbstractArrayInterface, interface2::AbstractSparseArrayInterface -) - return interface2 + interface1::AbstractArrayInterface, interface2::AbstractSparseArrayInterface + ) + return interface2 end to_vec(x) = vec(collect(x)) @@ -93,15 +93,15 @@ to_vec(x::AbstractArray) = vec(x) # Most sparse arrays should overload `storedvalues` directly # and avoid this wrapper since it adds extra indirection to # access stored values. -struct StoredValues{T,A<:AbstractArray{T},I} <: AbstractVector{T} - array::A - storedindices::I +struct StoredValues{T, A <: AbstractArray{T}, I} <: AbstractVector{T} + array::A + storedindices::I end StoredValues(a::AbstractArray) = StoredValues(a, to_vec(eachstoredindex(a))) Base.size(a::StoredValues) = size(a.storedindices) @inline Base.getindex(a::StoredValues, I::Int) = getindex(a.array, a.storedindices[I]) @inline function Base.setindex!(a::StoredValues, value, I::Int) - return setindex!(a.array, value, a.storedindices[I]) + return setindex!(a.array, value, a.storedindices[I]) end using DerivableInterfaces: DerivableInterfaces, zero! @@ -111,54 +111,54 @@ using DerivableInterfaces: DerivableInterfaces, zero! # the sparse array storage. # We use a single function definition to minimize method ambiguities. @interface interface::AbstractSparseArrayInterface function DerivableInterfaces.zero!( - a::AbstractArray -) - # More generally, this codepath could be taking if `zero(eltype(a))` - # is defined and the elements are immutable. - f = eltype(a) <: Number ? Returns(zero(eltype(a))) : zero! - @inbounds for I in eachstoredindex(a) - a[I] = f(a[I]) - end - return a + a::AbstractArray + ) + # More generally, this codepath could be taking if `zero(eltype(a))` + # is defined and the elements are immutable. + f = eltype(a) <: Number ? Returns(zero(eltype(a))) : zero! + @inbounds for I in eachstoredindex(a) + a[I] = f(a[I]) + end + return a end # `f::typeof(norm)`, `op::typeof(max)` used by `norm`. function reduce_init(f, op, as...) - # TODO: Generalize this. - @assert isone(length(as)) - a = only(as) - ## TODO: Make this more efficient for block sparse - ## arrays, in that case it allocates a block. Maybe - ## it can use `FillArrays.Zeros`. - return f(getunstoredindex(a, first(eachindex(a)))) + # TODO: Generalize this. + @assert isone(length(as)) + a = only(as) + ## TODO: Make this more efficient for block sparse + ## arrays, in that case it allocates a block. Maybe + ## it can use `FillArrays.Zeros`. + return f(getunstoredindex(a, first(eachindex(a)))) end @interface ::AbstractSparseArrayInterface function Base.mapreduce( - f, op, as::AbstractArray...; init=reduce_init(f, op, as...), kwargs... -) - # TODO: Generalize this. - @assert isone(length(as)) - a = only(as) - output = mapreduce(f, op, storedvalues(a); init, kwargs...) - ## TODO: Bring this check back, or make the function more general. - ## f_notstored = apply_notstored(f, a) - ## @assert isequal(op(output, eltype(output)(f_notstored)), output) - return output + f, op, as::AbstractArray...; init = reduce_init(f, op, as...), kwargs... + ) + # TODO: Generalize this. + @assert isone(length(as)) + a = only(as) + output = mapreduce(f, op, storedvalues(a); init, kwargs...) + ## TODO: Bring this check back, or make the function more general. + ## f_notstored = apply_notstored(f, a) + ## @assert isequal(op(output, eltype(output)(f_notstored)), output) + return output end abstract type AbstractSparseArrayStyle{N} <: Broadcast.AbstractArrayStyle{N} end -@derive (T=AbstractSparseArrayStyle,) begin - Base.similar(::Broadcast.Broadcasted{<:T}, ::Type, ::Tuple) - Base.copyto!(::AbstractArray, ::Broadcast.Broadcasted{<:T}) +@derive (T = AbstractSparseArrayStyle,) begin + Base.similar(::Broadcast.Broadcasted{<:T}, ::Type, ::Tuple) + Base.copyto!(::AbstractArray, ::Broadcast.Broadcasted{<:T}) end struct SparseArrayStyle{N} <: AbstractSparseArrayStyle{N} end -SparseArrayStyle{M}(::Val{N}) where {M,N} = SparseArrayStyle{N}() +SparseArrayStyle{M}(::Val{N}) where {M, N} = SparseArrayStyle{N}() @interface ::AbstractSparseArrayInterface function Broadcast.BroadcastStyle(type::Type) - return SparseArrayStyle{ndims(type)}() + return SparseArrayStyle{ndims(type)}() end using ArrayLayouts: ArrayLayouts, MatMulMatAdd @@ -166,71 +166,71 @@ using ArrayLayouts: ArrayLayouts, MatMulMatAdd abstract type AbstractSparseLayout <: ArrayLayouts.MemoryLayout end function ArrayLayouts.sub_materialize(::AbstractSparseLayout, a::AbstractArray, axes::Tuple) - a_dest = similar(a) - a_dest .= a - return a_dest + a_dest = similar(a) + a_dest .= a + return a_dest end function mul_indices(I1::CartesianIndex{2}, I2::CartesianIndex{2}) - if I1[2] ≠ I2[1] - return nothing - end - return CartesianIndex(I1[1], I2[2]) + if I1[2] ≠ I2[1] + return nothing + end + return CartesianIndex(I1[1], I2[2]) end using LinearAlgebra: mul! function default_mul!!( - a_dest::AbstractMatrix, - a1::AbstractMatrix, - a2::AbstractMatrix, - α::Number=true, - β::Number=false, -) - mul!(a_dest, a1, a2, α, β) - return a_dest + a_dest::AbstractMatrix, + a1::AbstractMatrix, + a2::AbstractMatrix, + α::Number = true, + β::Number = false, + ) + mul!(a_dest, a1, a2, α, β) + return a_dest end function default_mul!!( - a_dest::Number, a1::Number, a2::Number, α::Number=true, β::Number=false -) - return a1 * a2 * α + a_dest * β + a_dest::Number, a1::Number, a2::Number, α::Number = true, β::Number = false + ) + return a1 * a2 * α + a_dest * β end # a1 * a2 * α + a_dest * β function sparse_mul!( - a_dest::AbstractArray, - a1::AbstractArray, - a2::AbstractArray, - α::Number=true, - β::Number=false; - (mul!!)=(default_mul!!), -) - a_dest .*= β - β′ = one(Bool) - for I1 in eachstoredindex(a1) - for I2 in eachstoredindex(a2) - I_dest = mul_indices(I1, I2) - if !isnothing(I_dest) - if isstored(a_dest, I_dest) - a_dest[I_dest] = mul!!(a_dest[I_dest], a1[I1], a2[I2], α, β′) - else - a_dest[I_dest] = a1[I1] * a2[I2] * α + a_dest::AbstractArray, + a1::AbstractArray, + a2::AbstractArray, + α::Number = true, + β::Number = false; + (mul!!) = (default_mul!!), + ) + a_dest .*= β + β′ = one(Bool) + for I1 in eachstoredindex(a1) + for I2 in eachstoredindex(a2) + I_dest = mul_indices(I1, I2) + if !isnothing(I_dest) + if isstored(a_dest, I_dest) + a_dest[I_dest] = mul!!(a_dest[I_dest], a1[I1], a2[I2], α, β′) + else + a_dest[I_dest] = a1[I1] * a2[I2] * α + end + end end - end end - end - return a_dest + return a_dest end function ArrayLayouts.materialize!( - m::MatMulMatAdd{<:AbstractSparseLayout,<:AbstractSparseLayout,<:AbstractSparseLayout} -) - sparse_mul!(m.C, m.A, m.B, m.α, m.β) - return m.C + m::MatMulMatAdd{<:AbstractSparseLayout, <:AbstractSparseLayout, <:AbstractSparseLayout} + ) + sparse_mul!(m.C, m.A, m.B, m.α, m.β) + return m.C end struct SparseLayout <: AbstractSparseLayout end @interface ::AbstractSparseArrayInterface function ArrayLayouts.MemoryLayout(type::Type) - return SparseLayout() + return SparseLayout() end diff --git a/src/indexing.jl b/src/indexing.jl index 2c2d6ca..85fdead 100644 --- a/src/indexing.jl +++ b/src/indexing.jl @@ -13,7 +13,7 @@ Obtain `getindex(A, I...)` with the guarantee that there is a stored entry at th Similar to `Base.getindex`, new definitions should be in line with `IndexStyle(A)`. """ @inline getstoredindex(A::AbstractArray, I...) = @interface interface(A) getstoredindex( - A, I... + A, I... ) """ @@ -27,7 +27,7 @@ instantiated object. Similar to `Base.getindex`, new definitions should be in line with `IndexStyle(A)`. """ @inline getunstoredindex(A::AbstractArray, I...) = @interface interface(A) getunstoredindex( - A, I... + A, I... ) """ @@ -49,7 +49,7 @@ Similar to `Base.getindex`, new definitions should be in line with `IndexStyle(A Similar to `Base.setindex!`, new definitions should be in line with `IndexStyle(A)`. """ @inline setstoredindex!(A::AbstractArray, v, I...) = @interface interface(A) setstoredindex!( - A, v, I... + A, v, I... ) """ @@ -60,7 +60,7 @@ Similar to `Base.setindex!`, new definitions should be in line with `IndexStyle( Similar to `Base.setindex!`, new definitions should be in line with `IndexStyle(A)`. """ @inline setunstoredindex!(A::AbstractArray, v, I...) = @interface interface(A) setunstoredindex!( - A, v, I... + A, v, I... ) # Indices interface @@ -109,12 +109,12 @@ to be the same as [`eachstoredindex`](@ref). """ function storedvalues end -@derive (T=AbstractArray,) begin - SparseArraysBase.eachstoredindex(::T...) - SparseArraysBase.eachstoredindex(::IndexStyle, ::T...) - SparseArraysBase.storedlength(::T) - SparseArraysBase.storedpairs(::T) - SparseArraysBase.storedvalues(::T) +@derive (T = AbstractArray,) begin + SparseArraysBase.eachstoredindex(::T...) + SparseArraysBase.eachstoredindex(::IndexStyle, ::T...) + SparseArraysBase.storedlength(::T) + SparseArraysBase.storedpairs(::T) + SparseArraysBase.storedvalues(::T) end # canonical indexing @@ -124,126 +124,126 @@ end # f(::AbstractArray{<:Any,N}, I::Vararg{Int,N}) if IndexCartesian for f in (:isstored, :getunstoredindex, :getstoredindex) - _f = Symbol(:_, f) - error_if_canonical = Symbol(:error_if_canonical_, f) - @eval begin - @interface ::AbstractArrayInterface function $f(A::AbstractArray, I...) - @_propagate_inbounds_meta - style = IndexStyle(A) - $error_if_canonical(style, A, I...) - return $_f(style, A, Base.to_indices(A, I)...) + _f = Symbol(:_, f) + error_if_canonical = Symbol(:error_if_canonical_, f) + @eval begin + @interface ::AbstractArrayInterface function $f(A::AbstractArray, I...) + @_propagate_inbounds_meta + style = IndexStyle(A) + $error_if_canonical(style, A, I...) + return $_f(style, A, Base.to_indices(A, I)...) + end + + # linear indexing + @inline $_f(::IndexLinear, A::AbstractVector, i::Int) = $f(A, i) + @inline $_f(::IndexLinear, A::AbstractArray, i::Int) = $f(A, i) + @inline function $_f(::IndexLinear, A::AbstractArray, I::Vararg{Int, M}) where {M} + @boundscheck checkbounds(A, I...) + return @inbounds $f(A, Base._to_linear_index(A, I...)) + end + + # cartesian indexing + @inline function $_f(::IndexCartesian, A::AbstractArray, I::Vararg{Int, M}) where {M} + @boundscheck checkbounds(A, I...) + return @inbounds $f(A, Base._to_subscript_indices(A, I...)...) + end + @inline function $_f( + ::IndexCartesian, A::AbstractArray{<:Any, N}, I::Vararg{Int, N} + ) where {N} + return $f(A, I...) + end + + # errors + $_f(::IndexStyle, A::AbstractArray, I...) = error( + "`$($f)` for $("$(typeof(A))") with types $("$(typeof(I))") is not supported" + ) + + $error_if_canonical(::IndexLinear, A::AbstractArray, ::Int) = throw( + Base.CanonicalIndexError("$($f)", typeof(A)) + ) + $error_if_canonical(::IndexCartesian, A::AbstractArray{<:Any, N}, ::Vararg{Int, N}) where {N} = throw( + Base.CanonicalIndexError("$($f)", typeof(A)) + ) + $error_if_canonical(::IndexStyle, A::AbstractArray, ::Any...) = nothing end - - # linear indexing - @inline $_f(::IndexLinear, A::AbstractVector, i::Int) = $f(A, i) - @inline $_f(::IndexLinear, A::AbstractArray, i::Int) = $f(A, i) - @inline function $_f(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where {M} - @boundscheck checkbounds(A, I...) - return @inbounds $f(A, Base._to_linear_index(A, I...)) - end - - # cartesian indexing - @inline function $_f(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where {M} - @boundscheck checkbounds(A, I...) - return @inbounds $f(A, Base._to_subscript_indices(A, I...)...) - end - @inline function $_f( - ::IndexCartesian, A::AbstractArray{<:Any,N}, I::Vararg{Int,N} - ) where {N} - return $f(A, I...) - end - - # errors - $_f(::IndexStyle, A::AbstractArray, I...) = error( - "`$($f)` for $("$(typeof(A))") with types $("$(typeof(I))") is not supported" - ) - - $error_if_canonical(::IndexLinear, A::AbstractArray, ::Int) = throw( - Base.CanonicalIndexError("$($f)", typeof(A)) - ) - $error_if_canonical(::IndexCartesian, A::AbstractArray{<:Any,N}, ::Vararg{Int,N}) where {N} = throw( - Base.CanonicalIndexError("$($f)", typeof(A)) - ) - $error_if_canonical(::IndexStyle, A::AbstractArray, ::Any...) = nothing - end end for f! in (:setunstoredindex!, :setstoredindex!) - _f! = Symbol(:_, f!) - error_if_canonical = Symbol(:error_if_canonical_, f!) - @eval begin - @interface ::AbstractArrayInterface function $f!(A::AbstractArray, v, I...) - @_propagate_inbounds_meta - style = IndexStyle(A) - $error_if_canonical(style, A, I...) - return $_f!(style, A, v, Base.to_indices(A, I)...) + _f! = Symbol(:_, f!) + error_if_canonical = Symbol(:error_if_canonical_, f!) + @eval begin + @interface ::AbstractArrayInterface function $f!(A::AbstractArray, v, I...) + @_propagate_inbounds_meta + style = IndexStyle(A) + $error_if_canonical(style, A, I...) + return $_f!(style, A, v, Base.to_indices(A, I)...) + end + + # linear indexing + @inline $_f!(::IndexLinear, A::AbstractVector, v, i::Int) = $f!(A, v, i) + @inline $_f!(::IndexLinear, A::AbstractArray, v, i::Int) = $f!(A, v, i) + @inline function $_f!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int, M}) where {M} + @boundscheck checkbounds(A, I...) + return @inbounds $f!(A, v, Base._to_linear_index(A, I...)) + end + + # cartesian indexing + @inline function $_f!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int, M}) where {M} + @boundscheck checkbounds(A, I...) + return @inbounds $f!(A, v, Base._to_subscript_indices(A, I...)...) + end + @inline function $_f!( + ::IndexCartesian, A::AbstractArray{<:Any, N}, v, I::Vararg{Int, N} + ) where {N} + return $f!(A, v, I...) + end + + # errors + $_f!(::IndexStyle, A::AbstractArray, I...) = error( + "`$f!` for $("$(typeof(A))") with types $("$(typeof(I))") is not supported" + ) + + $error_if_canonical(::IndexLinear, A::AbstractArray, ::Int) = throw( + Base.CanonicalIndexError("$($(string(f!)))", typeof(A)) + ) + $error_if_canonical(::IndexCartesian, A::AbstractArray{<:Any, N}, ::Vararg{Int, N}) where {N} = throw( + Base.CanonicalIndexError("$($f!)", typeof(A)) + ) + $error_if_canonical(::IndexStyle, A::AbstractArray, ::Any...) = nothing end - - # linear indexing - @inline $_f!(::IndexLinear, A::AbstractVector, v, i::Int) = $f!(A, v, i) - @inline $_f!(::IndexLinear, A::AbstractArray, v, i::Int) = $f!(A, v, i) - @inline function $_f!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where {M} - @boundscheck checkbounds(A, I...) - return @inbounds $f!(A, v, Base._to_linear_index(A, I...)) - end - - # cartesian indexing - @inline function $_f!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where {M} - @boundscheck checkbounds(A, I...) - return @inbounds $f!(A, v, Base._to_subscript_indices(A, I...)...) - end - @inline function $_f!( - ::IndexCartesian, A::AbstractArray{<:Any,N}, v, I::Vararg{Int,N} - ) where {N} - return $f!(A, v, I...) - end - - # errors - $_f!(::IndexStyle, A::AbstractArray, I...) = error( - "`$f!` for $("$(typeof(A))") with types $("$(typeof(I))") is not supported" - ) - - $error_if_canonical(::IndexLinear, A::AbstractArray, ::Int) = throw( - Base.CanonicalIndexError("$($(string(f!)))", typeof(A)) - ) - $error_if_canonical(::IndexCartesian, A::AbstractArray{<:Any,N}, ::Vararg{Int,N}) where {N} = throw( - Base.CanonicalIndexError("$($f!)", typeof(A)) - ) - $error_if_canonical(::IndexStyle, A::AbstractArray, ::Any...) = nothing - end end # AbstractArrayInterface fallback definitions # ------------------------------------------- @interface ::AbstractArrayInterface function isstored(A::AbstractArray, i::Int, I::Int...) - @inline - @boundscheck checkbounds(A, i, I...) - return true + @inline + @boundscheck checkbounds(A, i, I...) + return true end @interface ::AbstractArrayInterface function getunstoredindex(A::AbstractArray, I::Int...) - @inline - @boundscheck checkbounds(A, I...) - return zero(eltype(A)) + @inline + @boundscheck checkbounds(A, I...) + return zero(eltype(A)) end @interface ::AbstractArrayInterface function getstoredindex(A::AbstractArray, I::Int...) - @inline - return getindex(A, I...) + @inline + return getindex(A, I...) end @interface ::AbstractArrayInterface function setstoredindex!(A::AbstractArray, v, I::Int...) - @inline - return setindex!(A, v, I...) + @inline + return setindex!(A, v, I...) end @interface ::AbstractArrayInterface setunstoredindex!(A::AbstractArray, v, I::Int...) = error( - "setunstoredindex! for $(typeof(A)) is not supported" + "setunstoredindex! for $(typeof(A)) is not supported" ) @interface ::AbstractArrayInterface eachstoredindex(A::AbstractArray, B::AbstractArray...) = eachstoredindex( - IndexStyle(A, B...), A, B... + IndexStyle(A, B...), A, B... ) @interface ::AbstractArrayInterface eachstoredindex(style::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex( - style, A, B... + style, A, B... ) @interface ::AbstractArrayInterface storedvalues(A::AbstractArray) = values(A) @@ -255,86 +255,86 @@ end # canonical errors are moved to `isstored`, `getstoredindex` and `getunstoredindex` # so no errors at this level by defining both IndexLinear and IndexCartesian @interface ::AbstractSparseArrayInterface function Base.getindex( - A::AbstractArray{<:Any,N}, I::Vararg{Int,N} -) where {N} - @_propagate_inbounds_meta - @boundscheck checkbounds(A, I...) # generally isstored requires bounds checking - return @inbounds isstored(A, I...) ? getstoredindex(A, I...) : getunstoredindex(A, I...) + A::AbstractArray{<:Any, N}, I::Vararg{Int, N} + ) where {N} + @_propagate_inbounds_meta + @boundscheck checkbounds(A, I...) # generally isstored requires bounds checking + return @inbounds isstored(A, I...) ? getstoredindex(A, I...) : getunstoredindex(A, I...) end @interface ::AbstractSparseArrayInterface function Base.getindex(A::AbstractArray, I::Int) - @_propagate_inbounds_meta - @boundscheck checkbounds(A, I) - return @inbounds isstored(A, I) ? getstoredindex(A, I) : getunstoredindex(A, I) + @_propagate_inbounds_meta + @boundscheck checkbounds(A, I) + return @inbounds isstored(A, I) ? getstoredindex(A, I) : getunstoredindex(A, I) end # disambiguate vectors @interface ::AbstractSparseArrayInterface function Base.getindex(A::AbstractVector, I::Int) - @_propagate_inbounds_meta - @boundscheck checkbounds(A, I) - return @inbounds isstored(A, I) ? getstoredindex(A, I) : getunstoredindex(A, I) + @_propagate_inbounds_meta + @boundscheck checkbounds(A, I) + return @inbounds isstored(A, I) ? getstoredindex(A, I) : getunstoredindex(A, I) end @interface ::AbstractSparseArrayInterface function Base.setindex!( - A::AbstractArray{<:Any,N}, v, I::Vararg{Int,N} -) where {N} - @_propagate_inbounds_meta - @boundscheck checkbounds(A, I...) - return @inbounds if isstored(A, I...) - setstoredindex!(A, v, I...) - else - setunstoredindex!(A, v, I...) - end + A::AbstractArray{<:Any, N}, v, I::Vararg{Int, N} + ) where {N} + @_propagate_inbounds_meta + @boundscheck checkbounds(A, I...) + return @inbounds if isstored(A, I...) + setstoredindex!(A, v, I...) + else + setunstoredindex!(A, v, I...) + end end @interface ::AbstractSparseArrayInterface function Base.setindex!( - A::AbstractArray, v, I::Int -) - @_propagate_inbounds_meta - @boundscheck checkbounds(A, I) - return @inbounds if isstored(A, I) - setstoredindex!(A, v, I) - else - setunstoredindex!(A, v, I) - end + A::AbstractArray, v, I::Int + ) + @_propagate_inbounds_meta + @boundscheck checkbounds(A, I) + return @inbounds if isstored(A, I) + setstoredindex!(A, v, I) + else + setunstoredindex!(A, v, I) + end end # disambiguate vectors @interface ::AbstractSparseArrayInterface function Base.setindex!( - A::AbstractVector, v, I::Int -) - @_propagate_inbounds_meta - @boundscheck checkbounds(A, I) - return @inbounds if isstored(A, I) - setstoredindex!(A, v, I) - else - setunstoredindex!(A, v, I) - end + A::AbstractVector, v, I::Int + ) + @_propagate_inbounds_meta + @boundscheck checkbounds(A, I) + return @inbounds if isstored(A, I) + setstoredindex!(A, v, I) + else + setunstoredindex!(A, v, I) + end end @noinline function error_if_canonical_eachstoredindex(style::IndexStyle, A::AbstractArray) - style === IndexStyle(A) && throw(Base.CanonicalIndexError("eachstoredindex", typeof(A))) - return nothing + style === IndexStyle(A) && throw(Base.CanonicalIndexError("eachstoredindex", typeof(A))) + return nothing end # required: one implementation for canonical index style @interface ::AbstractSparseArrayInterface function eachstoredindex( - style::IndexStyle, A::AbstractArray -) - error_if_canonical_eachstoredindex(style, A) - inds = eachstoredindex(A) - if style === IndexCartesian() - eltype(inds) === CartesianIndex{ndims(A)} && return inds - return map(Base.Fix1(Base.getindex, CartesianIndices(A)), inds) - elseif style === IndexLinear() - eltype(inds) === Int && return inds - return map(Base.Fix1(Base.getindex, LinearIndices(A)), inds) - else - error(lazy"unkown index style $style") - end + style::IndexStyle, A::AbstractArray + ) + error_if_canonical_eachstoredindex(style, A) + inds = eachstoredindex(A) + if style === IndexCartesian() + eltype(inds) === CartesianIndex{ndims(A)} && return inds + return map(Base.Fix1(Base.getindex, CartesianIndices(A)), inds) + elseif style === IndexLinear() + eltype(inds) === Int && return inds + return map(Base.Fix1(Base.getindex, LinearIndices(A)), inds) + else + error(lazy"unkown index style $style") + end end # derived but may be specialized: @interface ::AbstractSparseArrayInterface function eachstoredindex( - style::IndexStyle, A::AbstractArray, B::AbstractArray... -) - return union(map(Base.Fix1(eachstoredindex, style), (A, B...))...) + style::IndexStyle, A::AbstractArray, B::AbstractArray... + ) + return union(map(Base.Fix1(eachstoredindex, style), (A, B...))...) end @interface ::AbstractSparseArrayInterface storedvalues(A::AbstractArray) = StoredValues(A) @@ -343,74 +343,74 @@ end # implementation, so we check this and otherwise map back to `_isstored` to canonicalize the # indices @interface ::AbstractSparseArrayInterface function isstored(A::AbstractArray, I::Int...) - @_propagate_inbounds_meta - style = IndexStyle(A) - # canonical linear indexing - if style == IndexLinear() && length(I) == 1 - @boundscheck checkbounds(A, I...) - return only(I) in eachstoredindex(style, A) - end + @_propagate_inbounds_meta + style = IndexStyle(A) + # canonical linear indexing + if style == IndexLinear() && length(I) == 1 + @boundscheck checkbounds(A, I...) + return only(I) in eachstoredindex(style, A) + end - # canonical cartesian indexing - if style == IndexCartesian() && length(I) == ndims(A) - @boundscheck checkbounds(A, I...) - return CartesianIndex(I...) in eachstoredindex(style, A) - end + # canonical cartesian indexing + if style == IndexCartesian() && length(I) == ndims(A) + @boundscheck checkbounds(A, I...) + return CartesianIndex(I...) in eachstoredindex(style, A) + end - # non-canonical indexing - return _isstored(style, A, Base.to_indices(A, I)...) + # non-canonical indexing + return _isstored(style, A, Base.to_indices(A, I)...) end @interface ::AbstractSparseArrayInterface function getunstoredindex( - A::AbstractArray, I::Int... -) - @_propagate_inbounds_meta - style = IndexStyle(A) + A::AbstractArray, I::Int... + ) + @_propagate_inbounds_meta + style = IndexStyle(A) - # canonical linear indexing - if style == IndexLinear() && length(I) == 1 - @boundscheck checkbounds(A, I...) - return zero(eltype(A)) - end + # canonical linear indexing + if style == IndexLinear() && length(I) == 1 + @boundscheck checkbounds(A, I...) + return zero(eltype(A)) + end - # canonical cartesian indexing - if style == IndexCartesian() && length(I) == ndims(A) - @boundscheck checkbounds(A, I...) - return zero(eltype(A)) - end + # canonical cartesian indexing + if style == IndexCartesian() && length(I) == ndims(A) + @boundscheck checkbounds(A, I...) + return zero(eltype(A)) + end - # non-canonical indexing - return _getunstoredindex(style, A, Base.to_indices(A, I)...) + # non-canonical indexing + return _getunstoredindex(style, A, Base.to_indices(A, I)...) end # make sure we don't call AbstractArrayInterface defaults @interface ::AbstractSparseArrayInterface function getstoredindex( - A::AbstractArray, I::Int... -) - @_propagate_inbounds_meta - style = IndexStyle(A) - error_if_canonical_getstoredindex(style, A, I...) - return _getstoredindex(style, A, Base.to_indices(A, I)...) + A::AbstractArray, I::Int... + ) + @_propagate_inbounds_meta + style = IndexStyle(A) + error_if_canonical_getstoredindex(style, A, I...) + return _getstoredindex(style, A, Base.to_indices(A, I)...) end for f! in (:setstoredindex!, :setunstoredindex!) - _f! = Symbol(:_, f!) - error_if_canonical_setstoredindex = Symbol(:error_if_canonical_, f!) - @eval begin - @interface ::AbstractSparseArrayInterface function $f!(A::AbstractArray, v, I::Int...) - @_propagate_inbounds_meta - style = IndexStyle(A) - $error_if_canonical_setstoredindex(style, A, I...) - return $_f!(style, A, v, Base.to_indices(A, I)...) + _f! = Symbol(:_, f!) + error_if_canonical_setstoredindex = Symbol(:error_if_canonical_, f!) + @eval begin + @interface ::AbstractSparseArrayInterface function $f!(A::AbstractArray, v, I::Int...) + @_propagate_inbounds_meta + style = IndexStyle(A) + $error_if_canonical_setstoredindex(style, A, I...) + return $_f!(style, A, v, Base.to_indices(A, I)...) + end end - end end @interface ::AbstractSparseArrayInterface storedlength(A::AbstractArray) = length( - storedvalues(A) + storedvalues(A) ) @interface ::AbstractSparseArrayInterface function storedpairs(A::AbstractArray) - return Iterators.map(I -> (I => A[I]), eachstoredindex(A)) + return Iterators.map(I -> (I => A[I]), eachstoredindex(A)) end #= @@ -422,15 +422,15 @@ eg: ArrayLayouts.@layoutgetindex ArrayType TODO: decide if we need the interface approach at all here =# for (Tr, Tc) in Iterators.product( - Iterators.repeated((:Colon, :AbstractUnitRange, :AbstractVector, :Integer), 2)... -) - Tr === Tc === :Integer && continue - @eval begin - @interface ::AbstractSparseArrayInterface function Base.getindex( - A::AbstractMatrix, kr::$Tr, jr::$Tc + Iterators.repeated((:Colon, :AbstractUnitRange, :AbstractVector, :Integer), 2)... ) - Base.@inline # needed to make boundschecks work - return ArrayLayouts.layout_getindex(A, kr, jr) + Tr === Tc === :Integer && continue + @eval begin + @interface ::AbstractSparseArrayInterface function Base.getindex( + A::AbstractMatrix, kr::$Tr, jr::$Tc + ) + Base.@inline # needed to make boundschecks work + return ArrayLayouts.layout_getindex(A, kr, jr) + end end - end end diff --git a/src/map.jl b/src/map.jl index fbaad34..83efe6b 100644 --- a/src/map.jl +++ b/src/map.jl @@ -18,134 +18,134 @@ To attempt to automatically determine this, either `ZeroPreserving(f, A::Abstrac abstract type ZeroPreserving <: Function end struct StrongPreserving{F} <: ZeroPreserving - f::F + f::F end struct WeakPreserving{F} <: ZeroPreserving - f::F + f::F end struct NonPreserving{F} <: ZeroPreserving - f::F + f::F end # Backport: remove in 1.12 @static if !isdefined(Base, :haszero) - _haszero(T::Type) = false - _haszero(::Type{<:Number}) = true + _haszero(T::Type) = false + _haszero(::Type{<:Number}) = true else - _haszero = Base.haszero + _haszero = Base.haszero end # warning: cannot automatically detect WeakPreserving since this would mean checking all values function ZeroPreserving(f, A::AbstractArray, Bs::AbstractArray...) - return ZeroPreserving(f, eltype(A), eltype.(Bs)...) + return ZeroPreserving(f, eltype(A), eltype.(Bs)...) end # TODO: the following might not properly specialize on the types # TODO: non-concrete element types function ZeroPreserving(f, T::Type, Ts::Type...) - if all(_haszero, (T, Ts...)) - return iszero(f(zero(T), zero.(Ts)...)) ? WeakPreserving(f) : NonPreserving(f) - else - return NonPreserving(f) - end + if all(_haszero, (T, Ts...)) + return iszero(f(zero(T), zero.(Ts)...)) ? WeakPreserving(f) : NonPreserving(f) + else + return NonPreserving(f) + end end ZeroPreserving(f::ZeroPreserving, T::Type, Ts::Type...) = f for F in (:(typeof(+)), :(typeof(-)), :(typeof(identity))) - @eval begin - ZeroPreserving(f::$F, ::Type, ::Type...) = WeakPreserving(f) - end + @eval begin + ZeroPreserving(f::$F, ::Type, ::Type...) = WeakPreserving(f) + end end using MapBroadcast: MapFunction for F in (:(typeof(*)), :(MapFunction{typeof(*)})) - @eval begin - function ZeroPreserving(f::$F, ::Type, ::Type...) - return StrongPreserving(f) + @eval begin + function ZeroPreserving(f::$F, ::Type, ::Type...) + return StrongPreserving(f) + end end - end end # map(!) # ------ @interface I::AbstractSparseArrayInterface function Base.map( - f, A::AbstractArray, Bs::AbstractArray... -) - f_pres = ZeroPreserving(f, A, Bs...) - return map_sparsearray(f_pres, A, Bs...) + f, A::AbstractArray, Bs::AbstractArray... + ) + f_pres = ZeroPreserving(f, A, Bs...) + return map_sparsearray(f_pres, A, Bs...) end -# This isn't an overload of `Base.map` since that leads to ambiguity errors. +# This isn't an overload of `Base.map` since that leads to ambiguity errors. function map_sparsearray(f::ZeroPreserving, A::AbstractArray, Bs::AbstractArray...) - T = Base.Broadcast.combine_eltypes(f.f, (A, Bs...)) - C = similar(A, T) - # TODO: Instead use: - # ```julia - # U = map(f.f, map(unstored, (A, Bs...))...) - # C = similar(A, Unstored(U)) - # ``` - # though right now `map` doesn't preserve `Zeros` or `BlockZeros`. - return map_sparsearray!(f, C, A, Bs...) + T = Base.Broadcast.combine_eltypes(f.f, (A, Bs...)) + C = similar(A, T) + # TODO: Instead use: + # ```julia + # U = map(f.f, map(unstored, (A, Bs...))...) + # C = similar(A, Unstored(U)) + # ``` + # though right now `map` doesn't preserve `Zeros` or `BlockZeros`. + return map_sparsearray!(f, C, A, Bs...) end @interface I::AbstractSparseArrayInterface function Base.map!( - f, C::AbstractArray, A::AbstractArray, Bs::AbstractArray... -) - f_pres = ZeroPreserving(f, A, Bs...) - return map_sparsearray!(f_pres, C, A, Bs...) + f, C::AbstractArray, A::AbstractArray, Bs::AbstractArray... + ) + f_pres = ZeroPreserving(f, A, Bs...) + return map_sparsearray!(f_pres, C, A, Bs...) end -# This isn't an overload of `Base.map!` since that leads to ambiguity errors. +# This isn't an overload of `Base.map!` since that leads to ambiguity errors. function map_sparsearray!( - f::ZeroPreserving, C::AbstractArray, A::AbstractArray, Bs::AbstractArray... -) - checkshape(C, A, Bs...) - unaliased = map(Base.Fix1(Base.unalias, C), (A, Bs...)) - if f isa StrongPreserving - style = IndexStyle(C, unaliased...) - inds = intersect(eachstoredindex.(Ref(style), unaliased)...) - zero!(C) - elseif f isa WeakPreserving - style = IndexStyle(C, unaliased...) - inds = union(eachstoredindex.(Ref(style), unaliased)...) - zero!(C) - elseif f isa NonPreserving - inds = eachindex(C, unaliased...) - else - error(lazy"unknown zero-preserving type $(typeof(f))") - end - @inbounds for I in inds - C[I] = f.f(ith_all(I, unaliased)...) - end - return C + f::ZeroPreserving, C::AbstractArray, A::AbstractArray, Bs::AbstractArray... + ) + checkshape(C, A, Bs...) + unaliased = map(Base.Fix1(Base.unalias, C), (A, Bs...)) + if f isa StrongPreserving + style = IndexStyle(C, unaliased...) + inds = intersect(eachstoredindex.(Ref(style), unaliased)...) + zero!(C) + elseif f isa WeakPreserving + style = IndexStyle(C, unaliased...) + inds = union(eachstoredindex.(Ref(style), unaliased)...) + zero!(C) + elseif f isa NonPreserving + inds = eachindex(C, unaliased...) + else + error(lazy"unknown zero-preserving type $(typeof(f))") + end + @inbounds for I in inds + C[I] = f.f(ith_all(I, unaliased)...) + end + return C end # Derived functions # ----------------- @interface I::AbstractSparseArrayInterface function Base.copyto!( - dest::AbstractArray, src::AbstractArray -) - @interface I map!(identity, dest, src) - return dest + dest::AbstractArray, src::AbstractArray + ) + @interface I map!(identity, dest, src) + return dest end # Only map the stored values of the inputs. function map_stored! end @interface interface::AbstractArrayInterface function map_stored!( - f, a_dest::AbstractArray, as::AbstractArray... -) - @interface interface map!(WeakPreserving(f), a_dest, as...) - return a_dest + f, a_dest::AbstractArray, as::AbstractArray... + ) + @interface interface map!(WeakPreserving(f), a_dest, as...) + return a_dest end # Only map all values, not just the stored ones. function map_all! end @interface interface::AbstractArrayInterface function map_all!( - f, a_dest::AbstractArray, as::AbstractArray... -) - @interface interface map!(NonPreserving(f), a_dest, as...) - return a_dest + f, a_dest::AbstractArray, as::AbstractArray... + ) + @interface interface map!(NonPreserving(f), a_dest, as...) + return a_dest end # Utility functions @@ -154,16 +154,16 @@ end checkshape(::Type{Bool}, A::AbstractArray) = true checkshape(::Type{Bool}, A::AbstractArray, B::AbstractArray) = size(A) == size(B) function checkshape(::Type{Bool}, A::AbstractArray, Bs::AbstractArray...) - return allequal(size, (A, Bs...)) + return allequal(size, (A, Bs...)) end function checkshape(A::AbstractArray, Bs::AbstractArray...) - return checkshape(Bool, A, Bs...) || - throw(DimensionMismatch("argument shapes must match")) + return checkshape(Bool, A, Bs...) || + throw(DimensionMismatch("argument shapes must match")) end @inline ith_all(i, ::Tuple{}) = () function ith_all(i, as) - @_propagate_inbounds_meta - return (as[1][i], ith_all(i, Base.tail(as))...) + @_propagate_inbounds_meta + return (as[1][i], ith_all(i, Base.tail(as))...) end diff --git a/src/oneelementarray.jl b/src/oneelementarray.jl index d5b361e..e276169 100644 --- a/src/oneelementarray.jl +++ b/src/oneelementarray.jl @@ -4,250 +4,250 @@ function _OneElementArray end # Like [`FillArrays.OneElement`](https://github.com/JuliaArrays/FillArrays.jl) # and [`OneHotArrays.OneHotArray`](https://github.com/FluxML/OneHotArrays.jl). -struct OneElementArray{T,N,I,Unstored<:AbstractArray{T,N}} <: AbstractSparseArray{T,N} - value::T - index::I - unstored::Unstored - global @inline function _OneElementArray( - value::T, index::I, unstored::Unstored - ) where {T,N,I,Unstored<:AbstractArray{T,N}} - @assert N == length(index) - return new{T,N,I,Unstored}(value, index, unstored) - end +struct OneElementArray{T, N, I, Unstored <: AbstractArray{T, N}} <: AbstractSparseArray{T, N} + value::T + index::I + unstored::Unstored + global @inline function _OneElementArray( + value::T, index::I, unstored::Unstored + ) where {T, N, I, Unstored <: AbstractArray{T, N}} + @assert N == length(index) + return new{T, N, I, Unstored}(value, index, unstored) + end end using DerivableInterfaces: @array_aliases # Define `OneElementMatrix`, `AnyOneElementArray`, etc. @array_aliases OneElementArray -function OneElementArray{T,N}( - value, index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange} -) where {T,N} - return _OneElementArray(convert(T, value), index, Zeros{T}(axes)) +function OneElementArray{T, N}( + value, index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange} + ) where {T, N} + return _OneElementArray(convert(T, value), index, Zeros{T}(axes)) end -function OneElementArray{<:Any,N}( - value::T, index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange} -) where {T,N} - return OneElementArray{T,N}(value, index, axes) +function OneElementArray{<:Any, N}( + value::T, index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange} + ) where {T, N} + return OneElementArray{T, N}(value, index, axes) end function OneElementArray( - value::T, index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange} -) where {T,N} - return OneElementArray{T,N}(value, index, axes) + value::T, index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange} + ) where {T, N} + return OneElementArray{T, N}(value, index, axes) end -function OneElementArray{T,N}( - index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange} -) where {T,N} - return OneElementArray{T,N}(one(T), index, axes) +function OneElementArray{T, N}( + index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange} + ) where {T, N} + return OneElementArray{T, N}(one(T), index, axes) end -function OneElementArray{<:Any,N}( - index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange} -) where {N} - return OneElementArray{Bool,N}(index, axes) +function OneElementArray{<:Any, N}( + index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange} + ) where {N} + return OneElementArray{Bool, N}(index, axes) end function OneElementArray{T}( - index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange} -) where {T,N} - return OneElementArray{T,N}(index, axes) + index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange} + ) where {T, N} + return OneElementArray{T, N}(index, axes) end -function OneElementArray(index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange}) where {N} - return OneElementArray{Bool,N}(index, axes) +function OneElementArray(index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange}) where {N} + return OneElementArray{Bool, N}(index, axes) end -function OneElementArray{T,N}( - value, ax_ind::Vararg{Pair{<:AbstractUnitRange,Int},N} -) where {T,N} - return OneElementArray{T,N}(value, last.(ax_ind), first.(ax_ind)) +function OneElementArray{T, N}( + value, ax_ind::Vararg{Pair{<:AbstractUnitRange, Int}, N} + ) where {T, N} + return OneElementArray{T, N}(value, last.(ax_ind), first.(ax_ind)) end -function OneElementArray{<:Any,N}( - value::T, ax_ind::Vararg{Pair{<:AbstractUnitRange,Int},N} -) where {T,N} - return OneElementArray{T,N}(value, ax_ind...) +function OneElementArray{<:Any, N}( + value::T, ax_ind::Vararg{Pair{<:AbstractUnitRange, Int}, N} + ) where {T, N} + return OneElementArray{T, N}(value, ax_ind...) end function OneElementArray{T}( - value, ax_ind::Vararg{Pair{<:AbstractUnitRange,Int},N} -) where {T,N} - return OneElementArray{T,N}(value, ax_ind...) + value, ax_ind::Vararg{Pair{<:AbstractUnitRange, Int}, N} + ) where {T, N} + return OneElementArray{T, N}(value, ax_ind...) end function OneElementArray( - value::T, ax_ind::Vararg{Pair{<:AbstractUnitRange,Int},N} -) where {T,N} - return OneElementArray{T,N}(value, ax_ind...) + value::T, ax_ind::Vararg{Pair{<:AbstractUnitRange, Int}, N} + ) where {T, N} + return OneElementArray{T, N}(value, ax_ind...) end -function OneElementArray{T,N}(ax_ind::Vararg{Pair{<:AbstractUnitRange,Int},N}) where {T,N} - return OneElementArray{T,N}(last.(ax_ind), first.(ax_ind)) +function OneElementArray{T, N}(ax_ind::Vararg{Pair{<:AbstractUnitRange, Int}, N}) where {T, N} + return OneElementArray{T, N}(last.(ax_ind), first.(ax_ind)) end -function OneElementArray{<:Any,N}(ax_ind::Vararg{Pair{<:AbstractUnitRange,Int},N}) where {N} - return OneElementArray{Bool,N}(ax_ind...) +function OneElementArray{<:Any, N}(ax_ind::Vararg{Pair{<:AbstractUnitRange, Int}, N}) where {N} + return OneElementArray{Bool, N}(ax_ind...) end -function OneElementArray{T}(ax_ind::Vararg{Pair{<:AbstractUnitRange,Int},N}) where {T,N} - return OneElementArray{T,N}(ax_ind...) +function OneElementArray{T}(ax_ind::Vararg{Pair{<:AbstractUnitRange, Int}, N}) where {T, N} + return OneElementArray{T, N}(ax_ind...) end -function OneElementArray(ax_ind::Vararg{Pair{<:AbstractUnitRange,Int},N}) where {N} - return OneElementArray{Bool,N}(ax_ind...) +function OneElementArray(ax_ind::Vararg{Pair{<:AbstractUnitRange, Int}, N}) where {N} + return OneElementArray{Bool, N}(ax_ind...) end # Fix ambiguity errors. -function OneElementArray{T,0}(value, index::Tuple{}, axes::Tuple{}) where {T} - return _OneElementArray(convert(T, value), index, Zeros{T}(axes)) +function OneElementArray{T, 0}(value, index::Tuple{}, axes::Tuple{}) where {T} + return _OneElementArray(convert(T, value), index, Zeros{T}(axes)) end -function OneElementArray{<:Any,0}(value::T, index::Tuple{}, axes::Tuple{}) where {T} - return OneElementArray{T,0}(value, index, axes) +function OneElementArray{<:Any, 0}(value::T, index::Tuple{}, axes::Tuple{}) where {T} + return OneElementArray{T, 0}(value, index, axes) end function OneElementArray{T}(value, index::Tuple{}, axes::Tuple{}) where {T} - return OneElementArray{T,0}(value, index, axes) + return OneElementArray{T, 0}(value, index, axes) end function OneElementArray(value::T, index::Tuple{}, axes::Tuple{}) where {T} - return OneElementArray{T,0}(value, index, axes) + return OneElementArray{T, 0}(value, index, axes) end # Fix ambiguity errors. -function OneElementArray{T,0}(index::Tuple{}, axes::Tuple{}) where {T} - return OneElementArray{T,0}(one(T), index, axes) +function OneElementArray{T, 0}(index::Tuple{}, axes::Tuple{}) where {T} + return OneElementArray{T, 0}(one(T), index, axes) end -function OneElementArray{<:Any,0}(index::Tuple{}, axes::Tuple{}) - return OneElementArray{Bool,0}(index, axes) +function OneElementArray{<:Any, 0}(index::Tuple{}, axes::Tuple{}) + return OneElementArray{Bool, 0}(index, axes) end function OneElementArray{T}(index::Tuple{}, axes::Tuple{}) where {T} - return OneElementArray{T,0}(index, axes) + return OneElementArray{T, 0}(index, axes) end function OneElementArray(index::Tuple{}, axes::Tuple{}) - return OneElementArray{Bool,0}(value, index, axes) + return OneElementArray{Bool, 0}(value, index, axes) end -function OneElementArray{T,0}(value) where {T} - return OneElementArray{T,0}(value, (), ()) +function OneElementArray{T, 0}(value) where {T} + return OneElementArray{T, 0}(value, (), ()) end -function OneElementArray{<:Any,0}(value::T) where {T} - return OneElementArray{T,0}(value) +function OneElementArray{<:Any, 0}(value::T) where {T} + return OneElementArray{T, 0}(value) end function OneElementArray{T}(value) where {T} - return OneElementArray{T,0}(value) + return OneElementArray{T, 0}(value) end function OneElementArray(value::T) where {T} - return OneElementArray{T}(value) + return OneElementArray{T}(value) end -function OneElementArray{T,0}() where {T} - return OneElementArray{T,0}((), ()) +function OneElementArray{T, 0}() where {T} + return OneElementArray{T, 0}((), ()) end -function OneElementArray{<:Any,0}() - return OneElementArray{Bool,0}(value) +function OneElementArray{<:Any, 0}() + return OneElementArray{Bool, 0}(value) end function OneElementArray{T}() where {T} - return OneElementArray{T,0}() + return OneElementArray{T, 0}() end function OneElementArray() - return OneElementArray{Bool}() + return OneElementArray{Bool}() end -function OneElementArray{T,N}( - value, index::NTuple{N,Int}, size::NTuple{N,Integer} -) where {T,N} - return OneElementArray{T,N}(value, index, Base.oneto.(size)) +function OneElementArray{T, N}( + value, index::NTuple{N, Int}, size::NTuple{N, Integer} + ) where {T, N} + return OneElementArray{T, N}(value, index, Base.oneto.(size)) end -function OneElementArray{<:Any,N}( - value::T, index::NTuple{N,Int}, size::NTuple{N,Integer} -) where {T,N} - return OneElementArray{T,N}(value, index, size) +function OneElementArray{<:Any, N}( + value::T, index::NTuple{N, Int}, size::NTuple{N, Integer} + ) where {T, N} + return OneElementArray{T, N}(value, index, size) end function OneElementArray{T}( - value, index::NTuple{N,Int}, size::NTuple{N,Integer} -) where {T,N} - return OneElementArray{T,N}(value, index, size) + value, index::NTuple{N, Int}, size::NTuple{N, Integer} + ) where {T, N} + return OneElementArray{T, N}(value, index, size) end function OneElementArray( - value::T, index::NTuple{N,Int}, size::NTuple{N,Integer} -) where {T,N} - return OneElementArray{T,N}(value, index, Base.oneto.(size)) + value::T, index::NTuple{N, Int}, size::NTuple{N, Integer} + ) where {T, N} + return OneElementArray{T, N}(value, index, Base.oneto.(size)) end -function OneElementArray{T,N}(index::NTuple{N,Int}, size::NTuple{N,Integer}) where {T,N} - return OneElementArray{T,N}(one(T), index, size) +function OneElementArray{T, N}(index::NTuple{N, Int}, size::NTuple{N, Integer}) where {T, N} + return OneElementArray{T, N}(one(T), index, size) end -function OneElementArray{<:Any,N}(index::NTuple{N,Int}, size::NTuple{N,Integer}) where {N} - return OneElementArray{Bool,N}(index, size) +function OneElementArray{<:Any, N}(index::NTuple{N, Int}, size::NTuple{N, Integer}) where {N} + return OneElementArray{Bool, N}(index, size) end -function OneElementArray{T}(index::NTuple{N,Int}, size::NTuple{N,Integer}) where {T,N} - return OneElementArray{T,N}(index, size) +function OneElementArray{T}(index::NTuple{N, Int}, size::NTuple{N, Integer}) where {T, N} + return OneElementArray{T, N}(index, size) end -function OneElementArray(index::NTuple{N,Int}, size::NTuple{N,Integer}) where {N} - return OneElementArray{Bool,N}(index, size) +function OneElementArray(index::NTuple{N, Int}, size::NTuple{N, Integer}) where {N} + return OneElementArray{Bool, N}(index, size) end function OneElementVector{T}(value, index::Int, length::Integer) where {T} - return OneElementVector{T}(value, (index,), (length,)) + return OneElementVector{T}(value, (index,), (length,)) end function OneElementVector(value::T, index::Int, length::Integer) where {T} - return OneElementVector{T}(value, index, length) + return OneElementVector{T}(value, index, length) end function OneElementArray{T}(value, index::Int, length::Integer) where {T} - return OneElementVector{T}(value, index, length) + return OneElementVector{T}(value, index, length) end function OneElementArray(value::T, index::Int, length::Integer) where {T} - return OneElementVector{T}(value, index, length) + return OneElementVector{T}(value, index, length) end function OneElementVector{T}(index::Int, size::Integer) where {T} - return OneElementVector{T}((index,), (size,)) + return OneElementVector{T}((index,), (size,)) end function OneElementVector(index::Int, length::Integer) - return OneElementVector{Bool}(index, length) + return OneElementVector{Bool}(index, length) end function OneElementArray{T}(index::Int, size::Integer) where {T} - return OneElementVector{T}(index, size) + return OneElementVector{T}(index, size) end function OneElementArray(index::Int, size::Integer) - return OneElementVector{Bool}(index, size) + return OneElementVector{Bool}(index, size) end # Interface to overload for constructing arrays like `OneElementArray`, # that may not be `OneElementArray` (i.e. wrapped versions). function oneelement( - value, index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange} -) where {N} - return OneElementArray(value, index, axes) + value, index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange} + ) where {N} + return OneElementArray(value, index, axes) end function oneelement( - eltype::Type, index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange} -) where {N} - return oneelement(one(eltype), index, axes) + eltype::Type, index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange} + ) where {N} + return oneelement(one(eltype), index, axes) end -function oneelement(index::NTuple{N,Int}, axes::NTuple{N,AbstractUnitRange}) where {N} - return oneelement(Bool, index, axes) +function oneelement(index::NTuple{N, Int}, axes::NTuple{N, AbstractUnitRange}) where {N} + return oneelement(Bool, index, axes) end -function oneelement(value, index::NTuple{N,Int}, size::NTuple{N,Integer}) where {N} - return oneelement(value, index, Base.oneto.(size)) +function oneelement(value, index::NTuple{N, Int}, size::NTuple{N, Integer}) where {N} + return oneelement(value, index, Base.oneto.(size)) end -function oneelement(eltype::Type, index::NTuple{N,Int}, size::NTuple{N,Integer}) where {N} - return oneelement(one(eltype), index, size) +function oneelement(eltype::Type, index::NTuple{N, Int}, size::NTuple{N, Integer}) where {N} + return oneelement(one(eltype), index, size) end -function oneelement(index::NTuple{N,Int}, size::NTuple{N,Integer}) where {N} - return oneelement(Bool, index, size) +function oneelement(index::NTuple{N, Int}, size::NTuple{N, Integer}) where {N} + return oneelement(Bool, index, size) end -function oneelement(value, ax_ind::Pair{<:AbstractUnitRange,Int}...) - return oneelement(value, last.(ax_ind), first.(ax_ind)) +function oneelement(value, ax_ind::Pair{<:AbstractUnitRange, Int}...) + return oneelement(value, last.(ax_ind), first.(ax_ind)) end -function oneelement(eltype::Type, ax_ind::Pair{<:AbstractUnitRange,Int}...) - return oneelement(one(eltype), ax_ind...) +function oneelement(eltype::Type, ax_ind::Pair{<:AbstractUnitRange, Int}...) + return oneelement(one(eltype), ax_ind...) end -function oneelement(ax_ind::Pair{<:AbstractUnitRange,Int}...) - return oneelement(Bool, ax_ind...) +function oneelement(ax_ind::Pair{<:AbstractUnitRange, Int}...) + return oneelement(Bool, ax_ind...) end function oneelement(value) - return oneelement(value, (), ()) + return oneelement(value, (), ()) end function oneelement(eltype::Type) - return oneelement(one(eltype)) + return oneelement(one(eltype)) end function oneelement() - return oneelement(Bool) + return oneelement(Bool) end unstored(a::OneElementArray) = getfield(a, :unstored) @@ -258,21 +258,21 @@ storedvalues(a::OneElementArray) = Fill(storedvalue(a), 1) storedindex(a::OneElementArray) = getfield(a, :index) function isstored(a::OneElementArray, I::Int...) - return I == storedindex(a) + return I == storedindex(a) end function eachstoredindex(::IndexCartesian, a::OneElementArray) - return Fill(CartesianIndex(storedindex(a)), 1) + return Fill(CartesianIndex(storedindex(a)), 1) end function getstoredindex(a::OneElementArray, I::Int...) - return storedvalue(a) + return storedvalue(a) end function getunstoredindex(a::OneElementArray, I::Int...) - return unstored(a)[I...] + return unstored(a)[I...] end function setstoredindex!(a::OneElementArray, value, I::Int...) - return error("`OneElementArray` is immutable, you can't set elements.") + return error("`OneElementArray` is immutable, you can't set elements.") end function setunstoredindex!(a::OneElementArray, value, I::Int...) - return error("`OneElementArray` is immutable, you can't set elements.") + return error("`OneElementArray` is immutable, you can't set elements.") end diff --git a/src/sparsearraydok.jl b/src/sparsearraydok.jl index 902f267..674ae35 100644 --- a/src/sparsearraydok.jl +++ b/src/sparsearraydok.jl @@ -2,7 +2,7 @@ using Accessors: @set using DerivableInterfaces: DerivableInterfaces, @interface, interface, zero! using Dictionaries: Dictionary, IndexError, set! -const DOKStorage{T,N} = Dictionary{CartesianIndex{N},T} +const DOKStorage{T, N} = Dictionary{CartesianIndex{N}, T} function _SparseArrayDOK end @@ -12,32 +12,32 @@ function _SparseArrayDOK end `N`-dimensional sparse dictionary-of-keys (DOK) array with elements of type `T`, with a specified background of unstored values `unstored` of the size of the array. """ -struct SparseArrayDOK{T,N,Unstored<:AbstractArray{T,N}} <: AbstractSparseArray{T,N} - storage::DOKStorage{T,N} - unstored::Unstored - global @inline function _SparseArrayDOK( - storage::DOKStorage{T,N}, unstored::Unstored - ) where {T,N,Unstored<:AbstractArray{T,N}} - return new{T,N,Unstored}(storage, unstored) - end +struct SparseArrayDOK{T, N, Unstored <: AbstractArray{T, N}} <: AbstractSparseArray{T, N} + storage::DOKStorage{T, N} + unstored::Unstored + global @inline function _SparseArrayDOK( + storage::DOKStorage{T, N}, unstored::Unstored + ) where {T, N, Unstored <: AbstractArray{T, N}} + return new{T, N, Unstored}(storage, unstored) + end end unstored(a::SparseArrayDOK) = a.unstored Base.size(a::SparseArrayDOK) = size(unstored(a)) Base.axes(a::SparseArrayDOK) = axes(unstored(a)) -function SparseArrayDOK{T,N}(::UndefInitializer, a::Unstored) where {T,N} - storage = DOKStorage{T,N}() - return _SparseArrayDOK(storage, parent(a)) +function SparseArrayDOK{T, N}(::UndefInitializer, a::Unstored) where {T, N} + storage = DOKStorage{T, N}() + return _SparseArrayDOK(storage, parent(a)) end function SparseArrayDOK{T}(::UndefInitializer, a::Unstored) where {T} - return SparseArrayDOK{T,ndims(a)}(undef, a) + return SparseArrayDOK{T, ndims(a)}(undef, a) end -function SparseArrayDOK{<:Any,N}(::UndefInitializer, a::Unstored) where {N} - return SparseArrayDOK{eltype(a),N}(a) +function SparseArrayDOK{<:Any, N}(::UndefInitializer, a::Unstored) where {N} + return SparseArrayDOK{eltype(a), N}(a) end function SparseArrayDOK(::UndefInitializer, a::Unstored) - return SparseArrayDOK{eltype(a),ndims(a)}(undef, a) + return SparseArrayDOK{eltype(a), ndims(a)}(undef, a) end # Constructors @@ -50,25 +50,25 @@ Construct an uninitialized `N`-dimensional [`SparseArrayDOK`](@ref) containing elements of type `T`. `N` can either be supplied explicitly, or be determined by the length or number of `dims`. """ -SparseArrayDOK{T,N}(::UndefInitializer, dims...) +SparseArrayDOK{T, N}(::UndefInitializer, dims...) -function SparseArrayDOK{T,N}(::UndefInitializer, ax::Tuple{Vararg{Any,N}}) where {T,N} - return SparseArrayDOK{T,N}(undef, Unstored(Zeros{T}(ax))) +function SparseArrayDOK{T, N}(::UndefInitializer, ax::Tuple{Vararg{Any, N}}) where {T, N} + return SparseArrayDOK{T, N}(undef, Unstored(Zeros{T}(ax))) end -function SparseArrayDOK{T}(::UndefInitializer, ax::Tuple{Vararg{Any,N}}) where {T,N} - return SparseArrayDOK{T,N}(undef, ax) +function SparseArrayDOK{T}(::UndefInitializer, ax::Tuple{Vararg{Any, N}}) where {T, N} + return SparseArrayDOK{T, N}(undef, ax) end -function SparseArrayDOK{T,N}(::UndefInitializer, ax::Vararg{Int,N}) where {T,N} - return SparseArrayDOK{T,N}(undef, ax) +function SparseArrayDOK{T, N}(::UndefInitializer, ax::Vararg{Int, N}) where {T, N} + return SparseArrayDOK{T, N}(undef, ax) end -function SparseArrayDOK{T}(::UndefInitializer, ax::Vararg{Any,N}) where {T,N} - return SparseArrayDOK{T,N}(undef, ax) +function SparseArrayDOK{T}(::UndefInitializer, ax::Vararg{Any, N}) where {T, N} + return SparseArrayDOK{T, N}(undef, ax) end using DerivableInterfaces: DerivableInterfaces # This defines the destination type of various operations in DerivableInterfaces.jl. function Base.similar(::AbstractSparseArrayInterface, T::Type, ax::Tuple) - return similar(SparseArrayDOK{T}, ax) + return similar(SparseArrayDOK{T}, ax) end using DerivableInterfaces: @array_aliases @@ -78,37 +78,37 @@ using DerivableInterfaces: @array_aliases storage(a::SparseArrayDOK) = a.storage storedvalues(a::SparseArrayDOK) = values(storage(a)) -@inline function isstored(a::SparseArrayDOK{<:Any,N}, I::Vararg{Int,N}) where {N} - @boundscheck checkbounds(a, I...) - return haskey(storage(a), CartesianIndex(I)) +@inline function isstored(a::SparseArrayDOK{<:Any, N}, I::Vararg{Int, N}) where {N} + @boundscheck checkbounds(a, I...) + return haskey(storage(a), CartesianIndex(I)) end function eachstoredindex(::IndexCartesian, a::SparseArrayDOK) - return keys(storage(a)) + return keys(storage(a)) end -@inline function getstoredindex(a::SparseArrayDOK{<:Any,N}, I::Vararg{Int,N}) where {N} - @boundscheck checkbounds(a, I...) - return storage(a)[CartesianIndex(I)] +@inline function getstoredindex(a::SparseArrayDOK{<:Any, N}, I::Vararg{Int, N}) where {N} + @boundscheck checkbounds(a, I...) + return storage(a)[CartesianIndex(I)] end -@inline function getunstoredindex(a::SparseArrayDOK{<:Any,N}, I::Vararg{Int,N}) where {N} - @boundscheck checkbounds(a, I...) - return unstored(a)[I...] +@inline function getunstoredindex(a::SparseArrayDOK{<:Any, N}, I::Vararg{Int, N}) where {N} + @boundscheck checkbounds(a, I...) + return unstored(a)[I...] end @inline function setstoredindex!( - a::SparseArrayDOK{<:Any,N}, value, I::Vararg{Int,N} -) where {N} - # `isstored` includes a boundscheck as well - @boundscheck isstored(a, I...) || - throw(IndexError(lazy"key $(CartesianIndex(I...)) not found")) - # TODO: If `iszero(value)`, unstore the index. - storage(a)[CartesianIndex(I)] = value - return a + a::SparseArrayDOK{<:Any, N}, value, I::Vararg{Int, N} + ) where {N} + # `isstored` includes a boundscheck as well + @boundscheck isstored(a, I...) || + throw(IndexError(lazy"key $(CartesianIndex(I...)) not found")) + # TODO: If `iszero(value)`, unstore the index. + storage(a)[CartesianIndex(I)] = value + return a end @inline function setunstoredindex!( - a::SparseArrayDOK{<:Any,N}, value, I::Vararg{Int,N} -) where {N} - @boundscheck checkbounds(a, I...) - insert!(storage(a), CartesianIndex(I), value) - return a + a::SparseArrayDOK{<:Any, N}, value, I::Vararg{Int, N} + ) where {N} + @boundscheck checkbounds(a, I...) + insert!(storage(a), CartesianIndex(I), value) + return a end # Optional, but faster than the default. @@ -116,9 +116,9 @@ storedpairs(a::SparseArrayDOK) = pairs(storage(a)) # TODO: Also handle wrappers. function DerivableInterfaces.zero!(a::SparseArrayDOK) - empty!(storage(a)) - return a + empty!(storage(a)) + return a end function ArrayLayouts.zero!(a::SparseArrayDOK) - return zero!(a) + return zero!(a) end diff --git a/src/sparsearrayinterface.jl b/src/sparsearrayinterface.jl index 7cc1c01..a0307fd 100644 --- a/src/sparsearrayinterface.jl +++ b/src/sparsearrayinterface.jl @@ -3,28 +3,28 @@ using DerivableInterfaces: DerivableInterfaces struct SparseArrayInterface{N} <: AbstractSparseArrayInterface{N} end SparseArrayInterface() = SparseArrayInterface{Any}() SparseArrayInterface(::Val{N}) where {N} = SparseArrayInterface{N}() -SparseArrayInterface{M}(::Val{N}) where {M,N} = SparseArrayInterface{N}() +SparseArrayInterface{M}(::Val{N}) where {M, N} = SparseArrayInterface{N}() # Fix ambiguity error. function DerivableInterfaces.combine_interface_rule( - ::SparseArrayInterface{N}, ::SparseArrayInterface{N} -) where {N} - return SparseArrayInterface{N}() + ::SparseArrayInterface{N}, ::SparseArrayInterface{N} + ) where {N} + return SparseArrayInterface{N}() end function DerivableInterfaces.combine_interface_rule( - ::SparseArrayInterface, ::SparseArrayInterface -) - return SparseArrayInterface() + ::SparseArrayInterface, ::SparseArrayInterface + ) + return SparseArrayInterface() end function DerivableInterfaces.combine_interface_rule( - interface1::SparseArrayInterface, interface2::AbstractSparseArrayInterface -) - return interface1 + interface1::SparseArrayInterface, interface2::AbstractSparseArrayInterface + ) + return interface1 end function DerivableInterfaces.combine_interface_rule( - interface1::AbstractSparseArrayInterface, interface2::SparseArrayInterface -) - return interface2 + interface1::AbstractSparseArrayInterface, interface2::SparseArrayInterface + ) + return interface2 end # Convenient shorthand to refer to the sparse interface. diff --git a/src/wrappers.jl b/src/wrappers.jl index 33ef3c1..3851114 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -2,34 +2,34 @@ parentvalue_to_value(a::AbstractArray, value) = value value_to_parentvalue(a::AbstractArray, value) = value eachstoredparentindex(a::AbstractArray) = eachstoredindex(parent(a)) function eachstoredparentindex(style::IndexStyle, a::AbstractArray) - return eachstoredindex(style, parent(a)) + return eachstoredindex(style, parent(a)) end storedparentvalues(a::AbstractArray) = storedvalues(parent(a)) -function parentindex_to_index(a::AbstractArray{<:Any,N}, I::CartesianIndex{N}) where {N} - return throw(MethodError(parentindex_to_index, Tuple{typeof(a),typeof(I)})) +function parentindex_to_index(a::AbstractArray{<:Any, N}, I::CartesianIndex{N}) where {N} + return throw(MethodError(parentindex_to_index, Tuple{typeof(a), typeof(I)})) end -function parentindex_to_index(a::AbstractArray{<:Any,N}, I::Vararg{Int,N}) where {N} - return Tuple(parentindex_to_index(a, CartesianIndex(I))) +function parentindex_to_index(a::AbstractArray{<:Any, N}, I::Vararg{Int, N}) where {N} + return Tuple(parentindex_to_index(a, CartesianIndex(I))) end # Handle linear indexing. function parentindex_to_index(a::AbstractArray, I::Int) - return parentindex_to_index(a, CartesianIndices(parent(a))[I]) + return parentindex_to_index(a, CartesianIndices(parent(a))[I]) end -function index_to_parentindex(a::AbstractArray{<:Any,N}, I::CartesianIndex{N}) where {N} - return throw(MethodError(index_to_parentindex, Tuple{typeof(a),typeof(I)})) +function index_to_parentindex(a::AbstractArray{<:Any, N}, I::CartesianIndex{N}) where {N} + return throw(MethodError(index_to_parentindex, Tuple{typeof(a), typeof(I)})) end -function index_to_parentindex(a::AbstractArray{<:Any,N}, I::Vararg{Int,N}) where {N} - return Tuple(index_to_parentindex(a, CartesianIndex(I))) +function index_to_parentindex(a::AbstractArray{<:Any, N}, I::Vararg{Int, N}) where {N} + return Tuple(index_to_parentindex(a, CartesianIndex(I))) end # Handle linear indexing. function index_to_parentindex(a::AbstractArray, I::Int) - return LinearIndices(parent(a))[index_to_parentindex(a, CartesianIndices(a)[I])] + return LinearIndices(parent(a))[index_to_parentindex(a, CartesianIndices(a)[I])] end function cartesianindex_reverse(I::CartesianIndex) - return CartesianIndex(reverse(Tuple(I))) + return CartesianIndex(reverse(Tuple(I))) end tuple_oneto(n) = ntuple(identity, n) @@ -39,25 +39,25 @@ genperm(v, perm) = map(j -> v[j], perm) using LinearAlgebra: Adjoint function parentindex_to_index(a::Adjoint, I::CartesianIndex{2}) - return cartesianindex_reverse(I) + return cartesianindex_reverse(I) end function index_to_parentindex(a::Adjoint, I::CartesianIndex{2}) - return cartesianindex_reverse(I) + return cartesianindex_reverse(I) end function parentvalue_to_value(a::Adjoint, value) - return adjoint(value) + return adjoint(value) end function value_to_parentvalue(a::Adjoint, value) - return adjoint(value) + return adjoint(value) end -perm(::PermutedDimsArray{<:Any,<:Any,p}) where {p} = p -iperm(::PermutedDimsArray{<:Any,<:Any,<:Any,ip}) where {ip} = ip -function index_to_parentindex(a::PermutedDimsArray{<:Any,N}, I::CartesianIndex{N}) where {N} - return CartesianIndex(genperm(I, iperm(a))) +perm(::PermutedDimsArray{<:Any, <:Any, p}) where {p} = p +iperm(::PermutedDimsArray{<:Any, <:Any, <:Any, ip}) where {ip} = ip +function index_to_parentindex(a::PermutedDimsArray{<:Any, N}, I::CartesianIndex{N}) where {N} + return CartesianIndex(genperm(I, iperm(a))) end -function parentindex_to_index(a::PermutedDimsArray{<:Any,N}, I::CartesianIndex{N}) where {N} - return CartesianIndex(genperm(I, perm(a))) +function parentindex_to_index(a::PermutedDimsArray{<:Any, N}, I::CartesianIndex{N}) where {N} + return CartesianIndex(genperm(I, perm(a))) end using Base: ReshapedArray @@ -65,43 +65,43 @@ using Base: ReshapedArray # and index since the parent array can have a different # number of dimensions than the `SubArray`. function parentindex_to_index(a::ReshapedArray, I::CartesianIndex) - return CartesianIndices(size(a))[LinearIndices(parent(a))[I]] + return CartesianIndices(size(a))[LinearIndices(parent(a))[I]] end # Don't constrain the number of dimensions of the array # and index since the parent array can have a different # number of dimensions than the `SubArray`. function index_to_parentindex(a::ReshapedArray, I::CartesianIndex) - return CartesianIndices(parent(a))[LinearIndices(size(a))[I]] + return CartesianIndices(parent(a))[LinearIndices(size(a))[I]] end function eachstoredparentindex(a::SubArray) - return filter(eachstoredindex(parent(a))) do I - return all(d -> I[d] ∈ parentindices(a)[d], 1:ndims(parent(a))) - end + return filter(eachstoredindex(parent(a))) do I + return all(d -> I[d] ∈ parentindices(a)[d], 1:ndims(parent(a))) + end end function eachstoredparentindex(style::IndexStyle, a::SubArray) - return filter(eachstoredindex(style, parent(a))) do I - return all(d -> I[d] ∈ parentindices(a)[d], 1:ndims(parent(a))) - end + return filter(eachstoredindex(style, parent(a))) do I + return all(d -> I[d] ∈ parentindices(a)[d], 1:ndims(parent(a))) + end end # Don't constrain the number of dimensions of the array # and index since the parent array can have a different # number of dimensions than the `SubArray`. function index_to_parentindex(a::SubArray, I::CartesianIndex) - return CartesianIndex(Base.reindex(parentindices(a), Tuple(I))) + return CartesianIndex(Base.reindex(parentindices(a), Tuple(I))) end # Don't constrain the number of dimensions of the array # and index since the parent array can have a different # number of dimensions than the `SubArray`. function parentindex_to_index(a::SubArray, I::CartesianIndex) - nonscalardims = filter(tuple_oneto(ndims(parent(a)))) do d - return !(parentindices(a)[d] isa Real) - end - return CartesianIndex( - map(nonscalardims) do d - return findfirst(==(I[d]), parentindices(a)[d]) - end, - ) + nonscalardims = filter(tuple_oneto(ndims(parent(a)))) do d + return !(parentindices(a)[d] isa Real) + end + return CartesianIndex( + map(nonscalardims) do d + return findfirst(==(I[d]), parentindices(a)[d]) + end, + ) end ## TODO: Use this and something similar for `Dictionary` to make a faster ## implementation of `storedvalues(::SubArray)`. @@ -109,85 +109,85 @@ end ## return @view d.vals[[Base.ht_keyindex(d, key) for key in keys]] ## end function storedparentvalues(a::SubArray) - # We use `StoredValues` rather than `@view`/`SubArray` so that - # it gets interpreted as a dense array. - return StoredValues(parent(a), collect(eachstoredparentindex(a))) + # We use `StoredValues` rather than `@view`/`SubArray` so that + # it gets interpreted as a dense array. + return StoredValues(parent(a), collect(eachstoredparentindex(a))) end using LinearAlgebra: Transpose function parentindex_to_index(a::Transpose, I::CartesianIndex{2}) - return cartesianindex_reverse(I) + return cartesianindex_reverse(I) end function index_to_parentindex(a::Transpose, I::CartesianIndex{2}) - return cartesianindex_reverse(I) + return cartesianindex_reverse(I) end function parentvalue_to_value(a::Transpose, value) - return transpose(value) + return transpose(value) end function value_to_parentvalue(a::Transpose, value) - return transpose(value) + return transpose(value) end -function isstored_wrapped(a::AbstractArray{<:Any,N}, I::Vararg{Int,N}) where {N} - return isstored(parent(a), index_to_parentindex(a, I...)...) +function isstored_wrapped(a::AbstractArray{<:Any, N}, I::Vararg{Int, N}) where {N} + return isstored(parent(a), index_to_parentindex(a, I...)...) end -function isstored(a::Adjoint, I::Vararg{Int,2}) - return isstored_wrapped(a, I...) +function isstored(a::Adjoint, I::Vararg{Int, 2}) + return isstored_wrapped(a, I...) end -function isstored(a::PermutedDimsArray{<:Any,N}, I::Vararg{Int,N}) where {N} - return isstored_wrapped(a, I...) +function isstored(a::PermutedDimsArray{<:Any, N}, I::Vararg{Int, N}) where {N} + return isstored_wrapped(a, I...) end -function isstored(a::ReshapedArray{<:Any,N}, I::Vararg{Int,N}) where {N} - return isstored_wrapped(a, I...) +function isstored(a::ReshapedArray{<:Any, N}, I::Vararg{Int, N}) where {N} + return isstored_wrapped(a, I...) end -function isstored(a::SubArray{<:Any,N}, I::Vararg{Int,N}) where {N} - return isstored_wrapped(a, I...) +function isstored(a::SubArray{<:Any, N}, I::Vararg{Int, N}) where {N} + return isstored_wrapped(a, I...) end -function isstored(a::Transpose, I::Vararg{Int,2}) - return isstored_wrapped(a, I...) +function isstored(a::Transpose, I::Vararg{Int, 2}) + return isstored_wrapped(a, I...) end # TODO: Turn these into `AbstractWrappedSparseArrayInterface` functions? for type in (:Adjoint, :PermutedDimsArray, :ReshapedArray, :SubArray, :Transpose) - @eval begin - @interface ::AbstractSparseArrayInterface storedvalues(a::$type) = storedparentvalues(a) - @interface ::AbstractSparseArrayInterface function eachstoredindex(a::$type) - return map(Base.Fix1(parentindex_to_index, a), eachstoredparentindex(a)) - end - @interface ::AbstractSparseArrayInterface function eachstoredindex( - style::IndexStyle, a::$type - ) - # TODO: Make lazy with `Iterators.map`. - return map(Base.Fix1(parentindex_to_index, a), eachstoredparentindex(style, a)) - end - @interface ::AbstractSparseArrayInterface function getstoredindex(a::$type, I::Int...) - return parentvalue_to_value( - a, getstoredindex(parent(a), index_to_parentindex(a, I...)...) - ) + @eval begin + @interface ::AbstractSparseArrayInterface storedvalues(a::$type) = storedparentvalues(a) + @interface ::AbstractSparseArrayInterface function eachstoredindex(a::$type) + return map(Base.Fix1(parentindex_to_index, a), eachstoredparentindex(a)) + end + @interface ::AbstractSparseArrayInterface function eachstoredindex( + style::IndexStyle, a::$type + ) + # TODO: Make lazy with `Iterators.map`. + return map(Base.Fix1(parentindex_to_index, a), eachstoredparentindex(style, a)) + end + @interface ::AbstractSparseArrayInterface function getstoredindex(a::$type, I::Int...) + return parentvalue_to_value( + a, getstoredindex(parent(a), index_to_parentindex(a, I...)...) + ) + end + @interface ::AbstractSparseArrayInterface function getunstoredindex(a::$type, I::Int...) + return parentvalue_to_value( + a, getunstoredindex(parent(a), index_to_parentindex(a, I...)...) + ) + end + @interface ::AbstractSparseArrayInterface function setstoredindex!( + a::$type, value, I::Int... + ) + setstoredindex!( + parent(a), value_to_parentvalue(a, value), index_to_parentindex(a, I...)... + ) + return a + end + @interface ::AbstractSparseArrayInterface function setunstoredindex!( + a::$type, value, I::Int... + ) + setunstoredindex!( + parent(a), value_to_parentvalue(a, value), index_to_parentindex(a, I...)... + ) + return a + end end - @interface ::AbstractSparseArrayInterface function getunstoredindex(a::$type, I::Int...) - return parentvalue_to_value( - a, getunstoredindex(parent(a), index_to_parentindex(a, I...)...) - ) - end - @interface ::AbstractSparseArrayInterface function setstoredindex!( - a::$type, value, I::Int... - ) - setstoredindex!( - parent(a), value_to_parentvalue(a, value), index_to_parentindex(a, I...)... - ) - return a - end - @interface ::AbstractSparseArrayInterface function setunstoredindex!( - a::$type, value, I::Int... - ) - setunstoredindex!( - parent(a), value_to_parentvalue(a, value), index_to_parentindex(a, I...)... - ) - return a - end - end end using LinearAlgebra: LinearAlgebra, Diagonal @@ -195,26 +195,26 @@ using LinearAlgebra: LinearAlgebra, Diagonal # compat with LTS: @static if VERSION ≥ v"1.11" - _diagind = LinearAlgebra.diagind + _diagind = LinearAlgebra.diagind else - function _diagind(x::Diagonal, ::IndexCartesian) - return view(CartesianIndices(x), LinearAlgebra.diagind(x)) - end + function _diagind(x::Diagonal, ::IndexCartesian) + return view(CartesianIndices(x), LinearAlgebra.diagind(x)) + end end @interface ::AbstractArrayInterface eachstoredindex(D::Diagonal) = _diagind( - D, IndexCartesian() + D, IndexCartesian() ) @interface ::AbstractArrayInterface function isstored(D::Diagonal, i::Int, j::Int) - return i == j && checkbounds(Bool, D, i, j) + return i == j && checkbounds(Bool, D, i, j) end @interface ::AbstractArrayInterface function getstoredindex(D::Diagonal, i::Int, j::Int) - return D.diag[i] + return D.diag[i] end @interface ::AbstractArrayInterface function getunstoredindex(D::Diagonal, i::Int, j::Int) - return zero(eltype(D)) + return zero(eltype(D)) end @interface ::AbstractArrayInterface function setstoredindex!(D::Diagonal, v, i::Int, j::Int) - D.diag[i] = v - return D + D.diag[i] = v + return D end diff --git a/test/runtests.jl b/test/runtests.jl index 98b2d2b..0008050 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,60 +6,62 @@ using Suppressor: Suppressor const pat = r"(?:--group=)(\w+)" arg_id = findfirst(contains(pat), ARGS) const GROUP = uppercase( - if isnothing(arg_id) - get(ENV, "GROUP", "ALL") - else - only(match(pat, ARGS[arg_id]).captures) - end, + if isnothing(arg_id) + get(ENV, "GROUP", "ALL") + else + only(match(pat, ARGS[arg_id]).captures) + end, ) "match files of the form `test_*.jl`, but exclude `*setup*.jl`" function istestfile(fn) - return endswith(fn, ".jl") && startswith(basename(fn), "test_") && !contains(fn, "setup") + return endswith(fn, ".jl") && startswith(basename(fn), "test_") && !contains(fn, "setup") end "match files of the form `*.jl`, but exclude `*_notest.jl` and `*setup*.jl`" function isexamplefile(fn) - return endswith(fn, ".jl") && !endswith(fn, "_notest.jl") && !contains(fn, "setup") + return endswith(fn, ".jl") && !endswith(fn, "_notest.jl") && !contains(fn, "setup") end @time begin - # tests in groups based on folder structure - for testgroup in filter(isdir, readdir(@__DIR__)) - if GROUP == "ALL" || GROUP == uppercase(testgroup) - groupdir = joinpath(@__DIR__, testgroup) - for file in filter(istestfile, readdir(groupdir)) - filename = joinpath(groupdir, file) - @eval @safetestset $file begin - include($filename) + # tests in groups based on folder structure + for testgroup in filter(isdir, readdir(@__DIR__)) + if GROUP == "ALL" || GROUP == uppercase(testgroup) + groupdir = joinpath(@__DIR__, testgroup) + for file in filter(istestfile, readdir(groupdir)) + filename = joinpath(groupdir, file) + @eval @safetestset $file begin + include($filename) + end + end end - end end - end - # single files in top folder - for file in filter(istestfile, readdir(@__DIR__)) - (file == basename(@__FILE__)) && continue # exclude this file to avoid infinite recursion - @eval @safetestset $file begin - include($file) + # single files in top folder + for file in filter(istestfile, readdir(@__DIR__)) + (file == basename(@__FILE__)) && continue # exclude this file to avoid infinite recursion + @eval @safetestset $file begin + include($file) + end end - end - # test examples - examplepath = joinpath(@__DIR__, "..", "examples") - for (root, _, files) in walkdir(examplepath) - contains(chopprefix(root, @__DIR__), "setup") && continue - for file in filter(isexamplefile, files) - filename = joinpath(root, file) - @eval begin - @safetestset $file begin - $(Expr( - :macrocall, - GlobalRef(Suppressor, Symbol("@suppress")), - LineNumberNode(@__LINE__, @__FILE__), - :(include($filename)), - )) + # test examples + examplepath = joinpath(@__DIR__, "..", "examples") + for (root, _, files) in walkdir(examplepath) + contains(chopprefix(root, @__DIR__), "setup") && continue + for file in filter(isexamplefile, files) + filename = joinpath(root, file) + @eval begin + @safetestset $file begin + $( + Expr( + :macrocall, + GlobalRef(Suppressor, Symbol("@suppress")), + LineNumberNode(@__LINE__, @__FILE__), + :(include($filename)), + ) + ) + end + end end - end end - end end diff --git a/test/test_aqua.jl b/test/test_aqua.jl index 0bff54a..66974b6 100644 --- a/test/test_aqua.jl +++ b/test/test_aqua.jl @@ -3,5 +3,5 @@ using Aqua: Aqua using Test: @testset @testset "Code quality (Aqua.jl)" begin - Aqua.test_all(SparseArraysBase; ambiguities=false) + Aqua.test_all(SparseArraysBase; ambiguities = false) end diff --git a/test/test_basics.jl b/test/test_basics.jl index d9f7661..3145f62 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -1,74 +1,74 @@ using Adapt: adapt using JLArrays: JLArray, @allowscalar using SparseArraysBase: - SparseArraysBase, - eachstoredindex, - getstoredindex, - getunstoredindex, - isstored, - setstoredindex!, - setunstoredindex!, - storedlength, - storedpairs, - storedvalues + SparseArraysBase, + eachstoredindex, + getstoredindex, + getunstoredindex, + isstored, + setstoredindex!, + setunstoredindex!, + storedlength, + storedpairs, + storedvalues using Test: @test, @test_throws, @testset elts = (Float32, Float64, Complex{Float32}, Complex{Float64}) arrayts = (Array, JLArray) @testset "SparseArraysBase (arraytype=$arrayt, eltype=$elt)" for arrayt in arrayts, - elt in elts + elt in elts - dev(x) = adapt(arrayt, x) + dev(x) = adapt(arrayt, x) - n = 2 - a = dev(randn(elt, n, n)) - @test storedlength(a) == length(a) - for indexstyle in (IndexLinear(), IndexCartesian()) - for I in eachindex(indexstyle, a) - @test isstored(a, I) - if indexstyle == IndexCartesian() - @test isstored(a, Tuple(I)..., 1) - end + n = 2 + a = dev(randn(elt, n, n)) + @test storedlength(a) == length(a) + for indexstyle in (IndexLinear(), IndexCartesian()) + for I in eachindex(indexstyle, a) + @test isstored(a, I) + if indexstyle == IndexCartesian() + @test isstored(a, Tuple(I)..., 1) + end + end + end + @test eachstoredindex(a) == eachindex(a) + # TODO: We should be specializing these for dense/strided arrays, + # probably we can have a trait for that. It could be based + # on the `ArrayLayouts.MemoryLayout`. + @allowscalar @test storedvalues(a) == a + @allowscalar @test storedpairs(a) == pairs(a) + @allowscalar for I in eachindex(a) + @test getstoredindex(a, I) == a[I] + @test iszero(getunstoredindex(a, I)) + end + @allowscalar for I in eachindex(IndexCartesian(), a) + @test getstoredindex(a, I) == a[I] + @test iszero(getunstoredindex(a, I)) end - end - @test eachstoredindex(a) == eachindex(a) - # TODO: We should be specializing these for dense/strided arrays, - # probably we can have a trait for that. It could be based - # on the `ArrayLayouts.MemoryLayout`. - @allowscalar @test storedvalues(a) == a - @allowscalar @test storedpairs(a) == pairs(a) - @allowscalar for I in eachindex(a) - @test getstoredindex(a, I) == a[I] - @test iszero(getunstoredindex(a, I)) - end - @allowscalar for I in eachindex(IndexCartesian(), a) - @test getstoredindex(a, I) == a[I] - @test iszero(getunstoredindex(a, I)) - end - n = 2 - a = @view dev(randn(elt, n, n))[1:2, 1] - @test storedlength(a) == length(a) - for indexstyle in (IndexLinear(), IndexCartesian()) - for I in eachindex(indexstyle, a) - @test isstored(a, I) + n = 2 + a = @view dev(randn(elt, n, n))[1:2, 1] + @test storedlength(a) == length(a) + for indexstyle in (IndexLinear(), IndexCartesian()) + for I in eachindex(indexstyle, a) + @test isstored(a, I) + end end - end - a = dev(randn(elt, n, n)) - for I in ((1, 2), (CartesianIndex(1, 2),)) - b = copy(a) - value = randn(elt) - @allowscalar setstoredindex!(b, value, I...) - @allowscalar b[I...] == value - end + a = dev(randn(elt, n, n)) + for I in ((1, 2), (CartesianIndex(1, 2),)) + b = copy(a) + value = randn(elt) + @allowscalar setstoredindex!(b, value, I...) + @allowscalar b[I...] == value + end - # TODO: Should `setunstoredindex!` error by default - # if the value at that index is already stored? - a = dev(randn(elt, n, n)) - for I in ((1, 2), (CartesianIndex(1, 2),)) - b = copy(a) - value = randn(elt) - @test_throws ErrorException setunstoredindex!(b, value, I...) - end + # TODO: Should `setunstoredindex!` error by default + # if the value at that index is already stored? + a = dev(randn(elt, n, n)) + for I in ((1, 2), (CartesianIndex(1, 2),)) + b = copy(a) + value = randn(elt) + @test_throws ErrorException setunstoredindex!(b, value, I...) + end end diff --git a/test/test_diagonal.jl b/test/test_diagonal.jl index 3c5d443..8e85539 100644 --- a/test/test_diagonal.jl +++ b/test/test_diagonal.jl @@ -1,34 +1,34 @@ using LinearAlgebra: Diagonal, diagind using SparseArraysBase: - eachstoredindex, - getstoredindex, - getunstoredindex, - setstoredindex!, - isstored, - storedlength, - storedpairs, - storedvalues + eachstoredindex, + getstoredindex, + getunstoredindex, + setstoredindex!, + isstored, + storedlength, + storedpairs, + storedvalues using Test: @test, @testset # compat with LTS: @static if VERSION ≥ v"1.11" - _diagind = diagind + _diagind = diagind else - function _diagind(x::Diagonal, ::IndexCartesian) - return view(CartesianIndices(x), diagind(x)) - end + function _diagind(x::Diagonal, ::IndexCartesian) + return view(CartesianIndices(x), diagind(x)) + end end elts = (Float32, Float64, Complex{Float32}, Complex{Float64}) @testset "Diagonal{$T}" for T in elts - L = 4 - D = Diagonal(rand(T, 4)) - @test storedlength(D) == 4 - @test eachstoredindex(D) == _diagind(D, IndexCartesian()) - @test isstored(D, 2, 2) - @test getstoredindex(D, 2, 2) == D[2, 2] - @test !isstored(D, 2, 1) - @test getunstoredindex(D, 2, 2) == zero(T) + L = 4 + D = Diagonal(rand(T, 4)) + @test storedlength(D) == 4 + @test eachstoredindex(D) == _diagind(D, IndexCartesian()) + @test isstored(D, 2, 2) + @test getstoredindex(D, 2, 2) == D[2, 2] + @test !isstored(D, 2, 1) + @test getunstoredindex(D, 2, 2) == zero(T) end diff --git a/test/test_exports.jl b/test/test_exports.jl index 15dce45..da47e5d 100644 --- a/test/test_exports.jl +++ b/test/test_exports.jl @@ -1,24 +1,24 @@ using SparseArraysBase: SparseArraysBase using Test: @test, @testset @testset "Test exports" begin - exports = [ - :SparseArraysBase, - :SparseArrayDOK, - :SparseMatrixDOK, - :SparseVectorDOK, - :OneElementArray, - :OneElementMatrix, - :OneElementVector, - :eachstoredindex, - :isstored, - :oneelement, - :sparse, - :sparserand, - :sparserand!, - :sparsezeros, - :storedlength, - :storedpairs, - :storedvalues, - ] - @test issetequal(names(SparseArraysBase), exports) + exports = [ + :SparseArraysBase, + :SparseArrayDOK, + :SparseMatrixDOK, + :SparseVectorDOK, + :OneElementArray, + :OneElementMatrix, + :OneElementVector, + :eachstoredindex, + :isstored, + :oneelement, + :sparse, + :sparserand, + :sparserand!, + :sparsezeros, + :storedlength, + :storedpairs, + :storedvalues, + ] + @test issetequal(names(SparseArraysBase), exports) end diff --git a/test/test_linalg.jl b/test/test_linalg.jl index 98ba4c0..4426fb9 100644 --- a/test/test_linalg.jl +++ b/test/test_linalg.jl @@ -6,48 +6,48 @@ using Test: @test, @testset const rng = StableRNG(123) @testset "mul!" begin - T = Float64 - szA = (2, 2) - szB = (2, 2) - szC = (szA[1], szB[2]) - - for density in 0.0:0.25:1 + T = Float64 + szA = (2, 2) + szB = (2, 2) + szC = (szA[1], szB[2]) + + for density in 0.0:0.25:1 + C = sparserand(rng, T, szC; density) + A = sparserand(rng, T, szA; density) + B = sparserand(rng, T, szB; density) + + check = mul!(Array(C), Array(A), Array(B)) + @test mul!(copy(C), A, B) ≈ check + + check = mul!(Array(C), Array(A)', Array(B)) + @test mul!(copy(C), A', B) ≈ check + + check = mul!(Array(C), Array(A), Array(B)') + @test mul!(copy(C), A, B') ≈ check + + check = mul!(Array(C), Array(A)', Array(B)') + @test mul!(copy(C), A', B') ≈ check + + α = rand(rng, T) + β = rand(rng, T) + check = mul!(Array(C), Array(A), Array(B), α, β) + @test mul!(copy(C), A, B, α, β) ≈ check + end + + # test empty matrix + szA = (2, 0) + szB = (0, 2) + szC = (szA[1], szB[2]) + density = 0.1 C = sparserand(rng, T, szC; density) A = sparserand(rng, T, szA; density) B = sparserand(rng, T, szB; density) - check = mul!(Array(C), Array(A), Array(B)) - @test mul!(copy(C), A, B) ≈ check - - check = mul!(Array(C), Array(A)', Array(B)) - @test mul!(copy(C), A', B) ≈ check - - check = mul!(Array(C), Array(A), Array(B)') - @test mul!(copy(C), A, B') ≈ check - - check = mul!(Array(C), Array(A)', Array(B)') - @test mul!(copy(C), A', B') ≈ check + check1 = mul!(Array(C), Array(A), Array(B)) + @test mul!(copy(C), A, B) ≈ check1 α = rand(rng, T) β = rand(rng, T) - check = mul!(Array(C), Array(A), Array(B), α, β) - @test mul!(copy(C), A, B, α, β) ≈ check - end - - # test empty matrix - szA = (2, 0) - szB = (0, 2) - szC = (szA[1], szB[2]) - density = 0.1 - C = sparserand(rng, T, szC; density) - A = sparserand(rng, T, szA; density) - B = sparserand(rng, T, szB; density) - - check1 = mul!(Array(C), Array(A), Array(B)) - @test mul!(copy(C), A, B) ≈ check1 - - α = rand(rng, T) - β = rand(rng, T) - check2 = mul!(Array(C), Array(A), Array(B), α, β) - @test mul!(copy(C), A, B, α, β) ≈ check2 + check2 = mul!(Array(C), Array(A), Array(B), α, β) + @test mul!(copy(C), A, B, α, β) ≈ check2 end diff --git a/test/test_oneelementarray.jl b/test/test_oneelementarray.jl index 1cb9599..b2ace03 100644 --- a/test/test_oneelementarray.jl +++ b/test/test_oneelementarray.jl @@ -1,111 +1,111 @@ using SparseArraysBase: - OneElementArray, - OneElementMatrix, - OneElementVector, - eachstoredindex, - isstored, - oneelement, - storedlength, - storedpairs, - storedvalues + OneElementArray, + OneElementMatrix, + OneElementVector, + eachstoredindex, + isstored, + oneelement, + storedlength, + storedpairs, + storedvalues using Test: @test, @test_broken, @testset elts = (Float32, Float64, Complex{Float32}, Complex{Float64}) @testset "OneElementArray (eltype=$elt)" for elt in elts - for a in ( - OneElementArray((1, 2), (2, 2)), - OneElementMatrix((1, 2), (2, 2)), - OneElementArray((1, 2), Base.OneTo.((2, 2))), - OneElementMatrix((1, 2), Base.OneTo.((2, 2))), - OneElementArray(Base.OneTo(2) => 1, Base.OneTo(2) => 2), - OneElementMatrix(Base.OneTo(2) => 1, Base.OneTo(2) => 2), - oneelement((1, 2), (2, 2)), - oneelement((1, 2), Base.OneTo.((2, 2))), - oneelement(Base.OneTo(2) => 1, Base.OneTo(2) => 2), - ) - @test a isa OneElementArray{Bool,2} - @test a isa OneElementMatrix{Bool} - @test eltype(a) === Bool - @test size(a) == (2, 2) - @test length(a) == 4 - @test axes(a) == Base.OneTo.((2, 2)) - @test a[1, 1] === zero(Bool) - @test a[2, 1] === zero(Bool) - @test a[1, 2] === one(Bool) - @test a[2, 2] === zero(Bool) - @test storedlength(a) == 1 - @test collect(eachstoredindex(a)) == [CartesianIndex(1, 2)] - @test collect(storedpairs(a)) == [CartesianIndex(1, 2) => 1] - @test collect(storedvalues(a)) == [1] - end - - for a in (OneElementArray(1, 2), OneElementVector(1, 2)) - @test a isa OneElementArray{Bool,1} - @test a isa OneElementVector{Bool} - @test eltype(a) === Bool - @test a[1] === one(Bool) - @test a[2] === zero(Bool) - @test storedlength(a) == 1 - @test collect(eachstoredindex(a)) == [CartesianIndex(1)] - @test collect(storedpairs(a)) == [CartesianIndex(1) => 1] - @test collect(storedvalues(a)) == [1] - end + for a in ( + OneElementArray((1, 2), (2, 2)), + OneElementMatrix((1, 2), (2, 2)), + OneElementArray((1, 2), Base.OneTo.((2, 2))), + OneElementMatrix((1, 2), Base.OneTo.((2, 2))), + OneElementArray(Base.OneTo(2) => 1, Base.OneTo(2) => 2), + OneElementMatrix(Base.OneTo(2) => 1, Base.OneTo(2) => 2), + oneelement((1, 2), (2, 2)), + oneelement((1, 2), Base.OneTo.((2, 2))), + oneelement(Base.OneTo(2) => 1, Base.OneTo(2) => 2), + ) + @test a isa OneElementArray{Bool, 2} + @test a isa OneElementMatrix{Bool} + @test eltype(a) === Bool + @test size(a) == (2, 2) + @test length(a) == 4 + @test axes(a) == Base.OneTo.((2, 2)) + @test a[1, 1] === zero(Bool) + @test a[2, 1] === zero(Bool) + @test a[1, 2] === one(Bool) + @test a[2, 2] === zero(Bool) + @test storedlength(a) == 1 + @test collect(eachstoredindex(a)) == [CartesianIndex(1, 2)] + @test collect(storedpairs(a)) == [CartesianIndex(1, 2) => 1] + @test collect(storedvalues(a)) == [1] + end - a = OneElementArray() - @test eltype(a) === Bool - @test size(a) == () - @test a[] === one(Bool) + for a in (OneElementArray(1, 2), OneElementVector(1, 2)) + @test a isa OneElementArray{Bool, 1} + @test a isa OneElementVector{Bool} + @test eltype(a) === Bool + @test a[1] === one(Bool) + @test a[2] === zero(Bool) + @test storedlength(a) == 1 + @test collect(eachstoredindex(a)) == [CartesianIndex(1)] + @test collect(storedpairs(a)) == [CartesianIndex(1) => 1] + @test collect(storedvalues(a)) == [1] + end - a = OneElementArray{elt}() - @test eltype(a) === elt - @test size(a) == () - @test a[] === one(elt) + a = OneElementArray() + @test eltype(a) === Bool + @test size(a) == () + @test a[] === one(Bool) - for a in ( - OneElementArray{elt}((1, 2), (2, 2)), - OneElementMatrix{elt}((1, 2), (2, 2)), - OneElementArray(one(elt), (1, 2), (2, 2)), - OneElementMatrix(one(elt), (1, 2), (2, 2)), - OneElementArray{elt}((1, 2), Base.OneTo.((2, 2))), - OneElementMatrix{elt}((1, 2), Base.OneTo.((2, 2))), - OneElementArray(one(elt), (1, 2), Base.OneTo.((2, 2))), - OneElementMatrix(one(elt), (1, 2), Base.OneTo.((2, 2))), - OneElementArray{elt}(Base.OneTo(2) => 1, Base.OneTo(2) => 2), - OneElementMatrix{elt}(Base.OneTo(2) => 1, Base.OneTo(2) => 2), - OneElementArray(one(elt), Base.OneTo(2) => 1, Base.OneTo(2) => 2), - OneElementMatrix(one(elt), Base.OneTo(2) => 1, Base.OneTo(2) => 2), - oneelement(elt, (1, 2), (2, 2)), - oneelement(one(elt), (1, 2), (2, 2)), - oneelement(elt, (1, 2), Base.OneTo.((2, 2))), - oneelement(one(elt), (1, 2), Base.OneTo.((2, 2))), - oneelement(elt, Base.OneTo(2) => 1, Base.OneTo(2) => 2), - oneelement(one(elt), Base.OneTo(2) => 1, Base.OneTo(2) => 2), - ) + a = OneElementArray{elt}() @test eltype(a) === elt - @test a[1, 1] === zero(elt) - @test a[2, 1] === zero(elt) - @test a[1, 2] === one(elt) - @test a[2, 2] === zero(elt) - end + @test size(a) == () + @test a[] === one(elt) + + for a in ( + OneElementArray{elt}((1, 2), (2, 2)), + OneElementMatrix{elt}((1, 2), (2, 2)), + OneElementArray(one(elt), (1, 2), (2, 2)), + OneElementMatrix(one(elt), (1, 2), (2, 2)), + OneElementArray{elt}((1, 2), Base.OneTo.((2, 2))), + OneElementMatrix{elt}((1, 2), Base.OneTo.((2, 2))), + OneElementArray(one(elt), (1, 2), Base.OneTo.((2, 2))), + OneElementMatrix(one(elt), (1, 2), Base.OneTo.((2, 2))), + OneElementArray{elt}(Base.OneTo(2) => 1, Base.OneTo(2) => 2), + OneElementMatrix{elt}(Base.OneTo(2) => 1, Base.OneTo(2) => 2), + OneElementArray(one(elt), Base.OneTo(2) => 1, Base.OneTo(2) => 2), + OneElementMatrix(one(elt), Base.OneTo(2) => 1, Base.OneTo(2) => 2), + oneelement(elt, (1, 2), (2, 2)), + oneelement(one(elt), (1, 2), (2, 2)), + oneelement(elt, (1, 2), Base.OneTo.((2, 2))), + oneelement(one(elt), (1, 2), Base.OneTo.((2, 2))), + oneelement(elt, Base.OneTo(2) => 1, Base.OneTo(2) => 2), + oneelement(one(elt), Base.OneTo(2) => 1, Base.OneTo(2) => 2), + ) + @test eltype(a) === elt + @test a[1, 1] === zero(elt) + @test a[2, 1] === zero(elt) + @test a[1, 2] === one(elt) + @test a[2, 2] === zero(elt) + end - a = OneElementArray{elt}((1, 2), (2, 2)) - b = 2a - @test eltype(b) === elt - @test storedlength(b) == 1 - # TODO: Need to preserve that it is a `OneElementArray`. - # Currently falls back to constructing a `SparseArrayDOK`. - @test_broken b isa OneElementMatrix{elt} - @test b == 2 * Array(a) + a = OneElementArray{elt}((1, 2), (2, 2)) + b = 2a + @test eltype(b) === elt + @test storedlength(b) == 1 + # TODO: Need to preserve that it is a `OneElementArray`. + # Currently falls back to constructing a `SparseArrayDOK`. + @test_broken b isa OneElementMatrix{elt} + @test b == 2 * Array(a) - a1 = OneElementArray{elt}(2, (1, 2), (2, 2)) - a2 = OneElementArray{elt}(3, (2, 1), (2, 2)) - b = a1 * a2 - @test eltype(b) === elt - @test b[1, 1] === elt(6) - @test storedlength(b) == 1 - @test isstored(b, 1, 1) - # TODO: Need to preserve that it is a `OneElementArray`. - # Currently falls back to constructing a `SparseArrayDOK`. - @test_broken b isa OneElementMatrix{elt} - @test b == Array(a1) * Array(a2) + a1 = OneElementArray{elt}(2, (1, 2), (2, 2)) + a2 = OneElementArray{elt}(3, (2, 1), (2, 2)) + b = a1 * a2 + @test eltype(b) === elt + @test b[1, 1] === elt(6) + @test storedlength(b) == 1 + @test isstored(b, 1, 1) + # TODO: Need to preserve that it is a `OneElementArray`. + # Currently falls back to constructing a `SparseArrayDOK`. + @test_broken b isa OneElementMatrix{elt} + @test b == Array(a1) * Array(a2) end diff --git a/test/test_sparsearraydok.jl b/test/test_sparsearraydok.jl index ec50f23..bd1b20c 100644 --- a/test/test_sparsearraydok.jl +++ b/test/test_sparsearraydok.jl @@ -4,21 +4,21 @@ using Dictionaries: Dictionary using FillArrays: Zeros using JLArrays: JLArray, @allowscalar using SparseArraysBase: - SparseArraysBase, - SparseArrayDOK, - SparseMatrixDOK, - eachstoredindex, - getstoredindex, - getunstoredindex, - isstored, - setstoredindex!, - setunstoredindex!, - sparse, - sparserand, - sparsezeros, - storedlength, - storedpairs, - storedvalues + SparseArraysBase, + SparseArrayDOK, + SparseMatrixDOK, + eachstoredindex, + getstoredindex, + getunstoredindex, + isstored, + setstoredindex!, + setunstoredindex!, + sparse, + sparserand, + sparsezeros, + storedlength, + storedpairs, + storedvalues using StableRNGs: StableRNG using Test: @test, @test_throws, @testset @@ -26,299 +26,299 @@ elts = (Float32, Float64, Complex{Float32}, Complex{Float64}) # arrayts = (Array, JLArray) arrayts = (Array,) @testset "SparseArrayDOK (arraytype=$arrayt, eltype=$elt)" for arrayt in arrayts, - elt in elts - - dev(x) = adapt(arrayt, x) - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - @test a isa SparseArrayDOK{elt,2} - @test size(a) == (2, 2) - @test a[1] == 0 - @test a[1, 1] == 0 - @test a[1, 1, 1] == 0 - @test a[3] == 12 - @test a[1, 2] == 12 - @test a[1, 2, 1] == 12 - @test storedlength(a) == 1 - @test_throws BoundsError a[5] - @test_throws BoundsError a[1, 3] - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[3] = 12 - for b in (similar(a, Float32, (3, 3)), similar(a, Float32, Base.OneTo.((3, 3)))) - @test b isa SparseArrayDOK{Float32,2} - @test b == zeros(Float32, 3, 3) - @test size(b) == (3, 3) - end - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = similar(a) - bc = Broadcast.Broadcasted(x -> 2x, (a,)) - copyto!(b, bc) - @test b isa SparseArrayDOK{elt,2} - @test b == [0 24; 0 0] - @test storedlength(b) == 1 - - # isstored - a = SparseArrayDOK{elt}(undef, 4, 4) - a[2, 3] = 23 - for (I, i) in zip(CartesianIndices(a), LinearIndices(a)) - if I == CartesianIndex(2, 3) - @test isstored(a, I) - @test isstored(a, Tuple(I)...) - @test isstored(a, i) - else - @test !isstored(a, I) - @test !isstored(a, Tuple(I)...) - @test !isstored(a, i) - end - end - - # isstored SubArray - a′ = SparseArrayDOK{elt}(undef, 4, 4) - a′[2, 3] = 23 - a = @view a′[2:3, 2:3] - for I in CartesianIndices(a) - if I == CartesianIndex(1, 2) - @test isstored(a, I) - @test isstored(a, Tuple(I)...) - else - @test !isstored(a, I) - @test !isstored(a, Tuple(I)...) + elt in elts + + dev(x) = adapt(arrayt, x) + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + @test a isa SparseArrayDOK{elt, 2} + @test size(a) == (2, 2) + @test a[1] == 0 + @test a[1, 1] == 0 + @test a[1, 1, 1] == 0 + @test a[3] == 12 + @test a[1, 2] == 12 + @test a[1, 2, 1] == 12 + @test storedlength(a) == 1 + @test_throws BoundsError a[5] + @test_throws BoundsError a[1, 3] + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[3] = 12 + for b in (similar(a, Float32, (3, 3)), similar(a, Float32, Base.OneTo.((3, 3)))) + @test b isa SparseArrayDOK{Float32, 2} + @test b == zeros(Float32, 3, 3) + @test size(b) == (3, 3) end - end - - # vector - a = SparseArrayDOK{elt}(undef, 2) - a[2] = 12 - @test b[1] == 0 - @test a[2] == 12 - @test storedlength(a) == 1 - - a = SparseArrayDOK{elt}(undef, 3, 3, 3) - a[1, 2, 3] = 123 - b = permutedims(a, (2, 3, 1)) - @test b isa SparseArrayDOK{elt,3} - @test b[2, 3, 1] == 123 - @test storedlength(b) == 1 - @test b[1] == 0 - @test b[LinearIndices(b)[2, 3, 1]] == 123 - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = copy(a') - @test b isa SparseArrayDOK{elt,2} - @test b == [0 0; 12 0] - @test storedlength(b) == 1 - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = map(x -> 2x, a) - @test b isa SparseArrayDOK{elt,2} - @test b == [0 24; 0 0] - @test storedlength(b) == 1 - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = a * a' - @test b isa SparseArrayDOK{elt,2} - @test b == [144 0; 0 0] - @test storedlength(b) == 1 - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = a .+ 2 .* a' - @test b isa SparseArrayDOK{elt,2} - @test b == [0 12; 24 0] - @test storedlength(b) == 2 - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = a[1:2, 2] - @test b isa SparseArrayDOK{elt,1} - @test b == [12, 0] - @test storedlength(b) == 1 - - a = SparseArrayDOK{elt}(undef, 2, 2) - @test iszero(a) - a[2, 1] = 21 - a[1, 2] = 12 - @test !iszero(a) - @test isreal(a) - @test sum(a) == 33 - @test mapreduce(x -> 2x, +, a) == 66 - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = similar(a) - copyto!(b, a) - @test b isa SparseArrayDOK{elt,2} - @test b == a - @test b[1, 2] == 12 - @test storedlength(b) == 1 - - a = SparseArrayDOK{elt}(undef, 2, 2) - a .= 2 - @test storedlength(a) == length(a) - for I in eachindex(a) - @test a[I] == 2 - end - - a = SparseArrayDOK{elt}(undef, 2, 2) - fill!(a, 2) - @test storedlength(a) == length(a) - for I in eachindex(a) - @test a[I] == 2 - end - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - zero!(a) - @test iszero(a) - @test iszero(storedlength(a)) - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = zero(a) - @test b isa SparseArrayDOK{elt,2} - @test iszero(b) - @test iszero(storedlength(b)) - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = SparseArrayDOK{elt}(undef, 4, 4) - b[2:3, 2:3] .= a - @test isone(storedlength(b)) - @test b[2, 3] == 12 - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = SparseArrayDOK{elt}(undef, 4, 4) - b[2:3, 2:3] = a - @test isone(storedlength(b)) - @test b[2, 3] == 12 - - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 2] = 12 - b = SparseArrayDOK{elt}(undef, 4, 4) - c = @view b[2:3, 2:3] - c .= a - @test isone(storedlength(b)) - @test b[2, 3] == 12 - - a1 = SparseArrayDOK{elt}(undef, 2, 2) - a1[1, 2] = 12 - a2 = SparseArrayDOK{elt}(undef, 2, 2) - a2[2, 1] = 21 - b = cat(a1, a2; dims=(1, 2)) - @test b isa SparseArrayDOK{elt,2} - @test storedlength(b) == 2 - @test b[1, 2] == 12 - @test b[4, 3] == 21 - - if elt === Float64 - # Printing - # Not testing other element types since they change the - # spacing so it isn't easy to make the test general. + a = SparseArrayDOK{elt}(undef, 2, 2) a[1, 2] = 12 - @test sprint(show, "text/plain", a) == - "$(summary(a)):\n ⋅ $(eltype(a)(12))\n ⋅ ⋅ " + b = similar(a) + bc = Broadcast.Broadcasted(x -> 2x, (a,)) + copyto!(b, bc) + @test b isa SparseArrayDOK{elt, 2} + @test b == [0 24; 0 0] + @test storedlength(b) == 1 + + # isstored + a = SparseArrayDOK{elt}(undef, 4, 4) + a[2, 3] = 23 + for (I, i) in zip(CartesianIndices(a), LinearIndices(a)) + if I == CartesianIndex(2, 3) + @test isstored(a, I) + @test isstored(a, Tuple(I)...) + @test isstored(a, i) + else + @test !isstored(a, I) + @test !isstored(a, Tuple(I)...) + @test !isstored(a, i) + end + end - a = SparseArrayDOK{elt}(undef, 2) - a[1] = 1 - @test sprint(show, "text/plain", a) == "$(summary(a)):\n $(eltype(a)(1))\n ⋅ " - end - - # Regression test for: - # https://github.com/ITensor/SparseArraysBase.jl/issues/19 - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 1] = 1 - a .*= 2 - @test a == [2 0; 0 0] - @test storedlength(a) == 1 - - # Test aliasing behavior. - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 1] = 11 - a[1, 2] = 12 - a[2, 2] = 22 - c1 = @view a[:, 1] - r1 = @view a[1, :] - r1 .= c1 - @test c1 == [11, 0] - @test storedlength(c1) == 1 - @test r1 == [11, 0] - @test storedlength(r1) == 2 - @test a == [11 0; 0 22] - @test storedlength(a) == 3 - - # Test aliasing behavior. - a = SparseArrayDOK{elt}(undef, 2, 2) - a[1, 1] = 11 - a[1, 2] = 12 - a[2, 2] = 22 - c1 = @view a[:, 1] - r1 = @view a[1, :] - c1 .= r1 - @test c1 == [11, 12] - @test storedlength(c1) == 2 - @test r1 == [11, 12] - @test storedlength(r1) == 2 - @test a == [11 12; 12 22] - @test storedlength(a) == 4 - - for d in ( - Dict([CartesianIndex(1, 2) => elt(12), CartesianIndex(2, 1) => elt(21)]), - Dictionary([CartesianIndex(1, 2), CartesianIndex(2, 1)], [elt(12), elt(21)]), - ) - for a in ( - sparse(d, 2, 2), - sparse(d, Zeros{elt}(2, 2)), - sparse(d, (2, 2)), - # Determine the size automatically. - sparse(d), - ) - @test !iszero(a) - @test iszero(a[1, 1]) - @test a[2, 1] == elt(21) - @test a[1, 2] == elt(12) - @test iszero(a[2, 2]) - @test size(a) == (2, 2) - @test storedlength(a) == 2 - @test eltype(a) === elt - @test a isa SparseMatrixDOK{elt} + # isstored SubArray + a′ = SparseArrayDOK{elt}(undef, 4, 4) + a′[2, 3] = 23 + a = @view a′[2:3, 2:3] + for I in CartesianIndices(a) + if I == CartesianIndex(1, 2) + @test isstored(a, I) + @test isstored(a, Tuple(I)...) + else + @test !isstored(a, I) + @test !isstored(a, Tuple(I)...) + end end - end - - for (a, elt′) in ( - (sparsezeros(elt, 2, 2), elt), - (sparsezeros(elt, Zeros{elt}(2, 2)), elt), - (sparsezeros(elt, (2, 2)), elt), - (sparsezeros(2, 2), Float64), - (sparsezeros(Zeros{Float64}(2, 2)), Float64), - (sparsezeros((2, 2)), Float64), - ) + + # vector + a = SparseArrayDOK{elt}(undef, 2) + a[2] = 12 + @test b[1] == 0 + @test a[2] == 12 + @test storedlength(a) == 1 + + a = SparseArrayDOK{elt}(undef, 3, 3, 3) + a[1, 2, 3] = 123 + b = permutedims(a, (2, 3, 1)) + @test b isa SparseArrayDOK{elt, 3} + @test b[2, 3, 1] == 123 + @test storedlength(b) == 1 + @test b[1] == 0 + @test b[LinearIndices(b)[2, 3, 1]] == 123 + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = copy(a') + @test b isa SparseArrayDOK{elt, 2} + @test b == [0 0; 12 0] + @test storedlength(b) == 1 + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = map(x -> 2x, a) + @test b isa SparseArrayDOK{elt, 2} + @test b == [0 24; 0 0] + @test storedlength(b) == 1 + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = a * a' + @test b isa SparseArrayDOK{elt, 2} + @test b == [144 0; 0 0] + @test storedlength(b) == 1 + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = a .+ 2 .* a' + @test b isa SparseArrayDOK{elt, 2} + @test b == [0 12; 24 0] + @test storedlength(b) == 2 + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = a[1:2, 2] + @test b isa SparseArrayDOK{elt, 1} + @test b == [12, 0] + @test storedlength(b) == 1 + + a = SparseArrayDOK{elt}(undef, 2, 2) @test iszero(a) - @test size(a) == (2, 2) - @test storedlength(a) == 0 - @test eltype(a) === elt′ - @test a isa SparseMatrixDOK{elt′} - end - - rng = StableRNG(123) - for (a, elt′) in ( - (sparserand(rng, elt, 20, 20; density=0.5), elt), - (sparserand(rng, elt, (20, 20); density=0.5), elt), - (sparserand(rng, 20, 20; density=0.5), Float64), - (sparserand(rng, (20, 20); density=0.5), Float64), - ) + a[2, 1] = 21 + a[1, 2] = 12 @test !iszero(a) - @test size(a) == (20, 20) - @test !iszero(storedlength(a)) - @test eltype(a) === elt′ - @test a isa SparseMatrixDOK{elt′} - end + @test isreal(a) + @test sum(a) == 33 + @test mapreduce(x -> 2x, +, a) == 66 + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = similar(a) + copyto!(b, a) + @test b isa SparseArrayDOK{elt, 2} + @test b == a + @test b[1, 2] == 12 + @test storedlength(b) == 1 + + a = SparseArrayDOK{elt}(undef, 2, 2) + a .= 2 + @test storedlength(a) == length(a) + for I in eachindex(a) + @test a[I] == 2 + end + + a = SparseArrayDOK{elt}(undef, 2, 2) + fill!(a, 2) + @test storedlength(a) == length(a) + for I in eachindex(a) + @test a[I] == 2 + end + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + zero!(a) + @test iszero(a) + @test iszero(storedlength(a)) + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = zero(a) + @test b isa SparseArrayDOK{elt, 2} + @test iszero(b) + @test iszero(storedlength(b)) + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = SparseArrayDOK{elt}(undef, 4, 4) + b[2:3, 2:3] .= a + @test isone(storedlength(b)) + @test b[2, 3] == 12 + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = SparseArrayDOK{elt}(undef, 4, 4) + b[2:3, 2:3] = a + @test isone(storedlength(b)) + @test b[2, 3] == 12 + + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + b = SparseArrayDOK{elt}(undef, 4, 4) + c = @view b[2:3, 2:3] + c .= a + @test isone(storedlength(b)) + @test b[2, 3] == 12 + + a1 = SparseArrayDOK{elt}(undef, 2, 2) + a1[1, 2] = 12 + a2 = SparseArrayDOK{elt}(undef, 2, 2) + a2[2, 1] = 21 + b = cat(a1, a2; dims = (1, 2)) + @test b isa SparseArrayDOK{elt, 2} + @test storedlength(b) == 2 + @test b[1, 2] == 12 + @test b[4, 3] == 21 + + if elt === Float64 + # Printing + # Not testing other element types since they change the + # spacing so it isn't easy to make the test general. + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 2] = 12 + @test sprint(show, "text/plain", a) == + "$(summary(a)):\n ⋅ $(eltype(a)(12))\n ⋅ ⋅ " + + a = SparseArrayDOK{elt}(undef, 2) + a[1] = 1 + @test sprint(show, "text/plain", a) == "$(summary(a)):\n $(eltype(a)(1))\n ⋅ " + end + + # Regression test for: + # https://github.com/ITensor/SparseArraysBase.jl/issues/19 + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 1] = 1 + a .*= 2 + @test a == [2 0; 0 0] + @test storedlength(a) == 1 + + # Test aliasing behavior. + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 1] = 11 + a[1, 2] = 12 + a[2, 2] = 22 + c1 = @view a[:, 1] + r1 = @view a[1, :] + r1 .= c1 + @test c1 == [11, 0] + @test storedlength(c1) == 1 + @test r1 == [11, 0] + @test storedlength(r1) == 2 + @test a == [11 0; 0 22] + @test storedlength(a) == 3 + + # Test aliasing behavior. + a = SparseArrayDOK{elt}(undef, 2, 2) + a[1, 1] = 11 + a[1, 2] = 12 + a[2, 2] = 22 + c1 = @view a[:, 1] + r1 = @view a[1, :] + c1 .= r1 + @test c1 == [11, 12] + @test storedlength(c1) == 2 + @test r1 == [11, 12] + @test storedlength(r1) == 2 + @test a == [11 12; 12 22] + @test storedlength(a) == 4 + + for d in ( + Dict([CartesianIndex(1, 2) => elt(12), CartesianIndex(2, 1) => elt(21)]), + Dictionary([CartesianIndex(1, 2), CartesianIndex(2, 1)], [elt(12), elt(21)]), + ) + for a in ( + sparse(d, 2, 2), + sparse(d, Zeros{elt}(2, 2)), + sparse(d, (2, 2)), + # Determine the size automatically. + sparse(d), + ) + @test !iszero(a) + @test iszero(a[1, 1]) + @test a[2, 1] == elt(21) + @test a[1, 2] == elt(12) + @test iszero(a[2, 2]) + @test size(a) == (2, 2) + @test storedlength(a) == 2 + @test eltype(a) === elt + @test a isa SparseMatrixDOK{elt} + end + end + + for (a, elt′) in ( + (sparsezeros(elt, 2, 2), elt), + (sparsezeros(elt, Zeros{elt}(2, 2)), elt), + (sparsezeros(elt, (2, 2)), elt), + (sparsezeros(2, 2), Float64), + (sparsezeros(Zeros{Float64}(2, 2)), Float64), + (sparsezeros((2, 2)), Float64), + ) + @test iszero(a) + @test size(a) == (2, 2) + @test storedlength(a) == 0 + @test eltype(a) === elt′ + @test a isa SparseMatrixDOK{elt′} + end + + rng = StableRNG(123) + for (a, elt′) in ( + (sparserand(rng, elt, 20, 20; density = 0.5), elt), + (sparserand(rng, elt, (20, 20); density = 0.5), elt), + (sparserand(rng, 20, 20; density = 0.5), Float64), + (sparserand(rng, (20, 20); density = 0.5), Float64), + ) + @test !iszero(a) + @test size(a) == (20, 20) + @test !iszero(storedlength(a)) + @test eltype(a) === elt′ + @test a isa SparseMatrixDOK{elt′} + end end diff --git a/test/test_unstored.jl b/test/test_unstored.jl index 12a83eb..9125056 100644 --- a/test/test_unstored.jl +++ b/test/test_unstored.jl @@ -3,9 +3,9 @@ using FillArrays: Zeros using Test: @test, @testset @testset "Unstored" begin - a = Zeros(2, 2) - u = Unstored(a) - @test parent(u) ≡ a - @test size(u) ≡ size(a) - @test axes(u) ≡ axes(a) + a = Zeros(2, 2) + u = Unstored(a) + @test parent(u) ≡ a + @test size(u) ≡ size(a) + @test axes(u) ≡ axes(a) end From 7c2ce49685b1dc29ccd83495b89abd8e8560791c Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 2 Oct 2025 14:58:23 -0400 Subject: [PATCH 2/3] Update skeleton --- .github/workflows/CompatHelper.yml | 2 +- .github/workflows/FormatCheck.yml | 13 ++++++++----- .gitignore | 4 ++++ .pre-commit-config.yaml | 8 ++++---- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml index 456fa05..0614de9 100644 --- a/.github/workflows/CompatHelper.yml +++ b/.github/workflows/CompatHelper.yml @@ -2,7 +2,7 @@ name: "CompatHelper" on: schedule: - - cron: 0 0 * * * + - cron: '0 0 * * *' workflow_dispatch: permissions: contents: write diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml index 3f78afc..1525861 100644 --- a/.github/workflows/FormatCheck.yml +++ b/.github/workflows/FormatCheck.yml @@ -1,11 +1,14 @@ name: "Format Check" on: - push: - branches: - - 'main' - tags: '*' - pull_request: + pull_request_target: + paths: ['**/*.jl'] + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + contents: read + actions: write + pull-requests: write jobs: format-check: diff --git a/.gitignore b/.gitignore index 10593a9..7085ca8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,10 @@ .vscode/ Manifest.toml benchmark/*.json +dev/ +docs/LocalPreferences.toml docs/Manifest.toml docs/build/ docs/src/index.md +examples/LocalPreferences.toml +test/LocalPreferences.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 88bc8b4..3fc4743 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ ci: - skip: [julia-formatter] + skip: [runic] repos: - repo: https://github.com/pre-commit/pre-commit-hooks @@ -11,7 +11,7 @@ repos: - id: end-of-file-fixer exclude_types: [markdown] # incompatible with Literate.jl -- repo: "https://github.com/domluna/JuliaFormatter.jl" - rev: v2.1.6 +- repo: https://github.com/fredrikekre/runic-pre-commit + rev: v2.0.1 hooks: - - id: "julia-formatter" + - id: runic From cf152453119ebfd34a474ec99510f589dce20424 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 2 Oct 2025 15:15:39 -0400 Subject: [PATCH 3/3] Update README and version --- Project.toml | 2 +- README.md | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Project.toml b/Project.toml index d7a8a21..ab15cdb 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "SparseArraysBase" uuid = "0d5efcca-f356-4864-8770-e1ed8d78f208" authors = ["ITensor developers and contributors"] -version = "0.7.4" +version = "0.7.5" [deps] Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" diff --git a/README.md b/README.md index dc22266..46718c0 100644 --- a/README.md +++ b/README.md @@ -43,19 +43,19 @@ julia> Pkg.add("SparseArraysBase") ````julia using SparseArraysBase: - SparseArrayDOK, - SparseMatrixDOK, - SparseVectorDOK, - eachstoredindex, - getstoredindex, - getunstoredindex, - isstored, - setstoredindex!, - setunstoredindex!, - storedlength, - storedpairs, - storedvalues, - zero! + SparseArrayDOK, + SparseMatrixDOK, + SparseVectorDOK, + eachstoredindex, + getstoredindex, + getunstoredindex, + isstored, + setstoredindex!, + setunstoredindex!, + storedlength, + storedpairs, + storedvalues, + zero! using Test: @test, @test_throws a = SparseArrayDOK{Float64}(undef, 2, 2) @@ -135,14 +135,14 @@ b = a[1:2, 2] a = SparseArrayDOK{Float64}(undef, 2, 2) a .= 2 for I in eachindex(a) - @test a[I] == 2 + @test a[I] == 2 end @test storedlength(a) == length(a) a = SparseArrayDOK{Float64}(undef, 2, 2) fill!(a, 2) for I in eachindex(a) - @test a[I] == 2 + @test a[I] == 2 end @test storedlength(a) == length(a)