juliaflux.jl

Double Broadcasting in Julia for Matrix Vector Addition?


Newbie Julia question here. Given two arrays,

W = [randn(3,2), randn(3,2)]
b = [randn(3), randn(3)]

I would like to do a "nested broadcast" along the lines of,

W .+ b = [W[1].+b[1], W[2].+b[2]]

So far the best I've been able to come up with is,

[Wi.+bi (Wi,bi) for zip(W,b)]

Coming from a Python background this feels sacrilegious. Is there a better way to do this in Julia?


Solution

  • You could do something like the following:

    julia> W = [randn(3,2), randn(3,2)]
    2-element Array{Array{Float64,2},1}:
     [0.39179718902868116 -0.5387622679356612; -0.594274465053327 0.018804631512093436; -2.273706742420988 -0.4638617400026042]
     [0.3249960563405678 -0.4877554417492699; 0.5036437919340767 1.3172770503034696; 0.03501532820428975 -0.2675024677340758]
    
    julia> b = [randn(3), randn(3)]
    2-element Array{Array{Float64,1},1}:
     [1.2571527266220441, 0.21599608118129476, 0.21498843153804936]
     [-0.528960345932853, 0.5610435189953311, -0.8636370930615718]
    
    # A helper function which broadcasts once
    julia> s_(Wi, bi) = Wi .+ bi
    s_ (generic function with 1 method)
    
    # Broadcast the helper function
    julia> s_.(W, b)
    2-element Array{Array{Float64,2},1}:
     [1.6489499156507252 0.718390458686383; -0.3782783838720323 0.2348007126933882; -2.0587183108829388 -0.24887330846455485]
     [-0.20396428959228524 -1.016715787682123; 1.0646873109294077 1.8783205692988008; -0.828621764857282 -1.1311395607956476]
    

    As mentioned in comments, you can use one of the available user-definable infix operators to name the helper function, which allows for a nicer syntax (the particular symbol used below can be obtained by typing \oplus then Tab):

    julia> ⊕(x, y) = x .+ y
    ⊕ (generic function with 1 method)
    
    julia> W .⊕ b
    2-element Array{Array{Float64,2},1}:
     [1.6489499156507252 0.718390458686383; -0.3782783838720323 0.2348007126933882; -2.0587183108829388 -0.24887330846455485]
     [-0.20396428959228524 -1.016715787682123; 1.0646873109294077 1.8783205692988008; -0.828621764857282 -1.1311395607956476]
    
    

    Or - again as mentioned in comments - if you don't feel like explicitly declaring a helper function:

    julia> ((Wi, bi)->Wi.+bi).(W, b)
    2-element Array{Array{Float64,2},1}:
     [1.6489499156507252 0.718390458686383; -0.3782783838720323 0.2348007126933882; -2.0587183108829388 -0.24887330846455485]
     [-0.20396428959228524 -1.016715787682123; 1.0646873109294077 1.8783205692988008; -0.828621764857282 -1.1311395607956476]
    

    (I personally have more difficulty reading that last version, but YMMV)