Skip to content

Commit 9bad85a

Browse files
authored
Generalize BlockArray/BlockedArray to non-integer block lengths (#405)
* Generalize element type of axes * Try fixing tests * Fix ambiguity error in reshape * Fix BlockMatrix and BlockedMatrix constructors * Fix more constructors * Fix broadcasting * Fix broadcasting * Fix broadcasting * Add tests * Add BlockedArray tests * Fix test * Fix some coverage issues * More test coverage * More test coverage * More test coverage, redesign BlockIndexRange * Generalize blockaxis.jl * Revert definition of DefaultBlockAxis to fix downstream test failures * Fix dispatch issue
1 parent fd96cb5 commit 9bad85a

File tree

8 files changed

+230
-148
lines changed

8 files changed

+230
-148
lines changed

src/blockarray.jl

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,18 @@ const undef_blocks = UndefBlocksInitializer()
5151
function _BlockArray end
5252

5353
"""
54-
BlockArray{T, N, R<:AbstractArray{<:AbstractArray{T,N},N}, BS<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractBlockArray{T, N}
54+
BlockArray{T, N, R<:AbstractArray{<:AbstractArray{T,N},N}, BS<:Tuple{Vararg{AbstractUnitRange{<:Integer},N}}} <: AbstractBlockArray{T, N}
5555
5656
A `BlockArray` is an array where each block is stored contiguously. This means that insertions and retrieval of blocks
5757
can be very fast and non allocating since no copying of data is needed.
5858
5959
In the type definition, `R` defines the array type that holds the blocks, for example `Matrix{Matrix{Float64}}`.
6060
"""
61-
struct BlockArray{T, N, R <: AbstractArray{<:AbstractArray{T,N},N}, BS<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractBlockArray{T, N}
61+
struct BlockArray{T, N, R <: AbstractArray{<:AbstractArray{T,N},N}, BS <: Tuple{Vararg{AbstractUnitRange{<:Integer},N}}} <: AbstractBlockArray{T, N}
6262
blocks::R
6363
axes::BS
6464

65-
global @inline function _BlockArray(blocks::R, block_axes::BS) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}, BS<:NTuple{N,AbstractUnitRange{Int}}}
65+
global @inline function _BlockArray(blocks::R, block_axes::BS) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}, BS<:Tuple{Vararg{AbstractUnitRange{<:Integer},N}}}
6666
Base.require_one_based_indexing(block_axes...)
6767
Base.require_one_based_indexing(blocks)
6868
new{T, N, R, BS}(blocks, block_axes)
@@ -74,7 +74,7 @@ end
7474
_BlockArray(blocks, map(blockedrange, block_axes))
7575

7676
# support non-concrete eltypes in blocks
77-
_BlockArray(blocks::R, block_axes::BS) where {N, R<:AbstractArray{<:AbstractArray{V,N} where V,N}, BS<:NTuple{N,AbstractUnitRange{Int}}} =
77+
_BlockArray(blocks::R, block_axes::BS) where {N, R<:AbstractArray{<:AbstractArray{V,N} where V,N}, BS<:Tuple{Vararg{AbstractUnitRange{<:Integer},N}}} =
7878
_BlockArray(convert(AbstractArray{AbstractArray{mapreduce(eltype,promote_type,blocks),N},N}, blocks), block_axes)
7979
_BlockArray(blocks::R, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {N, R<:AbstractArray{<:AbstractArray{<:Any,N},N}} =
8080
_BlockArray(convert(AbstractArray{AbstractArray{mapreduce(eltype,promote_type,blocks),N},N}, blocks), block_sizes...)
@@ -90,7 +90,7 @@ const BlockVecOrMat{T, R} = Union{BlockMatrix{T, R}, BlockVector{T, R}}
9090
@inline _BlockArray(::Type{R}, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}} =
9191
_BlockArray(R, map(blockedrange,block_sizes))
9292

93-
function _BlockArray(::Type{R}, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}}
93+
function _BlockArray(::Type{R}, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}}
9494
n_blocks = map(blocklength,baxes)
9595
blocks = R(undef, n_blocks)
9696
_BlockArray(blocks, baxes)
@@ -186,7 +186,7 @@ See also [`undef_blocks`](@ref), [`UndefBlocksInitializer`](@ref)
186186
@inline BlockArray{T,N,R}(::UndefBlocksInitializer, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}} =
187187
undef_blocks_BlockArray(R, block_sizes...)
188188

