Skip to content

Commit f6c5555

Browse files
authored
Preserve block information in more slicing operations (#459)
This introduces a generalization of `BlockSlice` for views involving vectors of `Block` and `BlockIndexRange`, building off of #445. I call it `BlockedSlice` but I'm open to suggestions. At first I tried to just generalize `BlockSlice` to be an `AbstractVector` subtype but some operations depend on it being an `AbstractUnitRange` so I think it makes sense to have both. The motivation is that in https://github.com/ITensor/BlockSparseArrays.jl it would be helpful to preserve information about the original blocks being sliced when taking views involving vectors of `Block` and `BlockIndexRange`. #445 drops the blocks input in the slice operation, so it is hard to tell if a certain slice operation was really originally blockwise. @dlfivefifty curious to hear your thoughts on this since you wrote #445.
1 parent 2b4e54f commit f6c5555

File tree

4 files changed

+44
-3
lines changed

4 files changed

+44
-3
lines changed

src/blockindices.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,27 @@ _indices(B) = B
290290

291291
Block(bs::BlockSlice{<:BlockIndexRange}) = Block(bs.block)
292292

293+
"""
294+
BlockedSlice(blocks, indices)
295+
296+
Represents blocked indices attached to a collection of corresponding blocks.
297+
298+
Upon calling `to_indices()`, a collection of blocks are converted to BlockedSlice objects to represent
299+
the indices over which the blocks span.
300+
301+
This mimics the relationship between `Colon` and `Base.Slice`, `Block` and `BlockSlice`, etc.
302+
"""
303+
struct BlockedSlice{BB,T<:Integer,INDS<:AbstractVector{T}} <: AbstractVector{T}
304+
blocks::BB
305+
indices::INDS
306+
end
307+
308+
for f in (:axes, :size)
309+
@eval $f(S::BlockedSlice) = $f(S.indices)
310+
end
311+
312+
@propagate_inbounds getindex(S::BlockedSlice, i::Integer) = getindex(S.indices, i)
313+
@propagate_inbounds getindex(S::BlockedSlice, k::Block{1}) = BlockSlice(S.blocks[Int(k)], getindex(S.indices, k))
293314

294315
struct BlockRange{N,R<:NTuple{N,AbstractUnitRange{<:Integer}}} <: AbstractArray{Block{N,Int},N}
295316
indices::R

src/views.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function unblock(A, inds, I)
1111
end
1212

1313
_blockslice(B, a::AbstractUnitRange) = BlockSlice(B, a)
14-
_blockslice(B, a) = a # drop block structure
14+
_blockslice(B, a) = BlockedSlice(B, a)
1515

1616
# Allow `ones(2)[Block(1)[1:1], Block(1)[1:1]]` which is
1717
# similar to `ones(2)[1:1, 1:1]`.
@@ -150,10 +150,11 @@ block(A::Block) = A
150150
@inline view(block_arr::AbstractBlockArray{<:Any,N}, blocks::Vararg{BlockSlice1, N}) where N =
151151
view(block_arr, map(block,blocks)...)
152152

153-
const BlockSlices = Union{Base.Slice,BlockSlice{<:BlockRange{1}}}
153+
const BlockSlices = Union{Base.Slice,BlockSlice{<:BlockRange{1}},BlockedSlice}
154154
# view(V::SubArray{<:Any,N,NTuple{N,BlockSlices}},
155155

156156
_block_reindex(b::BlockSlice, i::Block{1}) = b.block[Int(i)]
157+
_block_reindex(b::BlockedSlice, i::Block{1}) = b.blocks[Int(i)]
157158
_block_reindex(b::Slice, i::Block{1}) = i
158159

159160
@inline view(V::SubArray{<:Any,N,<:AbstractBlockArray,<:NTuple{N,BlockSlices}}, block::Block{N}) where N =

test/test_blockindices.jl

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module TestBlockIndices
22

33
using BlockArrays, FillArrays, Test, StaticArrays, ArrayLayouts
44
using OffsetArrays
5-
import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice
5+
import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice, BlockedSlice
66

77
@testset "Blocks" begin
88
@test Int(Block(2)) === Integer(Block(2)) === Number(Block(2)) === 2
@@ -831,6 +831,16 @@ end
831831
end
832832
end
833833

834+
@testset "BlockedSlice" begin
835+
b = BlockedSlice([Block(2), Block(1)], mortar([3:5, 1:2]))
836+
@test length(b) == 5
837+
for i in eachindex(b.indices)
838+
@test b[i] === b.indices[i]
839+
end
840+
@test b[Block(1)] === BlockSlice(Block(2), 3:5)
841+
@test b[Block(2)] === BlockSlice(Block(1), 1:2)
842+
end
843+
834844
#=
835845
[1,1 1,2] | [1,3 1,4 1,5]
836846
--------------------------

test/test_blockrange.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ using BlockArrays, Test
2323
@test view(A, Block.(1:2)) == [1,2,3]
2424
@test A[Block.(1:2)] == [1,2,3]
2525

26+
V = view(A, [Block(3), Block(2)])
27+
@test V == [4, 5, 6, 2, 3]
28+
I = parentindices(V)[1]
29+
@test I isa BlockArrays.BlockedSlice{<:Vector{<:Block{1}}}
30+
@test V[Block(1)] == 4:6
31+
@test V[Block(2)] == 2:3
32+
@test view(V, Block(1)) === view(A, Block(3))
33+
@test view(V, Block(2)) === view(A, Block(2))
34+
2635
A = BlockArray(reshape(collect(1:(6*12)),6,12), 1:3, 3:5)
2736

2837
@test view(A, Block.(1:2), Block.(1:2)) == A[1:3,1:7]

0 commit comments

Comments
 (0)