Skip to content

Commit 39a9424

Browse files
authored
Merge branch 'JuliaArrays:master' into mf/blockindexrange_merge
2 parents 309619c + 562fb53 commit 39a9424

File tree

10 files changed

+230
-46
lines changed

10 files changed

+230
-46
lines changed

Project.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ name = "BlockArrays"
22
uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
33
version = "1.7.0"
44

5-
65
[deps]
76
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
87
BandedMatrices = "aae01518-5342-5314-be14-df237901396f"

docs/src/man/blockarrays.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ julia> view(A, Block(2)) .= [3,4]; A[Block(2)]
151151
4.0
152152
153153
julia> view(A, Block.(1:2))
154-
3-element view(::BlockVector{Float64, Vector{Vector{Float64}}, Tuple{BlockedOneTo{Int64, ArrayLayouts.RangeCumsum{Int64, UnitRange{Int64}}}}}, BlockSlice(BlockRange(1:2),1:1:3)) with eltype Float64 with indices BlockedOneTo([1, 3]):
154+
3-element view(::BlockVector{Float64, Vector{Vector{Float64}}, Tuple{BlockedOneTo{Int64, ArrayLayouts.RangeCumsum{Int64, UnitRange{Int64}}}}}, BlockSlice(BlockRange((1:2,)),1:1:3)) with eltype Float64 with indices BlockedOneTo([1, 3]):
155155
1.0
156156
3.0
157157
4.0

