From 627f67dc5dabdda4ba90e8bc39387d089fe52586 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Sat, 26 Apr 2025 18:24:54 -0400 Subject: [PATCH 1/4] Preserve block information in more slicing operations --- Project.toml | 2 +- src/blockindices.jl | 10 ++++++++++ src/views.jl | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index bd608f58..1935c38a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "BlockArrays" uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -version = "1.6.2" +version = "1.7.0" [deps] ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" diff --git a/src/blockindices.jl b/src/blockindices.jl index f924cb63..ea676eed 100644 --- a/src/blockindices.jl +++ b/src/blockindices.jl @@ -288,6 +288,16 @@ _indices(B) = B Block(bs::BlockSlice{<:BlockIndexRange}) = Block(bs.block) +struct BlockInds{BB,T<:Integer,INDS<:AbstractVector{T}} <: AbstractVector{T} + block::BB + indices::INDS +end + +for f in (:axes, :size) + @eval $f(S::BlockInds) = $f(S.indices) +end + +@propagate_inbounds getindex(S::BlockInds, i::Integer) = getindex(S.indices, i) struct BlockRange{N,R<:NTuple{N,AbstractUnitRange{<:Integer}}} <: AbstractArray{Block{N,Int},N} indices::R diff --git a/src/views.jl b/src/views.jl index ec8a9952..2b9b0c5d 100644 --- a/src/views.jl +++ b/src/views.jl @@ -11,7 +11,7 @@ function unblock(A, inds, I) end _blockslice(B, a::AbstractUnitRange) = BlockSlice(B, a) -_blockslice(B, a) = a # drop block structure +_blockslice(B, a) = BlockInds(B, a) # Allow `ones(2)[Block(1)[1:1], Block(1)[1:1]]` which is # similar to `ones(2)[1:1, 1:1]`. From 1ae9fe898ed9261640de919c2f517cea00ed1dc4 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Tue, 6 May 2025 15:48:13 -0400 Subject: [PATCH 2/4] Add docstring and some tests --- src/blockindices.jl | 19 +++++++++++++++---- src/views.jl | 2 +- test/test_blockindices.jl | 12 +++++++++++- test/test_blockrange.jl | 7 +++++++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/blockindices.jl b/src/blockindices.jl index ace7795d..af098fe7 100644 --- a/src/blockindices.jl +++ b/src/blockindices.jl @@ -290,16 +290,27 @@ _indices(B) = B Block(bs::BlockSlice{<:BlockIndexRange}) = Block(bs.block) -struct BlockInds{BB,T<:Integer,INDS<:AbstractVector{T}} <: AbstractVector{T} - block::BB +""" + BlockedSlice(blocks, indices) + +Represents blocked indices attached to a collection of corresponding blocks. + +Upon calling `to_indices()`, a collection of blocks are converted to BlockedSlice objects to represent +the indices over which the Blocks span. + +This mimics the relationship between `Colon` and `Base.Slice`, `Block` and `BlockSlice`, etc. +""" +struct BlockedSlice{BB,T<:Integer,INDS<:AbstractVector{T}} <: AbstractVector{T} + blocks::BB indices::INDS end for f in (:axes, :size) - @eval $f(S::BlockInds) = $f(S.indices) + @eval $f(S::BlockedSlice) = $f(S.indices) end -@propagate_inbounds getindex(S::BlockInds, i::Integer) = getindex(S.indices, i) +@propagate_inbounds getindex(S::BlockedSlice, i::Integer) = getindex(S.indices, i) +@propagate_inbounds getindex(S::BlockedSlice, k::Block{1}) = BlockSlice(S.blocks[Int(k)], getindex(S.indices, k)) struct BlockRange{N,R<:NTuple{N,AbstractUnitRange{<:Integer}}} <: AbstractArray{Block{N,Int},N} indices::R diff --git a/src/views.jl b/src/views.jl index 2b9b0c5d..53d54706 100644 --- a/src/views.jl +++ b/src/views.jl @@ -11,7 +11,7 @@ function unblock(A, inds, I) end _blockslice(B, a::AbstractUnitRange) = BlockSlice(B, a) -_blockslice(B, a) = BlockInds(B, a) +_blockslice(B, a) = BlockedSlice(B, a) # Allow `ones(2)[Block(1)[1:1], Block(1)[1:1]]` which is # similar to `ones(2)[1:1, 1:1]`. diff --git a/test/test_blockindices.jl b/test/test_blockindices.jl index b57512be..93542d23 100644 --- a/test/test_blockindices.jl +++ b/test/test_blockindices.jl @@ -2,7 +2,7 @@ module TestBlockIndices using BlockArrays, FillArrays, Test, StaticArrays, ArrayLayouts using OffsetArrays -import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice +import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice, BlockedSlice @testset "Blocks" begin @test Int(Block(2)) === Integer(Block(2)) === Number(Block(2)) === 2 @@ -831,6 +831,16 @@ end end end +@testset "BlockedSlice" begin + b = BlockedSlice([Block(2), Block(1)], mortar([3:5, 1:2])) + @test length(b) == 5 + for i in eachindex(b.indices) + @test b[i] === b.indices[i] + end + @test b[Block(1)] === BlockSlice(Block(2), 3:5) + @test b[Block(2)] === BlockSlice(Block(1), 1:2) +end + #= [1,1 1,2] | [1,3 1,4 1,5] -------------------------- diff --git a/test/test_blockrange.jl b/test/test_blockrange.jl index 76f81e3e..a99c43bb 100644 --- a/test/test_blockrange.jl +++ b/test/test_blockrange.jl @@ -23,6 +23,13 @@ using BlockArrays, Test @test view(A, Block.(1:2)) == [1,2,3] @test A[Block.(1:2)] == [1,2,3] + V = view(A, [Block(3), Block(2)]) + @test V == [4, 5, 6, 2, 3] + I = parentindices(V)[1] + @test I isa BlockArrays.BlockedSlice{<:Vector{<:Block{1}}} + @test V[Block(1)] == 4:6 + @test V[Block(2)] == 2:3 + A = BlockArray(reshape(collect(1:(6*12)),6,12), 1:3, 3:5) @test view(A, Block.(1:2), Block.(1:2)) == A[1:3,1:7] From 974091f251081a611ec0a8d97124b9292851440f Mon Sep 17 00:00:00 2001 From: mtfishman Date: Tue, 6 May 2025 15:50:36 -0400 Subject: [PATCH 3/4] Tweak docstring --- src/blockindices.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blockindices.jl b/src/blockindices.jl index af098fe7..4aa4b8a1 100644 --- a/src/blockindices.jl +++ b/src/blockindices.jl @@ -296,7 +296,7 @@ Block(bs::BlockSlice{<:BlockIndexRange}) = Block(bs.block) Represents blocked indices attached to a collection of corresponding blocks. Upon calling `to_indices()`, a collection of blocks are converted to BlockedSlice objects to represent -the indices over which the Blocks span. +the indices over which the blocks span. This mimics the relationship between `Colon` and `Base.Slice`, `Block` and `BlockSlice`, etc. """ From d97e3a4621550a83cfcea544a8ee31757654bc64 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Tue, 6 May 2025 16:13:10 -0400 Subject: [PATCH 4/4] Reindexing/nested slicing --- src/views.jl | 3 ++- test/test_blockrange.jl | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/views.jl b/src/views.jl index 53d54706..d56b3d2c 100644 --- a/src/views.jl +++ b/src/views.jl @@ -150,10 +150,11 @@ block(A::Block) = A @inline view(block_arr::AbstractBlockArray{<:Any,N}, blocks::Vararg{BlockSlice1, N}) where N = view(block_arr, map(block,blocks)...) -const BlockSlices = Union{Base.Slice,BlockSlice{<:BlockRange{1}}} +const BlockSlices = Union{Base.Slice,BlockSlice{<:BlockRange{1}},BlockedSlice} # view(V::SubArray{<:Any,N,NTuple{N,BlockSlices}}, _block_reindex(b::BlockSlice, i::Block{1}) = b.block[Int(i)] +_block_reindex(b::BlockedSlice, i::Block{1}) = b.blocks[Int(i)] _block_reindex(b::Slice, i::Block{1}) = i @inline view(V::SubArray{<:Any,N,<:AbstractBlockArray,<:NTuple{N,BlockSlices}}, block::Block{N}) where N = diff --git a/test/test_blockrange.jl b/test/test_blockrange.jl index a99c43bb..8fee153f 100644 --- a/test/test_blockrange.jl +++ b/test/test_blockrange.jl @@ -29,6 +29,8 @@ using BlockArrays, Test @test I isa BlockArrays.BlockedSlice{<:Vector{<:Block{1}}} @test V[Block(1)] == 4:6 @test V[Block(2)] == 2:3 + @test view(V, Block(1)) === view(A, Block(3)) + @test view(V, Block(2)) === view(A, Block(2)) A = BlockArray(reshape(collect(1:(6*12)),6,12), 1:3, 3:5)