189-
function initialized_blocks_BlockArray(::Type{R}, baxes::NTuple{N,AbstractUnitRange{Int}}) where R<:AbstractArray{V,N} where {T,N,V<:AbstractArray{T,N}}
189+
function initialized_blocks_BlockArray(::Type{R}, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where R<:AbstractArray{V,N} where {T,N,V<:AbstractArray{T,N}}
190190
blocks = map(Iterators.product(map(x -> blockaxes(x,1), baxes)...)) do block_index
191191
indices = map((x,y) -> x[y], baxes, block_index)
192192
similar(V, map(length, indices))
@@ -198,16 +198,16 @@ end
198198
initialized_blocks_BlockArray(::Type{R}, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}} =
199199
initialized_blocks_BlockArray(R, map(blockedrange,block_sizes))
200200

201-
@inline BlockArray{T}(::UndefInitializer, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T, N} =
201+
@inline BlockArray{T}(::UndefInitializer, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where {T, N} =
202202
initialized_blocks_BlockArray(Array{Array{T,N},N}, baxes)
203203

204-
@inline BlockArray{T, N}(::UndefInitializer, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T, N} =
204+
@inline BlockArray{T, N}(::UndefInitializer, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where {T, N} =
205205
initialized_blocks_BlockArray(Array{Array{T,N},N}, baxes)
206206

207-
@inline BlockArray{T, N, R}(::UndefInitializer, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}} =
207+
@inline BlockArray{T, N, R}(::UndefInitializer, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}} =
208208
initialized_blocks_BlockArray(R, baxes)
209209

210-
@inline BlockArray{T,N,R,BS}(::UndefInitializer, baxes::BS) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}, BS<:NTuple{N,AbstractUnitRange{Int}}} =
210+
@inline BlockArray{T,N,R,BS}(::UndefInitializer, baxes::BS) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}, BS<:Tuple{Vararg{AbstractUnitRange{<:Integer},N}}} =
211211
initialized_blocks_BlockArray(R, baxes)
212212

