From 2895f99213fd9bafecd8fd077f8c32929f9541c9 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 13:44:20 -0500 Subject: [PATCH 01/16] [WIP] Switch to FunctionImplementations --- Project.toml | 13 +-- .../wrappedabstractblocksparsearray.jl | 83 ++++++++++--------- 2 files changed, 45 insertions(+), 51 deletions(-) diff --git a/Project.toml b/Project.toml index 321cdfbf..660486c1 100644 --- a/Project.toml +++ b/Project.toml @@ -1,13 +1,12 @@ 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" @@ -31,7 +30,6 @@ 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" @@ -47,10 +45,5 @@ 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/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( From 9e7f1861fb167beea86f39f7edcb54a1c9564ee9 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 13:56:48 -0500 Subject: [PATCH 02/16] Fix Projects --- Project.toml | 2 -- docs/Project.toml | 3 +++ examples/Project.toml | 3 +++ test/Project.toml | 5 ++--- test/test_map.jl | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Project.toml b/Project.toml index 660486c1..633d0862 100644 --- a/Project.toml +++ b/Project.toml @@ -27,7 +27,6 @@ BlockSparseArraysTensorAlgebraExt = "TensorAlgebra" [compat] Adapt = "4.1.1" -Aqua = "0.8.9" ArrayLayouts = "1.10.4" BlockArrays = "1.2" DiagonalArrays = "0.3" @@ -41,7 +40,6 @@ MatrixAlgebraKit = "0.6" SparseArraysBase = "0.7.1" SplitApplyCombine = "1.2.3" TensorAlgebra = "0.6.2" -Test = "1.10" TypeParameterAccessors = "0.4.1" julia = "1.10" 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/test/Project.toml b/test/Project.toml index d330c169..4af01d74 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" @@ -41,6 +40,6 @@ SparseArraysBase = "0.7" StableRNGs = "1" Suppressor = "0.2" TensorAlgebra = "0.6" -Test = "1" +Test = "1.10" TestExtras = "0.3" TypeParameterAccessors = "0.4" 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 From d421aa0c4432cf15ba91211bb23f9bb876c3ee03 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 14:41:46 -0500 Subject: [PATCH 03/16] Remove usages of @interface --- .../BlockArraysExtensions.jl | 2 +- .../abstractblocksparsearray.jl | 11 +- src/abstractblocksparsearray/cat.jl | 3 +- src/abstractblocksparsearray/map.jl | 27 ++-- .../sparsearrayinterface.jl | 1 - .../unblockedsubarray.jl | 5 +- src/abstractblocksparsearray/views.jl | 19 +-- src/blocksparsearray/blockdiagonalarray.jl | 2 +- src/blocksparsearray/blocksparsearray.jl | 6 +- src/blocksparsearrayinterface/arraylayouts.jl | 18 +-- .../blocksparsearrayinterface.jl | 140 ++++++++---------- src/blocksparsearrayinterface/broadcast.jl | 100 ++++++------- src/blocksparsearrayinterface/cat.jl | 4 +- .../getunstoredblock.jl | 2 +- .../linearalgebra.jl | 3 +- src/blocksparsearrayinterface/map.jl | 27 ++-- src/blocksparsearrayinterface/views.jl | 3 +- 17 files changed, 180 insertions(+), 193 deletions(-) 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/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..7c5e2633 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,28 @@ 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 # This avoids going through the generic version that calls `Base.permutedims!`, @@ -85,7 +86,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 +97,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..87184a28 100644 --- a/src/abstractblocksparsearray/unblockedsubarray.jl +++ b/src/abstractblocksparsearray/unblockedsubarray.jl @@ -18,8 +18,9 @@ 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}) 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/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..8d6f604c 100644 --- a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl +++ b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl @@ -16,17 +16,17 @@ using BlockArrays: blocklength, blocks, findblockindex -using DerivableInterfaces: - DerivableInterfaces, - @interface, - AbstractArrayInterface, - DefaultArrayInterface, - interface, - permuteddims, - zero! +## using DerivableInterfaces: +## DerivableInterfaces, +## @interface, +## AbstractArrayInterface, +## DefaultArrayInterface, +## interface, +## permuteddims, +## zero! using LinearAlgebra: Adjoint, Transpose using SparseArraysBase: - AbstractSparseArrayInterface, + AbstractSparseArrayStyle, getstoredindex, getunstoredindex, eachstoredindex, @@ -116,59 +116,44 @@ 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 +## 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 +## # 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 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}() +struct BlockSparseArrayStyle <: AbstractBlockSparseArrayStyle end -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( +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 -@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 +161,7 @@ end end # Fix ambiguity error. -@interface ::AbstractBlockSparseArrayInterface function Base.getindex( +function getindex_blocksparse( a::AbstractArray{<:Any, 0} ) return a[Block()[]] @@ -188,7 +173,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 +182,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 +191,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 +200,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 +209,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 +230,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 +242,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 +252,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 +262,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 +271,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 +283,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 +307,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 +320,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 +349,8 @@ end return a end -@interface ::AbstractBlockSparseArrayInterface function DerivableInterfaces.zero!( - a::AbstractArray - ) +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 +378,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 +418,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 +427,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 +530,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..4d0e3ec9 100644 --- a/src/blocksparsearrayinterface/broadcast.jl +++ b/src/blocksparsearrayinterface/broadcast.jl @@ -1,58 +1,56 @@ -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 + 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))) + end end -function DerivableInterfaces.interface( - ::Type{<:AbstractBlockSparseArrayStyle{N, B}} - ) where {N, B <: AbstractArrayStyle{N}} - return BlockSparseArrayInterface(interface(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) +function blockstyle( + ::Broadcast.AbstractBlockSparseArrayStyle{N, B}, + ) where {N, B <: Base.Broadcast.AbstractArrayStyle{N}} + return B() 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) # TODO: Make this more generic, base it off sure this handles GPU arrays properly. m = Mapped(bc) return similar(first(m.args), elt, ax) @@ -61,26 +59,28 @@ 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) 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 + ) where {N} # 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..14be291b 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. @@ -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 From ce2d74a739ce3c10426c957bd9cafea281c8b3d7 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 14:52:37 -0500 Subject: [PATCH 04/16] Get package loading --- Project.toml | 12 +++++++----- src/abstractblocksparsearray/broadcast.jl | 12 ++++++------ src/abstractblocksparsearray/unblockedsubarray.jl | 4 ++-- .../blocksparsearrayinterface.jl | 3 +++ src/blocksparsearrayinterface/broadcast.jl | 2 +- test/Project.toml | 2 +- 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Project.toml b/Project.toml index 633d0862..af1bda79 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,10 @@ name = "BlockSparseArrays" uuid = "2c9a651f-6452-4ace-a6ac-809f4280fbb4" -authors = ["ITensor developers and contributors"] version = "0.10.16" +authors = ["ITensor developers and contributors"] + +[workspace] +projects = ["benchmark", "dev", "docs", "examples", "test"] [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" @@ -10,6 +13,7 @@ BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" 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" @@ -32,16 +36,14 @@ BlockArrays = "1.2" 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" SplitApplyCombine = "1.2.3" TensorAlgebra = "0.6.2" TypeParameterAccessors = "0.4.1" julia = "1.10" - -[workspace] -projects = ["benchmark", "dev", "docs", "examples", "test"] diff --git a/src/abstractblocksparsearray/broadcast.jl b/src/abstractblocksparsearray/broadcast.jl index d2868ee8..9eae78d3 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}) +function Base.Broadcast.BroadcastStyle(arraytype::Type{<:AnyAbstractBlockSparseArray}) return BlockSparseArrayStyle(BroadcastStyle(blocktype(arraytype))) end # Fix ambiguity error with `BlockArrays`. -function Broadcast.BroadcastStyle( +function Base.Broadcast.BroadcastStyle( arraytype::Type{ <:SubArray{ <:Any, @@ -18,7 +18,7 @@ function Broadcast.BroadcastStyle( ) return BlockSparseArrayStyle{ndims(arraytype)}() end -function Broadcast.BroadcastStyle( +function Base.Broadcast.BroadcastStyle( arraytype::Type{ <:SubArray{ <:Any, @@ -34,7 +34,7 @@ function Broadcast.BroadcastStyle( ) return BlockSparseArrayStyle{ndims(arraytype)}() end -function Broadcast.BroadcastStyle( +function Base.Broadcast.BroadcastStyle( arraytype::Type{ <:SubArray{ <:Any, @@ -61,7 +61,7 @@ function Base.copyto!( return dest 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 diff --git a/src/abstractblocksparsearray/unblockedsubarray.jl b/src/abstractblocksparsearray/unblockedsubarray.jl index 87184a28..044af541 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 @@ -27,7 +27,7 @@ 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 diff --git a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl index 8d6f604c..2d22d9f8 100644 --- a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl +++ b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl @@ -16,6 +16,7 @@ using BlockArrays: blocklength, blocks, findblockindex +using FunctionImplementations: FunctionImplementations ## using DerivableInterfaces: ## DerivableInterfaces, ## @interface, @@ -131,6 +132,7 @@ abstract type AbstractBlockSparseArrayStyle <: AbstractSparseArrayStyle end ## end struct BlockSparseArrayStyle <: AbstractBlockSparseArrayStyle end +const blocksparse_style = BlockSparseArrayStyle() function FunctionImplementations.Style( style1::AbstractBlockSparseArrayStyle, @@ -349,6 +351,7 @@ function fill!_blocksparse(a::AbstractArray, value) return a end +using FunctionImplementations: zero! const zero!_blocksparse = blocksparse_style(zero!) function zero!_blocksparse(a::AbstractArray) # This will try to empty the storage if possible. diff --git a/src/blocksparsearrayinterface/broadcast.jl b/src/blocksparsearrayinterface/broadcast.jl index 4d0e3ec9..1cac95bd 100644 --- a/src/blocksparsearrayinterface/broadcast.jl +++ b/src/blocksparsearrayinterface/broadcast.jl @@ -70,7 +70,7 @@ end function copyto!_blocksparse( dest::AbstractArray, bc::Broadcasted - ) where {N} + ) # convert to map # flatten and only keep the AbstractArray arguments m = Mapped(bc) diff --git a/test/Project.toml b/test/Project.toml index 4af01d74..7ae54cad 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -36,7 +36,7 @@ LinearAlgebra = "1" MatrixAlgebraKit = "0.6" Random = "1" SafeTestsets = "0.1" -SparseArraysBase = "0.7" +SparseArraysBase = "0.8" StableRNGs = "1" Suppressor = "0.2" TensorAlgebra = "0.6" From e6d637cd1e93a1108a0fe264fcbefc12117d3401 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 15:00:10 -0500 Subject: [PATCH 05/16] Reorganize Project --- Project.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Project.toml b/Project.toml index af1bda79..765b19b4 100644 --- a/Project.toml +++ b/Project.toml @@ -1,10 +1,7 @@ name = "BlockSparseArrays" uuid = "2c9a651f-6452-4ace-a6ac-809f4280fbb4" -version = "0.10.16" authors = ["ITensor developers and contributors"] - -[workspace] -projects = ["benchmark", "dev", "docs", "examples", "test"] +version = "0.10.16" [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" @@ -47,3 +44,6 @@ SplitApplyCombine = "1.2.3" TensorAlgebra = "0.6.2" TypeParameterAccessors = "0.4.1" julia = "1.10" + +[workspace] +projects = ["benchmark", "dev", "docs", "examples", "test"] From d6d46b5203eff4fa668b20eda4800ee5f8cad25b Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 16:55:47 -0500 Subject: [PATCH 06/16] Fix some tests --- src/abstractblocksparsearray/broadcast.jl | 11 ++++------- src/abstractblocksparsearray/map.jl | 12 ++++++++++++ src/blocksparsearrayinterface/map.jl | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/abstractblocksparsearray/broadcast.jl b/src/abstractblocksparsearray/broadcast.jl index 9eae78d3..5465c851 100644 --- a/src/abstractblocksparsearray/broadcast.jl +++ b/src/abstractblocksparsearray/broadcast.jl @@ -2,7 +2,7 @@ using BlockArrays: AbstractBlockedUnitRange, BlockSlice using Base.Broadcast: BroadcastStyle function Base.Broadcast.BroadcastStyle(arraytype::Type{<:AnyAbstractBlockSparseArray}) - return BlockSparseArrayStyle(BroadcastStyle(blocktype(arraytype))) + return Broadcast.BlockSparseArrayStyle(BroadcastStyle(blocktype(arraytype))) end # Fix ambiguity error with `BlockArrays`. @@ -51,18 +51,15 @@ end # `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{<:Broadcast.BlockSparseArrayStyle{N}} ) where {N} - copyto_blocksparse!(dest, bc) - return dest + return copyto!_blocksparse(dest, bc) end diff --git a/src/abstractblocksparsearray/map.jl b/src/abstractblocksparsearray/map.jl index 7c5e2633..671355fc 100644 --- a/src/abstractblocksparsearray/map.jl +++ b/src/abstractblocksparsearray/map.jl @@ -80,6 +80,18 @@ function Base.copyto!( 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!`, # which eventually calls block sparse `map!`, which involves slicing operations # that are not friendly to GPU (since they involve `SubArray` wrapping diff --git a/src/blocksparsearrayinterface/map.jl b/src/blocksparsearrayinterface/map.jl index 14be291b..40259fc6 100644 --- a/src/blocksparsearrayinterface/map.jl +++ b/src/blocksparsearrayinterface/map.jl @@ -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 From 9c86f48be7e5138452306cfa92f9949d9886e4d0 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 16:57:03 -0500 Subject: [PATCH 07/16] Fix more tests --- src/abstractblocksparsearray/broadcast.jl | 2 +- src/blocksparsearrayinterface/broadcast.jl | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/abstractblocksparsearray/broadcast.jl b/src/abstractblocksparsearray/broadcast.jl index 5465c851..734bc59e 100644 --- a/src/abstractblocksparsearray/broadcast.jl +++ b/src/abstractblocksparsearray/broadcast.jl @@ -44,7 +44,7 @@ function Base.Broadcast.BroadcastStyle( }, }, ) - return BlockSparseArrayStyle{ndims(arraytype)}() + return Broadcast.BlockSparseArrayStyle{ndims(arraytype)}() end # These catch cases that aren't caught by the standard diff --git a/src/blocksparsearrayinterface/broadcast.jl b/src/blocksparsearrayinterface/broadcast.jl index 1cac95bd..baf90cd0 100644 --- a/src/blocksparsearrayinterface/broadcast.jl +++ b/src/blocksparsearrayinterface/broadcast.jl @@ -16,7 +16,9 @@ module Broadcast function BlockSparseArrayStyle{N, B}() where {N, B <: AbstractArrayStyle{N}} return BlockSparseArrayStyle{N, B}(B()) end - BlockSparseArrayStyle{N}() where {N} = BlockSparseArrayStyle{N}(DefaultArrayStyle{N}()) + 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} From a6ef1be07ce38af49d7930b3edf55ec45d01cb73 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 17:00:47 -0500 Subject: [PATCH 08/16] Fix more tests --- src/abstractblocksparsearray/broadcast.jl | 4 ++-- src/blocksparsearrayinterface/blocksparsearrayinterface.jl | 2 +- src/blocksparsearrayinterface/broadcast.jl | 2 +- test/test_tensoralgebraext.jl | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/abstractblocksparsearray/broadcast.jl b/src/abstractblocksparsearray/broadcast.jl index 734bc59e..9ea3e159 100644 --- a/src/abstractblocksparsearray/broadcast.jl +++ b/src/abstractblocksparsearray/broadcast.jl @@ -16,7 +16,7 @@ function Base.Broadcast.BroadcastStyle( }, }, ) - return BlockSparseArrayStyle{ndims(arraytype)}() + return Broadcast.BlockSparseArrayStyle{ndims(arraytype)}() end function Base.Broadcast.BroadcastStyle( arraytype::Type{ @@ -32,7 +32,7 @@ function Base.Broadcast.BroadcastStyle( }, }, ) - return BlockSparseArrayStyle{ndims(arraytype)}() + return Broadcast.BlockSparseArrayStyle{ndims(arraytype)}() end function Base.Broadcast.BroadcastStyle( arraytype::Type{ diff --git a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl index 2d22d9f8..75b2771e 100644 --- a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl +++ b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl @@ -16,7 +16,7 @@ using BlockArrays: blocklength, blocks, findblockindex -using FunctionImplementations: FunctionImplementations +using FunctionImplementations: FunctionImplementations, permuteddims ## using DerivableInterfaces: ## DerivableInterfaces, ## @interface, diff --git a/src/blocksparsearrayinterface/broadcast.jl b/src/blocksparsearrayinterface/broadcast.jl index baf90cd0..2ddaaddb 100644 --- a/src/blocksparsearrayinterface/broadcast.jl +++ b/src/blocksparsearrayinterface/broadcast.jl @@ -65,7 +65,7 @@ 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 fill!_blocksparse(dest, value) end 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)) From c81fbbcad14ae9d20d6e6f77884945a09f481a87 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 17:03:42 -0500 Subject: [PATCH 09/16] Fix import --- test/test_basics.jl | 1 - 1 file changed, 1 deletion(-) 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, From 017e3ae2cfd5d2ecd0bcae53062fb24fe15b04b7 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 7 Jan 2026 17:11:24 -0500 Subject: [PATCH 10/16] Cleanup --- .../blocksparsearrayinterface.jl | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl index 75b2771e..db5e9f4a 100644 --- a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl +++ b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl @@ -16,15 +16,7 @@ using BlockArrays: blocklength, blocks, findblockindex -using FunctionImplementations: FunctionImplementations, permuteddims -## using DerivableInterfaces: -## DerivableInterfaces, -## @interface, -## AbstractArrayInterface, -## DefaultArrayInterface, -## interface, -## permuteddims, -## zero! +using FunctionImplementations: FunctionImplementations, permuteddims, zero! using LinearAlgebra: Adjoint, Transpose using SparseArraysBase: AbstractSparseArrayStyle, From 22c9257aadd5e4a0b64261a571c1e4e43afcf94b Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 8 Jan 2026 10:44:11 -0500 Subject: [PATCH 11/16] Skip broken tests --- Project.toml | 2 +- test/test_basics.jl | 4 +- test/test_map.jl | 122 ++++++++++++++++++++++---------------------- 3 files changed, 64 insertions(+), 64 deletions(-) diff --git a/Project.toml b/Project.toml index 765b19b4..972343b3 100644 --- a/Project.toml +++ b/Project.toml @@ -39,7 +39,7 @@ LinearAlgebra = "1.10" MacroTools = "0.5.13" MapBroadcast = "0.1.5" MatrixAlgebraKit = "0.6" -SparseArraysBase = "0.8" +SparseArraysBase = "0.8.2" SplitApplyCombine = "1.2.3" TensorAlgebra = "0.6.2" TypeParameterAccessors = "0.4.1" diff --git a/test/test_basics.jl b/test/test_basics.jl index 2310ec5f..aff6105d 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -426,7 +426,7 @@ arrayts = (Array, JLArray) @test a1' * a2 ≈ Array(a1)' * Array(a2) @test dot(a1, a2) ≈ a1' * a2 end - @testset "cat" begin + false && @testset "cat" begin a1 = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) a1[Block(2, 1)] = dev(randn(elt, size(@view(a1[Block(2, 1)])))) a2 = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) @@ -473,7 +473,7 @@ arrayts = (Array, JLArray) @test blockstoredlength(b) == 1 @test storedlength(b) == 1 end - @testset "show" begin + false && @testset "show" begin vectort_elt = arrayt{elt, 1} matrixt_elt = arrayt{elt, 2} arrayt_elt = arrayt{elt, 3} diff --git a/test/test_map.jl b/test/test_map.jl index 6497eeba..c1ce91a1 100644 --- a/test/test_map.jl +++ b/test/test_map.jl @@ -403,24 +403,24 @@ arrayts = (Array, JLArray) @test a[Block(2, 2)[1:2, 2:3]] == b @test blockstoredlength(a) == 1 - # Noncontiguous slicing. - a = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) - a[Block(1, 1)] = dev(randn(elt, 2, 2)) - a[Block(2, 2)] = dev(randn(elt, 3, 3)) - I = ([3, 5], [2, 4]) - @test Array(a[I...]) == Array(a)[I...] - - # Noncontiguous slicing. - a = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) - a[Block(1, 1)] = dev(randn(elt, 2, 2)) - a[Block(2, 2)] = dev(randn(elt, 3, 3)) - I = (:, [2, 4]) - if arrayt === Array - @test Array(a[I...]) == Array(a)[I...] - else - # TODO: Broken on GPU, fix this. - @test_broken a[I...] - end + ## # Noncontiguous slicing. + ## a = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) + ## a[Block(1, 1)] = dev(randn(elt, 2, 2)) + ## a[Block(2, 2)] = dev(randn(elt, 3, 3)) + ## I = ([3, 5], [2, 4]) + ## @test Array(a[I...]) == Array(a)[I...] + + ## # Noncontiguous slicing. + ## a = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) + ## a[Block(1, 1)] = dev(randn(elt, 2, 2)) + ## a[Block(2, 2)] = dev(randn(elt, 3, 3)) + ## I = (:, [2, 4]) + ## if arrayt === Array + ## @test Array(a[I...]) == Array(a)[I...] + ## else + ## # TODO: Broken on GPU, fix this. + ## @test_broken a[I...] + ## end a = BlockSparseArray{elt}(undef, [2, 3], [2, 3]) @views for b in [Block(1, 1), Block(2, 2)] @@ -666,26 +666,26 @@ arrayts = (Array, JLArray) @test i isa UnitRange{Int} end - a = BlockSparseArray{elt}(undef, [2, 2, 2, 2], [2, 2, 2, 2]) - @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] - a[I] = randn(elt, size(a[I])) - end - for I in (blockedrange([4, 4]), BlockedVector(Block.(1:4), [2, 2])) - b = @view a[I, I] - @test copy(b) == a - @test blocksize(b) == (2, 2) - @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) - # TODO: Fix in Julia 1.11 (https://github.com/ITensor/ITensors.jl/pull/1539). - if VERSION < v"1.11-" - @test b[Block(1, 1)] == a[Block.(1:2), Block.(1:2)] - @test b[Block(2, 1)] == a[Block.(3:4), Block.(1:2)] - @test b[Block(1, 2)] == a[Block.(1:2), Block.(3:4)] - @test b[Block(2, 2)] == a[Block.(3:4), Block.(3:4)] - end - c = @view b[Block(2, 2)] - @test blocksize(c) == (1, 1) - @test c == a[Block.(3:4), Block.(3:4)] - end + ## a = BlockSparseArray{elt}(undef, [2, 2, 2, 2], [2, 2, 2, 2]) + ## @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] + ## a[I] = randn(elt, size(a[I])) + ## end + ## for I in (blockedrange([4, 4]), BlockedVector(Block.(1:4), [2, 2])) + ## b = @view a[I, I] + ## @test copy(b) == a + ## @test blocksize(b) == (2, 2) + ## @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) + ## # TODO: Fix in Julia 1.11 (https://github.com/ITensor/ITensors.jl/pull/1539). + ## if VERSION < v"1.11-" + ## @test b[Block(1, 1)] == a[Block.(1:2), Block.(1:2)] + ## @test b[Block(2, 1)] == a[Block.(3:4), Block.(1:2)] + ## @test b[Block(1, 2)] == a[Block.(1:2), Block.(3:4)] + ## @test b[Block(2, 2)] == a[Block.(3:4), Block.(3:4)] + ## end + ## c = @view b[Block(2, 2)] + ## @test blocksize(c) == (1, 1) + ## @test c == a[Block.(3:4), Block.(3:4)] + ## end a = BlockSparseArray{elt}(undef, [2, 3], [2, 3]) a[Block(1, 1)] = randn(elt, 2, 2) @@ -695,29 +695,29 @@ arrayts = (Array, JLArray) @test b == Array(a)[:, [2, 4, 5]] end - # Merge and permute blocks. - a = BlockSparseArray{elt}(undef, [2, 2, 2, 2], [2, 2, 2, 2]) - @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] - a[I] = randn(elt, size(a[I])) - end - for I in ( - BlockVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), - BlockedVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), - ) - b = @view a[I, I] - J = [Block(4), Block(3), Block(2), Block(1)] - @test b == a[J, J] - @test copy(b) == a[J, J] - @test blocksize(b) == (2, 2) - @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) - @test b[Block(1, 1)] == Array(a)[[7, 8, 5, 6], [7, 8, 5, 6]] - c = @views b[Block(1, 1)][2:3, 2:3] - @test c == Array(a)[[8, 5], [8, 5]] - @test copy(c) == Array(a)[[8, 5], [8, 5]] - c = @view b[Block(1, 1)[2:3, 2:3]] - @test c == Array(a)[[8, 5], [8, 5]] - @test copy(c) == Array(a)[[8, 5], [8, 5]] - end + ## # Merge and permute blocks. + ## a = BlockSparseArray{elt}(undef, [2, 2, 2, 2], [2, 2, 2, 2]) + ## @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] + ## a[I] = randn(elt, size(a[I])) + ## end + ## for I in ( + ## BlockVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), + ## BlockedVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), + ## ) + ## b = @view a[I, I] + ## J = [Block(4), Block(3), Block(2), Block(1)] + ## @test b == a[J, J] + ## @test copy(b) == a[J, J] + ## @test blocksize(b) == (2, 2) + ## @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) + ## @test b[Block(1, 1)] == Array(a)[[7, 8, 5, 6], [7, 8, 5, 6]] + ## c = @views b[Block(1, 1)][2:3, 2:3] + ## @test c == Array(a)[[8, 5], [8, 5]] + ## @test copy(c) == Array(a)[[8, 5], [8, 5]] + ## c = @view b[Block(1, 1)[2:3, 2:3]] + ## @test c == Array(a)[[8, 5], [8, 5]] + ## @test copy(c) == Array(a)[[8, 5], [8, 5]] + ## end # TODO: Add more tests of this, it may # only be working accidentally. From 64b5a800b8915b562cbedfa6cc0e0cec7f671c79 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 8 Jan 2026 11:59:20 -0500 Subject: [PATCH 12/16] Fix cat --- src/blocksparsearrayinterface/broadcast.jl | 6 ++++-- test/test_basics.jl | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/blocksparsearrayinterface/broadcast.jl b/src/blocksparsearrayinterface/broadcast.jl index 2ddaaddb..4da8ce8e 100644 --- a/src/blocksparsearrayinterface/broadcast.jl +++ b/src/blocksparsearrayinterface/broadcast.jl @@ -53,9 +53,11 @@ function Base.Broadcast.BroadcastStyle( end 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`. diff --git a/test/test_basics.jl b/test/test_basics.jl index aff6105d..5102cf1f 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -426,7 +426,7 @@ arrayts = (Array, JLArray) @test a1' * a2 ≈ Array(a1)' * Array(a2) @test dot(a1, a2) ≈ a1' * a2 end - false && @testset "cat" begin + @testset "cat" begin a1 = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) a1[Block(2, 1)] = dev(randn(elt, size(@view(a1[Block(2, 1)])))) a2 = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) From f1309ff694aaacfe005b041ba82d853359a2d879 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 8 Jan 2026 12:21:38 -0500 Subject: [PATCH 13/16] Fix isstored with trailing 1 indices --- .../blocksparsearrayinterface.jl | 8 +++++--- test/test_basics.jl | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl index db5e9f4a..5519397c 100644 --- a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl +++ b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl @@ -139,12 +139,14 @@ function blocks_blocksparse(a::AbstractArray) end const isstored_blocksparse = blocksparse_style(isstored) -function isstored_blocksparse( - a::AbstractArray{<:Any, N}, I::Vararg{Int, N} - ) where {N} +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 const getindex_blocksparse = blocksparse_style(getindex) function getindex_blocksparse( diff --git a/test/test_basics.jl b/test/test_basics.jl index 5102cf1f..2310ec5f 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -473,7 +473,7 @@ arrayts = (Array, JLArray) @test blockstoredlength(b) == 1 @test storedlength(b) == 1 end - false && @testset "show" begin + @testset "show" begin vectort_elt = arrayt{elt, 1} matrixt_elt = arrayt{elt, 2} arrayt_elt = arrayt{elt, 3} From 8ec6fd9034fc074a0e801b81856678d730daa779 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 8 Jan 2026 12:54:31 -0500 Subject: [PATCH 14/16] Fix more tests --- src/abstractblocksparsearray/unblockedsubarray.jl | 10 ++++++++++ test/test_map.jl | 12 ++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/abstractblocksparsearray/unblockedsubarray.jl b/src/abstractblocksparsearray/unblockedsubarray.jl index 044af541..fee26f27 100644 --- a/src/abstractblocksparsearray/unblockedsubarray.jl +++ b/src/abstractblocksparsearray/unblockedsubarray.jl @@ -31,6 +31,12 @@ 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}} ) @@ -40,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/test/test_map.jl b/test/test_map.jl index c1ce91a1..a90aa775 100644 --- a/test/test_map.jl +++ b/test/test_map.jl @@ -403,12 +403,12 @@ arrayts = (Array, JLArray) @test a[Block(2, 2)[1:2, 2:3]] == b @test blockstoredlength(a) == 1 - ## # Noncontiguous slicing. - ## a = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) - ## a[Block(1, 1)] = dev(randn(elt, 2, 2)) - ## a[Block(2, 2)] = dev(randn(elt, 3, 3)) - ## I = ([3, 5], [2, 4]) - ## @test Array(a[I...]) == Array(a)[I...] + # Noncontiguous slicing. + a = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) + a[Block(1, 1)] = dev(randn(elt, 2, 2)) + a[Block(2, 2)] = dev(randn(elt, 3, 3)) + I = ([3, 5], [2, 4]) + @test Array(a[I...]) == Array(a)[I...] ## # Noncontiguous slicing. ## a = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) From 47f74735c6153dd0b1b26df6b337d7f87639acb5 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 8 Jan 2026 12:56:44 -0500 Subject: [PATCH 15/16] More fixed tests --- test/test_map.jl | 62 ++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/test/test_map.jl b/test/test_map.jl index a90aa775..3b4e22cd 100644 --- a/test/test_map.jl +++ b/test/test_map.jl @@ -410,17 +410,17 @@ arrayts = (Array, JLArray) I = ([3, 5], [2, 4]) @test Array(a[I...]) == Array(a)[I...] - ## # Noncontiguous slicing. - ## a = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) - ## a[Block(1, 1)] = dev(randn(elt, 2, 2)) - ## a[Block(2, 2)] = dev(randn(elt, 3, 3)) - ## I = (:, [2, 4]) - ## if arrayt === Array - ## @test Array(a[I...]) == Array(a)[I...] - ## else - ## # TODO: Broken on GPU, fix this. - ## @test_broken a[I...] - ## end + # Noncontiguous slicing. + a = dev(BlockSparseArray{elt}(undef, [2, 3], [2, 3])) + a[Block(1, 1)] = dev(randn(elt, 2, 2)) + a[Block(2, 2)] = dev(randn(elt, 3, 3)) + I = (:, [2, 4]) + if arrayt === Array + @test Array(a[I...]) == Array(a)[I...] + else + # TODO: Broken on GPU, fix this. + @test_broken a[I...] + end a = BlockSparseArray{elt}(undef, [2, 3], [2, 3]) @views for b in [Block(1, 1), Block(2, 2)] @@ -666,26 +666,26 @@ arrayts = (Array, JLArray) @test i isa UnitRange{Int} end - ## a = BlockSparseArray{elt}(undef, [2, 2, 2, 2], [2, 2, 2, 2]) - ## @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] - ## a[I] = randn(elt, size(a[I])) - ## end - ## for I in (blockedrange([4, 4]), BlockedVector(Block.(1:4), [2, 2])) - ## b = @view a[I, I] - ## @test copy(b) == a - ## @test blocksize(b) == (2, 2) - ## @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) - ## # TODO: Fix in Julia 1.11 (https://github.com/ITensor/ITensors.jl/pull/1539). - ## if VERSION < v"1.11-" - ## @test b[Block(1, 1)] == a[Block.(1:2), Block.(1:2)] - ## @test b[Block(2, 1)] == a[Block.(3:4), Block.(1:2)] - ## @test b[Block(1, 2)] == a[Block.(1:2), Block.(3:4)] - ## @test b[Block(2, 2)] == a[Block.(3:4), Block.(3:4)] - ## end - ## c = @view b[Block(2, 2)] - ## @test blocksize(c) == (1, 1) - ## @test c == a[Block.(3:4), Block.(3:4)] - ## end + a = BlockSparseArray{elt}(undef, [2, 2, 2, 2], [2, 2, 2, 2]) + @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] + a[I] = randn(elt, size(a[I])) + end + for I in (blockedrange([4, 4]), BlockedVector(Block.(1:4), [2, 2])) + b = @view a[I, I] + @test copy(b) == a + @test blocksize(b) == (2, 2) + @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) + # TODO: Fix in Julia 1.11 (https://github.com/ITensor/ITensors.jl/pull/1539). + if VERSION < v"1.11-" + @test b[Block(1, 1)] == a[Block.(1:2), Block.(1:2)] + @test b[Block(2, 1)] == a[Block.(3:4), Block.(1:2)] + @test b[Block(1, 2)] == a[Block.(1:2), Block.(3:4)] + @test b[Block(2, 2)] == a[Block.(3:4), Block.(3:4)] + end + c = @view b[Block(2, 2)] + @test blocksize(c) == (1, 1) + @test c == a[Block.(3:4), Block.(3:4)] + end a = BlockSparseArray{elt}(undef, [2, 3], [2, 3]) a[Block(1, 1)] = randn(elt, 2, 2) From 37c0a86ccd31dc19b8e849303f239594fa67a487 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 8 Jan 2026 13:28:16 -0500 Subject: [PATCH 16/16] Fix tests --- Project.toml | 2 +- .../blocksparsearrayinterface.jl | 12 ----- test/test_map.jl | 46 +++++++++---------- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/Project.toml b/Project.toml index 972343b3..a77bcd37 100644 --- a/Project.toml +++ b/Project.toml @@ -39,7 +39,7 @@ LinearAlgebra = "1.10" MacroTools = "0.5.13" MapBroadcast = "0.1.5" MatrixAlgebraKit = "0.6" -SparseArraysBase = "0.8.2" +SparseArraysBase = "0.8.3" SplitApplyCombine = "1.2.3" TensorAlgebra = "0.6.2" TypeParameterAccessors = "0.4.1" diff --git a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl index 5519397c..04a498ec 100644 --- a/src/blocksparsearrayinterface/blocksparsearrayinterface.jl +++ b/src/blocksparsearrayinterface/blocksparsearrayinterface.jl @@ -111,18 +111,6 @@ blocktype(a::BlockArray) = eltype(blocks(a)) 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() diff --git a/test/test_map.jl b/test/test_map.jl index 3b4e22cd..6497eeba 100644 --- a/test/test_map.jl +++ b/test/test_map.jl @@ -695,29 +695,29 @@ arrayts = (Array, JLArray) @test b == Array(a)[:, [2, 4, 5]] end - ## # Merge and permute blocks. - ## a = BlockSparseArray{elt}(undef, [2, 2, 2, 2], [2, 2, 2, 2]) - ## @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] - ## a[I] = randn(elt, size(a[I])) - ## end - ## for I in ( - ## BlockVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), - ## BlockedVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), - ## ) - ## b = @view a[I, I] - ## J = [Block(4), Block(3), Block(2), Block(1)] - ## @test b == a[J, J] - ## @test copy(b) == a[J, J] - ## @test blocksize(b) == (2, 2) - ## @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) - ## @test b[Block(1, 1)] == Array(a)[[7, 8, 5, 6], [7, 8, 5, 6]] - ## c = @views b[Block(1, 1)][2:3, 2:3] - ## @test c == Array(a)[[8, 5], [8, 5]] - ## @test copy(c) == Array(a)[[8, 5], [8, 5]] - ## c = @view b[Block(1, 1)[2:3, 2:3]] - ## @test c == Array(a)[[8, 5], [8, 5]] - ## @test copy(c) == Array(a)[[8, 5], [8, 5]] - ## end + # Merge and permute blocks. + a = BlockSparseArray{elt}(undef, [2, 2, 2, 2], [2, 2, 2, 2]) + @views for I in [Block(1, 1), Block(2, 2), Block(3, 3), Block(4, 4)] + a[I] = randn(elt, size(a[I])) + end + for I in ( + BlockVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), + BlockedVector([Block(4), Block(3), Block(2), Block(1)], [2, 2]), + ) + b = @view a[I, I] + J = [Block(4), Block(3), Block(2), Block(1)] + @test b == a[J, J] + @test copy(b) == a[J, J] + @test blocksize(b) == (2, 2) + @test blocklengths.(axes(b)) == ([4, 4], [4, 4]) + @test b[Block(1, 1)] == Array(a)[[7, 8, 5, 6], [7, 8, 5, 6]] + c = @views b[Block(1, 1)][2:3, 2:3] + @test c == Array(a)[[8, 5], [8, 5]] + @test copy(c) == Array(a)[[8, 5], [8, 5]] + c = @view b[Block(1, 1)[2:3, 2:3]] + @test c == Array(a)[[8, 5], [8, 5]] + @test copy(c) == Array(a)[[8, 5], [8, 5]] + end # TODO: Add more tests of this, it may # only be working accidentally.