Skip to content
This repository has been archived by the owner on May 4, 2019. It is now read-only.

Commit

Permalink
Revise broadcast! to support lift kwarg
Browse files Browse the repository at this point in the history
involves:
-Adding `Reexport` to REQUIRE
  • Loading branch information
davidagold committed Jul 21, 2015
1 parent ab6c4a0 commit 32a408a
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 1 deletion.
1 change: 1 addition & 0 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
Reexport
StatsBase
1 change: 1 addition & 0 deletions perf/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ function profile_broadcasted_right(C1, C2, V1, V2, H1, H2, Q1, Q2)
@time(.>>(Q2, Q1))
# print("For DataArray{Float64}: ")
# @time(.>>(I2, I1))
nothing
end

function profile_ops_halfnulls(A1, A2, Y1, Y2, F1, F2)
Expand Down
3 changes: 2 additions & 1 deletion src/NullableArrays.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module NullableArrays

using Base.Cartesian
using Reexport
@reexport using Base.Cartesian

export NullableArray,
NullableVector,
Expand Down
82 changes: 82 additions & 0 deletions src/broadcast.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,85 @@
using Base.Broadcast: check_broadcast_shape
# using Base.Cartesian

function gen_nullcheck(narrays::Int, nd::Int)
e_nullcheck = macroexpand(:( @nref $nd isnull_1 d->j_d_1 ))
for k = 2:narrays
isnull = symbol("isnull_$k")
j_d_k = symbol("j_d_$k")
e_isnull_k = macroexpand(:( @nref $nd $(isnull) d->$(j_d_k) ))
e_nullcheck = Expr(:||, e_nullcheck, e_isnull_k)
end
return e_nullcheck
end

function gen_broadcast_body(nd::Int, narrays::Int, f, lift::Bool)
F = Expr(:quote, f)
e_nullcheck = gen_nullcheck(narrays, nd)
if lift
return quote
# set up aliases to facilitate subsequent Base.Cartesian magic
B_isnull = B.isnull
@nexprs $narrays k->(values_k = A_k.values)
@nexprs $narrays k->(isnull_k = A_k.isnull)
# check size
@assert ndims(B) == $nd
@ncall $narrays Base.Broadcast.check_broadcast_shape size(B) k->A_k
# main loops
@nloops($nd, i, B,
d->(@nexprs $narrays k->(j_d_k = size(A_k, d) == 1 ? 1 : i_d)), # pre
begin # body
if $e_nullcheck
@inbounds (@nref $nd B_isnull i) = true
else
@nexprs $narrays k->(@inbounds v_k = @nref $nd values_k d->j_d_k)
@inbounds (@nref $nd B i) = (@ncall $narrays $F v)
end
end
)
end
else
return Base.Broadcast.gen_broadcast_body_cartesian(nd, narrays, f)
end
end

function gen_broadcast_function(nd::Int, narrays::Int, f::Function, lift::Bool)
As = [symbol("A_"*string(i)) for i = 1:narrays]
body = gen_broadcast_body(nd, narrays, f, lift)
# println(macroexpand( body ))
@eval let
local _F_
function _F_(B, $(As...))
$body
end
_F_
end
end

@eval let cache = Dict{Any, Dict{Bool, Dict{Int, Dict{Int, Any}}}}()
function Base.broadcast!(f, B::NullableArray, As::NullableArray...; lift::Bool=false)
nd = ndims(B)
narrays = length(As)

cache_f = Base.@get! cache f Dict{Bool, Dict{Int, Dict{Int, Any}}}()
cache_lift = Base.@get! cache_f lift Dict{Int, Dict{Int, Any}}()
cache_f_na = Base.@get! cache_lift narrays Dict{Int, Any}()
func = Base.@get! cache_f_na nd gen_broadcast_function(nd, narrays, f, lift)

func(B, As...)
return B
end
end # let cache

function Base.broadcast!(f, X::NullableArray; lift::Bool=false)
broacast!(f, X, X; lift=lift)
end

function Base.broadcast(f, As::NullableArray...;lift::Bool=false)
return broadcast!(f, NullableArray(eltype(Base.promote_eltype(As...)),
Base.Broadcast.broadcast_shape(As...)),
As...; lift=lift)
end

#----- broadcasted binary operations -----------------------------------------#

# The following require specialized implementations because the base/broadcast
Expand Down

0 comments on commit 32a408a

Please sign in to comment.