-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement
Base.broadcastable
for BioSequence
types.
- Loading branch information
Ben J. Ward
committed
Jul 20, 2021
1 parent
6f8c351
commit 5d7692e
Showing
2 changed files
with
156 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
#= | ||
Let's have a look at the example of broadcasting addition with a vector. | ||
@less broadcast(+, [1,2,3], 1) | ||
=== | ||
broadcast(f::Tf, As...) where {Tf} = materialize(broadcasted(f, As...)) | ||
@less Base.broadcasted(+, [1,2,3], 1) | ||
=== | ||
@inline function broadcasted(f, arg1, arg2, args...) | ||
arg1′ = broadcastable(arg1) | ||
arg2′ = broadcastable(arg2) | ||
args′ = map(broadcastable, args) | ||
broadcasted(combine_styles(arg1′, arg2′, args′...), f, arg1′, arg2′, args′...) | ||
end | ||
@inline broadcasted(::S, f, args...) where S<:BroadcastStyle = Broadcasted{S}(f, args) | ||
bc = Base.broadcasted(Base.Broadcast.combine_styles(arg1, arg2), +, arg1, arg2) | ||
Base.Broadcast.Broadcasted(+, ([1, 2, 3], 1)) | ||
typeof(bc) | ||
Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(+), Tuple{Vector{Int64}, Int64}} | ||
@less Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}}(+, (arg1, arg2)) | ||
=== | ||
function Broadcasted{Style}(f::F, args::Args, axes=nothing) where {Style, F, Args<:Tuple} | ||
# using Core.Typeof rather than F preserves inferrability when f is a type | ||
Broadcasted{Style, typeof(axes), Core.Typeof(f), Args}(f, args, axes) | ||
end | ||
@less materialize(bc) | ||
=== | ||
@inline materialize(bc::Broadcasted) = copy(instantiate(bc)) | ||
materialize(x) = x | ||
@less Base.Broadcast.instantiate(bc) | ||
=== | ||
@inline function instantiate(bc::Broadcasted{Style}) where {Style} | ||
if bc.axes isa Nothing # Not done via dispatch to make it easier to extend instantiate(::Broadcasted{Style}) | ||
axes = combine_axes(bc.args...) | ||
else | ||
axes = bc.axes | ||
check_broadcast_axes(axes, bc.args...) | ||
end | ||
return Broadcasted{Style}(bc.f, bc.args, axes) | ||
end | ||
@less Base.Broadcast.combine_axes(bc.args...) | ||
=== | ||
@inline combine_axes(A, B...) = broadcast_shape(axes(A), combine_axes(B...)) | ||
@inline combine_axes(A, B) = broadcast_shape(axes(A), axes(B)) | ||
@less @less Base.Broadcast.broadcast_shape(axes([1,2,3]), axes(1)) | ||
=== | ||
broadcast_shape(shape::Tuple) = shape | ||
broadcast_shape(shape::Tuple, shape1::Tuple, shapes::Tuple...) = broadcast_shape(_bcs(shape, shape1), shapes...) | ||
@less Base.Broadcast._bcs(axes([1,2,3]), axes(1)) | ||
=== | ||
_bcs(shape::Tuple, ::Tuple{}) = (shape[1], _bcs(tail(shape), ())...) | ||
_bcs consolidates two shapes into a single output shape | ||
shape = axes([1,2,3]) | ||
@less Base.Broadcast._bcs(Base.tail(shape), ()) | ||
=== | ||
_bcs(::Tuple{}, ::Tuple{}) = () | ||
() | ||
(shape[1], _bcs(tail(shape), ())...) | ||
@less copy(Base.Broadcast.instantiate(bc)) | ||
=== | ||
@inline function copy(bc::Broadcasted{Style}) where {Style} | ||
ElType = combine_eltypes(bc.f, bc.args) | ||
if Base.isconcretetype(ElType) | ||
# We can trust it and defer to the simpler `copyto!` | ||
return copyto!(similar(bc, ElType), bc) | ||
end | ||
# When ElType is not concrete, use narrowing. Use the first output | ||
# value to determine the starting output eltype; copyto_nonleaf! | ||
# will widen `dest` as needed to accommodate later values. | ||
bc′ = preprocess(nothing, bc) | ||
iter = eachindex(bc′) | ||
y = iterate(iter) | ||
if y === nothing | ||
# if empty, take the ElType at face value | ||
return similar(bc′, ElType) | ||
end | ||
# Initialize using the first value | ||
I, state = y | ||
@inbounds val = bc′[I] | ||
dest = similar(bc′, typeof(val)) | ||
@inbounds dest[I] = val | ||
# Now handle the remaining values | ||
# The typeassert gives inference a helping hand on the element type and dimensionality | ||
# (work-around for #28382) | ||
ElType′ = ElType === Union{} ? Any : ElType <: Type ? Type : ElType | ||
RT = dest isa AbstractArray ? AbstractArray{<:ElType′, ndims(dest)} : Any | ||
return copyto_nonleaf!(dest, bc′, iter, state, 1)::RT | ||
end | ||
@less Base.Broadcast.combine_eltypes(bc.f, bc.args) | ||
=== | ||
combine_eltypes(f, args::Tuple) = promote_typejoin_union(Base._return_type(f, eltypes(args))) | ||
@less Base.Broadcast.eltypes(bc.args) | ||
@less Base._return_type(+, Base.Broadcast.eltypes(bc.args)) | ||
@less Base.Broadcast.promote_typejoin_union(Base._return_type(+, Base.Broadcast.eltypes(bc.args))) | ||
=== | ||
function promote_typejoin_union(::Type{T}) where T | ||
if T === Union{} | ||
return Union{} | ||
elseif T isa UnionAll | ||
return Any # TODO: compute more precise bounds | ||
elseif T isa Union | ||
return promote_typejoin(promote_typejoin_union(T.a), promote_typejoin_union(T.b)) | ||
elseif T <: Tuple | ||
return typejoin_union_tuple(T) | ||
else | ||
return T | ||
end | ||
end | ||
@less similar(bc, Base.Broadcast.combine_eltypes(bc.f, bc.args)) | ||
=== | ||
Base.similar(bc::Broadcasted, ::Type{T}) where {T} = similar(bc, T, axes(bc)) | ||
Base.similar(::Broadcasted{DefaultArrayStyle{N}}, ::Type{ElType}, dims) where {N,ElType} = similar(Array{ElType}, dims) | ||
Base.similar(::Broadcasted{DefaultArrayStyle{N}}, ::Type{Bool}, dims) where N = similar(BitArray, dims) | ||
@less copyto!(similar(bc, Base.Broadcast.combine_eltypes(bc.f, bc.args)), bc) | ||
=# | ||
|
||
Base.broadcastable(x::BioSequence) = x | ||
|
||
|
||
|
||
|
||
|