Skip to content

Commit

Permalink
Redefine blocksizes (#399)
Browse files Browse the repository at this point in the history
* Redefine blocksizes

* Revert change to docstring

* Add tests, fix some tests, add docstring

* Fix more tests

* Add test Project.toml

* Git ignore vim temp files

* Fixes to test Project.toml

* Another test Project.toml fix

* Move code, change type design, better code coverage

* Backwards compatibility. Fix doctest.

* Fix tests

* Redesign BlockSizes to be AbstractArray subtype
  • Loading branch information
mtfishman authored May 14, 2024
1 parent 928dea7 commit ee57d11
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 45 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ src/.DS_Store
Manifest.toml
Manifest-v*.*.toml
.DS_Store
.*.swp
build
29 changes: 0 additions & 29 deletions src/blockaxis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -353,35 +353,6 @@ blocksize(A) = map(length, blockaxes(A))
blocksize(A,i) = length(blockaxes(A,i))
@inline blocklength(t) = prod(blocksize(t))

"""
blocksizes(A::AbstractArray)
blocksizes(A::AbstractArray, i::Int)
Return the tuple of the sizes of blocks along each
dimension. See also size and blocksize.
# Examples
```jldoctest
julia> A = BlockArray(ones(3,3),[2,1],[1,1,1])
2×3-blocked 3×3 BlockMatrix{Float64}:
1.0 │ 1.0 │ 1.0
1.0 │ 1.0 │ 1.0
─────┼───────┼─────
1.0 │ 1.0 │ 1.0
julia> blocksizes(A)
([2, 1], [1, 1, 1])
julia> blocksizes(A,2)
3-element Vector{Int64}:
1
1
1
```
"""
blocksizes(A) = map(blocklengths, axes(A))
blocksizes(A,i) = blocklengths(axes(A,i))

axes(b::AbstractBlockedUnitRange) = (BlockedOneTo(blocklasts(b) .- (first(b)-oneunit(eltype(b)))),)
unsafe_indices(b::AbstractBlockedUnitRange) = axes(b)
# ::Integer works around case where blocklasts might return different type
Expand Down
47 changes: 46 additions & 1 deletion src/blocks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ BlocksView(a::AbstractArray{S,N}) where {S,N} =
Base.IteratorEltype(::Type{<:BlocksView}) = Base.EltypeUnknown()

Base.size(a::BlocksView) = blocksize(a.array)
Base.axes(a::BlocksView) = map(br -> only(br.indices), blockaxes(a.array))
Base.axes(a::BlocksView) = map(br -> Int.(br), blockaxes(a.array))

#=
This is broken for now. See: https://github.com/JuliaArrays/BlockArrays.jl/issues/120
Expand All @@ -92,3 +92,48 @@ This is broken for now. See: https://github.com/JuliaArrays/BlockArrays.jl/issue
copyto!(a[i...], b)
a
end

"""
blocksizes(A::AbstractArray)
blocksizes(A::AbstractArray, d::Integer)
Return an iterator over the sizes of each block.
See also size and blocksize.
# Examples
```jldoctest
julia> A = BlockArray(ones(3,3),[2,1],[1,1,1])
2×3-blocked 3×3 BlockMatrix{Float64}:
1.0 │ 1.0 │ 1.0
1.0 │ 1.0 │ 1.0
─────┼───────┼─────
1.0 │ 1.0 │ 1.0
julia> blocksizes(A)
2×3 BlockArrays.BlockSizes{Tuple{Int64, Int64}, 2, BlockMatrix{Float64, Matrix{Matrix{Float64}}, Tuple{BlockedOneTo{Int64, Vector{Int64}}, BlockedOneTo{Int64, Vector{Int64}}}}}:
(2, 1) (2, 1) (2, 1)
(1, 1) (1, 1) (1, 1)
julia> blocksizes(A)[1,2]
(2, 1)
julia> blocksizes(A,2)
3-element Vector{Int64}:
1
1
1
```
"""
blocksizes(A::AbstractArray) = BlockSizes(A)
blocksizes(A::AbstractArray, d::Integer) = blocklengths(axes(A, d))

struct BlockSizes{T,N,A<:AbstractArray{<:Any,N}} <: AbstractArray{T,N}
array::A
end
BlockSizes(a::AbstractArray{<:Any,N}) where {N} =
BlockSizes{Tuple{eltype.(axes(a))...},N,typeof(a)}(a)

size(bs::BlockSizes) = blocksize(bs.array)
axes(bs::BlockSizes) = map(br -> Int.(br), blockaxes(bs.array))
@propagate_inbounds getindex(a::BlockSizes{T,N}, i::Vararg{Int,N}) where {T,N} =
size(view(a.array, Block.(i)...))
5 changes: 3 additions & 2 deletions test/test_blockarrayinterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ end
A = randn(5)
@test blocksize(A) == (1,)
@test blocksize(A, 1) == 1
@test blocksizes(A) == ([5],)
@test blocksizes(A, 1) == [5]
@test blocklengths.(axes(A)) == ([5],)
@test blocklengths(axes(A, 1)) == [5]
@test blocksizes(A) == [(5,)]
@test A[Block(1)] == A
view(A, Block(1))[1] = 2
@test A[1] == 2
Expand Down
3 changes: 2 additions & 1 deletion test/test_blockarrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ end

# test that BlockArrays may be created from immutable arrays
B = BlockArray(reshape(1:9,3,3), [2,1], [2,1])
@test blocksizes(B) == ([2,1], [2,1])
@test blocklengths.(axes(B)) == ([2,1], [2,1])
@test blocksizes(B) == [(2,2) (2,1); (1,2) (1,1)]
@test B == reshape([1:9;],3,3)
@test blocks(B) isa Matrix{Matrix{Int}}

Expand Down
9 changes: 6 additions & 3 deletions test/test_blockdeque.jl
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ using BlockArrays, Test
@test pop!(B) == 6
@test B == 1:5
@test !any(isempty, blocks(B))
@test blocksizes(B,1) == [1,2,2]
@test blocklengths(axes(B,1)) == [1,2,2]
@test blocksizes(B) == [(1,), (2,), (2,)]
end
end

Expand All @@ -183,13 +184,15 @@ using BlockArrays, Test
A = BlockArray([1:6;], [2,2,2])
@test popfirst!(A) == 1
@test A == 2:6
@test blocksizes(A,1) == [1,2,2]
@test blocklengths(axes(A,1)) == [1,2,2]
@test blocksizes(A) == [(1,), (2,), (2,)]

@testset "empty blocks" begin
B = BlockArray([1:6;], [0,0,1,2,3])
@test popfirst!(B) == 1
@test B == 2:6
@test blocksizes(B,1) == [2,3]
@test blocklengths(axes(B,1)) == [2,3]
@test blocksizes(B) == [(2,), (3,)]
@test !any(isempty, blocks(B))
end
end
Expand Down
7 changes: 0 additions & 7 deletions test/test_blockindices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -786,13 +786,6 @@ end
@test eltype(blocklengths(r)) === UInt16
end

@testset "blocksizes" begin
x = blockedrange(2:4)
@test blocksizes(x,1) === 2:4
y = blockedrange([2:4;])
@test blocksizes(x,1) == blocksizes(y,1)
end

@testset "show" begin
b = blockedrange([1,2])
@test repr(b) == "$BlockedOneTo($([1,3]))"
Expand Down
6 changes: 4 additions & 2 deletions test/test_blocklinalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,14 @@ bview(a, b) = Base.invoke(view, Tuple{AbstractArray,Any}, a, b)
v = BlockArray(rand(6), 1:3)
w = A * v
@test w isa BlockArray
@test blocksizes(w,1) == fill(2, 3)
@test blocklengths(axes(w,1)) == fill(2, 3)
@test blocksizes(w) == [(2,), (2,), (2,)]
@test w Array(A) * v A * Array(v) Array(A) * Array(v)

z = A * w
@test z isa BlockArray
@test blocksizes(z,1) == fill(2, 3)
@test blocklengths(axes(z,1)) == fill(2, 3)
@test blocksizes(z) == [(2,), (2,), (2,)]
@test z Array(A) * w A * Array(w) Array(A) * Array(w)
end

Expand Down
24 changes: 24 additions & 0 deletions test/test_blocks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,28 @@ using Test, BlockArrays
end
end

@testset "blocksizes" begin
@testset "blocksizes" begin
v = Array(reshape(1:20, (5, 4)))
A = BlockArray(v, [2, 3], [3, 1])
@test blocklengths.(axes(A)) == ([2, 3], [3, 1])
bs = @inferred(blocksizes(A))
@test @inferred(size(bs)) == (2, 2)
@test @inferred(length(bs)) == 4
@test @inferred(axes(bs)) == (1:2, 1:2)
@test @inferred(eltype(bs)) === Tuple{Int,Int}
@test bs == [(2, 3) (2, 1); (3, 3) (3, 1)]
@test @inferred(bs[1, 1]) == (2, 3)
@test @inferred(bs[2, 1]) == (3, 3)
@test @inferred(bs[1, 2]) == (2, 1)
@test @inferred(bs[2, 2]) == (3, 1)
@test @inferred(bs[1]) == (2, 3)
@test @inferred(bs[2]) == (3, 3)
@test @inferred(bs[3]) == (2, 1)
@test @inferred(bs[4]) == (3, 1)
@test blocksizes(A, 1) == [2, 3]
@test blocksizes(A, 2) == [3, 1]
end
end

end # module

0 comments on commit ee57d11

Please sign in to comment.