Skip to content

Commit

Permalink
Deprecate broadcast_(get|set)index in favor of broadcasted (get|set)i…
Browse files Browse the repository at this point in the history
…ndex (#27075)

* Deprecate broadcast_(get|set)index in favor of broadcasted (get|set)index

The performance here is comparable in my few quick tests, and only two packages used either of these functions -- both in situations where they would have gained much more by participating in dot-fusion.
  • Loading branch information
mbauman authored May 14, 2018
1 parent 12f4ebd commit 66c7b7d
Show file tree
Hide file tree
Showing 7 changed files with 18 additions and 135 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,9 @@ Deprecated or removed
using the broadcasted assignment syntax `A[I...] .= x` or `fill!(view(A, I...), x)`
([#26347]).

* `broadcast_getindex(A, I...)` and `broadcast_setindex!(A, v, I...)` are deprecated in
favor of `getindex.((A,), I...)` and `setindex!.((A,), v, I...)`, respectively ([#27075]).

* `LinAlg.fillslots!` has been renamed `LinAlg.fillstored!` ([#25030]).

* `fill!(A::Diagonal, x)` and `fill!(A::AbstractTriangular, x)` have been deprecated
Expand Down
121 changes: 1 addition & 120 deletions base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ using .Base: Indices, OneTo, tail, to_shape, isoperator, promote_typejoin,
_msk_end, unsafe_bitgetindex, bitcache_chunks, bitcache_size, dumpbitcache, unalias
import .Base: copy, copyto!
export broadcast, broadcast!, BroadcastStyle, broadcast_axes, broadcast_similar, broadcastable,
broadcast_getindex, broadcast_setindex!, dotview, @__dot__
dotview, @__dot__

### Objects with customized broadcasting behavior should declare a BroadcastStyle

Expand Down Expand Up @@ -1018,125 +1018,6 @@ broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::StepRange) = big(r.start):
broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::StepRangeLen) = StepRangeLen(big(r.ref), big(r.step), length(r), r.offset)
broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::LinRange) = LinRange(big(r.start), big(r.stop), length(r))


"""
broadcast_getindex(A, inds...)
Equivalent to [`broadcast`](@ref)ing the `inds` arrays to a common size
and returning an array `[A[ks...] for ks in zip(indsb...)]` (where `indsb`
would be the broadcast `inds`). The shape of the output is equal to the shape of each
element of `indsb`.
# Examples
```jldoctest bc_getindex
julia> A = [11 12; 21 22]
2×2 Array{Int64,2}:
11 12
21 22
julia> A[1:2, 1:2]
2×2 Array{Int64,2}:
11 12
21 22
julia> broadcast_getindex(A, 1:2, 1:2)
2-element Array{Int64,1}:
11
22
julia> A[1:2, 2:-1:1]
2×2 Array{Int64,2}:
12 11
22 21
julia> broadcast_getindex(A, 1:2, 2:-1:1)
2-element Array{Int64,1}:
12
21
```
Because the indices are all vectors, these calls are like `[A[i[k], j[k]] for k = 1:2]`
where `i` and `j` are the two index vectors.
```jldoctest bc_getindex
julia> broadcast_getindex(A, 1:2, (1:2)')
2×2 Array{Int64,2}:
11 12
21 22
julia> broadcast_getindex(A, (1:2)', 1:2)
2×2 Array{Int64,2}:
11 21
12 22
julia> broadcast_getindex(A, [1 2 1; 1 2 2], [1, 2])
2×3 Array{Int64,2}:
11 21 11
12 22 22
```
"""
broadcast_getindex(src::AbstractArray, I::AbstractArray...) =
broadcast_getindex!(Base.similar(Array{eltype(src)}, combine_axes(I...)), src, I...)

@generated function broadcast_getindex!(dest::AbstractArray, src::AbstractArray, I::AbstractArray...)
N = length(I)
Isplat = Expr[:(I[$d]) for d = 1:N]
quote
@nexprs $N d->(I_d = I[d])
check_broadcast_axes(Base.axes(dest), $(Isplat...)) # unnecessary if this function is never called directly
checkbounds(src, $(Isplat...))
@nexprs $N d->(@nexprs $N k->(Ibcast_d_k = Base.axes(I_k, d) == OneTo(1)))
@nloops $N i dest d->(@nexprs $N k->(j_d_k = Ibcast_d_k ? 1 : i_d)) begin
@nexprs $N k->(@inbounds J_k = @nref $N I_k d->j_d_k)
@inbounds (@nref $N dest i) = (@nref $N src J)
end
dest
end
end

"""
broadcast_setindex!(A, X, inds...)
Efficient element-by-element setting of the values of `A` in a pattern established by `inds`.
Equivalent to broadcasting the `X` and `inds` arrays to a common size, and then executing
for (is, js) in zip(zip(indsb), eachindex(Xb))
A[is...] = Xb[js...]
end
where `Xb` and `indsb` are the broadcast `X` and `inds`.
See [`broadcast_getindex`](@ref) for examples of the treatment of `inds`.
"""
@generated function broadcast_setindex!(A::AbstractArray, x, I::AbstractArray...)
N = length(I)
Isplat = Expr[:(I[$d]) for d = 1:N]
quote
@nexprs $N d->(I_d = I[d])
checkbounds(A, $(Isplat...))
shape = combine_axes($(Isplat...))
@nextract $N shape d->(length(shape) < d ? OneTo(1) : shape[d])
@nexprs $N d->(@nexprs $N k->(Ibcast_d_k = Base.axes(I_k, d) == 1:1))
if !isa(x, AbstractArray)
xA = convert(eltype(A), x)
@nloops $N i d->shape_d d->(@nexprs $N k->(j_d_k = Ibcast_d_k ? 1 : i_d)) begin
@nexprs $N k->(@inbounds J_k = @nref $N I_k d->j_d_k)
@inbounds (@nref $N A J) = xA
end
else
X = x
@nexprs $N d->(shapelen_d = length(shape_d))
@ncall $N Base.setindex_shape_check X shapelen
Xstate = start(X)
@inbounds @nloops $N i d->shape_d d->(@nexprs $N k->(j_d_k = Ibcast_d_k ? 1 : i_d)) begin
@nexprs $N k->(J_k = @nref $N I_k d->j_d_k)
x_el, Xstate = next(X, Xstate)
(@nref $N A J) = x_el
end
end
A
end
end

## In specific instances, we can broadcast masked BitArrays whole chunks at a time
# Very intentionally do not support much functionality here: scalar indexing would be O(n)
struct BitMaskedBitArray{N,M}
Expand Down
4 changes: 4 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,10 @@ end
@deprecate showcompact(io, x) show(IOContext(io, :compact => true), x)
@deprecate sprint(::typeof(showcompact), args...) sprint(show, args...; context=:compact => true)

# PR 27075
@deprecate broadcast_getindex(A, I...) getindex.((A,), I...)
@deprecate broadcast_setindex!(A, v, I...) setindex!.((A,), v, I...)

@deprecate isupper isuppercase
@deprecate islower islowercase
@deprecate ucfirst uppercasefirst
Expand Down
2 changes: 0 additions & 2 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,6 @@ export
axes,
broadcast!,
broadcast,
broadcast_getindex,
broadcast_setindex!,
cat,
checkbounds,
checkindex,
Expand Down
2 changes: 0 additions & 2 deletions doc/src/base/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ to operate on arrays, you should use `sin.(a)` to vectorize via `broadcast`.
Base.broadcast
Base.Broadcast.broadcast!
Base.@__dot__
Base.Broadcast.broadcast_getindex
Base.Broadcast.broadcast_setindex!
```

For specializing broadcast on custom types, see
Expand Down
3 changes: 1 addition & 2 deletions doc/src/manual/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -654,8 +654,7 @@ julia> broadcast(+, a, b)
[Dotted operators](@ref man-dot-operators) such as `.+` and `.*` are equivalent
to `broadcast` calls (except that they fuse, as described below). There is also a
[`broadcast!`](@ref) function to specify an explicit destination (which can also
be accessed in a fusing fashion by `.=` assignment), and functions [`broadcast_getindex`](@ref)
and [`broadcast_setindex!`](@ref) that broadcast the indices before indexing. Moreover, `f.(args...)`
be accessed in a fusing fashion by `.=` assignment). Moreover, `f.(args...)`
is equivalent to `broadcast(f, args...)`, providing a convenient syntax to broadcast any function
([dot syntax](@ref man-vectorized)). Nested "dot calls" `f.(...)` (including calls to `.+` etcetera)
[automatically fuse](@ref man-dot-operators) into a single `broadcast` call.
Expand Down
18 changes: 9 additions & 9 deletions test/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,22 +120,22 @@ for arr in (identity, as_sub)
@test arr(BitArray([true false])) .^ arr([0, 3]) == [true true; true false]

M = arr([11 12; 21 22])
@test broadcast_getindex(M, [2 1; 1 2], arr([1, 2])) == [21 11; 12 22]
@test_throws BoundsError broadcast_getindex(M, [2 1; 1 2], arr([1, -1]))
@test_throws BoundsError broadcast_getindex(M, [2 1; 1 2], arr([1, 2]), [2])
@test broadcast_getindex(M, [2 1; 1 2],arr([2, 1]), [1]) == [22 12; 11 21]
@test getindex.((M,), [2 1; 1 2], arr([1, 2])) == [21 11; 12 22]
@test_throws BoundsError getindex.((M,), [2 1; 1 2], arr([1, -1]))
@test_throws BoundsError getindex.((M,), [2 1; 1 2], arr([1, 2]), [2])
@test getindex.((M,), [2 1; 1 2],arr([2, 1]), [1]) == [22 12; 11 21]

A = arr(zeros(2,2))
broadcast_setindex!(A, arr([21 11; 12 22]), [2 1; 1 2], arr([1, 2]))
setindex!.((A,), arr([21 11; 12 22]), [2 1; 1 2], arr([1, 2]))
@test A == M
broadcast_setindex!(A, 5, [1,2], [2 2])
setindex!.((A,), 5, [1,2], [2 2])
@test A == [11 5; 21 5]
broadcast_setindex!(A, 7, [1,2], [1 2])
setindex!.((A,), 7, [1,2], [1 2])
@test A == fill(7, 2, 2)
A = arr(zeros(3,3))
broadcast_setindex!(A, 10:12, 1:3, 1:3)
setindex!.((A,), 10:12, 1:3, 1:3)
@test A == [10 0 0; 0 11 0; 0 0 12]
@test_throws BoundsError broadcast_setindex!(A, 7, [1,-1], [1 2])
@test_throws BoundsError setindex!.((A,), 7, [1,-1], [1 2])

for f in ((==), (<) , (!=), (<=))
bittest(f, arr([1 0; 0 1]), arr([1, 4]))
Expand Down

0 comments on commit 66c7b7d

Please sign in to comment.