Skip to content

Commit fe6b909

Browse files
Stricter BlockRange constructors (#472)
Closes #471. This removes constructors `BlockRange()`, `BlockRange(2, 2)`, and `BlockRange(1:2, 1:2)`. Instead, the more explicit versions `BlockRange(())`, `BlockRange((2, 2))`, and `BlockRange((1:2, 1:2))` can be used. This now makes `BlockRange` constructors more consistent with `CartesianIndices` constructors: ```julia julia> CartesianIndices() ERROR: MethodError: no method matching CartesianIndices() The type `CartesianIndices` exists, but no method is defined for this combination of argument types when trying to construct it. Closest candidates are: CartesianIndices(::Tuple{}) @ Base multidimensional.jl:271 CartesianIndices(::AbstractArray) @ Base multidimensional.jl:281 CartesianIndices(::R) where {N, R<:NTuple{N, OrdinalRange{Int64, Int64}}} @ Base multidimensional.jl:268 ... Stacktrace: [1] top-level scope @ REPL[9]:1 [2] top-level scope @ none:1 julia> CartesianIndices(2, 2) ERROR: MethodError: no method matching CartesianIndices(::Int64, ::Int64) The type `CartesianIndices` exists, but no method is defined for this combination of argument types when trying to construct it. Closest candidates are: CartesianIndices(::Tuple{}) @ Base multidimensional.jl:271 CartesianIndices(::AbstractArray) @ Base multidimensional.jl:281 CartesianIndices(::R) where {N, R<:NTuple{N, OrdinalRange{Int64, Int64}}} @ Base multidimensional.jl:268 ... Stacktrace: [1] top-level scope @ REPL[12]:1 [2] top-level scope @ none:1 julia> CartesianIndices(1:2, 1:2) ERROR: MethodError: no method matching CartesianIndices(::UnitRange{Int64}, ::UnitRange{Int64}) The type `CartesianIndices` exists, but no method is defined for this combination of argument types when trying to construct it. Closest candidates are: CartesianIndices(::AbstractArray) @ Base multidimensional.jl:281 CartesianIndices(::Tuple{}) @ Base multidimensional.jl:271 CartesianIndices(::R) where {N, R<:NTuple{N, OrdinalRange{Int64, Int64}}} @ Base multidimensional.jl:268 ... Stacktrace: [1] top-level scope @ REPL[13]:1 [2] top-level scope @ none:1 julia> CartesianIndices(()) CartesianIndices(()) julia> CartesianIndices((2, 2)) CartesianIndices((2, 2)) julia> CartesianIndices((1:2, 1:2)) CartesianIndices((1:2, 1:2)) ``` and removes the inconsistency pointed out in #471 when calling `BlockRange(::AbstractUnitRange)` vs. `BlockRange(::AbstractVector)`: ```julia julia> using BlockArrays julia> collect(BlockRange(blockedrange([2, 3]))) 5-element Vector{Block{1, Int64}}: Block(1) Block(2) Block(3) Block(4) Block(5) julia> collect(BlockRange(mortar([1:2, 3:5]))) 2-element Vector{Block{1, Int64}}: Block(1) Block(2) ``` This is technically breaking, though I would argue that it is a bug fix because of the inconsistency of the current code design (i.e. I would argue that the previous behavior of `BlockRange(::AbstractUnitRange)` was incorrect, and therefore was a bug). I'm curious to see if this leads to any downstream failures. --------- Co-authored-by: Sheehan Olver <[email protected]>
1 parent 0c73bef commit fe6b909

File tree

9 files changed

+42
-30
lines changed

9 files changed

+42
-30
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ end
9292

9393
# linear block indexing
9494
@inline function blockcheckbounds(::Type{Bool}, A::AbstractArray, i)
95-
blockcheckindex(Bool, BlockRange(blocklength(A)), i)
95+
blockcheckindex(Bool, BlockRange((blocklength(A),)), i)
9696
end
9797
# cartesian block indexing
9898
@inline function blockcheckbounds(::Type{Bool}, A::AbstractArray, i...)
@@ -118,7 +118,7 @@ The actual bounds-checking is performed by [`blockcheckindex`](@ref).
118118
julia> B = BlockArray(zeros(6,6), 1:3, 1:3);
119119
120120
julia> blockaxes(B)
121-
(BlockRange(Base.OneTo(3)), BlockRange(Base.OneTo(3)))
121+
(BlockRange((3,)), BlockRange((3,)))
122122
123123
julia> BlockArrays.blockcheckbounds_indices(Bool, blockaxes(B), (1,2))
124124
true

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: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,8 @@ end
324324

325325
# deleted code that isn't used, such as 0-dimensional case
326326
"""
327-
BlockRange(axes::Tuple{AbstractUnitRange{Int}})
328-
BlockRange(sizes::Vararg{Integer})
327+
BlockRange(axes::Tuple{Vararg{AbstractUnitRange{<:Integer}}})
328+
BlockRange(sizes::Tuple{Vararg{Integer}})
329329
330330
Represent a Cartesian range of blocks.
331331
@@ -334,18 +334,18 @@ The relationship between `Block` and `BlockRange` mimics the relationship betwee
334334
335335
# Examples
336336
```jldoctest
337-
julia> BlockRange(2:3, 3:4) |> collect
337+
julia> BlockRange((2:3, 3:4)) |> collect
338338
2×2 Matrix{Block{2, Int64}}:
339339
Block(2, 3) Block(2, 4)
340340
Block(3, 3) Block(3, 4)
341341
342-
julia> BlockRange(2, 2) |> collect # number of elements, starting at 1
342+
julia> BlockRange((2, 2)) |> collect # number of elements, starting at 1
343343
2×2 Matrix{Block{2, Int64}}:
344344
Block(1, 1) Block(1, 2)
345345
Block(2, 1) Block(2, 2)
346346
347347
julia> Block(1):Block(2)
348-
BlockRange(1:2)
348+
BlockRange((1:2,))
349349
```
350350
"""
351351
BlockRange
@@ -360,11 +360,8 @@ end
360360

361361
BlockRange(inds::Tuple{Vararg{AbstractUnitRange{<:Integer}}}) =
362362
BlockRange{length(inds),typeof(inds)}(inds)
363-
BlockRange(inds::Vararg{AbstractUnitRange{<:Integer}}) = BlockRange(inds)
364363

365-
BlockRange() = BlockRange(())
366364
BlockRange(sizes::Tuple{Integer, Vararg{Integer}}) = BlockRange(map(oneto, sizes))
367-
BlockRange(sizes::Vararg{Integer}) = BlockRange(sizes)
368365

369366
BlockRange(B::AbstractArray) = BlockRange(blockaxes(B))
370367

@@ -433,13 +430,13 @@ _in(b, ::Tuple{}, ::Tuple{}, ::Tuple{}) = b
433430
@inline _in(b, i, start, stop) = _in(b & (start[1] <= i[1] <= stop[1]), tail(i), tail(start), tail(stop))
434431

435432
# We sometimes need intersection of BlockRange to return a BlockRange
436-
intersect(a::BlockRange{1}, b::BlockRange{1}) = BlockRange(intersect(a.indices[1], b.indices[1]))
433+
intersect(a::BlockRange{1}, b::BlockRange{1}) = BlockRange((intersect(a.indices[1], b.indices[1]),))
437434

438435
# needed for scalar-like broadcasting
439436

440437
BlockSlice{Block{1,BT},T,RT}(a::Base.OneTo) where {BT,T,RT<:AbstractUnitRange} =
441438
BlockSlice(Block(convert(BT, 1)), convert(RT, a))::BlockSlice{Block{1,BT},T,RT}
442439
BlockSlice{BlockRange{1,Tuple{BT}},T,RT}(a::Base.OneTo) where {BT<:AbstractUnitRange,T,RT<:AbstractUnitRange} =
443-
BlockSlice(BlockRange(convert(BT, Base.OneTo(1))), convert(RT, a))::BlockSlice{BlockRange{1,Tuple{BT}},T,RT}
440+
BlockSlice(BlockRange((convert(BT, Base.OneTo(1)),)), convert(RT, a))::BlockSlice{BlockRange{1,Tuple{BT}},T,RT}
444441
BlockSlice{BlockIndexRange{1,Tuple{BT},I,BI},T,RT}(a::Base.OneTo) where {BT<:AbstractUnitRange,T,RT<:AbstractUnitRange,I,BI} =
445442
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

test/test_blockindices.jl

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,14 @@ import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice, BlockedSlice
159159
@test sprint(show, "text/plain", BlockIndex((1,2), (3,4))) == "Block(1, 2)[3, 4]"
160160
@test sprint(show, "text/plain", BlockArrays.BlockIndexRange(Block(1), 3:4)) == "Block(1)[3:4]"
161161

162-
@test sprint(show, "text/plain", BlockRange()) == "BlockRange()"
163-
@test sprint(show, "text/plain", BlockRange(1:2)) == "BlockRange(1:2)"
164-
@test sprint(show, "text/plain", BlockRange(1:2, 2:3)) == "BlockRange(1:2, 2:3)"
165-
@test sprint(show, BlockRange(1:2, 2:3)) == "BlockRange(1:2, 2:3)"
162+
@test sprint(show, "text/plain", BlockRange(())) == "BlockRange(())"
163+
@test sprint(show, "text/plain", BlockRange((1:2,))) == "BlockRange((1:2,))"
164+
@test sprint(show, "text/plain", BlockRange((2,))) == "BlockRange((2,))"
165+
@test sprint(show, "text/plain", BlockRange((Base.OneTo(2),))) == "BlockRange((2,))"
166+
@test sprint(show, "text/plain", BlockRange((1:2, 2:3,))) == "BlockRange((1:2, 2:3))"
167+
@test sprint(show, "text/plain", BlockRange((2, 3,))) == "BlockRange((2, 3))"
168+
@test sprint(show, "text/plain", BlockRange(Base.OneTo.((2, 3)))) == "BlockRange((2, 3))"
169+
@test sprint(show, BlockRange((1:2, 2:3))) == "BlockRange((1:2, 2:3))"
166170
end
167171
end
168172

@@ -220,7 +224,7 @@ end
220224
b = BlockRange(OffsetArrays.IdOffsetRange.((2:4, 3:5), 2))
221225
@test b[axes(b)...] === b
222226

223-
b = BlockRange(3)
227+
b = BlockRange((3,))
224228
for i in 1:3
225229
@test b[i] == Block(i)
226230
end
@@ -465,7 +469,7 @@ end
465469
b = BlockRange(OffsetArrays.IdOffsetRange.((2:4, 3:5), 2))
466470
@test b[axes(b)...] === b
467471

468-
b = BlockRange(3)
472+
b = BlockRange((3,))
469473
for i in 1:3
470474
@test b[i] == Block(i)
471475
end

test/test_blockrange.jl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ using BlockArrays, Test
44

55
@testset "block range" begin
66
# test backend code
7-
@test BlockRange((1:3),) == BlockRange{1,Tuple{UnitRange{Int}}}((1:3,))
8-
@test BlockRange(1:3) == BlockRange((1:3),)
7+
@test BlockRange((1:3,)) == BlockRange{1,Tuple{UnitRange{Int}}}((1:3,))
8+
@test BlockRange(1:3) === BlockRange(Base.OneTo(1))
9+
@test BlockRange(blockedrange([2,3])) === BlockRange((Base.OneTo(2),))
10+
@test BlockRange(blockedrange(2,[2,3])) === BlockRange((Base.OneTo(2),))
911
@test_throws ArgumentError Block(1,1):Block(2,2)
12+
@test_throws MethodError BlockRange(1:3, 1:3)
13+
@test_throws MethodError BlockRange(3)
14+
@test_throws MethodError BlockRange(3, 3)
15+
@test_throws MethodError BlockRange()
1016

1117
@test eltype(Block.(1:2)) == Block{1,Int}
1218
@test eltype(typeof(Block.(1:2))) == Block{1,Int}
@@ -78,9 +84,9 @@ using BlockArrays, Test
7884
@test V == A[Block.(1:2), Block.(2:3)]
7985

8086
@testset "iterator" begin
81-
@test BlockRange()[] == collect(BlockRange())[] == Block()
82-
@test BlockRange(1:3) == collect(BlockRange(1:3)) == [Block(1),Block(2),Block(3)]
83-
@test BlockRange(1:3,1:2) == collect(BlockRange(1:3,1:2))
87+
@test BlockRange(())[] == collect(BlockRange(()))[] == Block()
88+
@test BlockRange((1:3,)) == collect(BlockRange((1:3,))) == [Block(1),Block(2),Block(3)]
89+
@test BlockRange((1:3,1:2)) == collect(BlockRange((1:3,1:2)))
8490
end
8591

8692
# non Int64 range

0 commit comments

Comments
 (0)