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

RFC: Customizable lazy broadcasting with options for pure-Julia fusion and eager evaluation #25377

Closed
wants to merge 62 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
c0db74c
Reduce build-time calls to broadcasting machinery
timholy Jan 3, 2018
0c6617a
Allow test/core.jl to be run from REPL
timholy Jan 4, 2018
98fe8ab
Turn range&number arithmetic operations into broadcast methods
timholy Jan 3, 2018
aeba265
Make lazy dot fusion
vtjnash Sep 27, 2017
98f6bdc
Speed up range tests and fix printing at REPL
timholy Jan 3, 2018
0698edc
Integrate lazy broadcast representation into new broadcast machinery
timholy Jan 3, 2018
4c02b07
Temporarily disable failing tests
timholy Jan 7, 2018
e4d1962
Centralize broadcast support for structured matrices
timholy Jan 7, 2018
944e069
Docs: Slightly gentler introduction and overview of broadcast machinery
mbauman Jan 9, 2018
69eca0b
is_broadcast_incremental docstring: add implications about broadcast …
mbauman Jan 9, 2018
3cf994b
Update doctests for TupleLLEnd
mbauman Jan 10, 2018
de9e321
Fix and test nested scalar broadcasts
mbauman Jan 11, 2018
61bb21f
Merge remote-tracking branch 'origin/master' into teh-jn/lazydotfuse
mbauman Jan 13, 2018
8dcd8c1
Merge remote-tracking branch 'origin/master' into teh-jn/lazydotfuse
mbauman Jan 19, 2018
a14ed08
fixup merge
mbauman Jan 19, 2018
1774bdf
Allow construction of instantiated Broadcasted{Nothing} objects
mbauman Jan 20, 2018
7381ea4
Replace BitArray piecemeal broadcast...
mbauman Jan 20, 2018
25598ea
Fix `literal_pow` broadcast issue. (#25665)
ajkeller34 Jan 21, 2018
99507a2
WIP: broadcast style system for structured matrices
mbauman Jan 22, 2018
2e371e4
Structured broadcasts: Support Bidiagonal broadcasts and perform runt…
mbauman Jan 24, 2018
3e42812
fully detangle sparse and structured broadcast and tests
mbauman Jan 24, 2018
0115326
NFC: Style changes; use explicit returns, some line length considerat…
mbauman Jan 25, 2018
1de78ac
fixup comment
mbauman Jan 25, 2018
8e41f2f
Try implementing incremental broadcast in terms of `make`
mbauman Jan 26, 2018
adaf337
Rename execute to materialize; fixup .= with different size destination
mbauman Jan 27, 2018
cf0f8ce
Fix Sparse inference; improve allocations
mbauman Jan 29, 2018
4f8233f
Merge remote-tracking branch 'origin/master' into teh-jn/lazydotfuse
mbauman Jan 29, 2018
5749afc
fixup merge
mbauman Jan 29, 2018
f90f5fe
fix typejoin promotion and `y .= f.()` syntax
mbauman Jan 30, 2018
28d5421
Transform TupleLL to Tuple; capture Type arguments in a closure (#25844)
mbauman Apr 4, 2018
cfa9caa
Merge branch 'master' into teh-jn/lazydotfuse
mbauman Apr 10, 2018
8147932
Merge remote-tracking branch 'origin/master' into teh-jn/lazydotfuse
mbauman Apr 10, 2018
90ad8eb
Removing broadcasting from the new optimizer
mbauman Apr 12, 2018
03287c1
Remove Structured broadcast deferral to DefaultArrayStyle
mbauman Apr 12, 2018
f71db14
work around SparseArrays inference failure in broadcast!
mbauman Apr 12, 2018
e3eede4
Merge remote-tracking branch 'origin/master' into teh-jn/lazydotfuse
mbauman Apr 12, 2018
0edbd99
Decouple Broadcasting API from inference
mbauman Apr 13, 2018
71b830f
Merge remote-tracking branch 'origin/master' into teh-jn/lazydotfuse
mbauman Apr 13, 2018
b248953
Improve sparse allocation situation
mbauman Apr 13, 2018
964039a
Remove broadcast_skip_axes_initialization
mbauman Apr 18, 2018
37220d5
Improved accounting of the allocations when broadcasting over tranpos…
mbauman Apr 19, 2018
79ce497
Expose simpler axes/getindex methods for Broadcasted objects
mbauman Apr 19, 2018
a6cc656
Documentation update
mbauman Apr 19, 2018
98b5e84
Squash the most egregious perf bugs
mbauman Apr 19, 2018
2e9c0f2
More incremental perf improvements
mbauman Apr 19, 2018
3870fdf
Merge remote-tracking branch 'origin/master' into teh-jn/lazydotfuse
mbauman Apr 19, 2018
c1f2eba
fixup! More incremental perf improvements
mbauman Apr 19, 2018
9afdbbe
WIP: maybe don't use indexers?
mbauman Apr 20, 2018
81bd635
Try removing the indexing helper from Broadcasted
mbauman Apr 20, 2018
82d0a3b
WIP: move indexers into an argument wrapper
mbauman Apr 22, 2018
fb8234a
Completely move indexing helpers into wrappers
mbauman Apr 22, 2018
aba2da7
Don't recursively initialize the Broadcasted objects
mbauman Apr 22, 2018
5f99c2e
Inline copy(::Broadcasted) to avoid allocated the Broadcasted object
mbauman Apr 22, 2018
52a3202
Hack around losing Type{T} information in the final tuple...
mbauman Apr 22, 2018
a8a2608
Avoid re-using the same variable name
mbauman Apr 23, 2018
db690e0
Mitagate some of the performance issues with non-type-stable...
mbauman Apr 23, 2018
a2b9015
broadcast.jl cleanup:
mbauman Apr 23, 2018
c8bb374
Rename Broadcast.*_indices to *_axes as appropriate
mbauman Apr 23, 2018
110a0a5
Merge remote-tracking branch 'origin/master' into teh-jn/lazydotfuse
mbauman Apr 23, 2018
6fdb86e
Remove spurious NEWS item from merge mistake
mbauman Apr 23, 2018
df51b31
Fix broadcast_similar docstring
mbauman Apr 23, 2018
a1d4e7e
Fix #22255 by inlining the necessary methods
mbauman Apr 23, 2018
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
14 changes: 8 additions & 6 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ Language changes
* The syntax `using A.B` can now only be used when `A.B` is a module, and the syntax
`using A: B` can only be used for adding single bindings ([#8000]).


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

Expand Down Expand Up @@ -335,11 +334,6 @@ This section lists changes that do not have deprecation warnings.
Its return value has been removed. Use the `process_running` function
to determine if a process has already exited.

* Broadcasting has been redesigned with an extensible public interface. The new API is
documented at https://docs.julialang.org/en/latest/manual/interfaces/#Interfaces-1.
`AbstractArray` types that specialized broadcasting using the old internal API will
need to switch to the new API. ([#20740])

* The logging system has been redesigned - `info` and `warn` are deprecated
and replaced with the logging macros `@info`, `@warn`, `@debug` and
`@error`. The `logging` function is also deprecated and replaced with
Expand All @@ -365,6 +359,14 @@ This section lists changes that do not have deprecation warnings.
* `findn(x::AbstractVector)` now return a 1-tuple with the vector of indices, to be
consistent with higher order arrays ([#25365]).

* Broadcasting operations are no longer fused into a single operation by Julia's parser.
Instead, a lazy `Broadcasted` wrapper is created, and the parser will call
`copy(bc::Broadcasted)` or `copyto!(dest, bc::Broadcasted)`
to evaluate the wrapper. Consequently, package authors generally need to specialize
`copy` and `copyto!` methods rather than `broadcast` and `broadcast!`.
See the [Interfaces chapter](https://docs.julialang.org/en/latest/manual/interfaces/#Interfaces-1)
for more information.

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

Expand Down
781 changes: 562 additions & 219 deletions base/broadcast.jl

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Core: _apply, svec, apply_type, Builtin, IntrinsicFunction, MethodInstanc

#### parameters limiting potentially-infinite types ####
const MAX_TYPEUNION_LEN = 3
const MAX_TYPE_DEPTH = 8
const MAX_TYPE_DEPTH = 10
const TUPLE_COMPLEXITY_LIMIT_DEPTH = 3

const MAX_INLINE_CONST_SIZE = 256
Expand Down
27 changes: 17 additions & 10 deletions base/linalg/bidiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,23 @@ Bidiagonal{T}(A::Bidiagonal) where {T} =
# When asked to convert Bidiagonal to AbstractMatrix{T}, preserve structure by converting to Bidiagonal{T} <: AbstractMatrix{T}
AbstractMatrix{T}(A::Bidiagonal) where {T} = convert(Bidiagonal{T}, A)

broadcast(::typeof(big), B::Bidiagonal) = Bidiagonal(big.(B.dv), big.(B.ev), B.uplo)
function copyto!(dest::Bidiagonal, bc::Broadcasted{PromoteToSparse})
axs = axes(dest)
axes(bc) == axs || Broadcast.throwdm(axes(bc), axs)
for i in axs[1]
dest.dv[i] = Broadcast._broadcast_getindex(bc, CartesianIndex(i, i))
end
if dest.uplo == 'U'
for i = 1:size(dest, 1)-1
dest.ev[i] = Broadcast._broadcast_getindex(bc, CartesianIndex(i, i+1))
end
else
for i = 1:size(dest, 1)-1
dest.ev[i] = Broadcast._broadcast_getindex(bc, CartesianIndex(i+1, i))
end
end
dest
end

# For B<:Bidiagonal, similar(B[, neweltype]) should yield a Bidiagonal matrix.
# On the other hand, similar(B, [neweltype,] shape...) should yield a sparse matrix.
Expand Down Expand Up @@ -234,18 +250,9 @@ function size(M::Bidiagonal, d::Integer)
end

#Elementary operations
broadcast(::typeof(abs), M::Bidiagonal) = Bidiagonal(abs.(M.dv), abs.(M.ev), M.uplo)
broadcast(::typeof(round), M::Bidiagonal) = Bidiagonal(round.(M.dv), round.(M.ev), M.uplo)
broadcast(::typeof(trunc), M::Bidiagonal) = Bidiagonal(trunc.(M.dv), trunc.(M.ev), M.uplo)
broadcast(::typeof(floor), M::Bidiagonal) = Bidiagonal(floor.(M.dv), floor.(M.ev), M.uplo)
broadcast(::typeof(ceil), M::Bidiagonal) = Bidiagonal(ceil.(M.dv), ceil.(M.ev), M.uplo)
for func in (:conj, :copy, :real, :imag)
@eval ($func)(M::Bidiagonal) = Bidiagonal(($func)(M.dv), ($func)(M.ev), M.uplo)
end
broadcast(::typeof(round), ::Type{T}, M::Bidiagonal) where {T<:Integer} = Bidiagonal(round.(T, M.dv), round.(T, M.ev), M.uplo)
broadcast(::typeof(trunc), ::Type{T}, M::Bidiagonal) where {T<:Integer} = Bidiagonal(trunc.(T, M.dv), trunc.(T, M.ev), M.uplo)
broadcast(::typeof(floor), ::Type{T}, M::Bidiagonal) where {T<:Integer} = Bidiagonal(floor.(T, M.dv), floor.(T, M.ev), M.uplo)
broadcast(::typeof(ceil), ::Type{T}, M::Bidiagonal) where {T<:Integer} = Bidiagonal(ceil.(T, M.dv), ceil.(T, M.ev), M.uplo)

transpose(M::Bidiagonal) = Bidiagonal(M.dv, M.ev, M.uplo == 'U' ? :L : :U)
adjoint(M::Bidiagonal) = Bidiagonal(conj(M.dv), conj(M.ev), M.uplo == 'U' ? :L : :U)
Expand Down
10 changes: 9 additions & 1 deletion base/linalg/diagonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,18 @@ isposdef(D::Diagonal) = all(x -> x > 0, D.diag)

factorize(D::Diagonal) = D

broadcast(::typeof(abs), D::Diagonal) = Diagonal(abs.(D.diag))
real(D::Diagonal) = Diagonal(real(D.diag))
imag(D::Diagonal) = Diagonal(imag(D.diag))

function copyto!(dest::Diagonal, bc::Broadcasted{PromoteToSparse})
axs = axes(dest)
axes(bc) == axs || Broadcast.throwdm(axes(bc), axs)
for i in axs[1]
dest.diag[i] = Broadcast._broadcast_getindex(bc, CartesianIndex(i, i))
end
dest
end

istriu(D::Diagonal) = true
istril(D::Diagonal) = true
function triu!(D::Diagonal,k::Integer=0)
Expand Down
2 changes: 2 additions & 0 deletions base/linalg/linalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import Base: USE_BLAS64, abs, acos, acosh, acot, acoth, acsc, acsch, adjoint, as
StridedReshapedArray, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec
using Base: hvcat_fill, iszero, IndexLinear, _length, promote_op, promote_typeof,
@propagate_inbounds, @pure, reduce, typed_vcat
using Base.Broadcast: Broadcasted, PromoteToSparse

# We use `_length` because of non-1 indices; releases after julia 0.5
# can go back to `length`. `_length(A)` is equivalent to `length(linearindices(A))`.

Expand Down
47 changes: 25 additions & 22 deletions base/linalg/tridiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,22 @@ end
similar(S::SymTridiagonal, ::Type{T}) where {T} = SymTridiagonal(similar(S.dv, T), similar(S.ev, T))
similar(S::SymTridiagonal, ::Type{T}, dims::Union{Dims{1},Dims{2}}) where {T} = spzeros(T, dims...)

function copyto!(dest::SymTridiagonal, bc::Broadcasted{PromoteToSparse})
axs = axes(dest)
axes(bc) == axs || Broadcast.throwdm(axes(bc), axs)
for i in axs[1]
dest.dv[i] = Broadcast._broadcast_getindex(bc, CartesianIndex(i, i))
end
for i = 1:size(dest, 1)-1
dest.ev[i] = Broadcast._broadcast_getindex(bc, CartesianIndex(i, i+1))
end
dest
end

#Elementary operations
broadcast(::typeof(abs), M::SymTridiagonal) = SymTridiagonal(abs.(M.dv), abs.(M.ev))
broadcast(::typeof(round), M::SymTridiagonal) = SymTridiagonal(round.(M.dv), round.(M.ev))
broadcast(::typeof(trunc), M::SymTridiagonal) = SymTridiagonal(trunc.(M.dv), trunc.(M.ev))
broadcast(::typeof(floor), M::SymTridiagonal) = SymTridiagonal(floor.(M.dv), floor.(M.ev))
broadcast(::typeof(ceil), M::SymTridiagonal) = SymTridiagonal(ceil.(M.dv), ceil.(M.ev))
for func in (:conj, :copy, :real, :imag)
@eval ($func)(M::SymTridiagonal) = SymTridiagonal(($func)(M.dv), ($func)(M.ev))
end
broadcast(::typeof(round), ::Type{T}, M::SymTridiagonal) where {T<:Integer} = SymTridiagonal(round.(T, M.dv), round.(T, M.ev))
broadcast(::typeof(trunc), ::Type{T}, M::SymTridiagonal) where {T<:Integer} = SymTridiagonal(trunc.(T, M.dv), trunc.(T, M.ev))
broadcast(::typeof(floor), ::Type{T}, M::SymTridiagonal) where {T<:Integer} = SymTridiagonal(floor.(T, M.dv), floor.(T, M.ev))
broadcast(::typeof(ceil), ::Type{T}, M::SymTridiagonal) where {T<:Integer} = SymTridiagonal(ceil.(T, M.dv), ceil.(T, M.ev))

transpose(M::SymTridiagonal) = M #Identity operation
adjoint(M::SymTridiagonal) = conj(M)
Expand Down Expand Up @@ -500,24 +503,11 @@ similar(M::Tridiagonal, ::Type{T}, dims::Union{Dims{1},Dims{2}}) where {T} = spz
copyto!(dest::Tridiagonal, src::Tridiagonal) = (copyto!(dest.dl, src.dl); copyto!(dest.d, src.d); copyto!(dest.du, src.du); dest)

#Elementary operations
broadcast(::typeof(abs), M::Tridiagonal) = Tridiagonal(abs.(M.dl), abs.(M.d), abs.(M.du))
broadcast(::typeof(round), M::Tridiagonal) = Tridiagonal(round.(M.dl), round.(M.d), round.(M.du))
broadcast(::typeof(trunc), M::Tridiagonal) = Tridiagonal(trunc.(M.dl), trunc.(M.d), trunc.(M.du))
broadcast(::typeof(floor), M::Tridiagonal) = Tridiagonal(floor.(M.dl), floor.(M.d), floor.(M.du))
broadcast(::typeof(ceil), M::Tridiagonal) = Tridiagonal(ceil.(M.dl), ceil.(M.d), ceil.(M.du))
for func in (:conj, :copy, :real, :imag)
@eval function ($func)(M::Tridiagonal)
Tridiagonal(($func)(M.dl), ($func)(M.d), ($func)(M.du))
end
end
broadcast(::typeof(round), ::Type{T}, M::Tridiagonal) where {T<:Integer} =
Tridiagonal(round.(T, M.dl), round.(T, M.d), round.(T, M.du))
broadcast(::typeof(trunc), ::Type{T}, M::Tridiagonal) where {T<:Integer} =
Tridiagonal(trunc.(T, M.dl), trunc.(T, M.d), trunc.(T, M.du))
broadcast(::typeof(floor), ::Type{T}, M::Tridiagonal) where {T<:Integer} =
Tridiagonal(floor.(T, M.dl), floor.(T, M.d), floor.(T, M.du))
broadcast(::typeof(ceil), ::Type{T}, M::Tridiagonal) where {T<:Integer} =
Tridiagonal(ceil.(T, M.dl), ceil.(T, M.d), ceil.(T, M.du))

transpose(M::Tridiagonal) = Tridiagonal(M.du, M.d, M.dl)
adjoint(M::Tridiagonal) = conj(transpose(M))
Expand Down Expand Up @@ -576,6 +566,19 @@ function Base.replace_in_print_matrix(A::Tridiagonal,i::Integer,j::Integer,s::Ab
i==j-1||i==j||i==j+1 ? s : Base.replace_with_centered_mark(s)
end

function copyto!(dest::Tridiagonal, bc::Broadcasted{PromoteToSparse})
axs = axes(dest)
axes(bc) == axs || Broadcast.throwdm(axes(bc), axs)
for i in axs[1]
dest.d[i] = Broadcast._broadcast_getindex(bc, CartesianIndex(i, i))
end
for i = 1:size(dest, 1)-1
dest.du[i] = Broadcast._broadcast_getindex(bc, CartesianIndex(i, i+1))
dest.dl[i] = Broadcast._broadcast_getindex(bc, CartesianIndex(i+1, i))
end
dest
end

#tril and triu

istriu(M::Tridiagonal) = iszero(M.dl)
Expand Down
3 changes: 3 additions & 0 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ promote_rule(::Type{BigFloat}, ::Type{<:AbstractFloat}) = BigFloat

big(::Type{<:AbstractFloat}) = BigFloat

# Support conversion of AbstractRanges to high precision
Base.Broadcast.maybe_range_safe_f(::typeof(big)) = true

function (::Type{Rational{BigInt}})(x::AbstractFloat)
isnan(x) && return zero(BigInt) // zero(BigInt)
isinf(x) && return copysign(one(BigInt),x) // zero(BigInt)
Expand Down
80 changes: 31 additions & 49 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -734,67 +734,51 @@ end
StepRangeLen{T,R,S}(-r.ref, -r.step, length(r), r.offset)
-(r::LinSpace) = LinSpace(-r.start, -r.stop, length(r))

*(x::Number, r::AbstractRange) = range(x*first(r), x*step(r), length(r))
*(x::Number, r::StepRangeLen{T}) where {T} =
StepRangeLen{typeof(x*T(r.ref))}(x*r.ref, x*r.step, length(r), r.offset)
*(x::Number, r::LinSpace) = LinSpace(x * r.start, x * r.stop, r.len)
# separate in case of noncommutative multiplication
*(r::AbstractRange, x::Number) = range(first(r)*x, step(r)*x, length(r))
*(r::StepRangeLen{T}, x::Number) where {T} =
StepRangeLen{typeof(T(r.ref)*x)}(r.ref*x, r.step*x, length(r), r.offset)
*(r::LinSpace, x::Number) = LinSpace(r.start * x, r.stop * x, r.len)

/(r::AbstractRange, x::Number) = range(first(r)/x, step(r)/x, length(r))
/(r::StepRangeLen{T}, x::Number) where {T} =
StepRangeLen{typeof(T(r.ref)/x)}(r.ref/x, r.step/x, length(r), r.offset)
/(r::LinSpace, x::Number) = LinSpace(r.start / x, r.stop / x, r.len)
# also, separate in case of noncommutative multiplication (division)
\(x::Number, r::AbstractRange) = range(x\first(r), x\step(r), x\length(r))
\(x::Number, r::StepRangeLen) = StepRangeLen(x\r.ref, x\r.step, length(r), r.offset)
\(x::Number, r::LinSpace) = LinSpace(x \ r.start, x \ r.stop, r.len)

## scalar-range broadcast operations ##

broadcast(::typeof(-), r::OrdinalRange) = range(-first(r), -step(r), length(r))
broadcast(::typeof(-), r::StepRangeLen) = StepRangeLen(-r.ref, -r.step, length(r), r.offset)
broadcast(::typeof(-), r::LinSpace) = LinSpace(-r.start, -r.stop, length(r))

broadcast(::typeof(+), x::Real, r::AbstractUnitRange) = range(x + first(r), length(r))
broadcast(::typeof(+), r::AbstractUnitRange, x::Real) = range(first(r) + x, length(r))
# For #18336 we need to prevent promotion of the step type:
broadcast(::typeof(+), x::Number, r::AbstractUnitRange) = range(x + first(r), step(r), length(r))
broadcast(::typeof(+), x::Number, r::AbstractRange) = (x+first(r)):step(r):(x+last(r))
function broadcast(::typeof(+), x::Number, r::StepRangeLen{T}) where T
newref = x + r.ref
StepRangeLen{typeof(T(r.ref) + x)}(newref, r.step, length(r), r.offset)
end
function broadcast(::typeof(+), x::Number, r::LinSpace)
LinSpace(x + r.start, x + r.stop, r.len)
end
broadcast(::typeof(+), r::AbstractRange, x::Number) = broadcast(+, x, r) # assumes addition is commutative

broadcast(::typeof(-), x::Number, r::AbstractRange) = (x-first(r)):-step(r):(x-last(r))
broadcast(::typeof(-), x::Number, r::StepRangeLen) = broadcast(+, x, -r)
function broadcast(::typeof(-), x::Number, r::LinSpace)
LinSpace(x - r.start, x - r.stop, r.len)
end

broadcast(::typeof(-), r::AbstractRange, x::Number) = broadcast(+, -x, r) # assumes addition is commutative
broadcast(::typeof(+), r::AbstractRange, x::Number) = range(first(r) + x, step(r), length(r))
broadcast(::typeof(+), x::Number, r::AbstractRange) = range(x + first(r), step(r), length(r))
broadcast(::typeof(+), r::StepRangeLen{T}, x::Number) where T =
StepRangeLen{typeof(T(r.ref)+x)}(r.ref + x, r.step, length(r), r.offset)
broadcast(::typeof(+), x::Number, r::StepRangeLen{T}) where T =
StepRangeLen{typeof(x+T(r.ref))}(x + r.ref, r.step, length(r), r.offset)
broadcast(::typeof(+), r::LinSpace, x::Number) = LinSpace(r.start + x, r.stop + x, length(r))
broadcast(::typeof(+), x::Number, r::LinSpace) = LinSpace(x + r.start, x + r.stop, length(r))

broadcast(::typeof(-), r::AbstractUnitRange, x::Number) = range(first(r)-x, length(r))
broadcast(::typeof(-), r::AbstractRange, x::Number) = range(first(r)-x, step(r), length(r))
broadcast(::typeof(-), x::Number, r::AbstractRange) = range(x-first(r), -step(r), length(r))
broadcast(::typeof(-), r::StepRangeLen{T}, x::Number) where T =
StepRangeLen{typeof(T(r.ref)-x)}(r.ref - x, r.step, length(r), r.offset)
broadcast(::typeof(-), x::Number, r::StepRangeLen{T}) where T =
StepRangeLen{typeof(x-T(r.ref))}(x - r.ref, -r.step, length(r), r.offset)
broadcast(::typeof(-), r::LinSpace, x::Number) = LinSpace(r.start - x, r.stop - x, length(r))
broadcast(::typeof(-), x::Number, r::LinSpace) = LinSpace(x - r.start, x - r.stop, length(r))

broadcast(::typeof(*), x::Number, r::AbstractRange) = range(x*first(r), x*step(r), length(r))
broadcast(::typeof(*), x::Number, r::StepRangeLen) = StepRangeLen(x*r.ref, x*r.step, length(r), r.offset)
broadcast(::typeof(*), x::Number, r::LinSpace) = LinSpace(x * r.start, x * r.stop, r.len)
broadcast(::typeof(*), x::Number, r::StepRangeLen{T}) where {T} =
StepRangeLen{typeof(x*T(r.ref))}(x*r.ref, x*r.step, length(r), r.offset)
broadcast(::typeof(*), x::Number, r::LinSpace) = LinSpace(x * r.start, x * r.stop, r.len)
# separate in case of noncommutative multiplication
broadcast(::typeof(*), r::AbstractRange, x::Number) = range(first(r)*x, step(r)*x, length(r))
broadcast(::typeof(*), r::StepRangeLen, x::Number) = StepRangeLen(r.ref*x, r.step*x, length(r), r.offset)
broadcast(::typeof(*), r::LinSpace, x::Number) = LinSpace(r.start * x, r.stop * x, r.len)
broadcast(::typeof(*), r::StepRangeLen{T}, x::Number) where {T} =
StepRangeLen{typeof(T(r.ref)*x)}(r.ref*x, r.step*x, length(r), r.offset)
broadcast(::typeof(*), r::LinSpace, x::Number) = LinSpace(r.start * x, r.stop * x, r.len)

broadcast(::typeof(/), r::AbstractRange, x::Number) = range(first(r)/x, step(r)/x, length(r))
broadcast(::typeof(/), r::StepRangeLen, x::Number) = StepRangeLen(r.ref/x, r.step/x, length(r), r.offset)
broadcast(::typeof(/), r::LinSpace, x::Number) = LinSpace(r.start / x, r.stop / x, r.len)
# also, separate in case of noncommutative multiplication (division)
broadcast(::typeof(\), x::Number, r::AbstractRange) = range(x\first(r), x\step(r), x\length(r))
broadcast(::typeof(\), x::Number, r::StepRangeLen) = StepRangeLen(x\r.ref, x\r.step, length(r), r.offset)
broadcast(::typeof(\), x::Number, r::LinSpace) = LinSpace(x \ r.start, x \ r.stop, r.len)
broadcast(::typeof(/), r::StepRangeLen{T}, x::Number) where {T} =
StepRangeLen{typeof(T(r.ref)/x)}(r.ref/x, r.step/x, length(r), r.offset)
broadcast(::typeof(/), r::LinSpace, x::Number) = LinSpace(r.start / x, r.stop / x, r.len)

broadcast(::typeof(/), x::Number, r::AbstractRange) = [(x/y) for y in r]


# promote eltype if at least one container wouldn't change, otherwise join container types.
el_same(::Type{T}, a::Type{<:AbstractArray{T,n}}, b::Type{<:AbstractArray{T,n}}) where {T,n} = a
Expand Down Expand Up @@ -866,8 +850,6 @@ promote_rule(a::Type{LinSpace{T}}, ::Type{OR}) where {T,OR<:OrdinalRange} =
promote_rule(::Type{LinSpace{L}}, b::Type{StepRangeLen{T,R,S}}) where {L,T,R,S} =
promote_rule(StepRangeLen{L,L,L}, b)

# +/- of ranges is defined in operators.jl (to be able to use @eval etc.)

## concatenation ##

function vcat(rs::AbstractRange{T}...) where T
Expand Down
1 change: 1 addition & 0 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ end
show_comma_array(io::IO, itr, o, c) = show_delim_array(io, itr, o, ',', c, false)
show(io::IO, t::Tuple) = show_delim_array(io, t, '(', ',', ')', true)
show(io::IO, v::SimpleVector) = show_delim_array(io, v, "svec(", ',', ')', false)
show(io::IO, t::TupleLL) = show_delim_array(io, t, '{', ',', '}', true)

show(io::IO, s::Symbol) = show_unquoted_quote_expr(io, s, 0, 0)

Expand Down
7 changes: 5 additions & 2 deletions base/sort.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,12 @@ issorted(itr;
function partialsort!(v::AbstractVector, k::Union{Int,OrdinalRange}, o::Ordering)
inds = axes(v, 1)
sort!(v, first(inds), last(inds), PartialQuickSort(k), o)
@views v[k]
maybeview(v, k)
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a separate change?

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually intentional (and related), and it doesn't change any behaviors. The @views macro uses broadcast internally to do its expression-munging… and effectively lowers to the same thing. This just pulls that out to simplify bootstrap. Ref c0db74c

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the first time I wasted about 1.5 days trying to get this through bootstrap, until I realized that the smart thing to do was to get rid of all the usage of broadcasting during build. Once I had a finished build of Julia, it was a matter of a couple hours to fix up the problems in broadcasting.

end

maybeview(v, k) = view(v, k)
maybeview(v, k::Integer) = v[k]

"""
partialsort!(v, k, [by=<transform>,] [lt=<comparison>,] [rev=false])

Expand Down Expand Up @@ -707,7 +710,7 @@ function partialsortperm!(ix::AbstractVector{<:Integer}, v::AbstractVector,
# do partial quicksort
sort!(ix, PartialQuickSort(k), Perm(ord(lt, by, rev, order), v))

@views ix[k]
maybeview(ix, k)
end

## sortperm: the permutation to sort an array ##
Expand Down
Loading