From 3b8987f361d67cb7e2cf598b649c6f71a23e35b5 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Mon, 23 Jun 2025 16:17:42 -0400 Subject: [PATCH 1/6] Generalize BlockIndex and BlockIndexRange --- src/blockindices.jl | 24 ++++++++++++------------ test/test_blockindices.jl | 8 ++++++++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/blockindices.jl b/src/blockindices.jl index 1226e8af..b0bb6577 100644 --- a/src/blockindices.jl +++ b/src/blockindices.jl @@ -140,7 +140,7 @@ julia> a[BlockIndex((2,2), (2,3))] 20 ``` """ -struct BlockIndex{N,TI<:Tuple{Vararg{Integer,N}},Tα<:Tuple{Vararg{Integer,N}}} +struct BlockIndex{N,TI<:Tuple{Vararg{Any,N}},Tα<:Tuple{Vararg{Any,N}}} I::TI α::Tα end @@ -148,15 +148,15 @@ end @inline BlockIndex(a::NTuple{N,Block{1}}, b::Tuple) where N = BlockIndex(Int.(a), b) @inline BlockIndex(::Tuple{}, b::Tuple{}) = BlockIndex{0,Tuple{},Tuple{}}((), ()) -@inline BlockIndex(a::Integer, b::Integer) = BlockIndex((a,), (b,)) -@inline BlockIndex(a::Tuple, b::Integer) = BlockIndex(a, (b,)) -@inline BlockIndex(a::Integer, b::Tuple) = BlockIndex((a,), b) +@inline BlockIndex(a, b) = BlockIndex((a,), (b,)) +@inline BlockIndex(a::Tuple, b) = BlockIndex(a, (b,)) +@inline BlockIndex(a, b::Tuple) = BlockIndex((a,), b) @inline BlockIndex() = BlockIndex((), ()) @inline BlockIndex(a::Block, b::Tuple) = BlockIndex(a.n, b) -@inline BlockIndex(a::Block, b::Integer) = BlockIndex(a, (b,)) +@inline BlockIndex(a::Block, b) = BlockIndex(a, (b,)) -@inline function BlockIndex(I::Tuple{Vararg{Integer,N}}, α::Tuple{Vararg{Integer,M}}) where {M,N} +@inline function BlockIndex(I::Tuple{Vararg{Any,N}}, α::Tuple{Vararg{Any,M}}) where {M,N} M <= N || throw(ArgumentError("number of indices must not exceed the number of blocks")) α2 = ntuple(k -> k <= M ? α[k] : 1, N) BlockIndex(I, α2) @@ -182,10 +182,10 @@ end checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractVector{<:BlockIndex{N}}) where N = all(checkbounds.(Bool, Ref(A), I)) -struct BlockIndexRange{N,R<:Tuple{Vararg{AbstractUnitRange{<:Integer},N}},I<:Tuple{Vararg{Integer,N}},BI<:Integer} <: AbstractArray{BlockIndex{N,NTuple{N,BI},I},N} +struct BlockIndexRange{N,R<:Tuple{Vararg{AbstractVector,N}},I<:Tuple{Vararg{Any,N}},BI} <: AbstractArray{BlockIndex{N,NTuple{N,BI},I},N} block::Block{N,BI} indices::R - function BlockIndexRange(block::Block{N,BI}, inds::R) where {N,BI<:Integer,R<:Tuple{Vararg{AbstractUnitRange{<:Integer},N}}} + function BlockIndexRange(block::Block{N,BI}, inds::R) where {N,BI<:Integer,R<:Tuple{Vararg{AbstractVector,N}}} I = Tuple{eltype.(inds)...} return new{N,R,I,BI}(block,inds) end @@ -198,7 +198,7 @@ represents a cartesian range inside a block. """ BlockIndexRange -BlockIndexRange(block::Block{N}, inds::Vararg{AbstractUnitRange{<:Integer},N}) where {N} = +BlockIndexRange(block::Block{N}, inds::Vararg{AbstractVector,N}) where {N} = BlockIndexRange(block,inds) block(R::BlockIndexRange) = R.block @@ -206,12 +206,12 @@ block(R::BlockIndexRange) = R.block copy(R::BlockIndexRange) = BlockIndexRange(R.block, map(copy, R.indices)) getindex(::Block{0}) = BlockIndex() -getindex(B::Block{N}, inds::Vararg{Integer,N}) where N = BlockIndex(B,inds) -getindex(B::Block{N}, inds::Vararg{AbstractUnitRange{<:Integer},N}) where N = BlockIndexRange(B,inds) +getindex(B::Block{N}, inds::Vararg{Any,N}) where N = BlockIndex(B,inds) +getindex(B::Block{N}, inds::Vararg{AbstractVector,N}) where N = BlockIndexRange(B,inds) getindex(B::Block{1}, inds::Colon) = B getindex(B::Block{1}, inds::Base.Slice) = B -@propagate_inbounds getindex(B::BlockIndexRange{1}, kr::AbstractUnitRange{<:Integer}) = BlockIndexRange(B.block, B.indices[1][kr]) +@propagate_inbounds getindex(B::BlockIndexRange{1}, kr::AbstractVector) = BlockIndexRange(B.block, B.indices[1][kr]) @propagate_inbounds getindex(B::BlockIndexRange{N}, inds::Vararg{Int,N}) where N = B.block[Base.reindex(B.indices, inds)...] eltype(R::BlockIndexRange) = eltype(typeof(R)) diff --git a/test/test_blockindices.jl b/test/test_blockindices.jl index b57512be..0d44469e 100644 --- a/test/test_blockindices.jl +++ b/test/test_blockindices.jl @@ -86,16 +86,24 @@ import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice @testset "BlockIndex" begin @test Block()[] == BlockIndex() @test Block(1)[1] == BlockIndex((1,),(1,)) + @test Block(1)[Block(1)] == BlockIndex((1,),(Block(1),)) @test Block(1)[1:2] == BlockIndexRange(Block(1),(1:2,)) + @test Block(1)[[1,3]] == BlockIndexRange(Block(1),([1,3],)) @test Block(1,1)[1,1] == BlockIndex((1,1),(1,1)) == BlockIndex((1,1),(1,)) @test Block(1,1)[1:2,1:2] == BlockIndexRange(Block(1,1),(1:2,1:2)) + @test Block(1,1)[[1,3],1:2] == BlockIndexRange(Block(1,1),([1,3],1:2)) @test Block(1)[1:3][1:2] == BlockIndexRange(Block(1),1:2) + @test Block(1)[[1,3,5]][2:3] == BlockIndexRange(Block(1),[3,5]) + @test Block(1)[2:4][[1,3]] == BlockIndexRange(Block(1),[2,4]) @test BlockIndex((2,2,2),(2,)) == BlockIndex((2,2,2),(2,1,)) == BlockIndex((2,2,2),(2,1,1)) @test BlockIndex(2,(2,)) === BlockIndex((2,),(2,)) @test BlockIndex(UInt(2),(2,)) === BlockIndex((UInt(2),),(2,)) @test BlockIndex(Block(2),2) === BlockIndex(Block(2),(2,)) @test BlockIndex(Block(2),UInt(2)) === BlockIndex(Block(2),(UInt(2),)) + @test BlockIndex(Block(2),Block(2)) === BlockIndex(Block(2),(Block(2),)) @test copy(Block(1)[1:2]) === BlockIndexRange(Block(1),1:2) + @test copy(Block(1)[[1,3]]) == BlockIndexRange(Block(1),[1,3]) + @test copy(Block(1)[[1,3]]) ≢ BlockIndexRange(Block(1),[1,3]) end @testset "BlockRange" begin From 08b78eedd47caaaaad03113f334ab143afa6fc7c Mon Sep 17 00:00:00 2001 From: mtfishman Date: Mon, 23 Jun 2025 16:30:52 -0400 Subject: [PATCH 2/6] Generalize slicing into BlockIndexRange --- src/blockindices.jl | 2 +- test/test_blockindices.jl | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/blockindices.jl b/src/blockindices.jl index b0bb6577..bf0904b1 100644 --- a/src/blockindices.jl +++ b/src/blockindices.jl @@ -211,7 +211,7 @@ getindex(B::Block{N}, inds::Vararg{AbstractVector,N}) where N = BlockIndexRange( getindex(B::Block{1}, inds::Colon) = B getindex(B::Block{1}, inds::Base.Slice) = B -@propagate_inbounds getindex(B::BlockIndexRange{1}, kr::AbstractVector) = BlockIndexRange(B.block, B.indices[1][kr]) +@propagate_inbounds getindex(B::BlockIndexRange{N}, kr::Vararg{AbstractVector,N}) where N = BlockIndexRange(B.block, map(getindex, B.indices, kr)) @propagate_inbounds getindex(B::BlockIndexRange{N}, inds::Vararg{Int,N}) where N = B.block[Base.reindex(B.indices, inds)...] eltype(R::BlockIndexRange) = eltype(typeof(R)) diff --git a/test/test_blockindices.jl b/test/test_blockindices.jl index 0d44469e..56d4bc00 100644 --- a/test/test_blockindices.jl +++ b/test/test_blockindices.jl @@ -93,8 +93,11 @@ import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice @test Block(1,1)[1:2,1:2] == BlockIndexRange(Block(1,1),(1:2,1:2)) @test Block(1,1)[[1,3],1:2] == BlockIndexRange(Block(1,1),([1,3],1:2)) @test Block(1)[1:3][1:2] == BlockIndexRange(Block(1),1:2) + @test Block(1)[[1,3,5]][[1,3]] == BlockIndexRange(Block(1),[1,5]) @test Block(1)[[1,3,5]][2:3] == BlockIndexRange(Block(1),[3,5]) @test Block(1)[2:4][[1,3]] == BlockIndexRange(Block(1),[2,4]) + @test Block(1,1)[1:3,1:3][1:2,1:2] == BlockIndexRange(Block(1,1),1:2,1:2) + @test Block(1,1)[1:3,1:3][1:2,[1,3]] == BlockIndexRange(Block(1,1),1:2,[1,3]) @test BlockIndex((2,2,2),(2,)) == BlockIndex((2,2,2),(2,1,)) == BlockIndex((2,2,2),(2,1,1)) @test BlockIndex(2,(2,)) === BlockIndex((2,),(2,)) @test BlockIndex(UInt(2),(2,)) === BlockIndex((UInt(2),),(2,)) @@ -574,6 +577,7 @@ end b = blockedrange([1,2,3]) @test b[Block(3)[2]] == b[Block(3)][2] == 5 @test b[Block(3)[2:3]] == b[Block(3)][2:3] == 5:6 + @test b[Block(3)[[3,2]]] == b[Block(3)][[3,2]] == [6,5] end @testset "BlockRange indexing" begin From 48d1d44e7557d221b28e3e4b249188e2a290fde6 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Mon, 23 Jun 2025 17:27:10 -0400 Subject: [PATCH 3/6] More general blockwise slicing --- Project.toml | 2 +- src/blockindices.jl | 41 ++++++++++++++++++++++++++++++++++++--- src/views.jl | 5 +++-- test/test_blockarrays.jl | 16 +++++++++++++++ test/test_blockindices.jl | 12 +++++++++++- test/test_blockviews.jl | 19 +++++++++++++++++- 6 files changed, 87 insertions(+), 8 deletions(-) diff --git a/Project.toml b/Project.toml index edf66627..1935c38a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "BlockArrays" uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -version = "1.6.3" +version = "1.7.0" [deps] ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" diff --git a/src/blockindices.jl b/src/blockindices.jl index bf0904b1..01d5edb6 100644 --- a/src/blockindices.jl +++ b/src/blockindices.jl @@ -256,10 +256,11 @@ Block(bs::BlockIndexRange) = bs.block """ BlockSlice(block, indices) -Represent an AbstractUnitRange{<:Integer} of indices that attaches a block. +Represents an AbstractUnitRange{<:Integer} of indices attached to a block, +a subblock, or a range of blocks. Upon calling `to_indices()`, Blocks are converted to BlockSlice objects to represent -the indices over which the Block spans. +the indices over which the block, subblock, or range of blocks spans. This mimics the relationship between `Colon` and `Base.Slice`. """ @@ -282,7 +283,7 @@ _indices(B) = B @propagate_inbounds getindex(S::BlockSlice, i::Integer) = getindex(S.indices, i) @propagate_inbounds getindex(S::BlockSlice{<:Block{1}}, k::AbstractUnitRange{<:Integer}) = BlockSlice(S.block[_indices(k)], S.indices[_indices(k)]) -@propagate_inbounds getindex(S::BlockSlice{<:BlockIndexRange{1}}, k::AbstractUnitRange{<:Integer}) = +@propagate_inbounds getindex(S::BlockSlice{<:BlockIndexRange{1,<:Tuple{AbstractUnitRange{<:Integer}}}}, k::AbstractUnitRange{<:Integer}) = BlockSlice(S.block[_indices(k)], S.indices[_indices(k)]) # Avoid creating a SubArray wrapper in certain non-allocating cases @@ -290,12 +291,46 @@ _indices(B) = B Block(bs::BlockSlice{<:BlockIndexRange}) = Block(bs.block) +""" + NoncontiguousBlockSlice(blocks, indices) + +Represents an AbstractVector of indices attached to a (potentially non-contiguous) subblock, +set of blocks, or set of subblocks. This is the generalization of `BlockSlice` to +non-contiguous slices. + +Upon calling `to_indices()`, a collection of blocks are converted to NoncontiguousBlockSlice objects to represent +the indices over which the blocks span. + +This mimics the relationship between `Colon` and `Base.Slice`, `Block` and `BlockSlice`, etc. +""" +struct NoncontiguousBlockSlice{BB,T,INDS<:AbstractVector{T}} <: AbstractVector{T} + block::BB + indices::INDS +end + +Block(bs::NoncontiguousBlockSlice{<:Block}) = bs.block + +for f in (:axes, :unsafe_indices, :axes1, :first, :last, :size, :length, + :unsafe_length, :start) + @eval $f(S::NoncontiguousBlockSlice) = $f(S.indices) +end + +_indices(B::NoncontiguousBlockSlice) = B.indices + +@propagate_inbounds getindex(S::NoncontiguousBlockSlice, i::Integer) = getindex(S.indices, i) +@propagate_inbounds getindex(S::NoncontiguousBlockSlice{<:Block{1}}, k::AbstractVector{<:Integer}) = + NoncontiguousBlockSlice(S.block[_indices(k)], S.indices[_indices(k)]) +@propagate_inbounds getindex(S::NoncontiguousBlockSlice{<:BlockIndexRange{1,Tuple{AbstractVector}}}, k::AbstractVector{<:Integer}) = + NoncontiguousBlockSlice(S.block[_indices(k)], S.indices[_indices(k)]) +@propagate_inbounds getindex(S::NoncontiguousBlockSlice{<:AbstractVector{<:Block{1}}}, k::Block{1}) = + BlockSlice(S.block[Int(k)], getindex(S.indices, k)) struct BlockRange{N,R<:NTuple{N,AbstractUnitRange{<:Integer}}} <: AbstractArray{Block{N,Int},N} indices::R BlockRange{N,R}(inds::R) where {N,R} = new{N,R}(inds) end +Block(bs::NoncontiguousBlockSlice{<:BlockIndexRange}) = Block(bs.block) # The following is adapted from Julia v0.7 base/multidimensional.jl # definition of CartesianRange diff --git a/src/views.jl b/src/views.jl index ec8a9952..97e884cb 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) = NoncontiguousBlockSlice(B, a) # Allow `ones(2)[Block(1)[1:1], Block(1)[1:1]]` which is # similar to `ones(2)[1:1, 1:1]`. @@ -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}},NoncontiguousBlockSlice{<:AbstractVector{<:Block{1}}}} # view(V::SubArray{<:Any,N,NTuple{N,BlockSlices}}, _block_reindex(b::BlockSlice, i::Block{1}) = b.block[Int(i)] +_block_reindex(b::NoncontiguousBlockSlice, i::Block{1}) = b.block[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_blockarrays.jl b/test/test_blockarrays.jl index 30457f2b..7afa2cb9 100644 --- a/test/test_blockarrays.jl +++ b/test/test_blockarrays.jl @@ -861,6 +861,22 @@ end @test A[Block(1)[1], Block(1)[1:1]] == BlockArray(A)[Block(1)[1], Block(1)[1:1]] == A[1,1:1] end + @testset "Non-contiguous BlockIndexRange" begin + a = BlockedArray(randn(5), [2,3]) + @test a[Block(2)[[1,3]]] == a[[3,5]] + A = BlockedArray(randn(5,5), [2,3], [2,3]) + @test A[Block(2,2)[[1,3],[2,3]]] == A[[3,5],[4,5]] + @test A[Block(2,2)[[1,3],1:2]] == A[[3,5],3:4] + end + + @testset "Nested block indexing" begin + a = BlockedArray(randn(4), [2,2]) + b = BlockedArray(randn(4), [2,2]) + A = mortar([a,b]) + @test A[Block(2)[Block(1)]] == A[Block(2)][Block(1)] == b[Block(1)] + @test A[Block(2)[Block(1)[2]]] == A[Block(2)][Block(1)[2]] == b[Block(1)[2]] + end + @testset "BlockIndexRange blocks" begin a = mortar([Block(1)[1:2], Block(3)[2:3]]) @test a[Block(1)] === Block(1)[1:2] diff --git a/test/test_blockindices.jl b/test/test_blockindices.jl index 56d4bc00..17acb867 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, NoncontiguousBlockSlice @testset "Blocks" begin @test Int(Block(2)) === Integer(Block(2)) === Number(Block(2)) === 2 @@ -843,6 +843,16 @@ end end end +@testset "NoncontiguousBlockSlice" begin + b = NoncontiguousBlockSlice([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_blockviews.jl b/test/test_blockviews.jl index f701b7b5..7deed82a 100644 --- a/test/test_blockviews.jl +++ b/test/test_blockviews.jl @@ -2,6 +2,7 @@ module TestBlockViews using BlockArrays, ArrayLayouts, Test using FillArrays +import BlockArrays: NoncontiguousBlockSlice # useds to force SubArray return bview(a, b) = Base.invoke(view, Tuple{AbstractArray,Any}, a, b) @@ -217,6 +218,22 @@ bview(a, b) = Base.invoke(view, Tuple{AbstractArray,Any}, a, b) @test A[Block.(2:3)] == A[2:end] end + @testset "getindex and view with Block-vector" begin + A = BlockArray(reshape(collect(1:(6*12)),6,12), 1:3, 3:5) + V = view(A, [Block(3),Block(2)], [Block(3),Block(2)]) + @test V[Block(1,1)] == A[Block(3,3)] + @test V[Block(2,1)] == A[Block(2,3)] + @test V[Block(1,2)] == A[Block(3,2)] + @test V[Block(2,2)] == A[Block(2,2)] + I = parentindices(V) + @test I[1] isa NoncontiguousBlockSlice{<:Vector{<:Block{1}}} + @test I[2] isa NoncontiguousBlockSlice{<:Vector{<:Block{1}}} + @test view(V, Block(1,1)) === view(A, Block(3,3)) + @test view(V, Block(2,1)) === view(A, Block(2,3)) + @test view(V, Block(1,2)) === view(A, Block(3,2)) + @test view(V, Block(2,2)) === view(A, Block(2,2)) + end + @testset "non-allocation blocksize" begin A = BlockArray(randn(5050), 1:100) @test blocksize(A) == (100,) @@ -314,7 +331,7 @@ bview(a, b) = Base.invoke(view, Tuple{AbstractArray,Any}, a, b) @test a[Block(1)[1:3]] ≡ view(a,Block(1)[1:3]) ≡ view(v,Block(1)[1:3]) ≡ 7:9 end - @testset "blockrange-of-blockreange" begin + @testset "blockrange-of-blockrange" begin a = mortar([7:9,5:6]) v = view(a,Block.(1:2)) @test view(v, Block(1)) ≡ 7:9 From c0d59c1818769d56140ab3ae54e267747db9e5e3 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Mon, 23 Jun 2025 17:39:52 -0400 Subject: [PATCH 4/6] Small reorganization --- src/blockindices.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/blockindices.jl b/src/blockindices.jl index 01d5edb6..5a8309d9 100644 --- a/src/blockindices.jl +++ b/src/blockindices.jl @@ -270,6 +270,7 @@ struct BlockSlice{BB,T<:Integer,INDS<:AbstractUnitRange{T}} <: AbstractUnitRange end Block(bs::BlockSlice{<:Block}) = bs.block +Block(bs::BlockSlice{<:BlockIndexRange}) = Block(bs.block) for f in (:axes, :unsafe_indices, :axes1, :first, :last, :size, :length, @@ -289,8 +290,6 @@ _indices(B) = B # Avoid creating a SubArray wrapper in certain non-allocating cases @propagate_inbounds view(C::CartesianIndices{N}, bs::Vararg{BlockSlice,N}) where {N} = view(C, map(x->x.indices, bs)...) -Block(bs::BlockSlice{<:BlockIndexRange}) = Block(bs.block) - """ NoncontiguousBlockSlice(blocks, indices) @@ -309,6 +308,7 @@ struct NoncontiguousBlockSlice{BB,T,INDS<:AbstractVector{T}} <: AbstractVector{T end Block(bs::NoncontiguousBlockSlice{<:Block}) = bs.block +Block(bs::NoncontiguousBlockSlice{<:BlockIndexRange}) = Block(bs.block) for f in (:axes, :unsafe_indices, :axes1, :first, :last, :size, :length, :unsafe_length, :start) @@ -330,8 +330,6 @@ struct BlockRange{N,R<:NTuple{N,AbstractUnitRange{<:Integer}}} <: AbstractArray{ BlockRange{N,R}(inds::R) where {N,R} = new{N,R}(inds) end -Block(bs::NoncontiguousBlockSlice{<:BlockIndexRange}) = Block(bs.block) - # The following is adapted from Julia v0.7 base/multidimensional.jl # definition of CartesianRange From e383129ed35f7e7278c5fe011331fc3c5336964b Mon Sep 17 00:00:00 2001 From: mtfishman Date: Mon, 23 Jun 2025 19:04:33 -0400 Subject: [PATCH 5/6] Improve code coverage --- test/test_blockindices.jl | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/test/test_blockindices.jl b/test/test_blockindices.jl index 17acb867..c912d0b3 100644 --- a/test/test_blockindices.jl +++ b/test/test_blockindices.jl @@ -826,6 +826,10 @@ end @test b[1:2] ≡ b[1:2][1:2] ≡ BlockSlice(Block(5)[1:2],1:2) @test Block(b) ≡ Block(5) + bi = BlockSlice(Block(2)[2:4],3:5) + @test Block(bi) ≡ Block(2) + @test bi[2:3] ≡ BlockSlice(Block(2)[3:4],4:5) + @testset "OneTo converts" begin for b in (BlockSlice(Block(1), 1:1), BlockSlice(Block.(1:1), 1:1), BlockSlice(Block(1)[1:1], 1:1)) @test convert(typeof(b), Base.OneTo(1)) ≡ b @@ -844,13 +848,26 @@ end end @testset "NoncontiguousBlockSlice" begin - b = NoncontiguousBlockSlice([Block(2), Block(1)], mortar([3:5, 1:2])) + b = NoncontiguousBlockSlice([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) + @test BlockArrays._indices(b) == mortar([3:5,1:2]) + + b = NoncontiguousBlockSlice(Block(3), 2:4) + @test b[2:3] == NoncontiguousBlockSlice(Block(3)[3:4], 3:4) + @test b[[1,3]] == NoncontiguousBlockSlice(Block(3)[[1,3]], [2,4]) + @test Block(b) === Block(3) + @test BlockArrays._indices(b) === 2:4 + + b = NoncontiguousBlockSlice(Block(3)[[2,4,6]], [3,5,7]) + @test b[2:3] == NoncontiguousBlockSlice(Block(3)[[4,6]], [5,7]) + @test b[[1,3]] == NoncontiguousBlockSlice(Block(3)[[2,6]], [3,7]) + @test Block(b) === Block(3) + @test BlockArrays._indices(b) == [3,5,7] end #= From d5555b0183a9b6d3628fe0900629bf342487b7b1 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Mon, 23 Jun 2025 22:02:23 -0400 Subject: [PATCH 6/6] Fix type constraint --- src/blockindices.jl | 2 +- test/test_blockindices.jl | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/blockindices.jl b/src/blockindices.jl index 5a8309d9..5cf7c518 100644 --- a/src/blockindices.jl +++ b/src/blockindices.jl @@ -320,7 +320,7 @@ _indices(B::NoncontiguousBlockSlice) = B.indices @propagate_inbounds getindex(S::NoncontiguousBlockSlice, i::Integer) = getindex(S.indices, i) @propagate_inbounds getindex(S::NoncontiguousBlockSlice{<:Block{1}}, k::AbstractVector{<:Integer}) = NoncontiguousBlockSlice(S.block[_indices(k)], S.indices[_indices(k)]) -@propagate_inbounds getindex(S::NoncontiguousBlockSlice{<:BlockIndexRange{1,Tuple{AbstractVector}}}, k::AbstractVector{<:Integer}) = +@propagate_inbounds getindex(S::NoncontiguousBlockSlice{<:BlockIndexRange{1,<:Tuple{AbstractVector}}}, k::AbstractVector{<:Integer}) = NoncontiguousBlockSlice(S.block[_indices(k)], S.indices[_indices(k)]) @propagate_inbounds getindex(S::NoncontiguousBlockSlice{<:AbstractVector{<:Block{1}}}, k::Block{1}) = BlockSlice(S.block[Int(k)], getindex(S.indices, k)) diff --git a/test/test_blockindices.jl b/test/test_blockindices.jl index c912d0b3..cc0ed845 100644 --- a/test/test_blockindices.jl +++ b/test/test_blockindices.jl @@ -864,10 +864,18 @@ end @test BlockArrays._indices(b) === 2:4 b = NoncontiguousBlockSlice(Block(3)[[2,4,6]], [3,5,7]) - @test b[2:3] == NoncontiguousBlockSlice(Block(3)[[4,6]], [5,7]) - @test b[[1,3]] == NoncontiguousBlockSlice(Block(3)[[2,6]], [3,7]) + @test b isa NoncontiguousBlockSlice{<:BlockIndexRange{1}} @test Block(b) === Block(3) @test BlockArrays._indices(b) == [3,5,7] + @test b[2:3] == NoncontiguousBlockSlice(Block(3)[[4,6]], [5,7]) + @test b[2:3] isa NoncontiguousBlockSlice{<:BlockIndexRange{1}} + @test Block(b) === Block(3) + @test Block(b[2:3]) === Block(3) + @test BlockArrays._indices(b[2:3]) == [5,7] + @test b[[1,3]] == NoncontiguousBlockSlice(Block(3)[[2,6]], [3,7]) + @test b[[1,3]] isa NoncontiguousBlockSlice{<:BlockIndexRange{1}} + @test Block(b[[1,3]]) === Block(3) + @test BlockArrays._indices(b[[1,3]]) == [3,7] end #=