Last active
August 29, 2015 14:27
-
-
Save armanbilge/3c4113e1c1e6b42fb3b8 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| using Distributions | |
| using Iterators | |
| using StatsBase | |
| type Particle{T} | |
| value::T | |
| weight::Float64 | |
| end | |
| Particle{T}(value::T) = Particle(value, 1.0) | |
| function resetweight(p::Particle) | |
| Particle(deepcopy(p.value)) | |
| end | |
| function multiplyweight!(p::Particle, w::Float64) | |
| p.weight *= w | |
| end | |
| type Trajectory | |
| n::Int | |
| t::Float64 | |
| end | |
| Trajectory(t::Float64) = Trajectory(1, t) | |
| function increment!(E::Trajectory) | |
| E.n += 1 | |
| end | |
| function decrement!(E::Trajectory) | |
| E.n -= 1 | |
| end | |
| function forward!(E::Trajectory, t::Float64) | |
| E.t -= t | |
| end | |
| type ColoredTrajectory | |
| n::Array{Int,1} | |
| N::Int | |
| l::Array{Int,1} | |
| t::Float64 | |
| end | |
| ColoredTrajectory(t::Float64, n::Int) = ColoredTrajectory(zeros(Int, n), 0, zeros(Int, 0), t) | |
| countcolors(E::ColoredTrajectory) = length(E.n) | |
| lineagecount(E::ColoredTrajectory) = length(E.l) | |
| lineagecount(E::ColoredTrajectory, color::Int) = count(c -> c == color, E.l) | |
| lineages(E::ColoredTrajectory, color::Int) = filter(i -> E.l[i] == color, 1:lineagecount(E)) | |
| function increment!(E::ColoredTrajectory, c::Int) | |
| E.n[c] += 1 | |
| E.N += 1 | |
| end | |
| function decrement!(E::ColoredTrajectory, c::Int) | |
| E.n[c] -= 1 | |
| E.N -= 1 | |
| end | |
| function forward!(E::ColoredTrajectory, t::Float64) | |
| E.t -= t | |
| end | |
| function newlineage!(E::ColoredTrajectory, c::Int) | |
| push!(E.l, c) | |
| E.n[c] += 1 | |
| E.N += 1 | |
| end | |
| type SEISTrajectory | |
| N::Int | |
| S::Int | |
| E::Int | |
| I::Int | |
| l::Array{Int,1} | |
| t::Float64 | |
| end | |
| SEISTrajectory(S::Int, t::Float64) = SEISTrajectory(S, S, 0, 0, zeros(Int, 0), t) | |
| lineagecount(E::SEISTrajectory) = length(E.l) | |
| lineagecount(E::SEISTrajectory, color::Int) = count(c -> c == color, E.l) | |
| lineages(E::SEISTrajectory, color::Int) = filter(i -> E.l[i] == color, 1:lineagecount(E)) | |
| function incrementexposed!(E::SEISTrajectory) | |
| E.S -= 1 | |
| E.E += 1 | |
| end | |
| function incrementinfected!(E::SEISTrajectory) | |
| E.E -= 1 | |
| E.I += 1 | |
| end | |
| function incrementsusceptible!(E::SEISTrajectory) | |
| E.I -= 1 | |
| E.S += 1 | |
| end | |
| function forward!(E::SEISTrajectory, t::Float64) | |
| E.t -= t | |
| end | |
| function newlineage!(E::SEISTrajectoryt) | |
| push!(E.l, 1) | |
| incrementexposed!(E) | |
| end | |
| type NewColoredTrajectory | |
| n::Array{Int,2} | |
| m::Array{Int,1} | |
| N::Int | |
| t::Float64 | |
| end | |
| NewColoredTrajectory(t::Float64, n::Int) = NewColoredTrajectory(zeros(Int, 2, n), zeros(Int, n), 0, t) | |
| countcolors(E::NewColoredTrajectory) = size(E.n)[2] | |
| lineagecount(E::NewColoredTrajectory) = size(E.n)[1] | |
| function increment!(E::NewColoredTrajectory, l::Int, c::Int) | |
| E.n[l][c] += 1 | |
| E.m[l] += 1 | |
| E.N += 1 | |
| end | |
| function decrement!(E::NewColoredTrajectory, l::Int, c::Int) | |
| E.n[l][c] -= 1 | |
| E.m[l] -= 1 | |
| E.N -= 1 | |
| end | |
| function forward!(E::NewColoredTrajectory, t::Float64) | |
| E.t -= t | |
| end | |
| type BirthDeathSamplingModel | |
| lambda::Float64 | |
| mu::Float64 | |
| rho::Float64 | |
| end | |
| type ColoredBirthDeathSamplingModel | |
| lambda::Float64 | |
| tau::Float64 | |
| mu::Float64 | |
| rho::Float64 | |
| end | |
| type SEISModel | |
| N::Int | |
| beta::Float64 | |
| gamma::Float64 | |
| mu::Float64 | |
| psi::Float64 | |
| end | |
| type Node | |
| label::String | |
| height::Float64 | |
| parent::Node | |
| left::Node | |
| right::Node | |
| color::Int | |
| id::Int | |
| Node(label::String, height::Float64, color::Int) = (x = new(); x.label = label; x.height = height; x.color = color; x) | |
| Node(height::Float64, color::Int) = (x = new(); x.height = height; x.color = color; x) | |
| end | |
| function setchildren!(p::Node, l::Node, r::Node) | |
| p.left = l | |
| p.right = r | |
| l.parent = p | |
| r.parent = p | |
| end | |
| type Tree | |
| root::Node | |
| origin::Float64 | |
| color::Int | |
| end | |
| isroot(node::Node) = !isdefined(node, :parent) | |
| isleaf(node::Node) = !isinternal(node) | |
| isinternal(node::Node) = isdefined(node, :left) | |
| function preorder(node::Node) | |
| function iter() | |
| produce(node) | |
| if !isleaf(node) | |
| for n in preorder(node.left) | |
| produce(n) | |
| end | |
| for n in preorder(node.right) | |
| produce(n) | |
| end | |
| end | |
| end | |
| Task(iter) | |
| end | |
| preorder(tree::Tree) = preorder(tree.root) | |
| internalnodes(tree::Tree) = filter(isinternal, preorder(tree)) | |
| leaves(tree::Tree) = filter(isleaf, preorder(tree)) | |
| leafcount(tree::Tree, c::Int) = count(n -> n.color == c, leaves(tree)) | |
| function simulate!(E::Trajectory, bds::BirthDeathSamplingModel, stop::Float64, Ti::Int) | |
| TiC2 = binomial(Ti, 2) | |
| p = 1.0 | |
| nu = bds.lambda + bds.mu | |
| birthdist = Bernoulli(bds.lambda / nu) | |
| t = rand(Exponential(1/(E.n * nu))) | |
| while E.t - t > stop | |
| b = rand(birthdist) | |
| forward!(E, t) | |
| if b == 1 | |
| increment!(E) | |
| EnC2 = binomial(E.n, 2) | |
| q = (EnC2 - TiC2) / EnC2 | |
| if q <= 0 | |
| return 0.0 | |
| else | |
| p *= q | |
| end | |
| else | |
| decrement!(E) | |
| end | |
| t = rand(Exponential(1/(E.n * nu))) | |
| end | |
| p | |
| end | |
| function simulate!(E::ColoredTrajectory, cbds::ColoredBirthDeathSamplingModel, stop::Float64) | |
| p = 1.0 | |
| eventdist = WeightVec([cbds.lambda * (1 - cbds.tau), cbds.lambda * cbds.tau, cbds.mu]) | |
| nu = sum(eventdist) | |
| t = rand(Exponential(1/(E.N * nu))) | |
| while E.t - t > stop | |
| event = sample(eventdist) | |
| color = sample(WeightVec(E.n)) | |
| lineageaffected = rand(Bernoulli(lineagecount(E, color) / E.n[color])) | |
| forward!(E, t) | |
| if event == 1 # Birth, no transfer | |
| increment!(E, color) | |
| p *= lineageaffected + 1 | |
| elseif event == 2 # Birth, transfer | |
| destination = sample(filter(c -> c != color, 1:countcolors(E))) | |
| increment!(E, destination) | |
| if lineageaffected == 1 | |
| affectedlineage = sample(lineages(E, color)) | |
| E.l[affectedlineage] = destination | |
| end | |
| p *= lineageaffected + 1 | |
| else # Death | |
| if lineageaffected == 1 | |
| return 0.0 | |
| end | |
| decrement!(E, color) | |
| end | |
| t = rand(Exponential(1/(E.N * nu))) | |
| end | |
| p | |
| end | |
| function simulate!(E::SEISTrajectory, seis::SEISModel, stop::Float64) | |
| p = 1.0 | |
| eventdist = WeightVec([seis.beta * E.S * E.I / E.N, seis.gamma * E.E, (seis.mu + seis.psi) * E.I]) | |
| nu = sum(eventdist) | |
| t = rand(Exponential(1/nu) | |
| while E.t - t > stop | |
| event = sample(eventdist) | |
| forward!(E, t) | |
| if event == 1 # S + I -> E + I | |
| lineageaffected = rand(Bernoulli(lineagecount(E, 2) / E.I)) | |
| if lineageaffected == 1 && randbool() | |
| affected = sample(lineages(E, 2)) | |
| E.l[affected] = 1 | |
| end | |
| p *= lineageaffected + 1 | |
| incrementexposed!(E) | |
| elseif event == 2 # E -> I | |
| lineageaffected = rand(Bernoulli(lineagecount(E, 1) / E.E)) | |
| p *= lineageaffected + 1 | |
| if lineageaffected == 1 | |
| affected = sample(lineages(E, 1)) | |
| E.l[affected] = 2 | |
| end | |
| incrementinfected!(E) | |
| else # I -> S | |
| lineageaffected = rand(Bernoulli(lineagecount(E, 2) / E.I)) | |
| if lineageaffected == 1 | |
| return 0.0 | |
| end | |
| incrementsusceptible!(E) | |
| end | |
| eventdist = WeightVec([cbds.lambda * (1 - cbds.tau), cbds.lambda * cbds.tau, cbds.mu]) | |
| nu = sum(eventdist) | |
| t = rand(Exponential(1/nu)) | |
| end | |
| p | |
| end | |
| function simulate!(E::NewColoredTrajectory, cbds::ColoredBirthDeathSamplingModel, stop::Float64, Ti::Int) | |
| TiC2 = binomial(Ti, 2) | |
| p = 1.0 | |
| eventdist = WeightVec([cbds.lambda * (1 - cbds.tau), cbds.lambda * cbds.tau, cbds.mu]) | |
| nu = sum(eventdist) | |
| t = rand(Exponential(1/(E.N * nu))) | |
| while E.t - t > stop | |
| event = sample(eventdist) | |
| lineage = sample(E.m) | |
| color = sample(WeightVec(E.n[lineage])) | |
| forward!(E, t) | |
| if event == 1 # Birth, no transfer | |
| increment!(E, lineage, color) | |
| p *= lineageaffected + 1 | |
| elseif event == 2 # Birth, transfer | |
| destination = sample(filter(c -> c != color, 1:countcolors(E))) | |
| increment!(E, lineage, destination) | |
| # p *= lineageaffected + 1 | |
| else # Death | |
| decrement!(E, lineage, color) | |
| if E.n[color] == 0 | |
| return 0.0 | |
| end | |
| end | |
| t = rand(Exponential(1/(E.N * nu))) | |
| end | |
| p | |
| end | |
| p1(t::Float64, l::Float64, m::Float64, rho::Float64) = rho*(l-m)^2 * exp(-(l-m)*t)/(rho*l+(l*(1-rho)-m)*exp(-(l-m)*t))^2 | |
| function f(x::AbstractArray{Float64,1}, tau::Float64, lambda::Float64, mu::Float64, rho::Float64) | |
| log(p1(tau, lambda, mu, rho)) + sum(map(xi -> log(lambda * p1(xi, lambda, mu, rho)), x)) | |
| end | |
| function f_hat(x::AbstractArray{Float64,1}, tau::Float64, lambda::Float64, mu::Float64, rho::Float64, N::Int=100000) | |
| n = length(x) + 1 | |
| sort!(x, rev=true) | |
| bds = BirthDeathSamplingModel(lambda, mu, rho) | |
| particles = collect(repeatedly(() -> Particle(Trajectory(tau)), N)) | |
| f = 0 | |
| for (Ti, xi) in zip(1:(n-1), x) | |
| for p in particles | |
| multiplyweight!(p, simulate!(p.value, bds, xi, Ti)) | |
| p.value.t = xi | |
| increment!(p.value) | |
| q = binomial(p.value.n, 2) | |
| if q > 0 | |
| multiplyweight!(p, (p.value.n - 1) * lambda / q) | |
| else | |
| multiplyweight!(p, 0.0) | |
| end | |
| end | |
| w = Float64[p.weight for p in particles] | |
| f += log(mean(w)) | |
| if f == -Inf | |
| return -Inf | |
| end | |
| particles = collect(map(resetweight, sample(particles, WeightVec(w), N))) | |
| end | |
| for p in particles | |
| multiplyweight!(p, simulate!(p.value, bds, 0.0, n)) | |
| p.value.t = 0 | |
| multiplyweight!(p, pdf(Binomial(p.value.n, rho), n)) | |
| end | |
| w = Float64[p.weight for p in particles] | |
| f += log(mean(w)) | |
| f -= log(2) * (n-1) | |
| f += lfact(n) | |
| f | |
| end | |
| function f_hat(tree::Tree, cbds::ColoredBirthDeathSamplingModel, colors::Int, N::Int=10000) | |
| nodes = collect(internalnodes(tree)) | |
| sort!(nodes, by=n -> n.height, rev=true) | |
| n = length(nodes) + 1 | |
| eventdist = Bernoulli(1 - cbds.tau) | |
| particles = collect(repeatedly(() -> Particle(ColoredTrajectory(tree.origin, colors)), N)) | |
| f = 0 | |
| tree.root.id = 1 | |
| for p in particles | |
| newlineage!(p.value, tree.color) | |
| end | |
| for node in nodes | |
| for p in particles | |
| multiplyweight!(p, simulate!(p.value, cbds, node.height)) | |
| p.value.t = node.height | |
| if p.value.l[node.id] != node.color | |
| multiplyweight!(p, 0.0) | |
| else | |
| if rand(eventdist) == 1 | |
| newlineage!(p.value, node.color) | |
| multiplyweight!(p, cbds.lambda) | |
| else | |
| destination = sample(filter(c -> c != node.color, 1:countcolors(p.value))) | |
| newlineage!(p.value, destination) | |
| multiplyweight!(p, cbds.lambda) | |
| end | |
| if randbool() | |
| node.left.id = node.id | |
| node.right.id = length(p.value.l) | |
| else | |
| node.left.id = length(p.value.l) | |
| node.right.id = node.id | |
| end | |
| end | |
| end | |
| w = Float64[p.weight for p in particles] | |
| @show mean(w) | |
| f += log(mean(w)) | |
| if f == -Inf | |
| return -Inf, 0 | |
| end | |
| particles = collect(map(resetweight, sample(particles, WeightVec(w), N))) | |
| end | |
| w = Float64[p.weight for p in particles] | |
| @show mean(w) | |
| for p in particles | |
| multiplyweight!(p, simulate!(p.value, cbds, 0.0)) | |
| p.value.t = 0 | |
| end | |
| w = Float64[p.weight for p in particles] | |
| @show mean(w) | |
| for p in particles | |
| for l in leaves(tree) | |
| if p.value.l[l.id] != l.color | |
| multiplyweight!(p, 0.0) | |
| break | |
| end | |
| end | |
| if p.weight > 0 | |
| for c = 1:colors | |
| lc = leafcount(tree, c) | |
| multiplyweight!(p, cbds.rho ^ lc * (1 - cbds.rho) ^ (p.value.n[c] - lc)) | |
| end | |
| end | |
| end | |
| w = Float64[p.weight for p in particles] | |
| @show mean(w) | |
| f += log(mean(w)) | |
| f, effective(w) | |
| end | |
| function f_hat(tree::Tree, seis::SEISModel, N::Int=10000) | |
| nodes = collect(internalnodes(tree)) | |
| sort!(nodes, by=n -> n.height, rev=true) | |
| n = length(nodes) + 1 | |
| particles = collect(repeatedly(() -> Particle(SEISTrajectory(seis.N, tree.origin)), N)) | |
| f = 0 | |
| tree.root.id = 1 | |
| for p in particles | |
| newlineage!(p.value, tree.color) | |
| end | |
| for node in nodes | |
| for p in particles | |
| multiplyweight!(p, simulate!(p.value, seis, node.height)) | |
| p.value.t = node.height | |
| if p.value.l[node.id] != node.color | |
| multiplyweight!(p, 0.0) | |
| else | |
| multiplyweight!(p, seis.beta * / seis.N) | |
| newlineage!(p.value) | |
| if randbool() | |
| node.left.id = node.id | |
| node.right.id = length(p.value.l) | |
| else | |
| node.left.id = length(p.value.l) | |
| node.right.id = node.id | |
| end | |
| end | |
| end | |
| w = Float64[p.weight for p in particles] | |
| f += log(mean(w)) | |
| if f == -Inf | |
| return -Inf, 0 | |
| end | |
| particles = collect(map(resetweight, sample(particles, WeightVec(w), N))) | |
| end | |
| w = Float64[p.weight for p in particles] | |
| for p in particles | |
| multiplyweight!(p, simulate!(p.value, cbds, 0.0)) | |
| p.value.t = 0 | |
| end | |
| w = Float64[p.weight for p in particles] | |
| for p in particles | |
| for l in leaves(tree) | |
| if p.value.l[l.id] != l.color | |
| multiplyweight!(p, 0.0) | |
| break | |
| end | |
| end | |
| if p.weight > 0 | |
| multiplyweight!(p, seis.rho ^ n * (1 - seis.rho) ^ (p.value.I - n)) | |
| end | |
| end | |
| w = Float64[p.weight for p in particles] | |
| f += log(mean(w)) | |
| f#, effective(w) | |
| end | |
| effective(weight::Array{Float64,1}) = exp(entropy(weight)) | |
| function entropy(weight::Array{Float64,1}) | |
| nw = Float64[] | |
| for w in weight | |
| if w > 0.0 | |
| push!(nw, w) | |
| end | |
| end | |
| if length(nw) == 0 | |
| return -Inf | |
| end | |
| nw = nw / sum(nw) | |
| -sum(log(nw) .* nw) | |
| end | |
| logsum(x::AbstractArray{Float64}) = x[1] + log(sum(exp(x - x[1]))) | |
| function main() | |
| # for x in 1/16:1/16:3 | |
| # args = (Float64[0.5, 1.0, float(e), float(pi)], 5.0, x, 0.3, 0.6) | |
| # a = f_hat(args..., 100000) | |
| # b = f(args...) | |
| # println(x, "\t", a, "\t", x, "\t", b, "\t", exp(b-a)) | |
| # end | |
| nc = 2 | |
| node = [Node(0.0, 1), Node(0.0, 1), Node(0.0, 1), Node(0.0, 1), Node(0.0, 1), Node(1.0, 1), Node(2.0, 1), Node(float(e), 1), Node(float(pi), 1)] | |
| setchildren!(node[6], node[1], node[2]) | |
| setchildren!(node[7], node[4], node[5]) | |
| setchildren!(node[8], node[6], node[3]) | |
| setchildren!(node[9], node[7], node[8]) | |
| tree = Tree(node[9], 5.0, 1) | |
| # node = [Node(0.0, 1), Node(0.0, 1), Node(1.0, 1)] | |
| # setchildren!(node[3], node[1], node[2]) | |
| # tree = Tree(node[end], 2.0, 1) | |
| # node = [Node(0.0, 1), Node(0.0, 1), Node(0.0, 1), Node(1.0, 1), Node(float(e), 1)] | |
| # setchildren!(node[4], node[1], node[2]) | |
| # setchildren!(node[5], node[3], node[4]) | |
| # tree = Tree(node[end], float(pi), 1) | |
| node = [Node(0.0, 1)] | |
| tree = Tree(node[1], float(pi), 1) | |
| f_hat(tree, ColoredBirthDeathSamplingModel(0.5, 0, 0, 0.1), 1) | |
| # for x in 1/16:1/16:3 | |
| # mu = 0.1 | |
| # rho = 0.5 | |
| # cbds = ColoredBirthDeathSamplingModel(x, 0.25, mu, rho) | |
| # as = Float64[] | |
| # for color in product(1:nc, 1:nc, 1:nc) | |
| # for (c, n) in zip(color, node) | |
| # n.color = c | |
| # end | |
| # push!(as, f_hat(tree, cbds, nc, 10000)) | |
| # end | |
| # a = logsum(as) | |
| # b = f(Float64[1.0], 2.0, x, mu, rho) | |
| # # c = f_hat(Float64[], 1.0, x, mu, rho, 1000) | |
| # println(x, "\t", a, "\t", b, "\t", exp(a-b)) | |
| # end | |
| # lambda = 1.0 | |
| # mu = 0.5 | |
| # rho = 0.8 | |
| # cbds = ColoredBirthDeathSamplingModel(lambda, 1/3, mu, rho) | |
| # truth = f(Float64[1.0], 2.0, lambda, mu, rho) | |
| # f(Float64[1.0, float(e)], float(pi), lambda, mu, rho) | |
| # println("# ", truth) | |
| # println("10 20 50 100 200 500 1000") | |
| # # println("500 1000 2000 4000") | |
| # for _ in 1:100 | |
| # for N in [10, 20, 50, 100, 200, 500, 1000] | |
| # # for N in [500, 1000, 2000, 4000] | |
| # as = Float64[] | |
| # # for color in product(1:nc, 1:nc, 1:nc, 1:nc, 1:nc) | |
| # for color in product(1:nc, 1:nc, 1:nc) | |
| # for (c, n) in zip(color, node) | |
| # n.color = c | |
| # end | |
| # x, y = f_hat(tree, cbds, nc, N) | |
| # push!(as, x) | |
| # end | |
| # a = logsum(as) | |
| # print(a, " ") | |
| # end | |
| # println() | |
| # end | |
| # N = 1000 | |
| # for _ in 1:100 | |
| # x, y = f_hat(tree, cbds, nc, N) | |
| # xs = Float64[] | |
| # ys = Float64[] | |
| # for color in product(1:nc, 1:nc, 1:nc) | |
| # for (c, n) in zip(color, node) | |
| # n.color = c | |
| # end | |
| # x, y = f_hat(tree, cbds, nc, N) | |
| # push!(xs, x) | |
| # push!(ys, y) | |
| # end | |
| # println(sum(ys), " ", exp(logsum(xs) - truth)) | |
| # end | |
| # for N in [10, 20, 50, 100, 200, 500, 1000] | |
| # X = Float64[] | |
| # Y = Float64[] | |
| # for _ in 1:100 | |
| # xs = Float64[] | |
| # ys = Float64[] | |
| # for color in product(1:nc, 1:nc, 1:nc) | |
| # for (c, n) in zip(color, node) | |
| # n.color = c | |
| # end | |
| # x, y = f_hat(tree, cbds, nc, N) | |
| # push!(xs, x) | |
| # push!(ys, y) | |
| # end | |
| # push!(X, logsum(xs)) | |
| # push!(Y, logsum(ys)) | |
| # end | |
| # println(mean(Y), " ", mean(exp(X - truth)), ) | |
| # end | |
| # println(f(Float64[], 0.25, 0.0, 0.0, 0.8)) | |
| # println(f_hat(Float64[], 0.26, 0.0, 0.0, 1.0)) | |
| end | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment