using InstantiateFromURL github_project("QuantEcon/quantecon-notebooks-julia", version = "0.2.0") using LinearAlgebra, Statistics, Compat using Plots, QuantEcon, Distributions gr(fmt=:png); n = 50 a_vals = [0.5, 1, 100] b_vals = [0.5, 1, 100] plt = plot() for (a, b) in zip(a_vals, b_vals) ab_label = "a = $a, b = $b" dist = BetaBinomial(n, a, b) plot!(plt, 0:n, pdf.(dist, support(dist)), label = ab_label) end plt function CareerWorkerProblem(;β = 0.95, B = 5.0, N = 50, F_a = 1.0, F_b = 1.0, G_a = 1.0, G_b = 1.0) θ = range(0, B, length = N) ϵ = copy(θ) dist_F = BetaBinomial(N-1, F_a, F_b) dist_G = BetaBinomial(N-1, G_a, G_b) F_probs = pdf.(dist_F, support(dist_F)) G_probs = pdf.(dist_G, support(dist_G)) F_mean = sum(θ .* F_probs) G_mean = sum(ϵ .* G_probs) return (β = β, N = N, B = B, θ = θ, ϵ = ϵ, F_probs = F_probs, G_probs = G_probs, F_mean = F_mean, G_mean = G_mean) end function update_bellman!(cp, v, out; ret_policy = false) # new life. This is a function of the distribution parameters and is # always constant. No need to recompute it in the loop v3 = (cp.G_mean + cp.F_mean .+ cp.β .* cp.F_probs' * v * cp.G_probs)[1] # do not need 1 element array for j in 1:cp.N for i in 1:cp.N # stay put v1 = cp.θ[i] + cp.ϵ[j] + cp.β * v[i, j] # new job v2 = (cp.θ[i] .+ cp.G_mean .+ cp.β .* v[i, :]' * cp.G_probs)[1] # do not need a single element array if ret_policy if v1 > max(v2, v3) action = 1 elseif v2 > max(v1, v3) action = 2 else action = 3 end out[i, j] = action else out[i, j] = max(v1, v2, v3) end end end end function update_bellman(cp, v; ret_policy = false) out = similar(v) update_bellman!(cp, v, out, ret_policy = ret_policy) return out end function get_greedy!(cp, v, out) update_bellman!(cp, v, out, ret_policy = true) end function get_greedy(cp, v) update_bellman(cp, v, ret_policy = true) end wp = CareerWorkerProblem() v_init = fill(100.0, wp.N, wp.N) func(x) = update_bellman(wp, x) v = compute_fixed_point(func, v_init, max_iter = 500, verbose = false) plot(linetype = :surface, wp.θ, wp.ϵ, transpose(v), xlabel="theta", ylabel="epsilon", seriescolor=:plasma, gridalpha = 1) wp = CareerWorkerProblem() function solve_wp(wp) v_init = fill(100.0, wp.N, wp.N) func(x) = update_bellman(wp, x) v = compute_fixed_point(func, v_init, max_iter = 500, verbose = false) optimal_policy = get_greedy(wp, v) return v, optimal_policy end v, optimal_policy = solve_wp(wp) F = DiscreteRV(wp.F_probs) G = DiscreteRV(wp.G_probs) function gen_path(T = 20) i = j = 1 θ_ind = Int[] ϵ_ind = Int[] for t=1:T # do nothing if stay put if optimal_policy[i, j] == 2 # new job j = rand(G)[1] elseif optimal_policy[i, j] == 3 # new life i, j = rand(F)[1], rand(G)[1] end push!(θ_ind, i) push!(ϵ_ind, j) end return wp.θ[θ_ind], wp.ϵ[ϵ_ind] end plot_array = Any[] for i in 1:2 θ_path, ϵ_path = gen_path() plt = plot(ϵ_path, label="epsilon") plot!(plt, θ_path, label="theta") plot!(plt, legend=:bottomright) push!(plot_array, plt) end plot(plot_array..., layout = (2,1)) function gen_first_passage_time(optimal_policy) t = 0 i = j = 1 while true if optimal_policy[i, j] == 1 # Stay put return t elseif optimal_policy[i, j] == 2 # New job j = rand(G)[1] else # New life i, j = rand(F)[1], rand(G)[1] end t += 1 end end M = 25000 samples = zeros(M) for i in 1:M samples[i] = gen_first_passage_time(optimal_policy) end print(median(samples)) wp2 = CareerWorkerProblem(β=0.99) v2, optimal_policy2 = solve_wp(wp2) samples2 = zeros(M) for i in 1:M samples2[i] = gen_first_passage_time(optimal_policy2) end print(median(samples2)) wp = CareerWorkerProblem(); v, optimal_policy = solve_wp(wp) lvls = [0.5, 1.5, 2.5, 3.5] x_grid = range(0, 5, length = 50) y_grid = range(0, 5, length = 50) contour(x_grid, y_grid, optimal_policy', fill=true, levels=lvls,color = :Blues, fillalpha=1, cbar = false) contour!(xlabel="theta", ylabel="epsilon") annotate!([(1.8,2.5, text("new life", 14, :white, :center))]) annotate!([(4.5,2.5, text("new job", 14, :center))]) annotate!([(4.0,4.5, text("stay put", 14, :center))]) wp = CareerWorkerProblem(G_a=100.0, G_b=100.0); # use new params v, optimal_policy = solve_wp(wp) lvls = [0.5, 1.5, 2.5, 3.5] x_grid = range(0, 5, length = 50) y_grid = range(0, 5, length = 50) contour(x_grid, y_grid, optimal_policy', fill=true, levels=lvls,color = :Blues, fillalpha=1, cbar = false) contour!(xlabel="theta", ylabel="epsilon") annotate!([(1.8,2.5, text("new life", 14, :white, :center))]) annotate!([(4.5,2.5, text("new job", 14, :center))]) annotate!([(4.0,4.5, text("stay put", 14, :center))])