I have recently updated some code written for Julia 0.6.2 to Julia 1.0.0 and it actually got a bit slower. (Some context: The code is for updating probabilities partly on the basis of incoming information, partly on the basis of the probabilities held by those agents in one’s community whose probabilities are not ‘too far away’ from one’s own.) I used code_warntype
in an attempt to figure out what might be wrong, but I find it hard to make sense of the output. In particular, it seems that using parallel loops with @distributed
causes type instability (at least if I read the output from code_warntype
correctly, the Any
s get introduced in those loops). But I don’t understand why that should happen – I do indicate what type of array should be constructed by the loop. Below is a short version of my code. I’d appreciate any tips about how I might be able to make it more performant (and please don’t hesitate to say so if my code is very un-Julian).
using Distributed
addprocs(3)
@everywhere using Distributions, StatsBase, Distances, LinearAlgebra, SharedArrays
@everywhere const numb_hyp = 11
@everywhere const numb_agent = 50
@everywhere const numb_toss = 500
@everywhere const numb_sim = 50
@everywhere const start_pop = repeat(fill(1/numb_hyp, numb_hyp), 1, numb_agent)
@everywhere const likelihood_heads = range(0f0, stop=1, length=numb_hyp)
@everywhere const likelihood_tails = range(1f0, stop=0, length=numb_hyp)
datFunc(bias) = rand(Bernoulli(bias), numb_toss)
sim_dat = BitArray(undef, numb_agent, numb_toss, div(numb_hyp, 2) + 1, numb_sim)
for s in 1:numb_sim, i in 1:div(numb_hyp, 2) + 1, j in 1:numb_agent
sim_dat[j, :, i, s] = datFunc((i - 1) / (numb_hyp - 1))
end
@everywhere function expl_upd(probs::Array{Float32,1}, dat::BitArray{1}, toss_num::Int, bonus::Float32)
val::Float32 = mean(dat[1:toss_num]) * 10 + 1
vec::Array{Float32,1} = if dat[toss_num] == true
@. (probs * likelihood_heads) / $dot(probs, likelihood_heads)
else
@. (probs * likelihood_tails) / $dot(probs, likelihood_tails)
end
if val % 1 == .5
vec[floor(Int, val)] += bonus*0.5f0
vec[ceil(Int, val)] += bonus*0.5f0
else
vec[round(Int, val, RoundNearestTiesAway)] += bonus
end
return vec / (1 + bonus)
end
function SocialLearning(rule, dist, averaging, bonus::Float32, ϵ::Float32, sdat::BitArray{3})
UPD = SharedArray{Float32,4}(numb_hyp, numb_agent, numb_toss + 1, div(numb_hyp + 1, 2))
for k::Int in 1:div(numb_hyp + 1, 2)
UPD[:, :, 1, k] = start_pop
end
for h::Int in 1:div(numb_hyp + 1, 2)
for t::Int in 1:numb_toss
PROB::Array{Float32,2} = @distributed (hcat) for i::Int in 1:numb_agent
rule(UPD[:, i, t, h], sdat[i, :, h], t, bonus)
end
prob_dist::Array{Float32,2} = pairwise(dist(), PROB)
peers::Array{Bool,2} = map(x->x<=ϵ, prob_dist)
if averaging == mean
UPD[:, :, t + 1, h] = @distributed (hcat) for i::Int in 1:numb_agent
mean(PROB[:, peers[i, :]], dims=2)
end
else
UPD[:, :, t + 1, h] = @distributed (hcat) for i::Int in 1:numb_agent
map(row->averaging(PROB[:, peers[i, :]][row, :]), 1:numb_hyp)
end
end
end
end
return UPD
end
@code_warntype SocialLearning(expl_upd, Euclidean, mean, 0.0f0, 0.0f0, sim_dat[:,:,:,10])
PS The code got much slower on Julia 1.0.0 when, instead of Euclidean
(or also Cityblock
) I measure distances between probability functions with, e.g., KLDivergence
. Perhaps a problem with the Distances package?