StatProfilerHTML.jl report
Generated on Thu, 21 Dec 2023 12:59:22
File source code
Line Exclusive Inclusive Code
1 # This file is a part of Julia. License is MIT: https://julialang.org/license
2
3 """
4 Base.Broadcast
5
6 Module containing the broadcasting implementation.
7 """
8 module Broadcast
9
10 using .Base.Cartesian
11 using .Base: Indices, OneTo, tail, to_shape, isoperator, promote_typejoin, promote_typejoin_union,
12 _msk_end, unsafe_bitgetindex, bitcache_chunks, bitcache_size, dumpbitcache, unalias, negate
13 import .Base: copy, copyto!, axes
14 export broadcast, broadcast!, BroadcastStyle, broadcast_axes, broadcastable, dotview, @__dot__, BroadcastFunction
15
16 ## Computing the result's axes: deprecated name
17 const broadcast_axes = axes
18
19 ### Objects with customized broadcasting behavior should declare a BroadcastStyle
20
21 """
22 `BroadcastStyle` is an abstract type and trait-function used to determine behavior of
23 objects under broadcasting. `BroadcastStyle(typeof(x))` returns the style associated
24 with `x`. To customize the broadcasting behavior of a type, one can declare a style
25 by defining a type/method pair
26
27 struct MyContainerStyle <: BroadcastStyle end
28 Base.BroadcastStyle(::Type{<:MyContainer}) = MyContainerStyle()
29
30 One then writes method(s) (at least [`similar`](@ref)) operating on
31 `Broadcasted{MyContainerStyle}`. There are also several pre-defined subtypes of `BroadcastStyle`
32 that you may be able to leverage; see the
33 [Interfaces chapter](@ref man-interfaces-broadcasting) for more information.
34 """
35 abstract type BroadcastStyle end
36
37 struct Unknown <: BroadcastStyle end
38 BroadcastStyle(::Type{Union{}}, slurp...) = Unknown() # ambiguity resolution
39
40 """
41 `Broadcast.Style{C}()` defines a [`BroadcastStyle`](@ref) signaling through the type
42 parameter `C`. You can use this as an alternative to creating custom subtypes of `BroadcastStyle`,
43 for example
44
45 Base.BroadcastStyle(::Type{<:MyContainer}) = Broadcast.Style{MyContainer}()
46 """
47 struct Style{T} <: BroadcastStyle end
48
49 BroadcastStyle(::Type{<:Tuple}) = Style{Tuple}()
50
51 """
52 `Broadcast.AbstractArrayStyle{N} <: BroadcastStyle` is the abstract supertype for any style
53 associated with an `AbstractArray` type.
54 The `N` parameter is the dimensionality, which can be handy for AbstractArray types
55 that only support specific dimensionalities:
56
57 struct SparseMatrixStyle <: Broadcast.AbstractArrayStyle{2} end
58 Base.BroadcastStyle(::Type{<:SparseMatrixCSC}) = SparseMatrixStyle()
59
60 For `AbstractArray` types that support arbitrary dimensionality, `N` can be set to `Any`:
61
62 struct MyArrayStyle <: Broadcast.AbstractArrayStyle{Any} end
63 Base.BroadcastStyle(::Type{<:MyArray}) = MyArrayStyle()
64
65 In cases where you want to be able to mix multiple `AbstractArrayStyle`s and keep track
66 of dimensionality, your style needs to support a [`Val`](@ref) constructor:
67
68 struct MyArrayStyleDim{N} <: Broadcast.AbstractArrayStyle{N} end
69 (::Type{<:MyArrayStyleDim})(::Val{N}) where N = MyArrayStyleDim{N}()
70
71 Note that if two or more `AbstractArrayStyle` subtypes conflict, broadcasting machinery
72 will fall back to producing `Array`s. If this is undesirable, you may need to
73 define binary [`BroadcastStyle`](@ref) rules to control the output type.
74
75 See also [`Broadcast.DefaultArrayStyle`](@ref).
76 """
77 abstract type AbstractArrayStyle{N} <: BroadcastStyle end
78
79 """
80 `Broadcast.ArrayStyle{MyArrayType}()` is a [`BroadcastStyle`](@ref) indicating that an object
81 behaves as an array for broadcasting. It presents a simple way to construct
82 [`Broadcast.AbstractArrayStyle`](@ref)s for specific `AbstractArray` container types.
83 Broadcast styles created this way lose track of dimensionality; if keeping track is important
84 for your type, you should create your own custom [`Broadcast.AbstractArrayStyle`](@ref).
85 """
86 struct ArrayStyle{A<:AbstractArray} <: AbstractArrayStyle{Any} end
87 ArrayStyle{A}(::Val) where A = ArrayStyle{A}()
88
89 """
90 `Broadcast.DefaultArrayStyle{N}()` is a [`BroadcastStyle`](@ref) indicating that an object
91 behaves as an `N`-dimensional array for broadcasting. Specifically, `DefaultArrayStyle` is
92 used for any
93 `AbstractArray` type that hasn't defined a specialized style, and in the absence of
94 overrides from other `broadcast` arguments the resulting output type is `Array`.
95 When there are multiple inputs to `broadcast`, `DefaultArrayStyle` "loses" to any other [`Broadcast.ArrayStyle`](@ref).
96 """
97 struct DefaultArrayStyle{N} <: AbstractArrayStyle{N} end
98 DefaultArrayStyle(::Val{N}) where N = DefaultArrayStyle{N}()
99 DefaultArrayStyle{M}(::Val{N}) where {N,M} = DefaultArrayStyle{N}()
100 const DefaultVectorStyle = DefaultArrayStyle{1}
101 const DefaultMatrixStyle = DefaultArrayStyle{2}
102 BroadcastStyle(::Type{<:AbstractArray{T,N}}) where {T,N} = DefaultArrayStyle{N}()
103 BroadcastStyle(::Type{T}) where {T} = DefaultArrayStyle{ndims(T)}()
104
105 # `ArrayConflict` is an internal type signaling that two or more different `AbstractArrayStyle`
106 # objects were supplied as arguments, and that no rule was defined for resolving the
107 # conflict. The resulting output is `Array`. While this is the same output type
108 # produced by `DefaultArrayStyle`, `ArrayConflict` "poisons" the BroadcastStyle so that
109 # 3 or more arguments still return an `ArrayConflict`.
110 struct ArrayConflict <: AbstractArrayStyle{Any} end
111 ArrayConflict(::Val) = ArrayConflict()
112
113 ### Binary BroadcastStyle rules
114 """
115 BroadcastStyle(::Style1, ::Style2) = Style3()
116
117 Indicate how to resolve different `BroadcastStyle`s. For example,
118
119 BroadcastStyle(::Primary, ::Secondary) = Primary()
120
121 would indicate that style `Primary` has precedence over `Secondary`.
122 You do not have to (and generally should not) define both argument orders.
123 The result does not have to be one of the input arguments, it could be a third type.
124
125 Please see the [Interfaces chapter](@ref man-interfaces-broadcasting) of the manual for
126 more information.
127 """
128 BroadcastStyle(::S, ::S) where S<:BroadcastStyle = S() # homogeneous types preserved
129 # Fall back to Unknown. This is necessary to implement argument-swapping
130 BroadcastStyle(::BroadcastStyle, ::BroadcastStyle) = Unknown()
131 # Unknown loses to everything
132 BroadcastStyle(::Unknown, ::Unknown) = Unknown()
133 BroadcastStyle(::S, ::Unknown) where S<:BroadcastStyle = S()
134 # Precedence rules
135 BroadcastStyle(a::AbstractArrayStyle{0}, b::Style{Tuple}) = b
136 BroadcastStyle(a::AbstractArrayStyle, ::Style{Tuple}) = a
137 BroadcastStyle(::A, ::A) where A<:ArrayStyle = A()
138 BroadcastStyle(::ArrayStyle, ::ArrayStyle) = Unknown()
139 BroadcastStyle(::A, ::A) where A<:AbstractArrayStyle = A()
140 function BroadcastStyle(a::A, b::B) where {A<:AbstractArrayStyle{M},B<:AbstractArrayStyle{N}} where {M,N}
141 if Base.typename(A) === Base.typename(B)
142 return A(Val(max(M, N)))
143 end
144 return Unknown()
145 end
146 # Any specific array type beats DefaultArrayStyle
147 BroadcastStyle(a::AbstractArrayStyle{Any}, ::DefaultArrayStyle) = a
148 BroadcastStyle(a::AbstractArrayStyle{N}, ::DefaultArrayStyle{N}) where N = a
149 BroadcastStyle(a::AbstractArrayStyle{M}, ::DefaultArrayStyle{N}) where {M,N} =
150 typeof(a)(Val(max(M, N)))
151
152 ### Lazy-wrapper for broadcasting
153
154 # `Broadcasted` wrap the arguments to `broadcast(f, args...)`. A statement like
155 # y = x .* (x .+ 1)
156 # will result in code that is essentially
157 # y = copy(Broadcasted(*, x, Broadcasted(+, x, 1)))
158 # `broadcast!` results in `copyto!(dest, Broadcasted(...))`.
159
160 # The use of `Nothing` in place of a `BroadcastStyle` has a different
161 # application, in the fallback method
162 # copyto!(dest, bc::Broadcasted) = copyto!(dest, convert(Broadcasted{Nothing}, bc))
163 # This allows methods
164 # copyto!(dest::DestType, bc::Broadcasted{Nothing})
165 # that specialize on `DestType` to be easily disambiguated from
166 # methods that instead specialize on `BroadcastStyle`,
167 # copyto!(dest::AbstractArray, bc::Broadcasted{MyStyle})
168
169 struct Broadcasted{Style<:Union{Nothing,BroadcastStyle}, Axes, F, Args<:Tuple} <: Base.AbstractBroadcasted
170 style::Style
171 f::F
172 args::Args
173 axes::Axes # the axes of the resulting object (may be bigger than implied by `args` if this is nested inside a larger `Broadcasted`)
174
175 Broadcasted(style::Union{Nothing,BroadcastStyle}, f::Tuple, args::Tuple) = error() # disambiguation: tuple is not callable
176 function Broadcasted(style::Union{Nothing,BroadcastStyle}, f::F, args::Tuple, axes=nothing) where {F}
177 # using Core.Typeof rather than F preserves inferrability when f is a type
178 return new{typeof(style), typeof(axes), Core.Typeof(f), typeof(args)}(style, f, args, axes)
179 end
180
181 function Broadcasted(f::F, args::Tuple, axes=nothing) where {F}
182 Broadcasted(combine_styles(args...)::BroadcastStyle, f, args, axes)
183 end
184
185 function Broadcasted{Style}(f::F, args, axes=nothing) where {Style, F}
186 return new{Style, typeof(axes), Core.Typeof(f), typeof(args)}(Style()::Style, f, args, axes)
187 end
188
189 function Broadcasted{Style,Axes,F,Args}(f, args, axes) where {Style,Axes,F,Args}
190 return new{Style, Axes, F, Args}(Style()::Style, f, args, axes)
191 end
192 end
193
194 struct AndAnd end
195 const andand = AndAnd()
196 broadcasted(::AndAnd, a, b) = broadcasted((a, b) -> a && b, a, b)
197 function broadcasted(::AndAnd, a, bc::Broadcasted)
198 bcf = flatten(bc)
199 broadcasted((a, args...) -> a && bcf.f(args...), a, bcf.args...)
200 end
201 struct OrOr end
202 const oror = OrOr()
203 broadcasted(::OrOr, a, b) = broadcasted((a, b) -> a || b, a, b)
204 function broadcasted(::OrOr, a, bc::Broadcasted)
205 bcf = flatten(bc)
206 broadcasted((a, args...) -> a || bcf.f(args...), a, bcf.args...)
207 end
208
209 Base.convert(::Type{Broadcasted{NewStyle}}, bc::Broadcasted{<:Any,Axes,F,Args}) where {NewStyle,Axes,F,Args} =
210 Broadcasted{NewStyle,Axes,F,Args}(bc.f, bc.args, bc.axes)::Broadcasted{NewStyle,Axes,F,Args}
211
212 function Base.show(io::IO, bc::Broadcasted{Style}) where {Style}
213 print(io, Broadcasted)
214 # Only show the style parameter if we have a set of axes — representing an instantiated
215 # "outermost" Broadcasted. The styles of nested Broadcasteds represent an intermediate
216 # computation that is not relevant for dispatch, confusing, and just extra line noise.
217 bc.axes isa Tuple && print(io, "{", Style, "}")
218 print(io, "(", bc.f, ", ", bc.args, ")")
219 nothing
220 end
221
222 ## Allocating the output container
223 Base.similar(bc::Broadcasted, ::Type{T}) where {T} = similar(bc, T, axes(bc))
224 Base.similar(::Broadcasted{DefaultArrayStyle{N}}, ::Type{ElType}, dims) where {N,ElType} =
225 similar(Array{ElType}, dims)
226 Base.similar(::Broadcasted{DefaultArrayStyle{N}}, ::Type{Bool}, dims) where N =
227 similar(BitArray, dims)
228 # In cases of conflict we fall back on Array
229 Base.similar(::Broadcasted{ArrayConflict}, ::Type{ElType}, dims) where ElType =
230 similar(Array{ElType}, dims)
231 Base.similar(::Broadcasted{ArrayConflict}, ::Type{Bool}, dims) =
232 similar(BitArray, dims)
233
234 @inline Base.axes(bc::Broadcasted) = _axes(bc, bc.axes)
235 _axes(::Broadcasted, axes::Tuple) = axes
236 @inline _axes(bc::Broadcasted, ::Nothing) = combine_axes(bc.args...)
237 _axes(bc::Broadcasted{<:AbstractArrayStyle{0}}, ::Nothing) = ()
238
239 @inline Base.axes(bc::Broadcasted{<:Any, <:NTuple{N}}, d::Integer) where N =
240 d <= N ? axes(bc)[d] : OneTo(1)
241
242 BroadcastStyle(::Type{<:Broadcasted{Style}}) where {Style} = Style()
243 BroadcastStyle(::Type{<:Broadcasted{S}}) where {S<:Union{Nothing,Unknown}} =
244 throw(ArgumentError("Broadcasted{Unknown} wrappers do not have a style assigned"))
245
246 argtype(::Type{BC}) where {BC<:Broadcasted} = fieldtype(BC, :args)
247 argtype(bc::Broadcasted) = argtype(typeof(bc))
248
249 @inline Base.eachindex(bc::Broadcasted) = _eachindex(axes(bc))
250 _eachindex(t::Tuple{Any}) = t[1]
251 _eachindex(t::Tuple) = CartesianIndices(t)
252
253 Base.IndexStyle(bc::Broadcasted) = IndexStyle(typeof(bc))
254 Base.IndexStyle(::Type{<:Broadcasted{<:Any,<:Tuple{Any}}}) = IndexLinear()
255 Base.IndexStyle(::Type{<:Broadcasted{<:Any}}) = IndexCartesian()
256
257 Base.LinearIndices(bc::Broadcasted{<:Any,<:Tuple{Any}}) = LinearIndices(axes(bc))::LinearIndices{1}
258
259 Base.ndims(bc::Broadcasted) = ndims(typeof(bc))
260 Base.ndims(::Type{<:Broadcasted{<:Any,<:NTuple{N,Any}}}) where {N} = N
261
262 Base.size(bc::Broadcasted) = map(length, axes(bc))
263 Base.length(bc::Broadcasted) = prod(size(bc))
264
265 function Base.iterate(bc::Broadcasted)
266 iter = eachindex(bc)
267 iterate(bc, (iter,))
268 end
269 Base.@propagate_inbounds function Base.iterate(bc::Broadcasted, s)
270 y = iterate(s...)
271 y === nothing && return nothing
272 i, newstate = y
273 return (bc[i], (s[1], newstate))
274 end
275
276 Base.IteratorSize(::Type{T}) where {T<:Broadcasted} = Base.HasShape{ndims(T)}()
277 Base.ndims(BC::Type{<:Broadcasted{<:Any,Nothing}}) = _maxndims(fieldtype(BC, :args))
278 Base.ndims(::Type{<:Broadcasted{<:AbstractArrayStyle{N},Nothing}}) where {N<:Integer} = N
279
280 _maxndims(T::Type{<:Tuple}) = reduce(max, (ntuple(n -> _ndims(fieldtype(T, n)), Base._counttuple(T))))
281 _maxndims(::Type{<:Tuple{T}}) where {T} = ndims(T)
282 _maxndims(::Type{<:Tuple{T}}) where {T<:Tuple} = _ndims(T)
283 function _maxndims(::Type{<:Tuple{T, S}}) where {T, S}
284 return T<:Tuple || S<:Tuple ? max(_ndims(T), _ndims(S)) : max(ndims(T), ndims(S))
285 end
286
287 _ndims(x) = ndims(x)
288 _ndims(::Type{<:Tuple}) = 1
289
290 Base.IteratorEltype(::Type{<:Broadcasted}) = Base.EltypeUnknown()
291
292 ## Instantiation fills in the "missing" fields in Broadcasted.
293 instantiate(x) = x
294
295 """
296 Broadcast.instantiate(bc::Broadcasted)
297
298 Construct and check the axes for the lazy Broadcasted object `bc`.
299
300 Custom [`BroadcastStyle`](@ref)s may override this default in cases where it is fast and easy
301 to compute and verify the resulting `axes` on-demand, leaving the `axis` field
302 of the `Broadcasted` object empty (populated with [`nothing`](@ref)).
303 """
304 @inline function instantiate(bc::Broadcasted)
305 if bc.axes isa Nothing # Not done via dispatch to make it easier to extend instantiate(::Broadcasted{Style})
306 axes = combine_axes(bc.args...)
307 else
308 axes = bc.axes
309 check_broadcast_axes(axes, bc.args...)
310 end
311 return Broadcasted(bc.style, bc.f, bc.args, axes)
312 end
313 instantiate(bc::Broadcasted{<:AbstractArrayStyle{0}}) = bc
314 # Tuples don't need axes, but when they have axes (for .= assignment), we need to check them (#33020)
315 instantiate(bc::Broadcasted{Style{Tuple}, Nothing}) = bc
316 function instantiate(bc::Broadcasted{Style{Tuple}})
317 check_broadcast_axes(bc.axes, bc.args...)
318 return bc
319 end
320 ## Flattening
321
322 """
323 bcf = flatten(bc)
324
325 Create a "flat" representation of a lazy-broadcast operation.
326 From
327 f.(a, g.(b, c), d)
328 we produce the equivalent of
329 h.(a, b, c, d)
330 where
331 h(w, x, y, z) = f(w, g(x, y), z)
332 In terms of its internal representation,
333 Broadcasted(f, a, Broadcasted(g, b, c), d)
334 becomes
335 Broadcasted(h, a, b, c, d)
336
337 This is an optional operation that may make custom implementation of broadcasting easier in
338 some cases.
339 """
340 function flatten(bc::Broadcasted)
341 isflat(bc) && return bc
342 # concatenate the nested arguments into {a, b, c, d}
343 args = cat_nested(bc)
344 # build a function `makeargs` that takes a "flat" argument list and
345 # and creates the appropriate input arguments for `f`, e.g.,
346 # makeargs = (w, x, y, z) -> (w, g(x, y), z)
347 #
348 # `makeargs` is built recursively and looks a bit like this:
349 # makeargs(w, x, y, z) = (w, makeargs1(x, y, z)...)
350 # = (w, g(x, y), makeargs2(z)...)
351 # = (w, g(x, y), z)
352 let makeargs = make_makeargs(()->(), bc.args), f = bc.f
353 newf = @inline function(args::Vararg{Any,N}) where N
354 f(makeargs(args...)...)
355 end
356 return Broadcasted(bc.style, newf, args, bc.axes)
357 end
358 end
359
360 const NestedTuple = Tuple{<:Broadcasted,Vararg{Any}}
361 isflat(bc::Broadcasted) = _isflat(bc.args)
362 _isflat(args::NestedTuple) = false
363 _isflat(args::Tuple) = _isflat(tail(args))
364 _isflat(args::Tuple{}) = true
365
366 cat_nested(t::Broadcasted, rest...) = (cat_nested(t.args...)..., cat_nested(rest...)...)
367 cat_nested(t::Any, rest...) = (t, cat_nested(rest...)...)
368 cat_nested() = ()
369
370 """
371 make_makeargs(makeargs_tail::Function, t::Tuple) -> Function
372
373 Each element of `t` is one (consecutive) node in a broadcast tree.
374 Ignoring `makeargs_tail` for the moment, the job of `make_makeargs` is
375 to return a function that takes in flattened argument list and returns a
376 tuple (each entry corresponding to an entry in `t`, having evaluated
377 the corresponding element in the broadcast tree). As an additional
378 complication, the passed in tuple may be longer than the number of leaves
379 in the subtree described by `t`. The `makeargs_tail` function should
380 be called on such additional arguments (but not the arguments consumed
381 by `t`).
382 """
383 @inline make_makeargs(makeargs_tail, t::Tuple{}) = makeargs_tail
384 @inline function make_makeargs(makeargs_tail, t::Tuple)
385 makeargs = make_makeargs(makeargs_tail, tail(t))
386 (head, tail...)->(head, makeargs(tail...)...)
387 end
388 function make_makeargs(makeargs_tail, t::Tuple{<:Broadcasted, Vararg{Any}})
389 bc = t[1]
390 # c.f. the same expression in the function on leaf nodes above. Here
391 # we recurse into siblings in the broadcast tree.
392 let makeargs_tail = make_makeargs(makeargs_tail, tail(t)),
393 # Here we recurse into children. It would be valid to pass in makeargs_tail
394 # here, and not use it below. However, in that case, our recursion is no
395 # longer purely structural because we're building up one argument (the closure)
396 # while destructuing another.
397 makeargs_head = make_makeargs((args...)->args, bc.args),
398 f = bc.f
399 # Create two functions, one that splits of the first length(bc.args)
400 # elements from the tuple and one that yields the remaining arguments.
401 # N.B. We can't call headargs on `args...` directly because
402 # args is flattened (i.e. our children have not been evaluated
403 # yet).
404 headargs, tailargs = make_headargs(bc.args), make_tailargs(bc.args)
405 return @inline function(args::Vararg{Any,N}) where N
406 args1 = makeargs_head(args...)
407 a, b = headargs(args1...), makeargs_tail(tailargs(args1...)...)
408 (f(a...), b...)
409 end
410 end
411 end
412
413 @inline function make_headargs(t::Tuple)
414 let headargs = make_headargs(tail(t))
415 return @inline function(head, tail::Vararg{Any,N}) where N
416 (head, headargs(tail...)...)
417 end
418 end
419 end
420 @inline function make_headargs(::Tuple{})
421 return @inline function(tail::Vararg{Any,N}) where N
422 ()
423 end
424 end
425
426 @inline function make_tailargs(t::Tuple)
427 let tailargs = make_tailargs(tail(t))
428 return @inline function(head, tail::Vararg{Any,N}) where N
429 tailargs(tail...)
430 end
431 end
432 end
433 @inline function make_tailargs(::Tuple{})
434 return @inline function(tail::Vararg{Any,N}) where N
435 tail
436 end
437 end
438
439 ## Broadcasting utilities ##
440
441 ## logic for deciding the BroadcastStyle
442
443 """
444 combine_styles(cs...) -> BroadcastStyle
445
446 Decides which `BroadcastStyle` to use for any number of value arguments.
447 Uses [`BroadcastStyle`](@ref) to get the style for each argument, and uses
448 [`result_style`](@ref) to combine styles.
449
450 # Examples
451
452 ```jldoctest
453 julia> Broadcast.combine_styles([1], [1 2; 3 4])
454 Base.Broadcast.DefaultArrayStyle{2}()
455 ```
456 """
457 function combine_styles end
458
459 combine_styles() = DefaultArrayStyle{0}()
460 combine_styles(c) = result_style(BroadcastStyle(typeof(c)))
461 combine_styles(c1, c2) = result_style(combine_styles(c1), combine_styles(c2))
462 @inline combine_styles(c1, c2, cs...) = result_style(combine_styles(c1), combine_styles(c2, cs...))
463
464 """
465 result_style(s1::BroadcastStyle[, s2::BroadcastStyle]) -> BroadcastStyle
466
467 Takes one or two `BroadcastStyle`s and combines them using [`BroadcastStyle`](@ref) to
468 determine a common `BroadcastStyle`.
469
470 # Examples
471
472 ```jldoctest
473 julia> Broadcast.result_style(Broadcast.DefaultArrayStyle{0}(), Broadcast.DefaultArrayStyle{3}())
474 Base.Broadcast.DefaultArrayStyle{3}()
475
476 julia> Broadcast.result_style(Broadcast.Unknown(), Broadcast.DefaultArrayStyle{1}())
477 Base.Broadcast.DefaultArrayStyle{1}()
478 ```
479 """
480 function result_style end
481
482 result_style(s::BroadcastStyle) = s
483 result_style(s1::S, s2::S) where S<:BroadcastStyle = S()
484 # Test both orders so users typically only have to declare one order
485 result_style(s1, s2) = result_join(s1, s2, BroadcastStyle(s1, s2), BroadcastStyle(s2, s1))
486
487 # result_join is the final arbiter. Because `BroadcastStyle` for undeclared pairs results in Unknown,
488 # we defer to any case where the result of `BroadcastStyle` is known.
489 result_join(::Any, ::Any, ::Unknown, ::Unknown) = Unknown()
490 result_join(::Any, ::Any, ::Unknown, s::BroadcastStyle) = s
491 result_join(::Any, ::Any, s::BroadcastStyle, ::Unknown) = s
492 # For AbstractArray types with specialized broadcasting and undefined precedence rules,
493 # we have to signal conflict. Because ArrayConflict is a subtype of AbstractArray,
494 # this will "poison" any future operations (if we instead returned `DefaultArrayStyle`, then for
495 # 3-array broadcasting the returned type would depend on argument order).
496 result_join(::AbstractArrayStyle, ::AbstractArrayStyle, ::Unknown, ::Unknown) =
497 ArrayConflict()
498 # Fallbacks in case users define `rule` for both argument-orders (not recommended)
499 result_join(::Any, ::Any, ::S, ::S) where S<:BroadcastStyle = S()
500 @noinline function result_join(::S, ::T, ::U, ::V) where {S,T,U,V}
501 error("""
502 conflicting broadcast rules defined
503 Broadcast.BroadcastStyle(::$S, ::$T) = $U()
504 Broadcast.BroadcastStyle(::$T, ::$S) = $V()
505 One of these should be undefined (and thus return Broadcast.Unknown).""")
506 end
507
508 # Indices utilities
509
510 """
511 combine_axes(As...) -> Tuple
512
513 Determine the result axes for broadcasting across all values in `As`.
514
515 ```jldoctest
516 julia> Broadcast.combine_axes([1], [1 2; 3 4; 5 6])
517 (Base.OneTo(3), Base.OneTo(2))
518
519 julia> Broadcast.combine_axes(1, 1, 1)
520 ()
521 ```
522 """
523 @inline combine_axes(A, B...) = broadcast_shape(axes(A), combine_axes(B...))
524 @inline combine_axes(A, B) = broadcast_shape(axes(A), axes(B))
525 combine_axes(A) = axes(A)
526
527 """
528 broadcast_shape(As...) -> Tuple
529
530 Determine the result axes for broadcasting across all axes (size Tuples) in `As`.
531
532 ```jldoctest
533 julia> Broadcast.broadcast_shape((1,2), (2,1))
534 (2, 2)
535
536 julia> Broadcast.broadcast_shape((1,), (1,5), (4,5,3))
537 (4, 5, 3)
538 ```
539 """
540 function broadcast_shape end
541 # shape (i.e., tuple-of-indices) inputs
542 broadcast_shape(shape::Tuple) = shape
543 broadcast_shape(shape::Tuple, shape1::Tuple, shapes::Tuple...) = broadcast_shape(_bcs(shape, shape1), shapes...)
544 # _bcs consolidates two shapes into a single output shape
545 _bcs(::Tuple{}, ::Tuple{}) = ()
546 _bcs(::Tuple{}, newshape::Tuple) = (newshape[1], _bcs((), tail(newshape))...)
547 _bcs(shape::Tuple, ::Tuple{}) = (shape[1], _bcs(tail(shape), ())...)
548 function _bcs(shape::Tuple, newshape::Tuple)
549 return (_bcs1(shape[1], newshape[1]), _bcs(tail(shape), tail(newshape))...)
550 end
551 # _bcs1 handles the logic for a single dimension
552 _bcs1(a::Integer, b::Integer) = a == 1 ? b : (b == 1 ? a : (a == b ? a : throw(DimensionMismatch("arrays could not be broadcast to a common size; got a dimension with lengths $a and $b"))))
553 _bcs1(a::Integer, b) = a == 1 ? b : (first(b) == 1 && last(b) == a ? b : throw(DimensionMismatch("arrays could not be broadcast to a common size; got a dimension with lengths $a and $(length(b))")))
554 _bcs1(a, b::Integer) = _bcs1(b, a)
555 _bcs1(a, b) = _bcsm(b, a) ? axistype(b, a) : (_bcsm(a, b) ? axistype(a, b) : throw(DimensionMismatch("arrays could not be broadcast to a common size; got a dimension with lengths $(length(a)) and $(length(b))")))
556 # _bcsm tests whether the second index is consistent with the first
557 _bcsm(a, b) = a == b || length(b) == 1
558 _bcsm(a, b::Number) = b == 1
559 _bcsm(a::Number, b::Number) = a == b || b == 1
560 # Ensure inferrability when dealing with axes of different AbstractUnitRange types
561 # (We may not want to define general promotion rules between, say, OneTo and Slice, but if
562 # we get here we know the axes are at least consistent for the purposes of broadcasting)
563 axistype(a::T, b::T) where T = a
564 axistype(a::OneTo, b::OneTo) = OneTo{Int}(a)
565 axistype(a, b) = UnitRange{Int}(a)
566
567 ## Check that all arguments are broadcast compatible with shape
568 # comparing one input against a shape
569 check_broadcast_shape(shp) = nothing
570 check_broadcast_shape(shp, ::Tuple{}) = nothing
571 check_broadcast_shape(::Tuple{}, ::Tuple{}) = nothing
572 function check_broadcast_shape(::Tuple{}, Ashp::Tuple)
573 if any(ax -> length(ax) != 1, Ashp)
574 throw(DimensionMismatch("cannot broadcast array to have fewer non-singleton dimensions"))
575 end
576 nothing
577 end
578 function check_broadcast_shape(shp, Ashp::Tuple)
579 _bcsm(shp[1], Ashp[1]) || throw(DimensionMismatch("array could not be broadcast to match destination"))
580 check_broadcast_shape(tail(shp), tail(Ashp))
581 end
582 @inline check_broadcast_axes(shp, A) = check_broadcast_shape(shp, axes(A))
583 # comparing many inputs
584 @inline function check_broadcast_axes(shp, A, As...)
585 check_broadcast_axes(shp, A)
586 check_broadcast_axes(shp, As...)
587 end
588
589 ## Indexing manipulations
590 """
591 newindex(argument, I)
592 newindex(I, keep, default)
593
594 Recompute index `I` such that it appropriately constrains broadcasted dimensions to the source.
595
596 Two methods are supported, both allowing for `I` to be specified as either a [`CartesianIndex`](@ref) or
597 an `Int`.
598
599 * `newindex(argument, I)` dynamically constrains `I` based upon the axes of `argument`.
600 * `newindex(I, keep, default)` constrains `I` using the pre-computed tuples `keeps` and `defaults`.
601 * `keep` is a tuple of `Bool`s, where `keep[d] == true` means that dimension `d` in `I` should be preserved as is
602 * `default` is a tuple of Integers, specifying what index to use in dimension `d` when `keep[d] == false`.
603 Any remaining indices in `I` beyond the length of the `keep` tuple are truncated. The `keep` and `default`
604 tuples may be created by `newindexer(argument)`.
605 """
606 Base.@propagate_inbounds newindex(arg, I::CartesianIndex) = CartesianIndex(_newindex(axes(arg), I.I))
607 Base.@propagate_inbounds newindex(arg, I::Integer) = CartesianIndex(_newindex(axes(arg), (I,)))
608 Base.@propagate_inbounds _newindex(ax::Tuple, I::Tuple) = (ifelse(length(ax[1]) == 1, ax[1][1], I[1]), _newindex(tail(ax), tail(I))...)
609 Base.@propagate_inbounds _newindex(ax::Tuple{}, I::Tuple) = ()
610 Base.@propagate_inbounds _newindex(ax::Tuple, I::Tuple{}) = (ax[1][1], _newindex(tail(ax), ())...)
611 Base.@propagate_inbounds _newindex(ax::Tuple{}, I::Tuple{}) = ()
612
613 # If dot-broadcasting were already defined, this would be `ifelse.(keep, I, Idefault)`.
614 @inline newindex(I::CartesianIndex, keep, Idefault) = CartesianIndex(_newindex(I.I, keep, Idefault))
615 @inline newindex(i::Integer, keep::Tuple, idefault) = ifelse(keep[1], i, idefault[1])
616 @inline newindex(i::Integer, keep::Tuple{}, idefault) = CartesianIndex(())
617 @inline _newindex(I, keep, Idefault) =
618 (ifelse(keep[1], I[1], Idefault[1]), _newindex(tail(I), tail(keep), tail(Idefault))...)
619 @inline _newindex(I, keep::Tuple{}, Idefault) = () # truncate if keep is shorter than I
620 @inline _newindex(I::Tuple{}, keep, Idefault) = () # or I is shorter
621 @inline _newindex(I::Tuple{}, keep::Tuple{}, Idefault) = () # or both
622
623 # newindexer(A) generates `keep` and `Idefault` (for use by `newindex` above)
624 # for a particular array `A`; `shapeindexer` does so for its axes.
625 @inline newindexer(A) = shapeindexer(axes(A))
626 @inline shapeindexer(ax) = _newindexer(ax)
627 @inline _newindexer(indsA::Tuple{}) = (), ()
628 @inline function _newindexer(indsA::Tuple)
629 ind1 = indsA[1]
630 keep, Idefault = _newindexer(tail(indsA))
631 (Base.length(ind1)::Integer != 1, keep...), (first(ind1), Idefault...)
632 end
633
634 @inline function Base.getindex(bc::Broadcasted, I::Union{Integer,CartesianIndex})
635 @boundscheck checkbounds(bc, I)
636 24 (8 %)
24 (8 %) samples spent in getindex
24 (100 %) (incl.) when called from macro expansion line 1004
24 (100 %) samples spent calling _broadcast_getindex
@inbounds _broadcast_getindex(bc, I)
637 end
638 Base.@propagate_inbounds Base.getindex(
639 bc::Broadcasted,
640 i1::Union{Integer,CartesianIndex},
641 i2::Union{Integer,CartesianIndex},
642 I::Union{Integer,CartesianIndex}...,
643 ) =
644 bc[CartesianIndex((i1, i2, I...))]
645 Base.@propagate_inbounds Base.getindex(bc::Broadcasted) = bc[CartesianIndex(())]
646
647 @inline Base.checkbounds(bc::Broadcasted, I::Union{Integer,CartesianIndex}) =
648 Base.checkbounds_indices(Bool, axes(bc), (I,)) || Base.throw_boundserror(bc, (I,))
649
650
651 """
652 _broadcast_getindex(A, I)
653
654 Index into `A` with `I`, collapsing broadcasted indices to their singleton indices as appropriate.
655 """
656 Base.@propagate_inbounds _broadcast_getindex(A::Union{Ref,AbstractArray{<:Any,0},Number}, I) = A[] # Scalar-likes can just ignore all indices
657 Base.@propagate_inbounds _broadcast_getindex(::Ref{Type{T}}, I) where {T} = T
658 # Tuples are statically known to be singleton or vector-like
659 Base.@propagate_inbounds _broadcast_getindex(A::Tuple{Any}, I) = A[1]
660 Base.@propagate_inbounds _broadcast_getindex(A::Tuple, I) = A[I[1]]
661 # Everything else falls back to dynamically dropping broadcasted indices based upon its axes
662 Base.@propagate_inbounds _broadcast_getindex(A, I) = A[newindex(A, I)]
663
664 # In some cases, it's more efficient to sort out which dimensions should be dropped
665 # ahead of time (often when the size checks aren't able to be lifted out of the loop).
666 # The Extruded struct computes that information ahead of time and stores it as a pair
667 # of tuples to optimize indexing later. This is most commonly needed for `Array` and
668 # other `AbstractArray` subtypes that wrap `Array` and dynamically ask it for its size.
669 struct Extruded{T, K, D}
670 x::T
671 keeps::K # A tuple of booleans, specifying which indices should be passed normally
672 defaults::D # A tuple of integers, specifying the index to use when keeps[i] is false (as defaults[i])
673 end
674 @inline axes(b::Extruded) = axes(b.x)
675 24 (8 %)
24 (8 %) samples spent in _broadcast_getindex
24 (100 %) (incl.) when called from _getindex line 705
24 (100 %) samples spent calling getindex
Base.@propagate_inbounds _broadcast_getindex(b::Extruded, i) = b.x[newindex(i, b.keeps, b.defaults)]
676 extrude(x::AbstractArray) = Extruded(x, newindexer(x)...)
677 extrude(x) = x
678
679 # For Broadcasted
680 Base.@propagate_inbounds function _broadcast_getindex(bc::Broadcasted{<:Any,<:Any,<:Any,<:Any}, I)
681 24 (8 %)
24 (8 %) samples spent in _broadcast_getindex
24 (100 %) (incl.) when called from getindex line 636
24 (100 %) samples spent calling _getindex
args = _getindex(bc.args, I)
682 return _broadcast_getindex_evalf(bc.f, args...)
683 end
684 # Hack around losing Type{T} information in the final args tuple. Julia actually
685 # knows (in `code_typed`) the _value_ of these types, statically displaying them,
686 # but inference is currently skipping inferring the type of the types as they are
687 # transiently placed in a tuple as the argument list is lispily constructed. These
688 # additional methods recover type stability when a `Type` appears in one of the
689 # first two arguments of a function.
690 Base.@propagate_inbounds function _broadcast_getindex(bc::Broadcasted{<:Any,<:Any,<:Any,<:Tuple{Ref{Type{T}},Vararg{Any}}}, I) where {T}
691 args = _getindex(tail(bc.args), I)
692 return _broadcast_getindex_evalf(bc.f, T, args...)
693 end
694 Base.@propagate_inbounds function _broadcast_getindex(bc::Broadcasted{<:Any,<:Any,<:Any,<:Tuple{Any,Ref{Type{T}},Vararg{Any}}}, I) where {T}
695 arg1 = _broadcast_getindex(bc.args[1], I)
696 args = _getindex(tail(tail(bc.args)), I)
697 return _broadcast_getindex_evalf(bc.f, arg1, T, args...)
698 end
699 Base.@propagate_inbounds function _broadcast_getindex(bc::Broadcasted{<:Any,<:Any,<:Any,<:Tuple{Ref{Type{T}},Ref{Type{S}},Vararg{Any}}}, I) where {T,S}
700 args = _getindex(tail(tail(bc.args)), I)
701 return _broadcast_getindex_evalf(bc.f, T, S, args...)
702 end
703
704 # Utilities for _broadcast_getindex
705 24 (8 %)
24 (8 %) samples spent in _getindex
24 (100 %) (incl.) when called from _broadcast_getindex line 681
24 (100 %) samples spent calling _broadcast_getindex
Base.@propagate_inbounds _getindex(args::Tuple, I) = (_broadcast_getindex(args[1], I), _getindex(tail(args), I)...)
706 Base.@propagate_inbounds _getindex(args::Tuple{Any}, I) = (_broadcast_getindex(args[1], I),)
707 Base.@propagate_inbounds _getindex(args::Tuple{}, I) = ()
708
709 @inline _broadcast_getindex_evalf(f::Tf, args::Vararg{Any,N}) where {Tf,N} = f(args...) # not propagate_inbounds
710
711 """
712 Broadcast.broadcastable(x)
713
714 Return either `x` or an object like `x` such that it supports [`axes`](@ref), indexing, and its type supports [`ndims`](@ref).
715
716 If `x` supports iteration, the returned value should have the same `axes` and indexing
717 behaviors as [`collect(x)`](@ref).
718
719 If `x` is not an `AbstractArray` but it supports `axes`, indexing, and its type supports
720 `ndims`, then `broadcastable(::typeof(x))` may be implemented to just return itself.
721 Further, if `x` defines its own [`BroadcastStyle`](@ref), then it must define its
722 `broadcastable` method to return itself for the custom style to have any effect.
723
724 # Examples
725 ```jldoctest
726 julia> Broadcast.broadcastable([1,2,3]) # like `identity` since arrays already support axes and indexing
727 3-element Vector{Int64}:
728 1
729 2
730 3
731
732 julia> Broadcast.broadcastable(Int) # Types don't support axes, indexing, or iteration but are commonly used as scalars
733 Base.RefValue{Type{Int64}}(Int64)
734
735 julia> Broadcast.broadcastable("hello") # Strings break convention of matching iteration and act like a scalar instead
736 Base.RefValue{String}("hello")
737 ```
738 """
739 broadcastable(x::Union{Symbol,AbstractString,Function,UndefInitializer,Nothing,RoundingMode,Missing,Val,Ptr,AbstractPattern,Pair,IO,CartesianIndex}) = Ref(x)
740 broadcastable(::Type{T}) where {T} = Ref{Type{T}}(T)
741 broadcastable(x::Union{AbstractArray,Number,AbstractChar,Ref,Tuple,Broadcasted}) = x
742 # Default to collecting iterables — which will error for non-iterables
743 broadcastable(x) = collect(x)
744 broadcastable(::Union{AbstractDict, NamedTuple}) = throw(ArgumentError("broadcasting over dictionaries and `NamedTuple`s is reserved"))
745
746 ## Computation of inferred result type, for empty and concretely inferred cases only
747 _broadcast_getindex_eltype(bc::Broadcasted) = combine_eltypes(bc.f, bc.args)
748 _broadcast_getindex_eltype(A) = eltype(A) # Tuple, Array, etc.
749
750 eltypes(::Tuple{}) = Tuple{}
751 eltypes(t::Tuple{Any}) = Iterators.TupleOrBottom(_broadcast_getindex_eltype(t[1]))
752 eltypes(t::Tuple{Any,Any}) = Iterators.TupleOrBottom(_broadcast_getindex_eltype(t[1]), _broadcast_getindex_eltype(t[2]))
753 eltypes(t::Tuple) = (TT = eltypes(tail(t)); TT === Union{} ? Union{} : Iterators.TupleOrBottom(_broadcast_getindex_eltype(t[1]), TT.parameters...))
754 # eltypes(t::Tuple) = Iterators.TupleOrBottom(ntuple(i -> _broadcast_getindex_eltype(t[i]), Val(length(t)))...)
755
756 # Inferred eltype of result of broadcast(f, args...)
757 function combine_eltypes(f, args::Tuple)
758 argT = eltypes(args)
759 argT === Union{} && return Union{}
760 return promote_typejoin_union(Base._return_type(f, argT))
761 end
762
763 ## Broadcasting core
764
765 """
766 broadcast(f, As...)
767
768 Broadcast the function `f` over the arrays, tuples, collections, [`Ref`](@ref)s and/or scalars `As`.
769
770 Broadcasting applies the function `f` over the elements of the container arguments and the
771 scalars themselves in `As`. Singleton and missing dimensions are expanded to match the
772 extents of the other arguments by virtually repeating the value. By default, only a limited
773 number of types are considered scalars, including `Number`s, `String`s, `Symbol`s, `Type`s,
774 `Function`s and some common singletons like [`missing`](@ref) and [`nothing`](@ref). All other arguments are
775 iterated over or indexed into elementwise.
776
777 The resulting container type is established by the following rules:
778
779 - If all the arguments are scalars or zero-dimensional arrays, it returns an unwrapped scalar.
780 - If at least one argument is a tuple and all others are scalars or zero-dimensional arrays,
781 it returns a tuple.
782 - All other combinations of arguments default to returning an `Array`, but
783 custom container types can define their own implementation and promotion-like
784 rules to customize the result when they appear as arguments.
785
786 A special syntax exists for broadcasting: `f.(args...)` is equivalent to
787 `broadcast(f, args...)`, and nested `f.(g.(args...))` calls are fused into a
788 single broadcast loop.
789
790 # Examples
791 ```jldoctest
792 julia> A = [1, 2, 3, 4, 5]
793 5-element Vector{Int64}:
794 1
795 2
796 3
797 4
798 5
799
800 julia> B = [1 2; 3 4; 5 6; 7 8; 9 10]
801 5×2 Matrix{Int64}:
802 1 2
803 3 4
804 5 6
805 7 8
806 9 10
807
808 julia> broadcast(+, A, B)
809 5×2 Matrix{Int64}:
810 2 3
811 5 6
812 8 9
813 11 12
814 14 15
815
816 julia> parse.(Int, ["1", "2"])
817 2-element Vector{Int64}:
818 1
819 2
820
821 julia> abs.((1, -2))
822 (1, 2)
823
824 julia> broadcast(+, 1.0, (0, -2.0))
825 (1.0, -1.0)
826
827 julia> (+).([[0,2], [1,3]], Ref{Vector{Int}}([1,-1]))
828 2-element Vector{Vector{Int64}}:
829 [1, 1]
830 [2, 2]
831
832 julia> string.(("one","two","three","four"), ": ", 1:4)
833 4-element Vector{String}:
834 "one: 1"
835 "two: 2"
836 "three: 3"
837 "four: 4"
838
839 ```
840 """
841 broadcast(f::Tf, As...) where {Tf} = materialize(broadcasted(f, As...))
842
843 # special cases defined for performance
844 @inline broadcast(f, x::Number...) = f(x...)
845 @inline broadcast(f, t::NTuple{N,Any}, ts::Vararg{NTuple{N,Any}}) where {N} = map(f, t, ts...)
846
847 """
848 broadcast!(f, dest, As...)
849
850 Like [`broadcast`](@ref), but store the result of
851 `broadcast(f, As...)` in the `dest` array.
852 Note that `dest` is only used to store the result, and does not supply
853 arguments to `f` unless it is also listed in the `As`,
854 as in `broadcast!(f, A, A, B)` to perform `A[:] = broadcast(f, A, B)`.
855
856 # Examples
857 ```jldoctest
858 julia> A = [1.0; 0.0]; B = [0.0; 0.0];
859
860 julia> broadcast!(+, B, A, (0, -2.0));
861
862 julia> B
863 2-element Vector{Float64}:
864 1.0
865 -2.0
866
867 julia> A
868 2-element Vector{Float64}:
869 1.0
870 0.0
871
872 julia> broadcast!(+, A, A, (0, -2.0));
873
874 julia> A
875 2-element Vector{Float64}:
876 1.0
877 -2.0
878 ```
879 """
880 broadcast!(f::Tf, dest, As::Vararg{Any,N}) where {Tf,N} = (materialize!(dest, broadcasted(f, As...)); dest)
881
882 """
883 broadcast_preserving_zero_d(f, As...)
884
885 Like [`broadcast`](@ref), except in the case of a 0-dimensional result where it returns a 0-dimensional container
886
887 Broadcast automatically unwraps zero-dimensional results to be just the element itself,
888 but in some cases it is necessary to always return a container — even in the 0-dimensional case.
889 """
890 @inline function broadcast_preserving_zero_d(f, As...)
891 bc = broadcasted(f, As...)
892 r = materialize(bc)
893 return length(axes(bc)) == 0 ? fill!(similar(bc, typeof(r)), r) : r
894 end
895 @inline broadcast_preserving_zero_d(f) = fill(f())
896 @inline broadcast_preserving_zero_d(f, as::Number...) = fill(f(as...))
897
898 """
899 Broadcast.materialize(bc)
900
901 Take a lazy `Broadcasted` object and compute the result
902 """
903 @inline materialize(bc::Broadcasted) = copy(instantiate(bc))
904 materialize(x) = x
905
906 @inline function materialize!(dest, x)
907 return materialize!(dest, instantiate(Broadcasted(identity, (x,), axes(dest))))
908 end
909
910 @inline function materialize!(dest, bc::Broadcasted{<:Any})
911 70 (24 %)
70 (24 %) samples spent in materialize!
69 (99 %) (incl.) when called from extract_jacobian_chunk! line 112
1 (1 %) (incl.) when called from seed! line 45
70 (100 %) samples spent calling materialize!
return materialize!(combine_styles(dest, bc), dest, bc)
912 end
913 @inline function materialize!(::BroadcastStyle, dest, bc::Broadcasted{<:Any})
914 70 (24 %)
70 (24 %) samples spent in materialize!
70 (100 %) (incl.) when called from materialize! line 911
70 (100 %) samples spent calling copyto!
return copyto!(dest, instantiate(Broadcasted(bc.style, bc.f, bc.args, axes(dest))))
915 end
916
917 ## general `copy` methods
918 @inline copy(bc::Broadcasted{<:AbstractArrayStyle{0}}) = bc[CartesianIndex()]
919 copy(bc::Broadcasted{<:Union{Nothing,Unknown}}) =
920 throw(ArgumentError("broadcasting requires an assigned BroadcastStyle"))
921
922 const NonleafHandlingStyles = Union{DefaultArrayStyle,ArrayConflict}
923
924 @inline function copy(bc::Broadcasted)
925 ElType = combine_eltypes(bc.f, bc.args)
926 if Base.isconcretetype(ElType)
927 # We can trust it and defer to the simpler `copyto!`
928 return copyto!(similar(bc, ElType), bc)
929 end
930 # When ElType is not concrete, use narrowing. Use the first output
931 # value to determine the starting output eltype; copyto_nonleaf!
932 # will widen `dest` as needed to accommodate later values.
933 bc′ = preprocess(nothing, bc)
934 iter = eachindex(bc′)
935 y = iterate(iter)
936 if y === nothing
937 # if empty, take the ElType at face value
938 return similar(bc′, ElType)
939 end
940 # Initialize using the first value
941 I, state = y
942 @inbounds val = bc′[I]
943 dest = similar(bc′, typeof(val))
944 @inbounds dest[I] = val
945 # Now handle the remaining values
946 # The typeassert gives inference a helping hand on the element type and dimensionality
947 # (work-around for #28382)
948 ElType′ = ElType === Union{} ? Any : ElType <: Type ? Type : ElType
949 RT = dest isa AbstractArray ? AbstractArray{<:ElType′, ndims(dest)} : Any
950 return copyto_nonleaf!(dest, bc′, iter, state, 1)::RT
951 end
952
953 ## general `copyto!` methods
954 # The most general method falls back to a method that replaces Style->Nothing
955 # This permits specialization on typeof(dest) without introducing ambiguities
956 70 (24 %)
70 (24 %) samples spent in copyto!
70 (100 %) (incl.) when called from materialize! line 914
70 (100 %) samples spent calling copyto!
@inline copyto!(dest::AbstractArray, bc::Broadcasted) = copyto!(dest, convert(Broadcasted{Nothing}, bc))
957
958 # Performance optimization for the common identity scalar case: dest .= val
959 @inline function copyto!(dest::AbstractArray, bc::Broadcasted{<:AbstractArrayStyle{0}})
960 # Typically, we must independently execute bc for every storage location in `dest`, but:
961 # IF we're in the common no-op identity case with no nested args (like `dest .= val`),
962 if bc.f === identity && bc.args isa Tuple{Any} && isflat(bc)
963 # THEN we can just extract the argument and `fill!` the destination with it
964 return fill!(dest, bc.args[1][])
965 else
966 # Otherwise, fall back to the default implementation like above
967 return copyto!(dest, convert(Broadcasted{Nothing}, bc))
968 end
969 end
970
971 # For broadcasted assignments like `broadcast!(f, A, ..., A, ...)`, where `A`
972 # appears on both the LHS and the RHS of the `.=`, then we know we're only
973 # going to make one pass through the array, and even though `A` is aliasing
974 # against itself, the mutations won't affect the result as the indices on the
975 # LHS and RHS will always match. This is not true in general, but with the `.op=`
976 # syntax it's fairly common for an argument to be `===` a source.
977 broadcast_unalias(dest, src) = dest === src ? src : unalias(dest, src)
978 broadcast_unalias(::Nothing, src) = src
979
980 # Preprocessing a `Broadcasted` does two things:
981 # * unaliases any arguments from `dest`
982 # * "extrudes" the arguments where it is advantageous to pre-compute the broadcasted indices
983 @inline preprocess(dest, bc::Broadcasted) = Broadcasted(bc.style, bc.f, preprocess_args(dest, bc.args), bc.axes)
984 preprocess(dest, x) = extrude(broadcast_unalias(dest, x))
985
986 @inline preprocess_args(dest, args::Tuple) = (preprocess(dest, args[1]), preprocess_args(dest, tail(args))...)
987 @inline preprocess_args(dest, args::Tuple{Any}) = (preprocess(dest, args[1]),)
988 @inline preprocess_args(dest, args::Tuple{}) = ()
989
990 # Specialize this method if all you want to do is specialize on typeof(dest)
991 @inline function copyto!(dest::AbstractArray, bc::Broadcasted{Nothing})
992 axes(dest) == axes(bc) || throwdm(axes(dest), axes(bc))
993 # Performance optimization: broadcast!(identity, dest, A) is equivalent to copyto!(dest, A) if indices match
994 if bc.f === identity && bc.args isa Tuple{AbstractArray} # only a single input argument to broadcast!
995 A = bc.args[1]
996 if axes(dest) == axes(A)
997 return copyto!(dest, A)
998 end
999 end
1000 bc′ = preprocess(dest, bc)
1001 # Performance may vary depending on whether `@inbounds` is placed outside the
1002 # for loop or not. (cf. https://github.com/JuliaLang/julia/issues/38086)
1003 70 (24 %)
70 (24 %) samples spent in copyto!
70 (100 %) (incl.) when called from copyto! line 956
48 (69 %) samples spent calling macro expansion
13 (19 %) samples spent calling macro expansion
9 (13 %) samples spent calling macro expansion
@inbounds @simd for I in eachindex(bc′)
1004 48 (17 %)
48 (17 %) samples spent in macro expansion
48 (100 %) (incl.) when called from macro expansion line 77
24 (50 %) samples spent calling setindex!
24 (50 %) samples spent calling getindex
dest[I] = bc′[I]
1005 end
1006 return dest
1007 end
1008
1009 # Performance optimization: for BitArray outputs, we cache the result
1010 # in a "small" Vector{Bool}, and then copy in chunks into the output
1011 @inline function copyto!(dest::BitArray, bc::Broadcasted{Nothing})
1012 axes(dest) == axes(bc) || throwdm(axes(dest), axes(bc))
1013 ischunkedbroadcast(dest, bc) && return chunkedcopyto!(dest, bc)
1014 length(dest) < 256 && return invoke(copyto!, Tuple{AbstractArray, Broadcasted{Nothing}}, dest, bc)
1015 tmp = Vector{Bool}(undef, bitcache_size)
1016 destc = dest.chunks
1017 cind = 1
1018 bc′ = preprocess(dest, bc)
1019 @inbounds for P in Iterators.partition(eachindex(bc′), bitcache_size)
1020 ind = 1
1021 @simd for I in P
1022 tmp[ind] = bc′[I]
1023 ind += 1
1024 end
1025 @simd for i in ind:bitcache_size
1026 tmp[i] = false
1027 end
1028 dumpbitcache(destc, cind, tmp)
1029 cind += bitcache_chunks
1030 end
1031 return dest
1032 end
1033
1034 # For some BitArray operations, we can work at the level of chunks. The trivial
1035 # implementation just walks over the UInt64 chunks in a linear fashion.
1036 # This requires three things:
1037 # 1. The function must be known to work at the level of chunks (or can be converted to do so)
1038 # 2. The only arrays involved must be BitArrays or scalar Bools
1039 # 3. There must not be any broadcasting beyond scalar — all array sizes must match
1040 # We could eventually allow for all broadcasting and other array types, but that
1041 # requires very careful consideration of all the edge effects.
1042 const ChunkableOp = Union{typeof(&), typeof(|), typeof(xor), typeof(~), typeof(identity),
1043 typeof(!), typeof(*), typeof(==)} # these are convertible to chunkable ops by liftfuncs
1044 const BroadcastedChunkableOp{Style<:Union{Nothing,BroadcastStyle}, Axes, F<:ChunkableOp, Args<:Tuple} = Broadcasted{Style,Axes,F,Args}
1045 ischunkedbroadcast(R, bc::BroadcastedChunkableOp) = ischunkedbroadcast(R, bc.args)
1046 ischunkedbroadcast(R, args) = false
1047 ischunkedbroadcast(R, args::Tuple{<:BitArray,Vararg{Any}}) = size(R) == size(args[1]) && ischunkedbroadcast(R, tail(args))
1048 ischunkedbroadcast(R, args::Tuple{<:Bool,Vararg{Any}}) = ischunkedbroadcast(R, tail(args))
1049 ischunkedbroadcast(R, args::Tuple{<:BroadcastedChunkableOp,Vararg{Any}}) = ischunkedbroadcast(R, args[1]) && ischunkedbroadcast(R, tail(args))
1050 ischunkedbroadcast(R, args::Tuple{}) = true
1051
1052 # Convert compatible functions to chunkable ones. They must also be green-lighted as ChunkableOps
1053 liftfuncs(bc::Broadcasted{<:Any,<:Any,<:Any}) = Broadcasted(bc.style, bc.f, map(liftfuncs, bc.args), bc.axes)
1054 liftfuncs(bc::Broadcasted{<:Any,<:Any,typeof(sign)}) = Broadcasted(bc.style, identity, map(liftfuncs, bc.args), bc.axes)
1055 liftfuncs(bc::Broadcasted{<:Any,<:Any,typeof(!)}) = Broadcasted(bc.style, ~, map(liftfuncs, bc.args), bc.axes)
1056 liftfuncs(bc::Broadcasted{<:Any,<:Any,typeof(*)}) = Broadcasted(bc.style, &, map(liftfuncs, bc.args), bc.axes)
1057 liftfuncs(bc::Broadcasted{<:Any,<:Any,typeof(==)}) = Broadcasted(bc.style, (~)∘(xor), map(liftfuncs, bc.args), bc.axes)
1058 liftfuncs(x) = x
1059
1060 liftchunks(::Tuple{}) = ()
1061 liftchunks(args::Tuple{<:BitArray,Vararg{Any}}) = (args[1].chunks, liftchunks(tail(args))...)
1062 # Transform scalars to repeated scalars the size of a chunk
1063 liftchunks(args::Tuple{<:Bool,Vararg{Any}}) = (ifelse(args[1], typemax(UInt64), UInt64(0)), liftchunks(tail(args))...)
1064 ithchunk(i) = ()
1065 Base.@propagate_inbounds ithchunk(i, c::Vector{UInt64}, args...) = (c[i], ithchunk(i, args...)...)
1066 Base.@propagate_inbounds ithchunk(i, b::UInt64, args...) = (b, ithchunk(i, args...)...)
1067 @inline function chunkedcopyto!(dest::BitArray, bc::Broadcasted)
1068 isempty(dest) && return dest
1069 f = flatten(liftfuncs(bc))
1070 args = liftchunks(f.args)
1071 dc = dest.chunks
1072 @simd for i in eachindex(dc)
1073 @inbounds dc[i] = f.f(ithchunk(i, args...)...)
1074 end
1075 @inbounds dc[end] &= Base._msk_end(dest)
1076 return dest
1077 end
1078
1079
1080 @noinline throwdm(axdest, axsrc) =
1081 throw(DimensionMismatch("destination axes $axdest are not compatible with source axes $axsrc"))
1082
1083 function restart_copyto_nonleaf!(newdest, dest, bc, val, I, iter, state, count)
1084 # Function barrier that makes the copying to newdest type stable
1085 for II in Iterators.take(iter, count)
1086 newdest[II] = dest[II]
1087 end
1088 newdest[I] = val
1089 return copyto_nonleaf!(newdest, bc, iter, state, count+1)
1090 end
1091
1092 function copyto_nonleaf!(dest, bc::Broadcasted, iter, state, count)
1093 T = eltype(dest)
1094 while true
1095 y = iterate(iter, state)
1096 y === nothing && break
1097 I, state = y
1098 @inbounds val = bc[I]
1099 if val isa T
1100 @inbounds dest[I] = val
1101 else
1102 # This element type doesn't fit in dest. Allocate a new dest with wider eltype,
1103 # copy over old values, and continue
1104 newdest = Base.similar(bc, promote_typejoin(T, typeof(val)))
1105 return restart_copyto_nonleaf!(newdest, dest, bc, val, I, iter, state, count)
1106 end
1107 count += 1
1108 end
1109 return dest
1110 end
1111
1112 ## Tuple methods
1113
1114 @inline function copy(bc::Broadcasted{Style{Tuple}})
1115 dim = axes(bc)
1116 length(dim) == 1 || throw(DimensionMismatch("tuple only supports one dimension"))
1117 N = length(dim[1])
1118 return ntuple(k -> @inbounds(_broadcast_getindex(bc, k)), Val(N))
1119 end
1120
1121 ## scalar-range broadcast operations ##
1122 # DefaultArrayStyle and \ are not available at the time of range.jl
1123 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), r::AbstractRange) = r
1124
1125 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::AbstractRange) = range(-first(r), step=negate(step(r)), length=length(r))
1126 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::OrdinalRange) = range(-first(r), -last(r), step=negate(step(r)))
1127 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::StepRangeLen) = StepRangeLen(-r.ref, negate(r.step), length(r), r.offset)
1128 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::LinRange) = LinRange(-r.start, -r.stop, length(r))
1129
1130 # For #18336 we need to prevent promotion of the step type:
1131 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), r::AbstractRange, x::Number) = range(first(r) + x, step=step(r), length=length(r))
1132 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), x::Number, r::AbstractRange) = range(x + first(r), step=step(r), length=length(r))
1133 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), r::OrdinalRange, x::Integer) = range(first(r) + x, last(r) + x, step=step(r))
1134 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), x::Integer, r::OrdinalRange) = range(x + first(r), x + last(r), step=step(r))
1135 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), r::AbstractUnitRange, x::Integer) = range(first(r) + x, last(r) + x)
1136 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), x::Integer, r::AbstractUnitRange) = range(x + first(r), x + last(r))
1137 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), r::AbstractUnitRange, x::Real) = range(first(r) + x, length=length(r))
1138 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), x::Real, r::AbstractUnitRange) = range(x + first(r), length=length(r))
1139 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), r::StepRangeLen{T}, x::Number) where T =
1140 StepRangeLen{typeof(T(r.ref)+x)}(r.ref + x, r.step, length(r), r.offset)
1141 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), x::Number, r::StepRangeLen{T}) where T =
1142 StepRangeLen{typeof(x+T(r.ref))}(x + r.ref, r.step, length(r), r.offset)
1143 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), r::LinRange, x::Number) = LinRange(r.start + x, r.stop + x, length(r))
1144 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), x::Number, r::LinRange) = LinRange(x + r.start, x + r.stop, length(r))
1145 broadcasted(::DefaultArrayStyle{1}, ::typeof(+), r1::AbstractRange, r2::AbstractRange) = r1 + r2
1146
1147 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::AbstractRange, x::Number) = range(first(r) - x, step=step(r), length=length(r))
1148 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), x::Number, r::AbstractRange) = range(x - first(r), step=negate(step(r)), length=length(r))
1149 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::OrdinalRange, x::Integer) = range(first(r) - x, last(r) - x, step=step(r))
1150 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), x::Integer, r::OrdinalRange) = range(x - first(r), x - last(r), step=negate(step(r)))
1151 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::AbstractUnitRange, x::Integer) = range(first(r) - x, last(r) - x)
1152 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::AbstractUnitRange, x::Real) = range(first(r) - x, length=length(r))
1153 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::StepRangeLen{T}, x::Number) where T =
1154 StepRangeLen{typeof(T(r.ref)-x)}(r.ref - x, r.step, length(r), r.offset)
1155 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), x::Number, r::StepRangeLen{T}) where T =
1156 StepRangeLen{typeof(x-T(r.ref))}(x - r.ref, negate(r.step), length(r), r.offset)
1157 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::LinRange, x::Number) = LinRange(r.start - x, r.stop - x, length(r))
1158 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), x::Number, r::LinRange) = LinRange(x - r.start, x - r.stop, length(r))
1159 broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r1::AbstractRange, r2::AbstractRange) = r1 - r2
1160
1161 # at present Base.range_start_step_length(1,0,5) is an error, so for 0 .* (-2:2) we explicitly construct StepRangeLen:
1162 broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::Number, r::AbstractRange) = StepRangeLen(x*first(r), x*step(r), length(r))
1163 broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::Number, r::StepRangeLen{T}) where {T} =
1164 StepRangeLen{typeof(x*T(r.ref))}(x*r.ref, x*r.step, length(r), r.offset)
1165 broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::Number, r::LinRange) = LinRange(x * r.start, x * r.stop, r.len)
1166 broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::AbstractFloat, r::OrdinalRange) =
1167 Base.range_start_step_length(x*first(r), x*step(r), length(r)) # 0.2 .* (-2:2) needs TwicePrecision
1168 # separate in case of noncommutative multiplication:
1169 broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::AbstractRange, x::Number) = StepRangeLen(first(r)*x, step(r)*x, length(r))
1170 broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::StepRangeLen{T}, x::Number) where {T} =
1171 StepRangeLen{typeof(T(r.ref)*x)}(r.ref*x, r.step*x, length(r), r.offset)
1172 broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::LinRange, x::Number) = LinRange(r.start * x, r.stop * x, r.len)
1173 broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::OrdinalRange, x::AbstractFloat) =
1174 Base.range_start_step_length(first(r)*x, step(r)*x, length(r))
1175
1176 #broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::AbstractRange, x::Number) = range(first(r)/x, last(r)/x, length=length(r))
1177 broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::AbstractRange, x::Number) = range(first(r)/x, step=step(r)/x, length=length(r))
1178 broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::StepRangeLen{T}, x::Number) where {T} =
1179 StepRangeLen{typeof(T(r.ref)/x)}(r.ref/x, r.step/x, length(r), r.offset)
1180 broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::LinRange, x::Number) = LinRange(r.start / x, r.stop / x, r.len)
1181
1182 broadcasted(::DefaultArrayStyle{1}, ::typeof(\), x::Number, r::AbstractRange) = range(x\first(r), step=x\step(r), length=length(r))
1183 broadcasted(::DefaultArrayStyle{1}, ::typeof(\), x::Number, r::StepRangeLen) = StepRangeLen(x\r.ref, x\r.step, length(r), r.offset)
1184 broadcasted(::DefaultArrayStyle{1}, ::typeof(\), x::Number, r::LinRange) = LinRange(x \ r.start, x \ r.stop, r.len)
1185
1186 broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::UnitRange) = big(r.start):big(last(r))
1187 broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::StepRange) = big(r.start):big(r.step):big(last(r))
1188 broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::StepRangeLen) = StepRangeLen(big(r.ref), big(r.step), length(r), r.offset)
1189 broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::LinRange) = LinRange(big(r.start), big(r.stop), length(r))
1190
1191 ## CartesianIndices
1192 broadcasted(::typeof(+), I::CartesianIndices{N}, j::CartesianIndex{N}) where N =
1193 CartesianIndices(map((rng, offset)->rng .+ offset, I.indices, Tuple(j)))
1194 broadcasted(::typeof(+), j::CartesianIndex{N}, I::CartesianIndices{N}) where N =
1195 I .+ j
1196 broadcasted(::typeof(-), I::CartesianIndices{N}, j::CartesianIndex{N}) where N =
1197 CartesianIndices(map((rng, offset)->rng .- offset, I.indices, Tuple(j)))
1198 function broadcasted(::typeof(-), j::CartesianIndex{N}, I::CartesianIndices{N}) where N
1199 diffrange(offset, rng) = range(offset-last(rng), length=length(rng), step=step(rng))
1200 Iterators.reverse(CartesianIndices(map(diffrange, Tuple(j), I.indices)))
1201 end
1202
1203 ## In specific instances, we can broadcast masked BitArrays whole chunks at a time
1204 # Very intentionally do not support much functionality here: scalar indexing would be O(n)
1205 struct BitMaskedBitArray{N,M}
1206 parent::BitArray{N}
1207 mask::BitArray{M}
1208 BitMaskedBitArray{N,M}(parent, mask) where {N,M} = new(parent, mask)
1209 end
1210 @inline function BitMaskedBitArray(parent::BitArray{N}, mask::BitArray{M}) where {N,M}
1211 @boundscheck checkbounds(parent, mask)
1212 BitMaskedBitArray{N,M}(parent, mask)
1213 end
1214 Base.@propagate_inbounds dotview(B::BitArray, i::BitArray) = BitMaskedBitArray(B, i)
1215 Base.show(io::IO, B::BitMaskedBitArray) = foreach(arg->show(io, arg), (typeof(B), (B.parent, B.mask)))
1216 # Override materialize! to prevent the BitMaskedBitArray from escaping to an overridable method
1217 @inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any,<:Any,typeof(identity),Tuple{Bool}}) = fill!(B, bc.args[1])
1218 @inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any}) = materialize!(@inbounds(view(B.parent, B.mask)), bc)
1219 function Base.fill!(B::BitMaskedBitArray, b::Bool)
1220 Bc = B.parent.chunks
1221 Ic = B.mask.chunks
1222 @inbounds if b
1223 for i = 1:length(Bc)
1224 Bc[i] |= Ic[i]
1225 end
1226 else
1227 for i = 1:length(Bc)
1228 Bc[i] &= ~Ic[i]
1229 end
1230 end
1231 return B
1232 end
1233
1234
1235
1236 ############################################################
1237
1238 # x[...] .= f.(y...) ---> broadcast!(f, dotview(x, ...), y...).
1239 # The dotview function defaults to getindex, but we override it in
1240 # a few cases to get the expected in-place behavior without affecting
1241 # explicit calls to view. (All of this can go away if slices
1242 # are changed to generate views by default.)
1243
1244 Base.@propagate_inbounds dotview(args...) = Base.maybeview(args...)
1245
1246 ############################################################
1247 # The parser turns @. into a call to the __dot__ macro,
1248 # which converts all function calls and assignments into
1249 # broadcasting "dot" calls/assignments:
1250
1251 dottable(x) = false # avoid dotting spliced objects (e.g. view calls inserted by @view)
1252 # don't add dots to dot operators
1253 dottable(x::Symbol) = (!isoperator(x) || first(string(x)) != '.' || x === :..) && x !== :(:)
1254 dottable(x::Expr) = x.head !== :$
1255 undot(x) = x
1256 function undot(x::Expr)
1257 if x.head === :.=
1258 Expr(:(=), x.args...)
1259 elseif x.head === :block # occurs in for x=..., y=...
1260 Expr(:block, Base.mapany(undot, x.args)...)
1261 else
1262 x
1263 end
1264 end
1265 __dot__(x) = x
1266 function __dot__(x::Expr)
1267 dotargs = Base.mapany(__dot__, x.args)
1268 if x.head === :call && dottable(x.args[1])
1269 Expr(:., dotargs[1], Expr(:tuple, dotargs[2:end]...))
1270 elseif x.head === :comparison
1271 Expr(:comparison, (iseven(i) && dottable(arg) && arg isa Symbol && isoperator(arg) ?
1272 Symbol('.', arg) : arg for (i, arg) in pairs(dotargs))...)
1273 elseif x.head === :$
1274 x.args[1]
1275 elseif x.head === :let # don't add dots to `let x=...` assignments
1276 Expr(:let, undot(dotargs[1]), dotargs[2])
1277 elseif x.head === :for # don't add dots to for x=... assignments
1278 Expr(:for, undot(dotargs[1]), dotargs[2])
1279 elseif (x.head === :(=) || x.head === :function || x.head === :macro) &&
1280 Meta.isexpr(x.args[1], :call) # function or macro definition
1281 Expr(x.head, x.args[1], dotargs[2])
1282 elseif x.head === :(<:) || x.head === :(>:)
1283 tmp = x.head === :(<:) ? :.<: : :.>:
1284 Expr(:call, tmp, dotargs...)
1285 else
1286 head = String(x.head)::String
1287 if last(head) == '=' && first(head) != '.' || head == "&&" || head == "||"
1288 Expr(Symbol('.', head), dotargs...)
1289 else
1290 Expr(x.head, dotargs...)
1291 end
1292 end
1293 end
1294 """
1295 @. expr
1296
1297 Convert every function call or operator in `expr` into a "dot call"
1298 (e.g. convert `f(x)` to `f.(x)`), and convert every assignment in `expr`
1299 to a "dot assignment" (e.g. convert `+=` to `.+=`).
1300
1301 If you want to *avoid* adding dots for selected function calls in
1302 `expr`, splice those function calls in with `\$`. For example,
1303 `@. sqrt(abs(\$sort(x)))` is equivalent to `sqrt.(abs.(sort(x)))`
1304 (no dot for `sort`).
1305
1306 (`@.` is equivalent to a call to `@__dot__`.)
1307
1308 # Examples
1309 ```jldoctest
1310 julia> x = 1.0:3.0; y = similar(x);
1311
1312 julia> @. y = x + 3 * sin(x)
1313 3-element Vector{Float64}:
1314 3.5244129544236893
1315 4.727892280477045
1316 3.4233600241796016
1317 ```
1318 """
1319 macro __dot__(x)
1320 esc(__dot__(x))
1321 end
1322
1323 @inline function broadcasted_kwsyntax(f, args...; kwargs...)
1324 if isempty(kwargs) # some BroadcastStyles dispatch on `f`, so try to preserve its type
1325 return broadcasted(f, args...)
1326 else
1327 return broadcasted((args...) -> f(args...; kwargs...), args...)
1328 end
1329 end
1330 @inline function broadcasted(f::F, args...) where {F}
1331 args′ = map(broadcastable, args)
1332 broadcasted(combine_styles(args′...), f, args′...)
1333 end
1334 # Due to the current Type{T}/DataType specialization heuristics within Tuples,
1335 # the totally generic varargs broadcasted(f, args...) method above loses Type{T}s in
1336 # mapping broadcastable across the args. These additional methods with explicit
1337 # arguments ensure we preserve Type{T}s in the first or second argument position.
1338 @inline function broadcasted(f::F, arg1, args...) where {F}
1339 arg1′ = broadcastable(arg1)
1340 args′ = map(broadcastable, args)
1341 broadcasted(combine_styles(arg1′, args′...), f, arg1′, args′...)
1342 end
1343 @inline function broadcasted(f::F, arg1, arg2, args...) where {F}
1344 arg1′ = broadcastable(arg1)
1345 arg2′ = broadcastable(arg2)
1346 args′ = map(broadcastable, args)
1347 broadcasted(combine_styles(arg1′, arg2′, args′...), f, arg1′, arg2′, args′...)
1348 end
1349 @inline broadcasted(style::BroadcastStyle, f::F, args...) where {F} = Broadcasted(style, f, args)
1350
1351 """
1352 BroadcastFunction{F} <: Function
1353
1354 Represents the "dotted" version of an operator, which broadcasts the operator over its
1355 arguments, so `BroadcastFunction(op)` is functionally equivalent to `(x...) -> (op).(x...)`.
1356
1357 Can be created by just passing an operator preceded by a dot to a higher-order function.
1358
1359 # Examples
1360 ```jldoctest
1361 julia> a = [[1 3; 2 4], [5 7; 6 8]];
1362
1363 julia> b = [[9 11; 10 12], [13 15; 14 16]];
1364
1365 julia> map(.*, a, b)
1366 2-element Vector{Matrix{Int64}}:
1367 [9 33; 20 48]
1368 [65 105; 84 128]
1369
1370 julia> Base.BroadcastFunction(+)(a, b) == a .+ b
1371 true
1372 ```
1373
1374 !!! compat "Julia 1.6"
1375 `BroadcastFunction` and the standalone `.op` syntax are available as of Julia 1.6.
1376 """
1377 struct BroadcastFunction{F} <: Function
1378 f::F
1379 end
1380
1381 @inline (op::BroadcastFunction)(x...; kwargs...) = op.f.(x...; kwargs...)
1382
1383 function Base.show(io::IO, op::BroadcastFunction)
1384 print(io, BroadcastFunction, '(')
1385 show(io, op.f)
1386 print(io, ')')
1387 nothing
1388 end
1389 Base.show(io::IO, ::MIME"text/plain", op::BroadcastFunction) = show(io, op)
1390
1391 end # module