src/abstractblockarray.jl

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,26 +88,41 @@ ERROR: BlockBoundsError: attempt to access 2×2-blocked 2×3 BlockMatrix{Float64
8888
"""
8989
@inline function blockcheckbounds(A::AbstractArray, i...)
9090
blockcheckbounds(Bool, A, i...) || throw(BlockBoundsError(A, i))
91+
nothing
9192
end
9293

9394
# linear block indexing
9495
@inline function blockcheckbounds(::Type{Bool}, A::AbstractArray, i)
95-
blockcheckindex(Bool, BlockRange(blocklength(A)), i)
96+
blockcheckindex(Bool, BlockRange((blocklength(A),)), i)
9697
end
9798
# cartesian block indexing
9899
@inline function blockcheckbounds(::Type{Bool}, A::AbstractArray, i...)
99100
blockcheckbounds_indices(Bool, blockaxes(A), i)
100101
end
101102

102-
blockcheckbounds(A::AbstractArray{T, N}, i::Block{N}) where {T,N} = blockcheckbounds(A, i.n...)
103-
blockcheckbounds(A::AbstractArray{T, N}, i::Vararg{Block{1},N}) where {T,N} = blockcheckbounds(A, Int.(i)...)
104-
blockcheckbounds(::AbstractArray{T, 0}) where {T} = true
105-
blockcheckbounds(A::AbstractVector{T}, i::Block{1}) where {T} = blockcheckbounds(A, Int(i))
103+
# Used to ensure a `BlockBoundsError` is thrown instead of a `BoundsError`,
104+
# see https://github.com/JuliaArrays/BlockArrays.jl/issues/458
105+
checkbounds(A::AbstractArray{T, N}, I::Block{N}) where {T,N} = blockcheckbounds(A, I)
106+
checkbounds(A::AbstractArray{T}, I1::Block{1}, Irest::Block{1}...) where {T} = blockcheckbounds(A, I1, Irest...)
107+
checkbounds(A::AbstractArray{T}, I1::AbstractVector{<:Block{1}}, Irest::AbstractVector{<:Block{1}}...) where {T} =
108+
blockcheckbounds(A, I1, Irest...)
109+
110+
blockcheckbounds(::Type{Bool}, A::AbstractArray{T, N}, I::Block{N}) where {T,N} = blockcheckbounds(Bool, A, Int.(Tuple(I))...)
111+
blockcheckbounds(::Type{Bool}, A::AbstractArray{T, N}, I::Vararg{Block{1},N}) where {T,N} =
112+
blockcheckbounds(Bool, A, Int.(I)...)
113+
blockcheckbounds(::Type{Bool}, ::AbstractArray{T, 0}) where {T} = true
114+
blockcheckbounds(::Type{Bool}, A::AbstractVector{T}, I::Block{1}) where {T} = blockcheckbounds(Bool, A, Int(I))
115+
blockcheckbounds(::Type{Bool}, A::AbstractArray{T,N}, I::Vararg{AbstractVector{<:Block{1}},N}) where {T,N} =
116+
blockcheckbounds(Bool, A, map(i -> Int.(i), I)...)
117+
118+
blockcheckbounds(::Type{Bool}, A::AbstractArray{T,N}, I::Vararg{BlockRange{1},N}) where {T,N} =
119+
blockcheckbounds(Bool, A, map(i -> Int.(i), I)...)
120+
blockcheckbounds(::Type{Bool}, A::AbstractArray{T,N}, I::BlockRange{N}) where {T,N} = blockcheckbounds(Bool, A, I.indices...)
106121

107122
"""
108-
blockcheckbounds_indices(Bool, IA::Tuple{Vararg{BlockRange{1}}}, I::Tuple{Vararg{Integer}})
123+
blockcheckbounds_indices(Bool, IA::Tuple{Vararg{BlockRange{1}}}, I::Tuple)
109124
110-
Return true if the "requested" indices in the tuple `Block.(I)` fall within the bounds of the "permitted"
125+
Return true if the "requested" indices in the tuple `map(i -> Block.(i), I)` fall within the bounds of the "permitted"
111126
indices specified by the tuple `IA`. This function recursively consumes elements of these tuples
112127
in a 1-for-1 fashion.
113128
@@ -118,13 +133,19 @@ The actual bounds-checking is performed by [`blockcheckindex`](@ref).
118133
julia> B = BlockArray(zeros(6,6), 1:3, 1:3);
119134
120135
julia> blockaxes(B)
121-
(BlockRange(Base.OneTo(3)), BlockRange(Base.OneTo(3)))
136+
(BlockRange((3,)), BlockRange((3,)))
122137
123138
julia> BlockArrays.blockcheckbounds_indices(Bool, blockaxes(B), (1,2))
124139
true
125140
126141
julia> BlockArrays.blockcheckbounds_indices(Bool, blockaxes(B), (4,1))
127142
false
143+
144+
julia> BlockArrays.blockcheckbounds_indices(Bool, blockaxes(B), (1:2,2:3))
145+
true
146+
147+
julia> BlockArrays.blockcheckbounds_indices(Bool, blockaxes(B), (1:2,2:4))
148+
false
128149
```
129150
"""
130151
@inline blockcheckbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
@@ -143,20 +164,26 @@ end
143164
end
144165

145166
"""
146-
blockcheckindex(Bool, inds::BlockRange{1}, index::Integer)
167+
blockcheckindex(Bool, inds::BlockRange{1}, index)
147168
148-
Return `true` if `Block(index)` is within the bounds of `inds`.
169+
Return `true` if `Block.(index)` is within the bounds of `inds`.
149170
150171
# Examples
151172
```jldoctest
152-
julia> BlockArrays.blockcheckindex(Bool, BlockRange(1:2), 1)
173+
julia> BlockArrays.blockcheckindex(Bool, BlockRange((1:2,)), 1)
174+
true
175+
176+
julia> BlockArrays.blockcheckindex(Bool, BlockRange((1:2,)), 3)
177+
false
178+
179+
julia> BlockArrays.blockcheckindex(Bool, BlockRange((1:3,)), 2:3)
153180
true
154181
155-
julia> BlockArrays.blockcheckindex(Bool, BlockRange(1:2), 3)
182+
julia> BlockArrays.blockcheckindex(Bool, BlockRange((1:3,)), 2:4)
156183
false
157184
```
158185
"""
159-
@inline blockcheckindex(::Type{Bool}, inds::BlockRange{1}, i::Integer) = Block(i) in inds
186+
@inline blockcheckindex(::Type{Bool}, inds::BlockRange{1}, i) = checkindex(Bool, Int.(inds), i)
160187

161188
@propagate_inbounds setindex!(block_arr::AbstractBlockArray{T,N}, v, block::Block{N}) where {T,N} =
162189
setindex!(block_arr, v, Block.(block.n)...)

src/blockaxis.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ julia> A = BlockArray([1,2,3],[2,1])
289289
3
290290
291291
julia> blockaxes(A)
292-
(BlockRange(Base.OneTo(2)),)
292+
(BlockRange((2,)),)
293293
294294
julia> B = BlockArray(zeros(3,4), [1,2], [1,2,1])
295295
2×3-blocked 3×4 BlockMatrix{Float64}:
@@ -299,7 +299,7 @@ julia> B = BlockArray(zeros(3,4), [1,2], [1,2,1])
299299
0.0 │ 0.0 0.0 │ 0.0
300300
301301
julia> blockaxes(B)
302-
(BlockRange(Base.OneTo(2)), BlockRange(Base.OneTo(3)))
302+
(BlockRange((2,)), BlockRange((3,)))
303303
```
304304
"""
305305
blockaxes(b::AbstractBlockedUnitRange) = _blockaxes(blocklasts(b))
@@ -322,7 +322,7 @@ julia> A = BlockArray([1,2,3], [2,1])
322322
3
323323
324324
julia> blockaxes(A,1)
325-
BlockRange(Base.OneTo(2))
325+
BlockRange((2,))
326326
327327
julia> blockaxes(A,1) |> collect
328328
2-element Vector{Block{1, Int64}}:

src/blockindices.jl

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ end
164164

165165
block(b::BlockIndex) = Block(b.I...)
166166
blockindex(b::BlockIndex{1}) = b.α[1]
167+
blockindex(b::BlockIndex) = CartesianIndex(b.α)
167168

168169
BlockIndex(indcs::Tuple{Vararg{BlockIndex{1},N}}) where N = BlockIndex(block.(indcs), blockindex.(indcs))
169170

@@ -172,15 +173,16 @@ BlockIndex(indcs::Tuple{Vararg{BlockIndex{1},N}}) where N = BlockIndex(block.(in
172173
##
173174

174175
@inline checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::Block{N}) where N = blockcheckbounds(Bool, A, I.n...)
176+
175177
@inline function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::BlockIndex{N}) where N
176178
bl = block(I)
177179
checkbounds(Bool, A, bl) || return false
178-
B = A[bl]
179-
checkbounds(Bool, B, blockindex(I)...)
180+
# TODO: Replace with `eachblockaxes(A)[bl]` once that is defined.
181+
binds = map(Base.axes1 getindex, axes(A), Tuple(bl))
182+
Base.checkbounds_indices(Bool, binds, (blockindex(I),))
180183
end
181-
182-
checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractVector{<:BlockIndex{N}}) where N =
183-
all(checkbounds.(Bool, Ref(A), I))
184+
checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{<:BlockIndex{N}}) where N =
185+
all(i -> checkbounds(Bool, A, i), I)
184186

185187
struct BlockIndexRange{N,R<:Tuple{Vararg{AbstractUnitRange{<:Integer},N}},I<:Tuple{Vararg{Integer,N}},BI<:Integer} <: AbstractArray{BlockIndex{N,NTuple{N,BI},I},N}
186188
block::Block{N,BI}
@@ -247,6 +249,17 @@ length(iter::BlockIndexRange) = prod(size(iter))
247249

248250
Block(bs::BlockIndexRange) = bs.block
249251

252+
##
253+
# checkindex
254+
##
255+
256+
function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::BlockIndexRange{N}) where N
257+
bl = block(I)
258+
checkbounds(Bool, A, bl) || return false
259+
# TODO: Replace with `eachblockaxes(A)[bl]` once that is defined.
260+
binds = map(Base.axes1 getindex, axes(A), Tuple(bl))
261+
Base.checkbounds_indices(Bool, binds, I.indices)
262+
end
250263

251264
# #################
252265
# # support for pointers
@@ -328,8 +341,8 @@ end
328341

329342
# deleted code that isn't used, such as 0-dimensional case
330343
"""
331-
BlockRange(axes::Tuple{AbstractUnitRange{Int}})
332-
BlockRange(sizes::Vararg{Integer})
344+
BlockRange(axes::Tuple{Vararg{AbstractUnitRange{<:Integer}}})
345+
BlockRange(sizes::Tuple{Vararg{Integer}})
333346
334347
Represent a Cartesian range of blocks.
335348
@@ -338,18 +351,18 @@ The relationship between `Block` and `BlockRange` mimics the relationship betwee
338351
339352
# Examples
340353
```jldoctest
341-
julia> BlockRange(2:3, 3:4) |> collect
354+
julia> BlockRange((2:3, 3:4)) |> collect
342355
2×2 Matrix{Block{2, Int64}}:
343356
Block(2, 3) Block(2, 4)
344357
Block(3, 3) Block(3, 4)
345358
346-
julia> BlockRange(2, 2) |> collect # number of elements, starting at 1
359+
julia> BlockRange((2, 2)) |> collect # number of elements, starting at 1
347360
2×2 Matrix{Block{2, Int64}}:
348361
Block(1, 1) Block(1, 2)
349362
Block(2, 1) Block(2, 2)
350363
351364
julia> Block(1):Block(2)
352-
BlockRange(1:2)
365+
BlockRange((1:2,))
353366
```
354367
"""
355368
BlockRange
@@ -364,11 +377,8 @@ end
364377

365378
BlockRange(inds::Tuple{Vararg{AbstractUnitRange{<:Integer}}}) =
366379
BlockRange{length(inds),typeof(inds)}(inds)
367-
BlockRange(inds::Vararg{AbstractUnitRange{<:Integer}}) = BlockRange(inds)
368380

369-
BlockRange() = BlockRange(())
370381
BlockRange(sizes::Tuple{Integer, Vararg{Integer}}) = BlockRange(map(oneto, sizes))
371-
BlockRange(sizes::Vararg{Integer}) = BlockRange(sizes)
372382

373383
BlockRange(B::AbstractArray) = BlockRange(blockaxes(B))
374384

@@ -437,13 +447,29 @@ _in(b, ::Tuple{}, ::Tuple{}, ::Tuple{}) = b
437447
@inline _in(b, i, start, stop) = _in(b & (start[1] <= i[1] <= stop[1]), tail(i), tail(start), tail(stop))
438448

439449
# We sometimes need intersection of BlockRange to return a BlockRange
440-
intersect(a::BlockRange{1}, b::BlockRange{1}) = BlockRange(intersect(a.indices[1], b.indices[1]))
450+
intersect(a::BlockRange{1}, b::BlockRange{1}) = BlockRange((intersect(a.indices[1], b.indices[1]),))
451+
452+
##
453+
# checkindex
454+
##
455+
456+
# Used to ensure a `BlockBoundsError` is thrown instead of a `BoundsError`,
457+
# see https://github.com/JuliaArrays/BlockArrays.jl/issues/458
458+
checkbounds(A::AbstractArray{<:Any,N}, I::BlockRange{N}) where N = blockcheckbounds(A, I)
459+
checkbounds(A::AbstractArray, I1::BlockRange{1}, Irest::BlockRange{1}...) =
460+
blockcheckbounds(A, I1, Irest...)
461+
462+
# Convert Block inputs to integers.
463+
checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::BlockRange{N}) where N =
464+
blockcheckbounds(Bool, A, I.indices...)
465+
checkbounds(::Type{Bool}, A::AbstractArray, I1::AbstractVector{<:Block{1}}, Irest::AbstractVector{<:Block{1}}...) =
466+
blockcheckbounds(Bool, A, map(I -> Int.(I), (I1, Irest...))...)
441467

442468
# needed for scalar-like broadcasting
443469

444470
BlockSlice{Block{1,BT},T,RT}(a::Base.OneTo) where {BT,T,RT<:AbstractUnitRange} =
445471
BlockSlice(Block(convert(BT, 1)), convert(RT, a))::BlockSlice{Block{1,BT},T,RT}
446472
BlockSlice{BlockRange{1,Tuple{BT}},T,RT}(a::Base.OneTo) where {BT<:AbstractUnitRange,T,RT<:AbstractUnitRange} =
447-
BlockSlice(BlockRange(convert(BT, Base.OneTo(1))), convert(RT, a))::BlockSlice{BlockRange{1,Tuple{BT}},T,RT}
473+
BlockSlice(BlockRange((convert(BT, Base.OneTo(1)),)), convert(RT, a))::BlockSlice{BlockRange{1,Tuple{BT}},T,RT}
448474
BlockSlice{BlockIndexRange{1,Tuple{BT},I,BI},T,RT}(a::Base.OneTo) where {BT<:AbstractUnitRange,T,RT<:AbstractUnitRange,I,BI} =
449475
BlockSlice(BlockIndexRange(Block(BI(1)), convert(BT, Base.OneTo(1))), convert(RT, a))::BlockSlice{BlockIndexRange{1,Tuple{BT},I,BI},T,RT}

src/show.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,13 @@ end
212212

213213
# BlockRange
214214

215-
Base.show(io::IO, br::BlockRange) = print(io, "BlockRange(", join(br.indices, ", "), ")")
215+
function Base.show(io::IO, br::BlockRange)
216+
print(io, "BlockRange(")
217+
show(io, map(_xform_index, br.indices))
218+
print(io, ")")
219+
end
220+
_xform_index(i) = i
221+
_xform_index(i::Base.OneTo) = i.stop
216222
Base.show(io::IO, ::MIME"text/plain", br::BlockRange) = show(io, br)
217223

218224
# AbstractBlockedUnitRange

src/views.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ end
123123
# this is loosely based on Slice reindex in subarray.jl
124124
@propagate_inbounds reindex(idxs::Tuple{BlockSlice{<:BlockRange}, Vararg{Any}},
125125
subidxs::Tuple{BlockSlice{<:BlockRange}, Vararg{Any}}) =
126-
(BlockSlice(BlockRange(idxs[1].block.indices[1][Int.(subidxs[1].block)]),
126+
(BlockSlice(BlockRange((idxs[1].block.indices[1][Int.(subidxs[1].block)],)),
127127
idxs[1].indices[subidxs[1].block]),
128128
reindex(tail(idxs), tail(subidxs))...)
129129

0 commit comments

Comments
 (0)