Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make "dot" operations (.+ etc) fusing broadcasts #17623

Merged
merged 4 commits into from
Dec 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ New language features
Language changes
----------------

* Multiline and singleline nonstandard command literals have been added. A
* Multi-line and single-line nonstandard command literals have been added. A
nonstandard command literal is like a nonstandard string literal, but the
syntax uses backquotes (``` ` ```) instead of double quotes, and the
resulting macro called is suffixed with `_cmd`. For instance, the syntax
Expand All @@ -17,6 +17,11 @@ Language changes
module. For instance, `Base.r"x"` is now parsed as `Base.@r_str "x"`.
Previously, this syntax parsed as an implicit multiplication. ([#18690])

* For every binary operator `⨳`, `a .⨳ b` is now automatically equivalent to
the `broadcast` call `(⨳).(a, b)`. Hence, one no longer defines methods
for `.*` etcetera. This also means that "dot operations" automatically
fuse into a single loop, along with other dot calls `f.(x)`. ([#17623])

Breaking changes
----------------

Expand All @@ -34,6 +39,14 @@ This section lists changes that do not have deprecation warnings.
* `broadcast` now handles tuples, and treats any argument that is not a tuple
or an array as a "scalar" ([#16986]).

* `broadcast` now produces a `BitArray` instead of `Array{Bool}` for
functions yielding a boolean result. If you want `Array{Bool}`, use
`broadcast!` or `.=` ([#17623]).

* Operations like `.+` and `.*` on `Range` objects are now generic
`broadcast` calls (see above) and produce an `Array`. If you want
a `Range` result, use `+` and `*`, etcetera ([#17623]).

Library improvements
--------------------

Expand Down
2 changes: 1 addition & 1 deletion base/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ function splice_buffer!{T<:Integer}(buf::IOBuffer, r::UnitRange{T}, ins::Abstrac
elseif pos > last(r)
seek(buf, pos - length(r))
end
splice!(buf.data, r .+ 1, ins.data) # position(), etc, are 0-indexed
splice!(buf.data, r + 1, ins.data) # position(), etc, are 0-indexed
buf.size = buf.size + sizeof(ins) - length(r)
seek(buf, position(buf) + sizeof(ins))
end
Expand Down
10 changes: 1 addition & 9 deletions base/abstractarraymath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
isinteger(x::AbstractArray) = all(isinteger,x)
isinteger{T<:Integer,n}(x::AbstractArray{T,n}) = true
isreal(x::AbstractArray) = all(isreal,x)
iszero(x::AbstractArray) = all(iszero,x)
isreal{T<:Real,n}(x::AbstractArray{T,n}) = true
ctranspose(a::AbstractArray) = error("ctranspose not implemented for $(typeof(a)). Consider adding parentheses, e.g. A*(B*C') instead of A*B*C' to avoid explicit calculation of the transposed matrix.")
transpose(a::AbstractArray) = error("transpose not implemented for $(typeof(a)). Consider adding parentheses, e.g. A*(B*C.') instead of A*B*C' to avoid explicit calculation of the transposed matrix.")
Expand Down Expand Up @@ -91,15 +92,6 @@ imag{T<:Real}(x::AbstractArray{T}) = zero(x)
+{T<:Number}(x::AbstractArray{T}) = x
*{T<:Number}(x::AbstractArray{T,2}) = x

## Binary arithmetic operators ##

*(A::Number, B::AbstractArray) = A .* B
*(A::AbstractArray, B::Number) = A .* B

/(A::AbstractArray, B::Number) = A ./ B

\(A::Number, B::AbstractArray) = B ./ A

# index A[:,:,...,i,:,:,...] where "i" is in dimension "d"

"""
Expand Down
28 changes: 10 additions & 18 deletions base/arraymath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ end
promote_array_type(F, ::Type, ::Type, T::Type) = T
promote_array_type{S<:Real, A<:AbstractFloat}(F, ::Type{S}, ::Type{A}, ::Type) = A
promote_array_type{S<:Integer, A<:Integer}(F, ::Type{S}, ::Type{A}, ::Type) = A
promote_array_type{S<:Integer, A<:Integer}(::typeof(./), ::Type{S}, ::Type{A}, T::Type) = T
promote_array_type{S<:Integer, A<:Integer}(::typeof(.\), ::Type{S}, ::Type{A}, T::Type) = T
promote_array_type{S<:Integer}(::typeof(./), ::Type{S}, ::Type{Bool}, T::Type) = T
promote_array_type{S<:Integer}(::typeof(.\), ::Type{S}, ::Type{Bool}, T::Type) = T
promote_array_type{S<:Integer, A<:Integer}(::typeof(/), ::Type{S}, ::Type{A}, T::Type) = T
promote_array_type{S<:Integer, A<:Integer}(::typeof(\), ::Type{S}, ::Type{A}, T::Type) = T
promote_array_type{S<:Integer}(::typeof(/), ::Type{S}, ::Type{Bool}, T::Type) = T
promote_array_type{S<:Integer}(::typeof(\), ::Type{S}, ::Type{Bool}, T::Type) = T
promote_array_type{S<:Integer}(F, ::Type{S}, ::Type{Bool}, T::Type) = T

for f in (:+, :-, :div, :mod, :&, :|, :xor)
Expand All @@ -89,9 +89,9 @@ function _elementwise{T}(op, ::Type{T}, A::AbstractArray, B::AbstractArray)
return F
end

for f in (:.+, :.-, :.*, :./, :.\, :.^, :, :.%, :.<<, :.>>, :div, :mod, :rem, :&, :|, :xor)
@eval begin
function ($f){T}(A::Number, B::AbstractArray{T})
for f in (:div, :mod, :rem, :&, :|, :xor, :/, :\, :*, :+, :-)
if f != :/
@eval function ($f){T}(A::Number, B::AbstractArray{T})
R = promote_op($f, typeof(A), T)
S = promote_array_type($f, typeof(A), T, R)
S === Any && return [($f)(A, b) for b in B]
Expand All @@ -108,7 +108,9 @@ for f in (:.+, :.-, :.*, :./, :.\, :.^, :.÷, :.%, :.<<, :.>>, :div, :mod, :rem,
end
return F
end
function ($f){T}(A::AbstractArray{T}, B::Number)
end
if f != :\
@eval function ($f){T}(A::AbstractArray{T}, B::Number)
R = promote_op($f, T, typeof(B))
S = promote_array_type($f, typeof(B), T, R)
S === Any && return [($f)(a, B) for a in A]
Expand All @@ -128,16 +130,6 @@ for f in (:.+, :.-, :.*, :./, :.\, :.^, :.÷, :.%, :.<<, :.>>, :div, :mod, :rem,
end
end

# familiar aliases for broadcasting operations of array ± scalar (#7226):
(+)(A::AbstractArray{Bool},x::Bool) = A .+ x
(+)(x::Bool,A::AbstractArray{Bool}) = x .+ A
(-)(A::AbstractArray{Bool},x::Bool) = A .- x
(-)(x::Bool,A::AbstractArray{Bool}) = x .- A
(+)(A::AbstractArray,x::Number) = A .+ x
(+)(x::Number,A::AbstractArray) = x .+ A
(-)(A::AbstractArray,x::Number) = A .- x
(-)(x::Number,A::AbstractArray) = x .- A

## data movement ##

function flipdim{T}(A::Array{T}, d::Integer)
Expand Down
97 changes: 0 additions & 97 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1136,9 +1136,6 @@ function empty!(B::BitVector)
return B
end

## Misc functions
broadcast(::typeof(abs), B::BitArray) = copy(B)

## Unary operators ##

function (-)(B::BitArray)
Expand Down Expand Up @@ -1232,35 +1229,6 @@ for f in (:+, :-)
end
end

for (f) in (:.+, :.-)
for (arg1, arg2, T, t) in ((:(B::BitArray), :(x::Bool) , Int , (:b, :x)),
(:(B::BitArray), :(x::Number) , :(Bool, typeof(x)), (:b, :x)),
(:(x::Bool) , :(B::BitArray), Int , (:x, :b)),
(:(x::Number) , :(B::BitArray), :(typeof(x), Bool), (:x, :b)))
@eval function ($f)($arg1, $arg2)
$(if T === Int
quote
r = Array{Int}(size(B))
end
else
quote
T = promote_op($f, $(T.args[1]), $(T.args[2]))
T === Any && return [($f)($(t[1]), $(t[2])) for b in B]
r = Array{T}(size(B))
end
end)
bi = start(B)
ri = 1
while !done(B, bi)
b, bi = next(B, bi)
@inbounds r[ri] = ($f)($(t[1]), $(t[2]))
ri += 1
end
return r
end
end
end

for f in (:/, :\)
@eval begin
($f)(A::BitArray, B::BitArray) = ($f)(Array(A), Array(B))
Expand Down Expand Up @@ -1359,71 +1327,6 @@ for f in (:&, :|, :xor)
end
end

function (.^)(B::BitArray, x::Bool)
x ? copy(B) : trues(size(B))
end
function (.^)(x::Bool, B::BitArray)
x ? trues(size(B)) : ~B
end
function (.^)(x::Number, B::BitArray)
z = x ^ false
u = x ^ true
reshape([ B[i] ? u : z for i = 1:length(B) ], size(B))
end
function (.^)(B::BitArray, x::Integer)
x == 0 && return trues(size(B))
x < 0 && throw(DomainError())
return copy(B)
end
function (.^){T<:Number}(B::BitArray, x::T)
x == 0 && return ones(typeof(true ^ x), size(B))
T <: Real && x > 0 && return convert(Array{T}, B)

z = nothing
u = nothing
zerr = nothing
uerr = nothing
try
z = false^x
catch err
zerr = err
end
try
u = true^x
catch err
uerr = err
end
if zerr === nothing && uerr === nothing
t = promote_type(typeof(z), typeof(u))
elseif zerr === nothing
t = typeof(z)
else
t = typeof(u)
end
F = Array{t}(size(B))
for i = 1:length(B)
if B[i]
if uerr === nothing
F[i] = u
else
throw(uerr)
end
else
if zerr === nothing
F[i] = z
else
throw(zerr)
end
end
end
return F
end

(.*)(x::Bool, B::BitArray) = x & B
(.*)(B::BitArray, x::Bool) = B & x
(.*)(x::Number, B::BitArray) = x .* Array(B)
(.*)(B::BitArray, x::Number) = Array(B) .* x

## promotion to complex ##

# TODO?
Expand Down
Loading