213213
"""
@@ -242,7 +242,7 @@ julia> B
242242
initialized_blocks_BlockArray(R, block_sizes...)
243243

244244

245-
@inline BlockArray{T,N,R,BS}(::UndefInitializer, sizes::NTuple{N,Int}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}, BS<:NTuple{N,AbstractUnitRange{Int}}} =
245+
@inline BlockArray{T,N,R,BS}(::UndefInitializer, sizes::Tuple{Vararg{Integer, N}}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}, BS<:Tuple{Vararg{AbstractUnitRange{<:Integer},N}}} =
246246
BlockArray{T,N,R,BS}(undef, convert(BS, map(Base.OneTo, sizes)))
247247

248248
function BlockArray{T}(arr::AbstractArray{V, N}, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T,V,N}
@@ -257,38 +257,38 @@ end
257257
BlockArray(arr::AbstractArray{T, N}, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T,N} =
258258
BlockArray{T}(arr, block_sizes...)
259259

260-
function BlockArray{T}(arr::AbstractArray{T, N}, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T,N}
260+
function BlockArray{T}(arr::AbstractArray{T, N}, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where {T,N}
261261
blocks = map(Iterators.product(map(x -> blockaxes(x,1), baxes)...)) do block_index
262262
indices = map((x,y) -> x[y], baxes, block_index)
263263
arr[indices...]
264264
end
265265
return _BlockArray(blocks, baxes)
266266
end
267267

268-
BlockArray{T}(arr::AbstractArray{<:Any, N}, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T,N} =
268+
BlockArray{T}(arr::AbstractArray{<:Any, N}, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where {T,N} =
269269
BlockArray{T}(convert(AbstractArray{T, N}, arr), baxes)
270270

271-
BlockArray(arr::AbstractArray{T, N}, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T,N} =
271+
BlockArray(arr::AbstractArray{T, N}, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where {T,N} =
272272
BlockArray{T}(arr, baxes)
273273

274-
BlockVector(blocks::AbstractVector, baxes::Tuple{AbstractUnitRange{Int}}) = BlockArray(blocks, baxes)
274+
BlockVector(blocks::AbstractVector, baxes::Tuple{AbstractUnitRange{<:Integer}}) = BlockArray(blocks, baxes)
275275
BlockVector(blocks::AbstractVector, block_sizes::AbstractVector{<:Integer}) = BlockArray(blocks, block_sizes)
276-
BlockMatrix(blocks::AbstractMatrix, baxes::NTuple{2,AbstractUnitRange{Int}}) = BlockArray(blocks, baxes)
277-
BlockMatrix(blocks::AbstractMatrix, block_sizes::Vararg{AbstractVector{<:Integer},2}) = BlockArray(blocks, block_sizes...)
276+
BlockMatrix(blocks::AbstractMatrix, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer}, 2}}) = BlockArray(blocks, baxes)
277+
BlockMatrix(blocks::AbstractMatrix, block_sizes::Vararg{AbstractVector{<:Integer}, 2}) = BlockArray(blocks, block_sizes...)
278278

279-
BlockArray{T}::UniformScaling, baxes::NTuple{2,AbstractUnitRange{Int}}) where T = BlockArray{T}(Matrix(λ, map(length,baxes)...), baxes)
279+
BlockArray{T}::UniformScaling, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer}, 2}}) where T = BlockArray{T}(Matrix(λ, map(length,baxes)...), baxes)
280280
BlockArray{T}::UniformScaling, block_sizes::Vararg{AbstractVector{<:Integer}, 2}) where T = BlockArray{T}(λ, map(blockedrange,block_sizes))
281281
BlockArray::UniformScaling{T}, block_sizes::Vararg{AbstractVector{<:Integer}, 2}) where T = BlockArray{T}(λ, block_sizes...)
282-
BlockArray::UniformScaling{T}, baxes::NTuple{2,AbstractUnitRange{Int}}) where T = BlockArray{T}(λ, baxes)
283-
BlockMatrix::UniformScaling, baxes::NTuple{2,AbstractUnitRange{Int}}) = BlockArray(λ, baxes)
284-
BlockMatrix::UniformScaling, block_sizes::Vararg{AbstractVector{<:Integer},2}) = BlockArray(λ, block_sizes...)
285-
BlockMatrix{T}::UniformScaling, baxes::NTuple{2,AbstractUnitRange{Int}}) where T = BlockArray{T}(λ, baxes)
286-
BlockMatrix{T}::UniformScaling, block_sizes::Vararg{AbstractVector{<:Integer},2}) where T = BlockArray{T}(λ, block_sizes...)
282+
BlockArray::UniformScaling{T}, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer}, 2}}) where T = BlockArray{T}(λ, baxes)
283+
BlockMatrix::UniformScaling, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer}, 2}}) = BlockArray(λ, baxes)
284+
BlockMatrix::UniformScaling, block_sizes::Vararg{AbstractVector{<:Integer}, 2}) = BlockArray(λ, block_sizes...)
285+
BlockMatrix{T}::UniformScaling, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer}, 2}}) where T = BlockArray{T}(λ, baxes)
286+
BlockMatrix{T}::UniformScaling, block_sizes::Vararg{AbstractVector{<:Integer}, 2}) where T = BlockArray{T}(λ, block_sizes...)
287287

288288
"""
289289
mortar(blocks::AbstractArray)
290290
mortar(blocks::AbstractArray{R, N}, sizes_1, sizes_2, ..., sizes_N)
291-
mortar(blocks::AbstractArray{R, N}, block_sizes::NTuple{N,AbstractUnitRange{Int}})
291+
mortar(blocks::AbstractArray{R, N}, block_sizes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}})
292292
293293
Construct a `BlockArray` from `blocks`. `block_sizes` is computed from
294294
`blocks` if it is not given.
@@ -319,7 +319,7 @@ julia> M == mortar(
319319
true
320320
```
321321
"""
322-
mortar(blocks::AbstractArray{R, N}, baxes::NTuple{N,AbstractUnitRange{Int}}) where {R, N} =
322+
mortar(blocks::AbstractArray{R, N}, baxes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where {R, N} =
323323
_BlockArray(blocks, baxes)
324324

325325
mortar(blocks::AbstractArray{R, N}, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {R, N} =
@@ -355,7 +355,7 @@ end
355355

356356
getsizes(block_sizes, block_index) = getindex.(block_sizes, block_index)
357357

358-
function checksizes(fullsizes::Array{NTuple{N,Int}, N}, block_sizes::NTuple{N,Vector{Int}}) where N
358+
function checksizes(fullsizes::Array{<:Tuple{Vararg{Integer,N}}, N}, block_sizes::Tuple{Vararg{Vector{<:Integer},N}}) where N
359359
for I in CartesianIndices(fullsizes)
360360
block_index = Tuple(I)
361361
if fullsizes[block_index...] != getsizes(block_sizes, block_index)
@@ -431,18 +431,18 @@ end
431431
###########################
432432

433433

434-
@inline Base.similar(block_array::AbstractArray, ::Type{T}, axes::Tuple{AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{Int},Integer}}}) where T =
434+
@inline Base.similar(block_array::AbstractArray, ::Type{T}, axes::Tuple{AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{<:Integer},Integer}}}) where T =
435435
BlockArray{T}(undef, map(to_axes,axes))
436-
@inline Base.similar(block_array::AbstractArray, ::Type{T}, axes::Tuple{AbstractBlockedUnitRange,AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{Int},Integer}}}) where T =
436+
@inline Base.similar(block_array::AbstractArray, ::Type{T}, axes::Tuple{AbstractBlockedUnitRange,AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{<:Integer},Integer}}}) where T =
437437
BlockArray{T}(undef, map(to_axes,axes))
438-
@inline Base.similar(block_array::AbstractArray, ::Type{T}, axes::Tuple{Union{AbstractUnitRange{Int},Integer},AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{Int},Integer}}}) where T =
438+
@inline Base.similar(block_array::AbstractArray, ::Type{T}, axes::Tuple{Union{AbstractUnitRange{<:Integer},Integer},AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{<:Integer},Integer}}}) where T =
439439
BlockArray{T}(undef, map(to_axes,axes))
440440

441-
@inline Base.similar(block_array::Type{<:AbstractArray{T}}, axes::Tuple{AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{Int},Integer}}}) where T =
441+
@inline Base.similar(block_array::Type{<:AbstractArray{T}}, axes::Tuple{AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{<:Integer},Integer}}}) where T =
442442
BlockArray{T}(undef, map(to_axes,axes))
443-
@inline Base.similar(block_array::Type{<:AbstractArray{T}}, axes::Tuple{AbstractBlockedUnitRange,AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{Int},Integer}}}) where T =
443+
@inline Base.similar(block_array::Type{<:AbstractArray{T}}, axes::Tuple{AbstractBlockedUnitRange,AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{<:Integer},Integer}}}) where T =
444444
BlockArray{T}(undef, map(to_axes,axes))
445-
@inline Base.similar(block_array::Type{<:AbstractArray{T}}, axes::Tuple{Union{AbstractUnitRange{Int},Integer},AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{Int},Integer}}}) where T =
445+
@inline Base.similar(block_array::Type{<:AbstractArray{T}}, axes::Tuple{Union{AbstractUnitRange{<:Integer},Integer},AbstractBlockedUnitRange,Vararg{Union{AbstractUnitRange{<:Integer},Integer}}}) where T =
446446
BlockArray{T}(undef, map(to_axes,axes))
447447

448448
@inline Base.similar(B::BlockArray, ::Type{T}) where {T} = mortar(similar.(blocks(B), T))
@@ -454,7 +454,7 @@ const OffsetAxis = Union{Integer, UnitRange, Base.OneTo, Base.IdentityUnitRange}
454454
Array{T}(undef, dims)
455455
@inline Base.similar(block_array::BlockArray, ::Type{T}, axes::Tuple{OffsetAxis,Vararg{OffsetAxis}}) where T =
456456
BlockArray{T}(undef, map(to_axes,axes))
457-
@inline Base.similar(block_array::BlockArray, ::Type{T}, axes::Tuple{Base.OneTo{Int},Vararg{Base.OneTo{Int}}}) where T =
457+
@inline Base.similar(block_array::BlockArray, ::Type{T}, axes::Tuple{Base.OneTo{<:Integer},Vararg{Base.OneTo{<:Integer}}}) where T =
458458
BlockArray{T}(undef, map(to_axes,axes))
459459

460460
@inline function getindex(block_arr::BlockArray{T, N}, i::Vararg{Integer, N}) where {T,N}
@@ -545,12 +545,14 @@ function Base.fill!(block_array::BlockArray, v)
545545
end
546546

547547
# Temporary work around
548-
Base.reshape(block_array::BlockArray, axes::NTuple{N,AbstractUnitRange{Int}}) where N =
548+
Base.reshape(block_array::BlockArray, axes::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where N =
549549
reshape(BlockedArray(block_array), axes)
550550
Base.reshape(block_array::BlockArray, dims::Tuple{Int,Vararg{Int}}) =
551551
reshape(BlockedArray(block_array), dims)
552552
Base.reshape(block_array::BlockArray, axes::Tuple{Union{Integer,Base.OneTo}, Vararg{Union{Integer,Base.OneTo}}}) =
553553
reshape(BlockedArray(block_array), axes)
554+
Base.reshape(block_array::BlockArray, dims::Tuple{Vararg{Union{Integer,Colon}}}) =
555+
reshape(BlockedArray(block_array), dims)
554556
Base.reshape(block_array::BlockArray, dims::Tuple{Vararg{Union{Int,Colon}}}) =
555557
reshape(BlockedArray(block_array), dims)
556558

0 commit comments

Comments
 (0)