diff --git a/Project.toml b/Project.toml index 321cdfbf..a77bcd37 100644 --- a/Project.toml +++ b/Project.toml @@ -1,16 +1,16 @@ name = "BlockSparseArrays" uuid = "2c9a651f-6452-4ace-a6ac-809f4280fbb4" authors = ["ITensor developers and contributors"] -version = "0.10.15" +version = "0.10.16" [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -DerivableInterfaces = "6c5e35bf-e59e-4898-b73c-732dcc4ba65f" DiagonalArrays = "74fd4be6-21e2-4f6f-823a-4360d37c7a77" Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" +FunctionImplementations = "7c7cc465-9c6a-495f-bdd1-f42428e86d0c" GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" @@ -28,29 +28,22 @@ BlockSparseArraysTensorAlgebraExt = "TensorAlgebra" [compat] Adapt = "4.1.1" -Aqua = "0.8.9" ArrayLayouts = "1.10.4" BlockArrays = "1.2" -DerivableInterfaces = "0.5.3" DiagonalArrays = "0.3" Dictionaries = "0.4.3" FillArrays = "1.13" +FunctionImplementations = "0.3.1" GPUArraysCore = "0.1, 0.2" LinearAlgebra = "1.10" MacroTools = "0.5.13" MapBroadcast = "0.1.5" MatrixAlgebraKit = "0.6" -SparseArraysBase = "0.7.1" +SparseArraysBase = "0.8.3" SplitApplyCombine = "1.2.3" TensorAlgebra = "0.6.2" -Test = "1.10" TypeParameterAccessors = "0.4.1" julia = "1.10" -[extras] -Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" -GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[targets] -test = ["Aqua", "Test"] +[workspace] +projects = ["benchmark", "dev", "docs", "examples", "test"] diff --git a/docs/Project.toml b/docs/Project.toml index 6f5417fd..a7dd160b 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -4,6 +4,9 @@ BlockSparseArrays = "2c9a651f-6452-4ace-a6ac-809f4280fbb4" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" +[sources] +BlockSparseArrays = {path = ".."} + [compat] BlockArrays = "1" BlockSparseArrays = "0.10" diff --git a/examples/Project.toml b/examples/Project.toml index 14c5df39..a227724c 100644 --- a/examples/Project.toml +++ b/examples/Project.toml @@ -3,6 +3,9 @@ BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" BlockSparseArrays = "2c9a651f-6452-4ace-a6ac-809f4280fbb4" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +[sources] +BlockSparseArrays = {path = ".."} + [compat] BlockArrays = "1" BlockSparseArrays = "0.10" diff --git a/src/BlockArraysExtensions/BlockArraysExtensions.jl b/src/BlockArraysExtensions/BlockArraysExtensions.jl index b7ac41e3..f8effec8 100644 --- a/src/BlockArraysExtensions/BlockArraysExtensions.jl +++ b/src/BlockArraysExtensions/BlockArraysExtensions.jl @@ -172,7 +172,7 @@ Base.view(S::BlockIndices, i) = S[i] # @view b[Block(1, 1)[1:2, 2:2]] # ``` # This is similar to the definition: -# @interface interface(a) to_indices(a, inds, I::Tuple{UnitRange{<:Integer},Vararg{Any}}) +# style(a)(to_indices)(a, inds, I::Tuple{UnitRange{<:Integer},Vararg{Any}}) function Base.getindex( a::NonBlockedVector{<:Integer, <:BlockIndices}, I::UnitRange{<:Integer} ) diff --git a/src/abstractblocksparsearray/abstractblocksparsearray.jl b/src/abstractblocksparsearray/abstractblocksparsearray.jl index 5d4c7f34..8f833917 100644 --- a/src/abstractblocksparsearray/abstractblocksparsearray.jl +++ b/src/abstractblocksparsearray/abstractblocksparsearray.jl @@ -1,5 +1,6 @@ using BlockArrays: BlockArrays, AbstractBlockArray, Block, BlockIndex, BlockedUnitRange, blocks +using FunctionImplementations: style abstract type AbstractBlockSparseArray{T, N} <: AbstractBlockArray{T, N} end @@ -19,12 +20,12 @@ end # Specialized in order to fix ambiguity error with `BlockArrays`. function Base.getindex(a::AbstractBlockSparseArray{<:Any, N}, I::Vararg{Int, N}) where {N} - return @interface interface(a) getindex(a, I...) + return style(a)(getindex)(a, I...) end # Specialized in order to fix ambiguity error with `BlockArrays`. function Base.getindex(a::AbstractBlockSparseArray{<:Any, 0}) - return @interface interface(a) getindex(a) + return style(a)(getindex)(a) end ## # Fix ambiguity error with `BlockArrays`. @@ -39,7 +40,7 @@ end ## ## # Fix ambiguity error with `BlockArrays`. ## function Base.getindex(a::AbstractBlockSparseArray, I::Vararg{AbstractVector}) -## ## return @interface interface(a) getindex(a, I...) +## ## return style(a)(getindex)(a, I...) ## return ArrayLayouts.layout_getindex(a, I...) ## end @@ -47,13 +48,13 @@ end function Base.setindex!( a::AbstractBlockSparseArray{<:Any, N}, value, I::Vararg{Int, N} ) where {N} - @interface interface(a) setindex!(a, value, I...) + style(a)(setindex!)(a, value, I...) return a end # Fix ambiguity error. function Base.setindex!(a::AbstractBlockSparseArray{<:Any, 0}, value) - @interface interface(a) setindex!(a, value) + style(a)(setindex!)(a, value) return a end diff --git a/src/abstractblocksparsearray/broadcast.jl b/src/abstractblocksparsearray/broadcast.jl index d2868ee8..9ea3e159 100644 --- a/src/abstractblocksparsearray/broadcast.jl +++ b/src/abstractblocksparsearray/broadcast.jl @@ -1,12 +1,12 @@ using BlockArrays: AbstractBlockedUnitRange, BlockSlice -using Base.Broadcast: Broadcast, BroadcastStyle +using Base.Broadcast: BroadcastStyle -function Broadcast.BroadcastStyle(arraytype::Type{<:AnyAbstractBlockSparseArray}) - return BlockSparseArrayStyle(BroadcastStyle(blocktype(arraytype))) +function Base.Broadcast.BroadcastStyle(arraytype::Type{<:AnyAbstractBlockSparseArray}) + return Broadcast.BlockSparseArrayStyle(BroadcastStyle(blocktype(arraytype))) end # Fix ambiguity error with `BlockArrays`. -function Broadcast.BroadcastStyle( +function Base.Broadcast.BroadcastStyle( arraytype::Type{ <:SubArray{ <:Any, @@ -16,9 +16,9 @@ function Broadcast.BroadcastStyle( }, }, ) - return BlockSparseArrayStyle{ndims(arraytype)}() + return Broadcast.BlockSparseArrayStyle{ndims(arraytype)}() end -function Broadcast.BroadcastStyle( +function Base.Broadcast.BroadcastStyle( arraytype::Type{ <:SubArray{ <:Any, @@ -32,9 +32,9 @@ function Broadcast.BroadcastStyle( }, }, ) - return BlockSparseArrayStyle{ndims(arraytype)}() + return Broadcast.BlockSparseArrayStyle{ndims(arraytype)}() end -function Broadcast.BroadcastStyle( +function Base.Broadcast.BroadcastStyle( arraytype::Type{ <:SubArray{ <:Any, @@ -44,25 +44,22 @@ function Broadcast.BroadcastStyle( }, }, ) - return BlockSparseArrayStyle{ndims(arraytype)}() + return Broadcast.BlockSparseArrayStyle{ndims(arraytype)}() end # These catch cases that aren't caught by the standard # `BlockSparseArrayStyle` definition, and also fix # ambiguity issues. function Base.copyto!(dest::AnyAbstractBlockSparseArray, bc::Broadcasted) - copyto_blocksparse!(dest, bc) - return dest + return copyto!_blocksparse(dest, bc) end function Base.copyto!( dest::AnyAbstractBlockSparseArray, bc::Broadcasted{<:Base.Broadcast.AbstractArrayStyle{0}} ) - copyto_blocksparse!(dest, bc) - return dest + return copyto!_blocksparse(dest, bc) end function Base.copyto!( - dest::AnyAbstractBlockSparseArray{<:Any, N}, bc::Broadcasted{BlockSparseArrayStyle{N}} + dest::AnyAbstractBlockSparseArray{<:Any, N}, bc::Broadcasted{<:Broadcast.BlockSparseArrayStyle{N}} ) where {N} - copyto_blocksparse!(dest, bc) - return dest + return copyto!_blocksparse(dest, bc) end diff --git a/src/abstractblocksparsearray/cat.jl b/src/abstractblocksparsearray/cat.jl index 2e31cb3c..57844d7f 100644 --- a/src/abstractblocksparsearray/cat.jl +++ b/src/abstractblocksparsearray/cat.jl @@ -1,5 +1,4 @@ -using DerivableInterfaces: @interface, interface -using DerivableInterfaces.Concatenate: concatenate +using FunctionImplementations.Concatenate: concatenate function Base._cat(dims, as::AnyAbstractBlockSparseArray...) return concatenate(dims, as...) diff --git a/src/abstractblocksparsearray/map.jl b/src/abstractblocksparsearray/map.jl index 2d969f3f..671355fc 100644 --- a/src/abstractblocksparsearray/map.jl +++ b/src/abstractblocksparsearray/map.jl @@ -1,5 +1,6 @@ using ArrayLayouts: LayoutArray using BlockArrays: AbstractBlockVector, Block +using FunctionImplementations: style using LinearAlgebra: Adjoint, Transpose # TODO: Make this more general, independent of `AbstractBlockSparseArray`. @@ -36,17 +37,17 @@ function reblock( end function Base.map!(f, a_dest::AbstractArray, a_srcs::AnyAbstractBlockSparseArray...) - @interface interface(a_dest, a_srcs...) map!(f, a_dest, a_srcs...) + style(a_dest, a_srcs...)(map!)(f, a_dest, a_srcs...) return a_dest end function Base.map!(f, a_dest::AnyAbstractBlockSparseArray, a_srcs::AbstractArray...) - @interface interface(a_dest, a_srcs...) map!(f, a_dest, a_srcs...) + style(a_dest, a_srcs...)(map!)(f, a_dest, a_srcs...) return a_dest end function Base.map!( f, a_dest::AnyAbstractBlockSparseArray, a_srcs::AnyAbstractBlockSparseArray... ) - @interface interface(a_dest, a_srcs...) map!(f, a_dest, a_srcs...) + style(a_dest, a_srcs...)(map!)(f, a_dest, a_srcs...) return a_dest end @@ -55,28 +56,40 @@ function Base.map(f, as::Vararg{AnyAbstractBlockSparseArray}) end function Base.copy!(a_dest::AbstractArray, a_src::AnyAbstractBlockSparseArray) - return @interface interface(a_src) copy!(a_dest, a_src) + return style(a_src)(copy!)(a_dest, a_src) end function Base.copyto!(a_dest::AbstractArray, a_src::AnyAbstractBlockSparseArray) - return @interface interface(a_src) copyto!(a_dest, a_src) + return style(a_src)(copyto!)(a_dest, a_src) end # Fix ambiguity error function Base.copyto!(a_dest::LayoutArray, a_src::AnyAbstractBlockSparseArray) - return @interface interface(a_src) copyto!(a_dest, a_src) + return style(a_src)(copyto!)(a_dest, a_src) end function Base.copyto!( a_dest::AbstractMatrix, a_src::Transpose{T, <:AbstractBlockSparseMatrix{T}} ) where {T} - return @interface interface(a_src) copyto!(a_dest, a_src) + return style(a_src)(copyto!)(a_dest, a_src) end function Base.copyto!( a_dest::AbstractMatrix, a_src::Adjoint{T, <:AbstractBlockSparseMatrix{T}} ) where {T} - return @interface interface(a_src) copyto!(a_dest, a_src) + return style(a_src)(copyto!)(a_dest, a_src) +end + +const copyto!_blocksparse = blocksparse_style(copyto!) +function copyto!_blocksparse(dst::AbstractArray, src::AbstractArray) + # return sparse_style(copyto!)(dst, src) + return map!(identity, dst, src) +end + +const copy!_blocksparse = blocksparse_style(copy!) +function copy!_blocksparse(dst::AbstractArray, src::AbstractArray) + # return sparse_style(copy!)(dst, src) + return copyto!(dst, src) end # This avoids going through the generic version that calls `Base.permutedims!`, @@ -85,7 +98,7 @@ end # `PermutedDimsArray`). # TODO: Handle slicing better in `map!` so that this can be removed. function Base.permutedims(a::AnyAbstractBlockSparseArray, perm) - return @interface interface(a) permutedims(a, perm) + return style(a)(permutedims)(a, perm) end # The `::AbstractBlockSparseArrayInterface` version @@ -96,19 +109,19 @@ end # ``` # TODO: Handle slicing better in `map!` so that this can be removed. function Base.permutedims!(a_dest, a_src::AnyAbstractBlockSparseArray, perm) - return @interface interface(a_src) permutedims!(a_dest, a_src, perm) + return style(a_src)(permutedims!)(a_dest, a_src, perm) end function Base.mapreduce(f, op, as::AnyAbstractBlockSparseArray...; kwargs...) - return @interface interface(as...) mapreduce(f, op, as...; kwargs...) + return style(as...)(mapreduce)(f, op, as...; kwargs...) end function Base.iszero(a::AnyAbstractBlockSparseArray) - return @interface interface(a) iszero(a) + return style(a)(iszero)(a) end function Base.isreal(a::AnyAbstractBlockSparseArray) - return @interface interface(a) isreal(a) + return style(a)(isreal)(a) end # Helps with specialization of block operations by avoiding diff --git a/src/abstractblocksparsearray/sparsearrayinterface.jl b/src/abstractblocksparsearray/sparsearrayinterface.jl index 23dd9df7..54a0fc77 100644 --- a/src/abstractblocksparsearray/sparsearrayinterface.jl +++ b/src/abstractblocksparsearray/sparsearrayinterface.jl @@ -36,7 +36,6 @@ end ## return BlockSparseStorage(a) ## end -# TODO: Turn this into an `@interface ::AbstractBlockSparseArrayInterface` function. function SparseArraysBase.storedlength(a::AnyAbstractBlockSparseArray) return sum(storedlength, storedvalues(blocks(a)); init = zero(Int)) end diff --git a/src/abstractblocksparsearray/unblockedsubarray.jl b/src/abstractblocksparsearray/unblockedsubarray.jl index 4180745b..fee26f27 100644 --- a/src/abstractblocksparsearray/unblockedsubarray.jl +++ b/src/abstractblocksparsearray/unblockedsubarray.jl @@ -1,5 +1,5 @@ using ArrayLayouts: ArrayLayouts, MemoryLayout -using Base.Broadcast: Broadcast, BroadcastStyle +using Base.Broadcast: BroadcastStyle using BlockArrays: BlockArrays, Block, BlockIndexRange, BlockSlice using TypeParameterAccessors: TypeParameterAccessors, parenttype, similartype @@ -18,18 +18,25 @@ function BlockArrays.blocks(a::UnblockedSubArray) return SingleBlockView(a) end -function DerivableInterfaces.interface(arraytype::Type{<:UnblockedSubArray}) - return interface(blocktype(parenttype(arraytype))) +using FunctionImplementations: FunctionImplementations, Style +function FunctionImplementations.Style(arraytype::Type{<:UnblockedSubArray}) + return Style(blocktype(parenttype(arraytype))) end function ArrayLayouts.MemoryLayout(arraytype::Type{<:UnblockedSubArray}) return MemoryLayout(blocktype(parenttype(arraytype))) end -function Broadcast.BroadcastStyle(arraytype::Type{<:UnblockedSubArray}) +function Base.Broadcast.BroadcastStyle(arraytype::Type{<:UnblockedSubArray}) return BroadcastStyle(blocktype(parenttype(arraytype))) end +function Base.similar(a::UnblockedSubArray) + return similar(a, eltype(a)) +end +function Base.similar(a::UnblockedSubArray, elt::Type) + return similar(a, elt, axes(a)) +end function Base.similar( a::UnblockedSubArray, elt::Type, axes::Tuple{Base.OneTo, Vararg{Base.OneTo}} ) @@ -39,6 +46,10 @@ function Base.similar(a::UnblockedSubArray, elt::Type, size::Tuple{Int, Vararg{I return similar(a, elt, Base.OneTo.(size)) end +function Base.copyto!(dst::AbstractArray, src::UnblockedSubArray) + return @invoke copyto!(dst::AbstractArray, src::AbstractArray) +end + function ArrayLayouts.sub_materialize(a::UnblockedSubArray) a_cpu = adapt(Array, a) a_cpu′ = similar(a_cpu) diff --git a/src/abstractblocksparsearray/views.jl b/src/abstractblocksparsearray/views.jl index edddc77b..7c45f0ac 100644 --- a/src/abstractblocksparsearray/views.jl +++ b/src/abstractblocksparsearray/views.jl @@ -7,6 +7,7 @@ using BlockArrays: blocklength, blocksize, viewblock +using FunctionImplementations: style # This splits `BlockIndexRange{N}` into # `NTuple{N,BlockIndexRange{1}}`. @@ -39,7 +40,7 @@ function Base.view( }, I::Block{N}, ) where {N} - return @interface interface(a) view(a, I) + return style(a)(view)(a, I) end function Base.view( a::SubArray{ @@ -47,13 +48,13 @@ function Base.view( }, I::Vararg{Block{1}, N}, ) where {N} - return @interface interface(a) view(a, I...) + return style(a)(view)(a, I...) end function Base.view( V::SubArray{<:Any, 1, <:AnyAbstractBlockSparseArray, <:Tuple{BlockSlice{<:BlockRange{1}}}}, I::Block{1}, ) - return @interface interface(a) view(a, I) + return style(a)(view)(a, I) end # Specialized code for getting the view of a block. @@ -63,7 +64,7 @@ function BlockArrays.viewblock( return viewblock(a, Tuple(block)...) end -# TODO: Define `@interface interface(a) viewblock`. +# TODO: Define `style(a)(viewblock)`. function BlockArrays.viewblock( a::AbstractBlockSparseArray{<:Any, N}, block::Vararg{Block{1}, N} ) where {N} @@ -212,9 +213,9 @@ end # XXX: TODO: Distinguish if a sub-view of the block needs to be taken! # Define a new `SubBlockSlice` which is used in: -# `@interface interface(a) to_indices(a, inds, I::Tuple{UnitRange{<:Integer},Vararg{Any}})` +# `style(a)(to_indices)(a, inds, I::Tuple{UnitRange{<:Integer},Vararg{Any}})` # in `blocksparsearrayinterface/blocksparsearrayinterface.jl`. -# TODO: Define `@interface interface(a) viewblock`. +# TODO: Define `style(a)(viewblock)`. function BlockArrays.viewblock( a::SubArray{T, N, <:AbstractBlockSparseArray{T, N}, <:Tuple{Vararg{BlockSliceCollection, N}}}, block::Vararg{Block{1}, N}, @@ -281,7 +282,7 @@ function BlockArrays.viewblock( return @view parent(a)[brs...] end -# TODO: Define `@interface interface() viewblock`. +# TODO: Define `style(a)(viewblock)`. function BlockArrays.viewblock( a::SubArray{ T, @@ -345,7 +346,7 @@ function blockedslice_blocks(x::Base.Slice) ) end -# TODO: Define `@interface interface(a) viewblock`. +# TODO: Define `style(a)(viewblock)`. function BlockArrays.viewblock( a::SubArray{ T, N, <:AbstractBlockSparseArray{T, N}, <:Tuple{Vararg{SubBlockSliceCollection, N}}, @@ -362,7 +363,7 @@ function BlockArrays.viewblock( return @view parent(a)[brs...] end -# TODO: Define `@interface interface(a) viewblock`. +# TODO: Define `style(a)(viewblock)`. function BlockArrays.viewblock( a::SubArray{ T, N, <:AbstractBlockSparseArray{T, N}, <:Tuple{Vararg{SubBlockSliceCollection, N}}, diff --git a/src/abstractblocksparsearray/wrappedabstractblocksparsearray.jl b/src/abstractblocksparsearray/wrappedabstractblocksparsearray.jl index d85fbb47..9cce969a 100644 --- a/src/abstractblocksparsearray/wrappedabstractblocksparsearray.jl +++ b/src/abstractblocksparsearray/wrappedabstractblocksparsearray.jl @@ -9,7 +9,7 @@ using BlockArrays: blockedrange, mortar, unblock -using DerivableInterfaces: DerivableInterfaces, @interface, DefaultArrayInterface, zero! +using FunctionImplementations: FunctionImplementations, Style, style, zero! using GPUArraysCore: @allowscalar using SplitApplyCombine: groupcount using TypeParameterAccessors: similartype @@ -28,35 +28,35 @@ const AnyAbstractBlockSparseVecOrMat{T, N} = Union{ AnyAbstractBlockSparseVector{T}, AnyAbstractBlockSparseMatrix{T}, } -function DerivableInterfaces.interface(arrayt::Type{<:AnyAbstractBlockSparseArray}) - return BlockSparseArrayInterface(interface(blocktype(arrayt))) +function FunctionImplementations.Style(arrayt::Type{<:AnyAbstractBlockSparseArray}) + return BlockSparseArrayStyle() end # a[1:2, 1:2] function Base.to_indices( a::AnyAbstractBlockSparseArray, inds, I::Tuple{UnitRange{<:Integer}, Vararg{Any}} ) - return @interface interface(a) to_indices(a, inds, I) + return style(a)(to_indices)(a, inds, I) end function Base.to_indices( a::AnyAbstractBlockSparseArray, inds, I::Tuple{AbstractArray{Bool}, Vararg{Any}} ) - return @interface interface(a) to_indices(a, inds, I) + return style(a)(to_indices)(a, inds, I) end # Fix ambiguity error with Base for logical indexing in Julia 1.10. # TODO: Delete this once we drop support for Julia 1.10. function Base.to_indices( a::AnyAbstractBlockSparseArray, inds, I::Union{Tuple{BitArray{N}}, Tuple{Array{Bool, N}}} ) where {N} - return @interface interface(a) to_indices(a, inds, I) + return style(a)(to_indices)(a, inds, I) end # a[[Block(2), Block(1)], [Block(2), Block(1)]] function Base.to_indices( a::AnyAbstractBlockSparseArray, inds, I::Tuple{Vector{<:Block{1}}, Vararg{Any}} ) - return @interface interface(a) to_indices(a, inds, I) + return style(a)(to_indices)(a, inds, I) end # a[BlockVector([Block(2), Block(1)], [2]), BlockVector([Block(2), Block(1)], [2])] @@ -66,7 +66,7 @@ function Base.to_indices( inds, I::Tuple{AbstractBlockVector{<:Block{1}}, Vararg{Any}}, ) - return @interface interface(a) to_indices(a, inds, I) + return style(a)(to_indices)(a, inds, I) end # a[mortar([Block(1)[1:2], Block(2)[1:3]])] @@ -75,7 +75,7 @@ function Base.to_indices( inds, I::Tuple{BlockVector{<:BlockIndex{1}, <:Vector{<:BlockIndexRange{1}}}, Vararg{Any}}, ) - return @interface interface(a) to_indices(a, inds, I) + return style(a)(to_indices)(a, inds, I) end # a[mortar([Block(1)[[1, 2]], Block(2)[[1, 3]]])] @@ -84,14 +84,14 @@ function Base.to_indices( inds, I::Tuple{BlockVector{<:BlockIndex{1}, <:Vector{<:BlockIndexVector{1}}}, Vararg{Any}}, ) - return @interface interface(a) to_indices(a, inds, I) + return style(a)(to_indices)(a, inds, I) end function Base.to_indices( a::AnyAbstractBlockSparseArray, inds, I::Tuple{BlockVector{<:GenericBlockIndex{1}, <:Vector{<:BlockIndexVector{1}}}, Vararg{Any}}, ) - return @interface interface(a) to_indices(a, inds, I) + return style(a)(to_indices)(a, inds, I) end # a[[Block(1)[1:2], Block(2)[1:2]], [Block(1)[1:2], Block(2)[1:2]]] @@ -110,7 +110,7 @@ end # BlockArrays `AbstractBlockArray` interface function BlockArrays.blocks(a::AnyAbstractBlockSparseArray) - return @interface interface(a) blocks(a) + return style(a)(blocks)(a) end # Fix ambiguity error with `BlockArrays` @@ -118,7 +118,7 @@ using BlockArrays: BlockSlice function BlockArrays.blocks( a::SubArray{<:Any, <:Any, <:AbstractBlockSparseArray, <:Tuple{Vararg{BlockSlice}}} ) - return @interface interface(a) blocks(a) + return style(a)(blocks)(a) end using TypeParameterAccessors: parenttype @@ -151,7 +151,7 @@ function Base.getindex(a::AnyAbstractBlockSparseArray{<:Any, 0}) return ArrayLayouts.layout_getindex(a) end -# TODO: Define `@interface interface(a) isassigned`. +# TODO: Define `style(a)(isassigned)`. function Base.isassigned( a::AnyAbstractBlockSparseArray{<:Any, N}, index::Vararg{Block{1}, N} ) where {N} @@ -167,7 +167,7 @@ function Base.isassigned(a::AnyAbstractBlockSparseArray{<:Any, N}, index::Block{ return isassigned(a, Tuple(index)...) end -# TODO: Define `@interface interface(a) isassigned`. +# TODO: Define `style(a)(isassigned)`. function Base.isassigned( a::AnyAbstractBlockSparseArray{<:Any, N}, index::Vararg{BlockIndex{1}, N} ) where {N} @@ -178,14 +178,12 @@ end function Base.setindex!( a::AnyAbstractBlockSparseArray{<:Any, N}, value, I::BlockIndex{N} ) where {N} - # TODO: Use `@interface interface(a) setindex!(...)`. - @interface interface(a) setindex!(a, value, I) + style(a)(setindex!)(a, value, I) return a end # Fixes ambiguity error with BlockArrays.jl function Base.setindex!(a::AnyAbstractBlockSparseArray{<:Any, 1}, value, I::BlockIndex{1}) - # TODO: Use `@interface interface(a) setindex!(...)`. - @interface interface(a) setindex!(a, value, I) + style(a)(setindex!)(a, value, I) return a end @@ -193,9 +191,8 @@ function ArrayLayouts.zero!(a::AnyAbstractBlockSparseArray) return zero!(a) end -# TODO: Use `@derive`. function Base.fill!(a::AnyAbstractBlockSparseArray, value) - return @interface interface(a) fill!(a, value) + return style(a)(fill!)(a, value) end # Needed by `BlockArrays` matrix multiplication interface @@ -260,61 +257,66 @@ function blocksparse_similar(a, elt::Type, axes::Tuple) blockt′ = !isconcretetype(blockt) ? AbstractArray{elt, ndims} : blockt return BlockSparseArray{elt, ndims, blockt′}(undef, axes) end -@interface ::AbstractBlockSparseArrayInterface function Base.similar( +const similar_blocksparse = blocksparse_style(similar) +function similar_blocksparse( a::AbstractArray, elt::Type, axes::Tuple{Vararg{Int}} ) + # TODO: Define as `_similar_blocksparse`? return blocksparse_similar(a, elt, axes) end -@interface ::AbstractBlockSparseArrayInterface function Base.similar( +function similar_blocksparse( a::AbstractArray, elt::Type, axes::Tuple ) + # TODO: Define as `_similar_blocksparse`? return blocksparse_similar(a, elt, axes) end # Fix ambiguity error when non-blocked ranges are passed. -@interface ::AbstractBlockSparseArrayInterface function Base.similar( +function similar_blocksparse( a::AbstractArray, elt::Type, axes::Tuple{Base.OneTo, Vararg{Base.OneTo}} ) + # TODO: Define as `_similar_blocksparse`? return blocksparse_similar(a, elt, axes) end # Fix ambiguity error when empty axes are passed. -@interface ::AbstractBlockSparseArrayInterface function Base.similar( +function similar_blocksparse( a::AbstractArray, elt::Type, axes::Tuple{} ) + # TODO: Define as `_similar_blocksparse`? return blocksparse_similar(a, elt, axes) end -@interface ::AbstractBlockSparseArrayInterface function Base.similar( +function similar_blocksparse( a::Type{<:AbstractArray}, elt::Type, axes::Tuple{Vararg{Int}} ) + # TODO: Define as `_similar_blocksparse`? return blocksparse_similar(a, elt, axes) end -@interface ::AbstractBlockSparseArrayInterface function Base.similar( +function similar_blocksparse( a::Type{<:AbstractArray}, elt::Type, axes::Tuple ) + # TODO: Define as `_similar_blocksparse`? return blocksparse_similar(a, elt, axes) end # Needed by `BlockArrays` matrix multiplication interface -# TODO: Define a `@interface interface(a) similar` function. function Base.similar( arraytype::Type{<:AnyAbstractBlockSparseArray}, elt::Type, axes::Tuple{Vararg{AbstractUnitRange{<:Integer}}}, ) - return @interface interface(arraytype) similar(arraytype, elt, axes) + return Style(arraytype)(similar)(arraytype, elt, axes) end -# TODO: Define a `@interface interface(a) similar` function. function Base.similar( a::AnyAbstractBlockSparseArray, elt::Type, axes::Tuple{Vararg{AbstractUnitRange{<:Integer}}}, ) - return @interface interface(a) similar(a, elt, axes) + return style(a)(similar)(a, elt, axes) end # Fixes ambiguity error. function Base.similar(a::AnyAbstractBlockSparseArray, elt::Type, axes::Tuple{}) - return @interface interface(a) similar(a, elt, axes) + return style(a)(similar)(a, elt, axes) end # Fixes ambiguity error with `BlockArrays`. @@ -325,7 +327,7 @@ function Base.similar( AbstractBlockedUnitRange{<:Integer}, Vararg{AbstractBlockedUnitRange{<:Integer}}, }, ) - return @interface interface(a) similar(a, elt, axes) + return style(a)(similar)(a, elt, axes) end # Fixes ambiguity error with `OffsetArrays`. @@ -334,7 +336,7 @@ function Base.similar( elt::Type, axes::Tuple{AbstractUnitRange{<:Integer}, Vararg{AbstractUnitRange{<:Integer}}}, ) - return @interface interface(a) similar(a, elt, axes) + return style(a)(similar)(a, elt, axes) end # Fixes ambiguity error with `BlockArrays`. @@ -343,16 +345,16 @@ function Base.similar( elt::Type, axes::Tuple{AbstractBlockedUnitRange{<:Integer}, Vararg{AbstractUnitRange{<:Integer}}}, ) - return @interface interface(a) similar(a, elt, axes) + return style(a)(similar)(a, elt, axes) end function Base.similar(a::AnyAbstractBlockSparseArray, elt::Type) - return @interface interface(a) similar(a, elt, axes(a)) + return style(a)(similar)(a, elt, axes(a)) end function Base.similar( a::AnyAbstractBlockSparseArray, axes::Tuple{AbstractBlockedUnitRange{<:Integer}, Vararg{AbstractUnitRange{<:Integer}}}, ) - return @interface interface(a) similar(a, eltype(a), axes) + return style(a)(similar)(a, eltype(a), axes) end # Fixes ambiguity errors with BlockArrays. @@ -365,15 +367,14 @@ function Base.similar( Vararg{AbstractUnitRange{<:Integer}}, }, ) - # TODO: Use `@interface interface(a) similar(...)`. - return @interface interface(a) similar(a, elt, axes) + return style(a)(similar)(a, elt, axes) end # Fixes ambiguity error with `StaticArrays`. function Base.similar( a::AnyAbstractBlockSparseArray, elt::Type, axes::Tuple{Base.OneTo, Vararg{Base.OneTo}} ) - return @interface interface(a) similar(a, elt, axes) + return style(a)(similar)(a, elt, axes) end struct BlockType{T} end @@ -410,7 +411,7 @@ end function SparseArraysBase.isstored( a::AbstractBlockSparseArray{<:Any, N}, I::Vararg{Int, N} ) where {N} - return @interface interface(a) isstored(a, I...) + return style(a)(isstored)(a, I...) end function Base.replace_in_print_matrix( diff --git a/src/blocksparsearray/blockdiagonalarray.jl b/src/blocksparsearray/blockdiagonalarray.jl index e3bcb96c..8ecc7d1f 100644 --- a/src/blocksparsearray/blockdiagonalarray.jl +++ b/src/blocksparsearray/blockdiagonalarray.jl @@ -8,7 +8,7 @@ const BlockDiagonal{T, A, Axes, V <: AbstractVector{A}} = BlockSparseMatrix{ } const BlockSparseDiagonal{T, A <: AbstractBlockSparseVector{T}} = Diagonal{T, A} -@interface interface::BlockSparseArrayInterface function blocks(a::BlockSparseDiagonal) +function blocks_blocksparse(a::BlockSparseDiagonal) return Diagonal(Diagonal.(blocks(a.diag))) end diff --git a/src/blocksparsearray/blocksparsearray.jl b/src/blocksparsearray/blocksparsearray.jl index 7cf149fa..0768ecb1 100644 --- a/src/blocksparsearray/blocksparsearray.jl +++ b/src/blocksparsearray/blocksparsearray.jl @@ -6,7 +6,6 @@ using BlockArrays: blockedrange, blocklength, undef_blocks -using DerivableInterfaces: @interface using Dictionaries: Dictionary using SparseArraysBase: SparseArrayDOK, Unstored using TypeParameterAccessors: similartype @@ -280,8 +279,9 @@ Base.axes(a::BlockSparseArray) = a.axes # BlockArrays `AbstractBlockArray` interface. # This is used by `blocks(::AnyAbstractBlockSparseArray)`. -@interface ::AbstractBlockSparseArrayInterface BlockArrays.blocks(a::BlockSparseArray) = - a.blocks +using BlockArrays: blocks +const blocks_blocksparse = blocksparse_style(blocks) +blocks_blocksparse(a::BlockSparseArray) = a.blocks function blocktype( arraytype::Type{<:BlockSparseArray{T, N, A}} diff --git a/src/blocksparsearrayinterface/arraylayouts.jl b/src/blocksparsearrayinterface/arraylayouts.jl index f1511248..22d48457 100644 --- a/src/blocksparsearrayinterface/arraylayouts.jl +++ b/src/blocksparsearrayinterface/arraylayouts.jl @@ -1,20 +1,16 @@ using ArrayLayouts: ArrayLayouts, Dot, MatMulMatAdd, MatMulVecAdd, MulAdd using BlockArrays: BlockArrays, BlockLayout, muladd! -using DerivableInterfaces: @interface using SparseArraysBase: SparseLayout using LinearAlgebra: LinearAlgebra, dot, mul! -@interface ::AbstractBlockSparseArrayInterface function BlockArrays.muladd!( +const muladd!_blocksparse = blocksparse_style(muladd!) +function muladd!_blocksparse( α::Number, a1::AbstractArray, a2::AbstractArray, β::Number, a_dest::AbstractArray ) mul!(blocks(a_dest), blocks(a1), blocks(a2), α, β) return a_dest end -function DerivableInterfaces.interface(m::MulAdd) - return interface(m.A, m.B, m.C) -end - function ArrayLayouts.materialize!( m::MatMulMatAdd{ <:BlockLayout{<:SparseLayout}, @@ -22,7 +18,7 @@ function ArrayLayouts.materialize!( <:BlockLayout{<:SparseLayout}, }, ) - @interface interface(m) muladd!(m.α, m.A, m.B, m.β, m.C) + muladd!_blocksparse(m.α, m.A, m.B, m.β, m.C) return m.C end function ArrayLayouts.materialize!( @@ -32,11 +28,13 @@ function ArrayLayouts.materialize!( <:BlockLayout{<:SparseLayout}, }, ) - @interface interface(m) matmul!(m) + error("Not implemented.") + matmul!(m) return m.C end -@interface ::AbstractBlockSparseArrayInterface function LinearAlgebra.dot( +const dot_blocksparse = blocksparse_style(dot) +function dot_blocksparse( a1::AbstractArray, a2::AbstractArray ) # TODO: Add a check that the blocking of `a1` and `a2` are @@ -45,5 +43,5 @@ end end function Base.copy(d::Dot{<:BlockLayout{<:SparseLayout}, <:BlockLayout{<:SparseLayout}}) - return @interface interface(d.A, d.B) dot(d.A, d.B) + return dot_blocksparse(d.A, d.B) end diff --git a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl index 02e4fec4..04a498ec 100644 --- a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl +++ b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl @@ -16,17 +16,10 @@ using BlockArrays: blocklength, blocks, findblockindex -using DerivableInterfaces: - DerivableInterfaces, - @interface, - AbstractArrayInterface, - DefaultArrayInterface, - interface, - permuteddims, - zero! +using FunctionImplementations: FunctionImplementations, permuteddims, zero! using LinearAlgebra: Adjoint, Transpose using SparseArraysBase: - AbstractSparseArrayInterface, + AbstractSparseArrayStyle, getstoredindex, getunstoredindex, eachstoredindex, @@ -116,59 +109,35 @@ blockstype(a::BlockArray) = blockstype(typeof(a)) blocktype(arraytype::Type{<:BlockArray}) = eltype(blockstype(arraytype)) blocktype(a::BlockArray) = eltype(blocks(a)) -abstract type AbstractBlockSparseArrayInterface{N, B <: AbstractArrayInterface{N}} <: -AbstractSparseArrayInterface{N} end +abstract type AbstractBlockSparseArrayStyle <: AbstractSparseArrayStyle end -function blockinterface(interface::AbstractBlockSparseArrayInterface{<:Any, B}) where {B} - return B() -end - -# TODO: Also support specifying the `blocktype` along with the `eltype`. -function Base.similar(interface::AbstractBlockSparseArrayInterface, T::Type, ax::Tuple) - # TODO: Generalize by storing the block interface in the block sparse array interface. - N = length(ax) - B = similartype(typeof(blockinterface(interface)), Type{T}, Tuple{blockaxistype.(ax)...}) - return similar(BlockSparseArray{T, N, B}, ax) -end +struct BlockSparseArrayStyle <: AbstractBlockSparseArrayStyle end +const blocksparse_style = BlockSparseArrayStyle() -struct BlockSparseArrayInterface{N, B <: AbstractArrayInterface{N}} <: - AbstractBlockSparseArrayInterface{N, B} - blockinterface::B -end -function BlockSparseArrayInterface{N}(blockinterface::AbstractArrayInterface{N}) where {N} - return BlockSparseArrayInterface{N, typeof(blockinterface)}(blockinterface) -end -function BlockSparseArrayInterface{M, B}(::Val{N}) where {M, B <: AbstractArrayInterface{M}, N} - B′ = B(Val(N)) - return BlockSparseArrayInterface(B′) -end -function BlockSparseArrayInterface{N}() where {N} - return BlockSparseArrayInterface{N}(DefaultArrayInterface{N}()) -end -BlockSparseArrayInterface(::Val{N}) where {N} = BlockSparseArrayInterface{N}() -BlockSparseArrayInterface{M}(::Val{N}) where {M, N} = BlockSparseArrayInterface{N}() -BlockSparseArrayInterface() = BlockSparseArrayInterface{Any}() - -function DerivableInterfaces.combine_interface_rule( - interface1::AbstractBlockSparseArrayInterface, - interface2::AbstractBlockSparseArrayInterface, +function FunctionImplementations.Style( + style1::AbstractBlockSparseArrayStyle, + style2::AbstractBlockSparseArrayStyle, ) - B = interface(blockinterface(interface1), blockinterface(interface2)) - return BlockSparseArrayInterface(B) + return BlockSparseArrayStyle() end -@interface ::AbstractBlockSparseArrayInterface function BlockArrays.blocks(a::AbstractArray) +const blocks_blocksparse = blocksparse_style(blocks) +function blocks_blocksparse(a::AbstractArray) return error("Not implemented") end -@interface ::AbstractBlockSparseArrayInterface function SparseArraysBase.isstored( - a::AbstractArray{<:Any, N}, I::Vararg{Int, N} - ) where {N} +const isstored_blocksparse = blocksparse_style(isstored) +function isstored_blocksparse(a::AbstractArray{<:Any, N}, I::Vararg{Int, N}) where {N} bI = BlockIndex(findblockindex.(axes(a), I)) return isstored(blocks(a), bI.I...) && isstored(blocks(a)[bI.I...], bI.α...) end +function isstored_blocksparse(a::AbstractArray, I::Int...) + # Handle cases like linear indexing and trailing 1 indices. + return isstored_blocksparse(a, Tuple(CartesianIndices(a)[I...])...) +end -@interface ::AbstractBlockSparseArrayInterface function Base.getindex( +const getindex_blocksparse = blocksparse_style(getindex) +function getindex_blocksparse( a::AbstractArray{<:Any, N}, I::Vararg{Int, N} ) where {N} @boundscheck checkbounds(a, I...) @@ -176,7 +145,7 @@ end end # Fix ambiguity error. -@interface ::AbstractBlockSparseArrayInterface function Base.getindex( +function getindex_blocksparse( a::AbstractArray{<:Any, 0} ) return a[Block()[]] @@ -188,7 +157,8 @@ end # and make that explicit with `@blocked a[1:2, 1:2]`. See the discussion in # https://github.com/JuliaArrays/BlockArrays.jl/issues/347 and also # https://github.com/ITensor/ITensors.jl/issues/1336. -@interface ::AbstractBlockSparseArrayInterface function Base.to_indices( +const to_indices_blocksparse = blocksparse_style(to_indices) +function to_indices_blocksparse( a, inds, I::Tuple{UnitRange{<:Integer}, Vararg{Any}} ) bs1 = to_blockindices(inds[1], I[1]) @@ -196,7 +166,7 @@ end return (I1, to_indices(a, Base.tail(inds), Base.tail(I))...) end -@interface ::AbstractBlockSparseArrayInterface function Base.to_indices( +function to_indices_blocksparse( a, inds, I::Tuple{AbstractArray{Bool}, Vararg{Any}} ) bs1 = to_blockindices(inds[1], I[1]) @@ -205,7 +175,7 @@ end end # Special case when there is no blocking. -@interface ::AbstractBlockSparseArrayInterface function Base.to_indices( +function to_indices_blocksparse( a, inds::Tuple{Base.OneTo{<:Integer}, Vararg{Any}}, I::Tuple{UnitRange{<:Integer}, Vararg{Any}}, @@ -214,7 +184,7 @@ end end # a[[Block(2), Block(1)], [Block(2), Block(1)]] -@interface ::AbstractBlockSparseArrayInterface function Base.to_indices( +function to_indices_blocksparse( a, inds, I::Tuple{Vector{<:Block{1}}, Vararg{Any}} ) I1 = BlockIndices(I[1], blockedunitrange_getindices(inds[1], I[1])) @@ -223,7 +193,7 @@ end # a[mortar([Block(1)[1:2], Block(2)[1:3]]), mortar([Block(1)[1:2], Block(2)[1:3]])] # a[[Block(1)[1:2], Block(2)[1:3]], [Block(1)[1:2], Block(2)[1:3]]] -@interface ::AbstractBlockSparseArrayInterface function Base.to_indices( +function to_indices_blocksparse( a, inds, I::Tuple{ @@ -244,7 +214,7 @@ end I1 = BlockIndices(bs, blockedunitrange_getindices(inds[1], I[1])) return (I1, to_indices(a, Base.tail(inds), Base.tail(I))...) end -@interface ::AbstractBlockSparseArrayInterface function Base.to_indices( +function to_indices_blocksparse( a, inds, I::Tuple{BlockVector{<:GenericBlockIndex{1}, <:Vector{<:BlockIndexVector{1}}}, Vararg{Any}}, @@ -256,7 +226,7 @@ end # a[BlockVector([Block(2), Block(1)], [2]), BlockVector([Block(2), Block(1)], [2])] # Permute and merge blocks. # TODO: This isn't merging blocks yet, that needs to be implemented that. -@interface ::AbstractBlockSparseArrayInterface function Base.to_indices( +function to_indices_blocksparse( a, inds, I::Tuple{AbstractBlockVector{<:Block{1}}, Vararg{Any}} ) I1 = BlockIndices(I[1], blockedunitrange_getindices(inds[1], I[1])) @@ -266,7 +236,8 @@ end # TODO: Need to implement this! function block_merge end -@interface ::AbstractBlockSparseArrayInterface function Base.setindex!( +const setindex!_blocksparse = blocksparse_style(setindex!) +function setindex!_blocksparse( a::AbstractArray{<:Any, N}, value, I::Vararg{Int, N} ) where {N} @boundscheck checkbounds(a, I...) @@ -275,7 +246,7 @@ function block_merge end end # Fix ambiguity error. -@interface ::AbstractBlockSparseArrayInterface function Base.setindex!( +function setindex!_blocksparse( a::AbstractArray{<:Any, 0}, value ) # TODO: Use `Block()[]` once https://github.com/JuliaArrays/BlockArrays.jl/issues/430 @@ -284,7 +255,7 @@ end return a end -@interface ::AbstractBlockSparseArrayInterface function Base.setindex!( +function setindex!_blocksparse( a::AbstractArray{<:Any, N}, value, I::BlockIndex{N} ) where {N} i = Int.(Tuple(block(I))) @@ -296,7 +267,7 @@ end end # Fix ambiguity error. -@interface ::AbstractBlockSparseArrayInterface function Base.setindex!( +function setindex!_blocksparse( a::AbstractArray{<:Any, 0}, value, I::BlockIndex{0} ) a_b = blocks(a)[] @@ -320,11 +291,12 @@ end # We overload `permutedims` here so that we can assume the destination and source # have the same blocking and avoid non-GPU friendly slicing operations in block sparse `map!`. # TODO: Delete this and handle this logic in block sparse `map!`. -@interface ::AbstractBlockSparseArrayInterface function Base.permutedims( +const permutedims_blocksparse = blocksparse_style(permutedims) +function permutedims_blocksparse( a::AbstractArray, perm ) a_dest = similar(permuteddims(a, perm)) - # TODO: Maybe define this as `@interface BlockIsEqualInterface() permutedims!(...)`. + # TODO: Rename `permutedims!_blockisequal`. blockisequal_permutedims!(a_dest, a, perm) return a_dest end @@ -332,19 +304,22 @@ end # We overload `permutedims!` here so that we can special case when the destination and source # have the same blocking and avoid non-GPU friendly slicing operations in block sparse `map!`. # TODO: Delete this and handle this logic in block sparse `map!`. -@interface ::AbstractBlockSparseArrayInterface function Base.permutedims!( +const permutedims!_blocksparse = blocksparse_style(permutedims!) +function permutedims!_blocksparse( a_dest::AbstractArray, a_src::AbstractArray, perm ) if all(blockisequal.(axes(a_dest), axes(permuteddims(a_src, perm)))) - # TODO: Maybe define this as `@interface BlockIsEqualInterface() permutedims!(...)`. + # TODO: Rename `permutedims!_blockisequal`. blockisequal_permutedims!(a_dest, a_src, perm) return a_dest end - @interface DefaultArrayInterface() permutedims!(a_dest, a_src, perm) + # TODO: Is this defined? + DefaultArrayInterface()(permutedims!)(a_dest, a_src, perm) return a_dest end -@interface ::AbstractBlockSparseArrayInterface function Base.fill!(a::AbstractArray, value) +const fill!_blocksparse = blocksparse_style(fill!) +function fill!_blocksparse(a::AbstractArray, value) # TODO: Only do this check if `value isa Number`? if iszero(value) zero!(a) @@ -358,9 +333,9 @@ end return a end -@interface ::AbstractBlockSparseArrayInterface function DerivableInterfaces.zero!( - a::AbstractArray - ) +using FunctionImplementations: zero! +const zero!_blocksparse = blocksparse_style(zero!) +function zero!_blocksparse(a::AbstractArray) # This will try to empty the storage if possible. zero!(blocks(a)) return a @@ -388,9 +363,7 @@ struct SparsePermutedDimsArrayBlocks{ } <: AbstractSparseArray{BlockType, N} array::Array end -@interface ::AbstractBlockSparseArrayInterface function BlockArrays.blocks( - a::PermutedDimsArray - ) +function blocks_blocksparse(a::PermutedDimsArray) return SparsePermutedDimsArrayBlocks{eltype(a), ndims(a), blocktype(parent(a)), typeof(a)}(a) end function Base.size(a::SparsePermutedDimsArrayBlocks) @@ -430,12 +403,8 @@ end reverse_index(index) = reverse(index) reverse_index(index::CartesianIndex) = CartesianIndex(reverse(Tuple(index))) -@interface ::AbstractBlockSparseArrayInterface BlockArrays.blocks(a::Transpose) = transpose( - blocks(parent(a)) -) -@interface ::AbstractBlockSparseArrayInterface BlockArrays.blocks(a::Adjoint) = adjoint( - blocks(parent(a)) -) +blocks_blocksparse(a::Transpose) = transpose(blocks(parent(a))) +blocks_blocksparse(a::Adjoint) = adjoint(blocks(parent(a))) # Represents the array of arrays of a `SubArray` # wrapping a block spare array, i.e. `blocks(array)` where `a` is a `SubArray`. @@ -443,7 +412,7 @@ struct SparseSubArrayBlocks{T, N, BlockType <: AbstractArray{T, N}, Array <: Sub AbstractSparseArray{BlockType, N} array::Array end -@interface ::AbstractBlockSparseArrayInterface function BlockArrays.blocks(a::SubArray) +function blocks_blocksparse(a::SubArray) return SparseSubArrayBlocks{eltype(a), ndims(a), blocktype(parent(a)), typeof(a)}(a) end # TODO: Define this as `blockrange(a::AbstractArray, indices::Tuple{Vararg{AbstractUnitRange}})`. @@ -546,7 +515,7 @@ to_blocks_indices(I::BlockSlice{<:Block{1}}) = Int(I.block):Int(I.block) to_blocks_indices(I::BlockIndices{<:Vector{<:Block{1}}}) = Int.(I.blocks) to_blocks_indices(I::Base.Slice) = Base.OneTo(blocklength(I.indices)) -@interface ::AbstractBlockSparseArrayInterface function BlockArrays.blocks( +function blocks_blocksparse( a::SubArray{<:Any, <:Any, <:Any, <:Tuple{Vararg{BlockSliceCollection}}} ) return @view blocks(parent(a))[map(to_blocks_indices, parentindices(a))...] diff --git a/src/blocksparsearrayinterface/broadcast.jl b/src/blocksparsearrayinterface/broadcast.jl index dd24d884..4da8ce8e 100644 --- a/src/blocksparsearrayinterface/broadcast.jl +++ b/src/blocksparsearrayinterface/broadcast.jl @@ -1,86 +1,90 @@ -using Base.Broadcast: - Broadcast, BroadcastStyle, AbstractArrayStyle, DefaultArrayStyle, Broadcasted +using Base.Broadcast: BroadcastStyle, Broadcasted using GPUArraysCore: @allowscalar using MapBroadcast: Mapped -using DerivableInterfaces: DerivableInterfaces, @interface -abstract type AbstractBlockSparseArrayStyle{N, B <: AbstractArrayStyle{N}} <: -AbstractArrayStyle{N} end - -blockstyle(::AbstractBlockSparseArrayStyle{N, B}) where {N, B <: AbstractArrayStyle{N}} = B() - -function Broadcast.BroadcastStyle( - style1::AbstractBlockSparseArrayStyle, style2::AbstractBlockSparseArrayStyle - ) - style = Broadcast.result_style(blockstyle(style1), blockstyle(style2)) - return BlockSparseArrayStyle(style) +module Broadcast + using Base.Broadcast: AbstractArrayStyle + abstract type AbstractBlockSparseArrayStyle{N, B <: AbstractArrayStyle{N}} <: + AbstractArrayStyle{N} end + struct BlockSparseArrayStyle{N, B <: AbstractArrayStyle{N}} <: + AbstractBlockSparseArrayStyle{N, B} + blockstyle::B + end + function BlockSparseArrayStyle{N}(blockstyle::AbstractArrayStyle{N}) where {N} + return BlockSparseArrayStyle{N, typeof(blockstyle)}(blockstyle) + end + function BlockSparseArrayStyle{N, B}() where {N, B <: AbstractArrayStyle{N}} + return BlockSparseArrayStyle{N, B}(B()) + end + function BlockSparseArrayStyle{N}() where {N} + return BlockSparseArrayStyle{N}(Base.Broadcast.DefaultArrayStyle{N}()) + end + BlockSparseArrayStyle(::Val{N}) where {N} = BlockSparseArrayStyle{N}() + BlockSparseArrayStyle{M}(::Val{N}) where {M, N} = BlockSparseArrayStyle{N}() + function BlockSparseArrayStyle{M, B}(::Val{N}) where {M, B <: AbstractArrayStyle{M}, N} + return BlockSparseArrayStyle{N}(B(Val(N))) + end end -function DerivableInterfaces.interface( - ::Type{<:AbstractBlockSparseArrayStyle{N, B}} - ) where {N, B <: AbstractArrayStyle{N}} - return BlockSparseArrayInterface(interface(B)) +function blockstyle( + ::Broadcast.AbstractBlockSparseArrayStyle{N, B}, + ) where {N, B <: Base.Broadcast.AbstractArrayStyle{N}} + return B() end -struct BlockSparseArrayStyle{N, B <: AbstractArrayStyle{N}} <: - AbstractBlockSparseArrayStyle{N, B} - blockstyle::B -end -function BlockSparseArrayStyle{N}(blockstyle::AbstractArrayStyle{N}) where {N} - return BlockSparseArrayStyle{N, typeof(blockstyle)}(blockstyle) -end - -function BlockSparseArrayStyle{N, B}() where {N, B <: AbstractArrayStyle{N}} - return BlockSparseArrayStyle{N, B}(B()) -end -BlockSparseArrayStyle{N}() where {N} = BlockSparseArrayStyle{N}(DefaultArrayStyle{N}()) -BlockSparseArrayStyle(::Val{N}) where {N} = BlockSparseArrayStyle{N}() -BlockSparseArrayStyle{M}(::Val{N}) where {M, N} = BlockSparseArrayStyle{N}() -function BlockSparseArrayStyle{M, B}(::Val{N}) where {M, B <: AbstractArrayStyle{M}, N} - return BlockSparseArrayStyle{N}(B(Val(N))) +function Base.Broadcast.BroadcastStyle( + style1::Broadcast.AbstractBlockSparseArrayStyle, + style2::Broadcast.AbstractBlockSparseArrayStyle, + ) + style = Base.Broadcast.result_style(blockstyle(style1), blockstyle(style2)) + return Broadcast.BlockSparseArrayStyle(style) end -Broadcast.BroadcastStyle(a::BlockSparseArrayStyle, ::DefaultArrayStyle{0}) = a -function Broadcast.BroadcastStyle( - ::BlockSparseArrayStyle{N}, a::DefaultArrayStyle +Base.Broadcast.BroadcastStyle(a::Broadcast.BlockSparseArrayStyle, ::Base.Broadcast.DefaultArrayStyle{0}) = a +function Base.Broadcast.BroadcastStyle( + ::Broadcast.BlockSparseArrayStyle{N}, a::Base.Broadcast.DefaultArrayStyle ) where {N} - return BroadcastStyle(DefaultArrayStyle{N}(), a) + return Base.Broadcast.BroadcastStyle(Base.Broadcast.DefaultArrayStyle{N}(), a) end -function Broadcast.BroadcastStyle( - ::BlockSparseArrayStyle{N}, ::Broadcast.Style{Tuple} +function Base.Broadcast.BroadcastStyle( + ::Broadcast.BlockSparseArrayStyle{N}, ::Base.Broadcast.Style{Tuple} ) where {N} - return DefaultArrayStyle{N}() + return Base.Broadcast.DefaultArrayStyle{N}() end -function Base.similar(bc::Broadcasted{<:BlockSparseArrayStyle}, elt::Type, ax) +function Base.similar(bc::Broadcasted{<:Broadcast.BlockSparseArrayStyle}, elt::Type, ax) + # Find the first array in the broadcast expression. # TODO: Make this more generic, base it off sure this handles GPU arrays properly. - m = Mapped(bc) - return similar(first(m.args), elt, ax) + bc′ = Base.Broadcast.flatten(bc) + arg = bc′.args[findfirst(arg -> arg isa AbstractArray, bc′.args)] + return similar(arg, elt, ax) end # Catches cases like `dest .= value` or `dest .= value1 .+ value2`. # If the RHS is zero, this makes sure that the storage is emptied, # which is logic that is handled by `fill!`. -function copyto_blocksparse!(dest::AbstractArray, bc::Broadcasted{<:AbstractArrayStyle{0}}) +const copyto!_blocksparse = blocksparse_style(copyto!) +const fill!_blocksparse = blocksparse_style(fill!) +function copyto!_blocksparse(dest::AbstractArray, bc::Broadcasted{<:Base.Broadcast.AbstractArrayStyle{0}}) # `[]` is used to unwrap zero-dimensional arrays. - bcf = Broadcast.flatten(bc) + bcf = Base.Broadcast.flatten(bc) value = @allowscalar bcf.f(map(arg -> arg[], bcf.args)...) - return @interface BlockSparseArrayInterface() fill!(dest, value) + return fill!_blocksparse(dest, value) end -# Broadcasting implementation -# TODO: Delete this in favor of `DerivableInterfaces` version. -function copyto_blocksparse!(dest::AbstractArray, bc::Broadcasted) +function copyto!_blocksparse( + dest::AbstractArray, bc::Broadcasted + ) # convert to map # flatten and only keep the AbstractArray arguments m = Mapped(bc) - @interface interface(dest, bc) map!(m.f, dest, m.args...) + map!(m.f, dest, m.args...) return dest end +# Broadcasting implementation function Base.copyto!( - dest::AbstractArray{<:Any, N}, bc::Broadcasted{BlockSparseArrayStyle{N}} + dest::AbstractArray{<:Any, N}, bc::Broadcasted{Broadcast.BlockSparseArrayStyle{N}} ) where {N} - copyto_blocksparse!(dest, bc) - return dest + return copyto!_blocksparse(dest, bc) end diff --git a/src/blocksparsearrayinterface/cat.jl b/src/blocksparsearrayinterface/cat.jl index 851d161d..06d1ac9b 100644 --- a/src/blocksparsearrayinterface/cat.jl +++ b/src/blocksparsearrayinterface/cat.jl @@ -1,8 +1,8 @@ using BlockArrays: blocks -using DerivableInterfaces.Concatenate: Concatenated, cat! +using FunctionImplementations.Concatenate: Concatenated, cat! function Base.copyto!( - dest::AbstractArray, concat::Concatenated{<:BlockSparseArrayInterface} + dest::AbstractArray, concat::Concatenated{<:Broadcast.BlockSparseArrayStyle} ) # TODO: This assumes the destination blocking is commensurate with # the blocking of the sources, for example because it was constructed diff --git a/src/blocksparsearrayinterface/getunstoredblock.jl b/src/blocksparsearrayinterface/getunstoredblock.jl index 60cf6a88..1a354b35 100644 --- a/src/blocksparsearrayinterface/getunstoredblock.jl +++ b/src/blocksparsearrayinterface/getunstoredblock.jl @@ -1,5 +1,5 @@ using BlockArrays: Block -using DerivableInterfaces: zero! +using FunctionImplementations: zero! struct ZeroBlocks{ N, A <: AbstractArray{<:Any, N}, ParentAxes <: Tuple{Vararg{AbstractUnitRange{<:Integer}, N}}, diff --git a/src/blocksparsearrayinterface/linearalgebra.jl b/src/blocksparsearrayinterface/linearalgebra.jl index 837b18b8..e5f43136 100644 --- a/src/blocksparsearrayinterface/linearalgebra.jl +++ b/src/blocksparsearrayinterface/linearalgebra.jl @@ -1,6 +1,7 @@ using LinearAlgebra: LinearAlgebra, mul! -@interface ::AbstractBlockSparseArrayInterface function LinearAlgebra.mul!( +const mul!_blocksparse = blocksparse_style(mul!) +function mul!_blocksparse( a_dest::AbstractMatrix, a1::AbstractMatrix, a2::AbstractMatrix, diff --git a/src/blocksparsearrayinterface/map.jl b/src/blocksparsearrayinterface/map.jl index c243443d..40259fc6 100644 --- a/src/blocksparsearrayinterface/map.jl +++ b/src/blocksparsearrayinterface/map.jl @@ -1,5 +1,5 @@ using BlockArrays: BlockRange, blockisequal -using DerivableInterfaces: @interface, AbstractArrayInterface, interface +using FunctionImplementations: style using GPUArraysCore: @allowscalar # Check if the block structures are the same. @@ -45,7 +45,7 @@ function map_block!(f, a_dest::AbstractArray, I::Block, a_srcs::AbstractArray... if isstored(a_dest, I) a_dest[I] .= f.(a_srcs_I...) else - a_dest[I] = Broadcast.broadcast_preserving_zero_d(f, a_srcs_I...) + a_dest[I] = Base.Broadcast.broadcast_preserving_zero_d(f, a_srcs_I...) end return a_dest end @@ -68,15 +68,15 @@ end # made by combining the blocking of the axes (i.e. the blocking that # is used to determine `union_stored_blocked_cartesianindices(...)`). # `reblock` is a partial solution to that, but a bit ad-hoc. -## TODO: Make this an `@interface AbstractBlockSparseArrayInterface` function. -@interface interface::AbstractBlockSparseArrayInterface function Base.map!( +const map!_blocksparse = blocksparse_style(map!) +function map!_blocksparse( f, a_dest::AbstractArray, a_srcs::AbstractArray... ) if isempty(a_srcs) error("Can't call `map!` with zero source terms.") end if iszero(ndims(a_dest)) - @interface interface map_zero_dim!(f, a_dest, a_srcs...) + map_zero_dim!(f, a_dest, a_srcs...) return a_dest end if same_block_structure(a_dest, a_srcs...) @@ -115,23 +115,26 @@ end return a_dest end -@interface ::AbstractBlockSparseArrayInterface function Base.mapreduce( +const mapreduce_blocksparse = blocksparse_style(mapreduce) +function mapreduce_blocksparse( f, op, as::AbstractArray...; kwargs... ) # TODO: Define an `init` value based on the element type. - return @interface interface(blocks.(as)...) mapreduce( + return style(blocks.(as)...)(mapreduce)( block -> mapreduce(f, op, block), op, blocks.(as)...; kwargs... ) end -@interface ::AbstractBlockSparseArrayInterface function Base.iszero(a::AbstractArray) +const iszero_blocksparse = blocksparse_style(iszero) +function iszero_blocksparse(a::AbstractArray) # TODO: Just call `iszero(blocks(a))`? - return @interface interface(blocks(a)) iszero(blocks(a)) + return style(blocks(a))(iszero)(blocks(a)) end -@interface ::AbstractBlockSparseArrayInterface function Base.isreal(a::AbstractArray) +const isreal_blocksparse = blocksparse_style(isreal) +function isreal_blocksparse(a::AbstractArray) # TODO: Just call `isreal(blocks(a))`? - return @interface interface(blocks(a)) isreal(blocks(a)) + return style(blocks(a))(isreal)(blocks(a)) end # Helper functions for block sparse map. @@ -152,9 +155,7 @@ end reblock(a) = a # `map!` specialized to zero-dimensional inputs. -function map_zero_dim! end - -@interface ::AbstractArrayInterface function map_zero_dim!( +function map_zero_dim!( f, a_dest::AbstractArray, a_srcs::AbstractArray... ) @allowscalar a_dest[] = f.(map(a_src -> a_src[], a_srcs)...) diff --git a/src/blocksparsearrayinterface/views.jl b/src/blocksparsearrayinterface/views.jl index 7445684e..6c425bcd 100644 --- a/src/blocksparsearrayinterface/views.jl +++ b/src/blocksparsearrayinterface/views.jl @@ -1,3 +1,4 @@ -@interface ::AbstractBlockSparseArrayInterface function Base.view(a, I...) +const view_blocksparse = blocksparse_style(view) +function view_blocksparse(a, I...) return Base.invoke(view, Tuple{AbstractArray, Vararg{Any}}, a, I...) end diff --git a/test/Project.toml b/test/Project.toml index d330c169..7ae54cad 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -4,8 +4,8 @@ Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" BlockSparseArrays = "2c9a651f-6452-4ace-a6ac-809f4280fbb4" -DerivableInterfaces = "6c5e35bf-e59e-4898-b73c-732dcc4ba65f" DiagonalArrays = "74fd4be6-21e2-4f6f-823a-4360d37c7a77" +FunctionImplementations = "7c7cc465-9c6a-495f-bdd1-f42428e86d0c" GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -29,7 +29,6 @@ Aqua = "0.8" ArrayLayouts = "1" BlockArrays = "1.8" BlockSparseArrays = "0.10" -DerivableInterfaces = "0.5" DiagonalArrays = "0.3" GPUArraysCore = "0.2" JLArrays = "0.2, 0.3" @@ -37,10 +36,10 @@ LinearAlgebra = "1" MatrixAlgebraKit = "0.6" Random = "1" SafeTestsets = "0.1" -SparseArraysBase = "0.7" +SparseArraysBase = "0.8" StableRNGs = "1" Suppressor = "0.2" TensorAlgebra = "0.6" -Test = "1" +Test = "1.10" TestExtras = "0.3" TypeParameterAccessors = "0.4" diff --git a/test/test_basics.jl b/test/test_basics.jl index eb29dd18..2310ec5f 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -1,5 +1,4 @@ using Adapt: adapt -using ArrayLayouts: zero! using BlockArrays: BlockArrays, Block, diff --git a/test/test_map.jl b/test/test_map.jl index 34c5cfdd..6497eeba 100644 --- a/test/test_map.jl +++ b/test/test_map.jl @@ -10,7 +10,7 @@ using BlockSparseArrays: blockstoredlength, blocktype, eachblockstoredindex -using DerivableInterfaces: zero! +using FunctionImplementations: zero! using GPUArraysCore: @allowscalar using JLArrays: JLArray using SparseArraysBase: storedlength diff --git a/test/test_tensoralgebraext.jl b/test/test_tensoralgebraext.jl index 019080cb..11cef609 100644 --- a/test/test_tensoralgebraext.jl +++ b/test/test_tensoralgebraext.jl @@ -21,8 +21,8 @@ end @test contract((-1, -2, -3, -4), a, (1, -1, 2, -2), a, (2, -3, 1, -4)) isa BlockArray end -const elts = (Float32, Float64, Complex{Float32}, Complex{Float64}) -@testset "`contract` `BlockSparseArray` (eltype=$elt)" for elt in elts +@testset "`contract` `BlockSparseArray` (eltype=$elt)" for elt in + (Float32, Float64, Complex{Float32}, Complex{Float64}) @testset "BlockedOneTo" begin d = blockedrange([2, 3]) a1 = randn_blockdiagonal(elt, (d, d, d, d))