diff --git a/docs/src/lib/internals.md b/docs/src/lib/internals.md index 780cafaa..b94ebfcf 100644 --- a/docs/src/lib/internals.md +++ b/docs/src/lib/internals.md @@ -23,6 +23,7 @@ BlockedOneTo BlockedUnitRange BlockRange BlockIndexRange +BlockIndices BlockSlice unblock SubBlockIterator diff --git a/src/BlockArrays.jl b/src/BlockArrays.jl index 63497ce5..d824ab04 100644 --- a/src/BlockArrays.jl +++ b/src/BlockArrays.jl @@ -4,7 +4,7 @@ using LinearAlgebra, ArrayLayouts, FillArrays # AbstractBlockArray interface exports export AbstractBlockArray, AbstractBlockMatrix, AbstractBlockVector, AbstractBlockVecOrMat export Block, getblock, getblock!, setblock!, eachblock, blocks -export blockaxes, blocksize, blocklength, blockcheckbounds, BlockBoundsError, BlockIndex, BlockIndexRange +export blockaxes, blocksize, blocklength, blockcheckbounds, BlockBoundsError, BlockIndex, BlockIndexRange, BlockIndices export blocksizes, blocklengths, blocklasts, blockfirsts, blockisequal, blockequals, blockisapprox export eachblockaxes export BlockRange, blockedrange, BlockedUnitRange, BlockedOneTo diff --git a/src/blockaxis.jl b/src/blockaxis.jl index 022c661e..a8fbf930 100644 --- a/src/blockaxis.jl +++ b/src/blockaxis.jl @@ -7,9 +7,9 @@ @propagate_inbounds getindex(b::AbstractArray, K::BlockIndex{1}, J::BlockIndex{1}...) = b[BlockIndex(tuple(K, J...))] -@propagate_inbounds getindex(b::AbstractArray{T,N}, K::BlockIndexRange{N}) where {T,N} = b[block(K)][K.indices...] -@propagate_inbounds getindex(b::LayoutArray{T,N}, K::BlockIndexRange{N}) where {T,N} = b[block(K)][K.indices...] -@propagate_inbounds getindex(b::LayoutArray{T,1}, K::BlockIndexRange{1}) where {T} = b[block(K)][K.indices...] +@propagate_inbounds getindex(b::AbstractArray{T,N}, K::BlockIndices{N}) where {T,N} = b[block(K)][K.indices...] +@propagate_inbounds getindex(b::LayoutArray{T,N}, K::BlockIndices{N}) where {T,N} = b[block(K)][K.indices...] +@propagate_inbounds getindex(b::LayoutArray{T,1}, K::BlockIndices{1}) where {T} = b[block(K)][K.indices...] function findblockindex(b::AbstractVector, k::Integer) @boundscheck k in b || throw(BoundsError()) @@ -539,11 +539,11 @@ end getindex(b::AbstractBlockedUnitRange, KR::AbstractVector{<:Block{1}}) = mortar([b[K] for K in KR]) getindex(b::AbstractBlockedUnitRange, KR::AbstractVector{<:AbstractVector{<:Block{1}}}) = mortar([b[K] for K in KR]) -getindex(b::AbstractBlockedUnitRange, Kkr::BlockIndexRange{1}) = b[block(Kkr)][Kkr.indices...] +getindex(b::AbstractBlockedUnitRange, Kkr::BlockIndices{1}) = b[block(Kkr)][Kkr.indices...] getindex(b::AbstractBlockedUnitRange, KR::AbstractVector{<:BlockIndex{1}}) = [b[K] for K in KR] -getindex(b::AbstractBlockedUnitRange, KR::AbstractVector{<:BlockIndexRange{1}}) = mortar([b[K] for K in KR]) +getindex(b::AbstractBlockedUnitRange, KR::AbstractVector{<:BlockIndices{1}}) = mortar([b[K] for K in KR]) getindex(b::AbstractBlockedUnitRange, KR::AbstractVector{<:AbstractVector{<:BlockIndex{1}}}) = mortar([b[K] for K in KR]) -getindex(b::AbstractBlockedUnitRange, KR::AbstractVector{<:AbstractVector{<:BlockIndexRange{1}}}) = mortar([b[K] for K in KR]) +getindex(b::AbstractBlockedUnitRange, KR::AbstractVector{<:AbstractVector{<:BlockIndices{1}}}) = mortar([b[K] for K in KR]) getindex(b::AbstractBlockedUnitRange, KR::AbstractVector{<:AbstractVector{<:AbstractVector{<:BlockIndex{1}}}}) = mortar([b[K] for K in KR]) _searchsortedfirst(a::AbstractVector, k) = searchsortedfirst(a, k) @@ -567,7 +567,7 @@ Base.dataids(b::AbstractBlockedUnitRange) = Base.dataids(blocklasts(b)) Base.checkindex(::Type{Bool}, b::BlockRange, K::Integer) = checkindex(Bool, Integer.(b), K) Base.checkindex(::Type{Bool}, b::AbstractUnitRange{<:Integer}, K::Block{1}) = checkindex(Bool, blockaxes(b,1), Integer(K)) -function Base.checkindex(::Type{Bool}, axis::AbstractBlockedUnitRange, ind::BlockIndexRange{1}) +function Base.checkindex(::Type{Bool}, axis::AbstractBlockedUnitRange, ind::BlockIndices{1}) checkindex(Bool, axis, first(ind)) && checkindex(Bool, axis, last(ind)) end function Base.checkindex(::Type{Bool}, axis::AbstractBlockedUnitRange, ind::BlockIndex{1}) diff --git a/src/blockindices.jl b/src/blockindices.jl index d2ce8540..80a6dcf3 100644 --- a/src/blockindices.jl +++ b/src/blockindices.jl @@ -207,19 +207,68 @@ end checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{<:BlockIndex{N}}) where N = all(i -> checkbounds(Bool, A, i), 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 BlockIndices{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 BlockIndices(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 end +""" + BlockIndices(block, startind:stopind) +Represents a cartesian product of indices inside a block. +It can be constructed and used to index into `BlockArrays` in the following manner: +```jldoctest +julia> BlockIndices(Block(1,2), ([1,3],[2,4])) +Block(1, 2)[[1, 3], [2, 4]] + +julia> Block(1)[[1,3]] == BlockIndices(Block(1), [1,3]) +true + +julia> Block(1,2)[[1,3],[2,4]] == BlockIndices(Block(1,2), ([1,3],[2,4])) +true + +julia> BlockIndices((Block(1)[[1,3]], Block(2)[[2,4]])) +Block(1, 2)[[1, 3], [2, 4]] + +julia> arr = Array(reshape(1:25, (5,5))); + +julia> a = BlockedArray(arr, [3,2], [1,4]) +2×2-blocked 5×5 BlockedMatrix{Int64}: + 1 │ 6 11 16 21 + 2 │ 7 12 17 22 + 3 │ 8 13 18 23 + ───┼──────────────── + 4 │ 9 14 19 24 + 5 │ 10 15 20 25 + +julia> a[Block(1,2)[[1,3],[2,4]]] +2×2 Matrix{Int64}: + 11 21 + 13 23 + +julia> a[Block(2,2)[[2],[2,4]]] +1×2 Matrix{Int64}: + 15 25 +``` +""" +BlockIndices + +BlockIndices(block::Block{N}, inds::Vararg{AbstractVector,N}) where {N} = + BlockIndices(block,inds) +function BlockIndices(inds::Tuple{BlockIndices{1},Vararg{BlockIndices{1}}}) + BlockIndices(Block(block.(inds)), map(ind -> ind.indices[1], inds)) +end + +const BlockIndexRange{N,R<:Tuple{Vararg{AbstractUnitRange{<:Integer},N}},I<:Tuple{Vararg{Any,N}},BI} = BlockIndices{N,R,I,BI} + """ BlockIndexRange(block, startind:stopind) -Represents a cartesian range inside a block. +Represents a cartesian range inside a block. Type alias for `BlockIndices` with +the indices constrained to ranges. It can be constructed and used to index into `BlockArrays` in the following manner: @@ -260,60 +309,62 @@ julia> a[Block(2,2)[1:2,3:4]] """ BlockIndexRange +BlockIndexRange(block::Block{N}, inds::Tuple{Vararg{AbstractUnitRange{<:Integer},N}}) where {N} = + BlockIndices(block, inds) BlockIndexRange(block::Block{N}, inds::Vararg{AbstractUnitRange{<:Integer},N}) where {N} = - BlockIndexRange(block,inds) + BlockIndices(block,inds) function BlockIndexRange(inds::Tuple{BlockIndexRange{1},Vararg{BlockIndexRange{1}}}) BlockIndexRange(Block(block.(inds)), map(ind -> ind.indices[1], inds)) end -block(R::BlockIndexRange) = R.block +block(R::BlockIndices) = R.block -copy(R::BlockIndexRange) = BlockIndexRange(R.block, map(copy, R.indices)) +copy(R::BlockIndices) = BlockIndices(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{AbstractVector,N}) where N = BlockIndices(B,inds) getindex(B::Block{1}, inds::Colon) = B getindex(B::Block{1}, inds::Base.Slice) = B -getindex(B::BlockIndexRange{0}) = B.block[] -@propagate_inbounds getindex(B::BlockIndexRange{N}, kr::Vararg{AbstractUnitRange{<:Integer},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)...] +getindex(B::BlockIndices{0}) = B.block[] +@propagate_inbounds getindex(B::BlockIndices{N}, kr::Vararg{AbstractVector,N}) where {N} = BlockIndices(B.block, map(getindex, B.indices, kr)) +@propagate_inbounds getindex(B::BlockIndices{N}, inds::Vararg{Int,N}) where N = B.block[Base.reindex(B.indices, inds)...] -eltype(R::BlockIndexRange) = eltype(typeof(R)) -eltype(::Type{BlockIndexRange{N}}) where {N} = BlockIndex{N} -eltype(::Type{BlockIndexRange{N,R,I,BI}}) where {N,R,I,BI} = BlockIndex{N,NTuple{N,BI},I} -IteratorSize(::Type{<:BlockIndexRange}) = Base.HasShape{1}() +eltype(R::BlockIndices) = eltype(typeof(R)) +eltype(::Type{BlockIndices{N}}) where {N} = BlockIndex{N} +eltype(::Type{BlockIndices{N,R,I,BI}}) where {N,R,I,BI} = BlockIndex{N,NTuple{N,BI},I} +IteratorSize(::Type{<:BlockIndices}) = Base.HasShape{1}() -first(iter::BlockIndexRange) = BlockIndex(iter.block.n, map(first, iter.indices)) -last(iter::BlockIndexRange) = BlockIndex(iter.block.n, map(last, iter.indices)) +first(iter::BlockIndices) = BlockIndex(iter.block.n, map(first, iter.indices)) +last(iter::BlockIndices) = BlockIndex(iter.block.n, map(last, iter.indices)) -@inline function iterate(iter::BlockIndexRange) +@inline function iterate(iter::BlockIndices) iterfirst, iterlast = first(iter), last(iter) if any(map(>, iterfirst.α, iterlast.α)) return nothing end iterfirst, iterfirst end -@inline function iterate(iter::BlockIndexRange, state) +@inline function iterate(iter::BlockIndices, state) nextstate = BlockIndex(state.I, inc(state.α, first(iter).α, last(iter).α)) nextstate.α[end] > last(iter.indices[end]) && return nothing nextstate, nextstate end -size(iter::BlockIndexRange) = map(dimlength, first(iter).α, last(iter).α) -length(iter::BlockIndexRange) = prod(size(iter)) +size(iter::BlockIndices) = map(dimlength, first(iter).α, last(iter).α) +length(iter::BlockIndices) = prod(size(iter)) -Block(bs::BlockIndexRange) = bs.block +Block(bs::BlockIndices) = bs.block ## # checkindex ## -function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::BlockIndexRange{N}) where N +function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::BlockIndices{N}) where N bl = block(I) checkbounds(Bool, A, bl) || return false # TODO: Replace with `eachblockaxes(A)[bl]` once that is defined. @@ -334,10 +385,11 @@ end """ 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`. """ @@ -347,7 +399,7 @@ struct BlockSlice{BB,T<:Integer,INDS<:AbstractUnitRange{T}} <: AbstractUnitRange end Block(bs::BlockSlice{<:Block}) = bs.block - +Block(bs::BlockSlice{<:BlockIndices}) = Block(bs.block) for f in (:axes, :unsafe_indices, :axes1, :first, :last, :size, :length, :unsafe_length, :start) @@ -366,8 +418,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) - """ BlockedSlice(blocks, indices) diff --git a/src/show.jl b/src/show.jl index 1a66ef88..2544e94d 100644 --- a/src/show.jl +++ b/src/show.jl @@ -186,13 +186,13 @@ function Base.show(io::IO, B::BlockIndex) print(io, "]") end -function Base.show(io::IO, B::BlockIndexRange) +function Base.show(io::IO, B::BlockIndices) show(io, Block(B)) print(io, "[") print_tuple_elements(io, B.indices) print(io, "]") end -Base.show(io::IO, ::MIME"text/plain", B::BlockIndexRange) = show(io, B) +Base.show(io::IO, ::MIME"text/plain", B::BlockIndices) = show(io, B) Base.show(io::IO, mimetype::MIME"text/plain", a::AbstractBlockedUnitRange) = Base.invoke(show, Tuple{typeof(io),MIME"text/plain",AbstractArray},io, mimetype, a) diff --git a/src/views.jl b/src/views.jl index 5b0dbb80..899986ce 100644 --- a/src/views.jl +++ b/src/views.jl @@ -20,7 +20,7 @@ unblock(A, ::Tuple{}, I) = BlockSlice(first(I),Base.OneTo(length(I[1]))) to_index(::Block) = throw(ArgumentError("Block must be converted by to_indices(...)")) to_index(::BlockIndex) = throw(ArgumentError("BlockIndex must be converted by to_indices(...)")) -to_index(::BlockIndexRange) = throw(ArgumentError("BlockIndexRange must be converted by to_indices(...)")) +to_index(::BlockIndices) = throw(ArgumentError("BlockIndices must be converted by to_indices(...)")) to_index(::BlockRange) = throw(ArgumentError("BlockRange must be converted by to_indices(...)")) @@ -36,15 +36,15 @@ to_index(::BlockRange) = throw(ArgumentError("BlockRange must be converted by to (unblock(A, inds, I), to_indices(A, _maybetail(inds), tail(I))...) @inline to_indices(A, inds, I::Tuple{BlockIndex{1}, Vararg{Any}}) = (inds[1][I[1]], to_indices(A, _maybetail(inds), tail(I))...) -@inline to_indices(A, inds, I::Tuple{BlockIndexRange{1}, Vararg{Any}}) = +@inline to_indices(A, inds, I::Tuple{BlockIndices{1}, Vararg{Any}}) = (unblock(A, inds, I), to_indices(A, _maybetail(inds), tail(I))...) @inline to_indices(A, inds, I::Tuple{AbstractVector{<:BlockIndex{1}}, Vararg{Any}}) = (unblock(A, inds, I), to_indices(A, _maybetail(inds), tail(I))...) -@inline to_indices(A, inds, I::Tuple{AbstractVector{<:BlockIndexRange{1}}, Vararg{Any}}) = +@inline to_indices(A, inds, I::Tuple{AbstractVector{<:BlockIndices{1}}, Vararg{Any}}) = (unblock(A, inds, I), to_indices(A, _maybetail(inds), tail(I))...) @inline to_indices(A, inds, I::Tuple{AbstractVector{<:AbstractVector{<:BlockIndex{1}}}, Vararg{Any}}) = (unblock(A, inds, I), to_indices(A, _maybetail(inds), tail(I))...) -@inline to_indices(A, inds, I::Tuple{AbstractVector{<:AbstractVector{<:BlockIndexRange{1}}}, Vararg{Any}}) = +@inline to_indices(A, inds, I::Tuple{AbstractVector{<:AbstractVector{<:BlockIndices{1}}}, Vararg{Any}}) = (unblock(A, inds, I), to_indices(A, _maybetail(inds), tail(I))...) @inline to_indices(A, inds, I::Tuple{AbstractVector{<:AbstractVector{<:AbstractVector{<:BlockIndex{1}}}}, Vararg{Any}}) = (unblock(A, inds, I), to_indices(A, _maybetail(inds), tail(I))...) @@ -58,11 +58,11 @@ to_index(::BlockRange) = throw(ArgumentError("BlockRange must be converted by to to_indices(A, inds, (BlockRange.(tuple.(I[1].indices))..., tail(I)...)) @inline to_indices(A, inds, I::Tuple{BlockIndex, Vararg{Any}}) = to_indices(A, inds, (BlockIndex.(I[1].I, I[1].α)..., tail(I)...)) -@inline to_indices(A, inds, I::Tuple{BlockIndexRange, Vararg{Any}}) = - to_indices(A, inds, (BlockIndexRange.(Block.(I[1].block.n), tuple.(I[1].indices))..., tail(I)...)) +@inline to_indices(A, inds, I::Tuple{BlockIndices, Vararg{Any}}) = + to_indices(A, inds, (BlockIndices.(Block.(I[1].block.n), tuple.(I[1].indices))..., tail(I)...)) # In 0.7, we need to override to_indices to avoid calling linearindices -@inline to_indices(A, I::Tuple{BlockIndexRange, Vararg{Any}}) = to_indices(A, axes(A), I) +@inline to_indices(A, I::Tuple{BlockIndices, Vararg{Any}}) = to_indices(A, axes(A), I) @inline to_indices(A, I::Tuple{BlockIndex, Vararg{Any}}) = to_indices(A, axes(A), I) @inline to_indices(A, I::Tuple{Block, Vararg{Any}}) = to_indices(A, axes(A), I) @inline to_indices(A, I::Tuple{BlockRange, Vararg{Any}}) = to_indices(A, axes(A), I) @@ -70,9 +70,9 @@ to_index(::BlockRange) = throw(ArgumentError("BlockRange must be converted by to @inline to_indices(A, I::Tuple{AbstractVector{<:BlockRange{1}}, Vararg{Any}}) = to_indices(A, axes(A), I) @inline to_indices(A, I::Tuple{AbstractVector{<:AbstractVector{<:Block{1}}}, Vararg{Any}}) = to_indices(A, axes(A), I) @inline to_indices(A, I::Tuple{AbstractVector{<:BlockIndex{1}}, Vararg{Any}}) = to_indices(A, axes(A), I) -@inline to_indices(A, I::Tuple{AbstractVector{<:BlockIndexRange{1}}, Vararg{Any}}) = to_indices(A, axes(A), I) +@inline to_indices(A, I::Tuple{AbstractVector{<:BlockIndices{1}}, Vararg{Any}}) = to_indices(A, axes(A), I) @inline to_indices(A, I::Tuple{AbstractVector{<:AbstractVector{<:BlockIndex{1}}}, Vararg{Any}}) = to_indices(A, axes(A), I) -@inline to_indices(A, I::Tuple{AbstractVector{<:AbstractVector{<:BlockIndexRange{1}}}, Vararg{Any}}) = to_indices(A, axes(A), I) +@inline to_indices(A, I::Tuple{AbstractVector{<:AbstractVector{<:BlockIndices{1}}}, Vararg{Any}}) = to_indices(A, axes(A), I) @inline to_indices(A, I::Tuple{AbstractVector{<:AbstractVector{<:AbstractVector{<:BlockIndex{1}}}}, Vararg{Any}}) = to_indices(A, axes(A), I) ## BlockedLogicalIndex @@ -119,8 +119,8 @@ checkindex(::Type{Bool}, inds::AbstractUnitRange, i::BlockedLogicalIndex) = chec (blockcollect(I[1]), ensure_indexable(tail(I))...) @propagate_inbounds reindex(idxs::Tuple{BlockSlice{<:BlockRange}, Vararg{Any}}, - subidxs::Tuple{BlockSlice{<:BlockIndexRange}, Vararg{Any}}) = - (BlockSlice(BlockIndexRange(Block(idxs[1].block.indices[1][Int(subidxs[1].block.block)]), + subidxs::Tuple{BlockSlice{<:BlockIndices}, Vararg{Any}}) = + (BlockSlice(BlockIndices(Block(idxs[1].block.indices[1][Int(subidxs[1].block.block)]), subidxs[1].block.indices), idxs[1].indices[subidxs[1].indices]), reindex(tail(idxs), tail(subidxs))...) @@ -143,36 +143,36 @@ _splatmap(f, t::Tuple) = (f(t[1])..., _splatmap(f, tail(t))...) # path in `AbstractBlockStyle` broadcasting. @propagate_inbounds function Base.unsafe_view( A::BlockArray{<:Any, N}, - I::Vararg{BlockSlice{<:BlockIndexRange{1}}, N}) where {N} + I::Vararg{BlockSlice{<:BlockIndices{1}}, N}) where {N} B = view(A, map(block, I)...) return view(B, _splatmap(x -> x.block.indices, I)...) end @propagate_inbounds function Base.unsafe_view( A::BlockedArray{<:Any, N}, - I::Vararg{BlockSlice{<:BlockIndexRange{1}}, N}) where {N} + I::Vararg{BlockSlice{<:BlockIndices{1}}, N}) where {N} return view(A.blocks, map(x -> x.indices, I)...) end @propagate_inbounds function Base.unsafe_view( A::ReshapedArray{<:Any, N, <:AbstractBlockArray{<:Any, M}}, - I::Vararg{BlockSlice{<:BlockIndexRange{1}}, N}) where {N, M} + I::Vararg{BlockSlice{<:BlockIndices{1}}, N}) where {N, M} # Note: assuming that I[M+1:end] are verified to be singletons return reshape(view(A.parent, I[1:M]...), Val(N)) end @propagate_inbounds function Base.unsafe_view( A::Array, - I1::BlockSlice{<:BlockIndexRange{1}}, - Is::Vararg{BlockSlice{<:BlockIndexRange{1}}}, + I1::BlockSlice{<:BlockIndices{1}}, + Is::Vararg{BlockSlice{<:BlockIndices{1}}}, ) I = (I1, Is...) @assert ndims(A) == length(I) return view(A, map(x -> x.indices, I)...) end -# make sure we reindex correctrly -@inline function Base._maybe_reindex(V, I::Tuple{BlockSlice{<:BlockIndexRange{1}}, Vararg{Any}}, ::Tuple{}) +# make sure we reindex correctly +@inline function Base._maybe_reindex(V, I::Tuple{BlockSlice{<:BlockIndices{1}}, Vararg{Any}}, ::Tuple{}) @inbounds idxs = to_indices(V.parent, reindex(V.indices, I)) view(V.parent, idxs...) end diff --git a/test/test_blockarrays.jl b/test/test_blockarrays.jl index a2a73c5d..7d4eda9d 100644 --- a/test/test_blockarrays.jl +++ b/test/test_blockarrays.jl @@ -998,6 +998,14 @@ 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 "BlockIndices" 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 "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 d39e0c50..35b0da52 100644 --- a/test/test_blockindices.jl +++ b/test/test_blockindices.jl @@ -87,10 +87,19 @@ import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice, BlockedSlice @test Block()[] == BlockIndex() @test Block(1)[1] == BlockIndex((1,),(1,)) @test Block(1)[1:2] == BlockIndexRange(Block(1),(1:2,)) + @test Block(1)[[1,3]] == BlockIndices(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] == BlockIndices(Block(1,1),([1,3],1:2)) @test BlockIndexRange((Block(1)[1:2],Block(1)[1:2])) == BlockIndexRange(Block(1,1),(1:2,1:2)) + @test BlockIndices((Block(1)[[1,3]],Block(1)[[2,4]])) == BlockIndices(Block(1,1),([1,3],[2,4])) @test Block(1)[1:3][1:2] == BlockIndexRange(Block(1),1:2) + @test Block(1)[[1,3,5]][[1,3]] == BlockIndices(Block(1),[1,5]) + @test Block(1,2)[[1,3,5],[2,4,6]][2,3] == BlockIndex(Block(1,2),(3,6)) + @test Block(1)[[1,3,5]][2:3] == BlockIndices(Block(1),[3,5]) + @test Block(1)[2:4][[1,3]] == BlockIndices(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]] == BlockIndices(Block(1,1),1:2,[1,3]) @test Block(1,1)[2:4,2:4][2:3,2:3] == BlockIndexRange(Block(1,1),(3:4,3:4)) @test BlockIndexRange(Block(),())[] == BlockIndex() @test BlockIndex((2,2,2),(2,)) == BlockIndex((2,2,2),(2,1,)) == BlockIndex((2,2,2),(2,1,1)) @@ -99,6 +108,14 @@ import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice, BlockedSlice @test BlockIndex(Block(2),2) === BlockIndex(Block(2),(2,)) @test BlockIndex(Block(2),UInt(2)) === BlockIndex(Block(2),(UInt(2),)) @test copy(Block(1)[1:2]) === BlockIndexRange(Block(1),1:2) + @test copy(Block(1)[[1,3]]) == BlockIndices(Block(1),[1,3]) + @test copy(Block(1)[[1,3]]) ≢ BlockIndices(Block(1),[1,3]) + end + + @testset "BlockIndices" begin + @test eltype(BlockIndices{3}) ≡ BlockIndex{3} + @test Base.IteratorSize(BlockIndices{3}) ≡ Base.HasShape{1}() + @test isnothing(iterate(Block(3,3)[[1,3],[3,1]])) end @testset "BlockRange" begin @@ -615,6 +632,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 @@ -863,6 +881,8 @@ end @test b[1:2] ≡ b[1:2][1:2] ≡ BlockSlice(Block(5)[1:2],1:2) @test Block(b) ≡ Block(5) + @test Block(BlockSlice(Block(2)[1:2], 3:4)) ≡ Block(2) + @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 @@ -982,9 +1002,17 @@ end @test !blockisapprox(B1, B12; rtol=1e-9) end -@testset "BlockIndices" begin +@testset "Vector{<:Block{1}}" begin a = BlockedOneTo(1:3) @test a[[Block(1),Block(3)]] == a[Block.(1:2:3)] == [1,3] end +@testset "to_index" begin + @test_throws ArgumentError Base.to_index(Block(3)) + @test_throws ArgumentError Base.to_index(Block(3)[2]) + @test_throws ArgumentError Base.to_index(Block(3)[1:2]) + @test_throws ArgumentError Base.to_index(Block(3)[[1,3]]) + @test_throws ArgumentError Base.to_index(Block.(2:3)) +end + end # module