Chapter 3: Markov Dynamics#

inventory_sim.jl#

Hide code cell source
using Distributions, IterTools, QuantEcon

function create_inventory_model(; S=100,  # Order size
                                  s=10,   # Order threshold
                                  p=0.4)  # Demand parameter
    ϕ = Geometric(p)
    h(x, d) = max(x - d, 0) + S*(x <= s)
    return (; S, s, p, ϕ, h)
end

"Simulate the inventory process."
function sim_inventories(model; ts_length=200)
    (; S, s, p, ϕ, h) = model
    X = Vector{Int32}(undef, ts_length)
    X[1] = S  # Initial condition
    for t in 1:(ts_length-1)
        X[t+1] = h(X[t], rand(ϕ))
    end
    return X
end

"Compute the transition probabilities and state."
function compute_mc(model; d_max=100)
    (; S, s, p, ϕ, h) = model
    n = S + s + 1  # Size of state space
    state_vals = collect(0:(S + s))
    P = Matrix{Float64}(undef, n, n)
    for (i, j) in product(1:n, 1:n)
        P[i, j] = sum((h(i-1, d) == j-1)*pdf(ϕ, d) for d in 0:d_max)
    end
    return MarkovChain(P, state_vals)
end

"Compute the stationary distribution of the model."
function compute_stationary_dist(model)
    mc = compute_mc(model)
    return mc.state_values, stationary_distributions(mc)[1]
end


# Plots

using PyPlot
using LaTeXStrings
PyPlot.matplotlib[:rc]("text", usetex=true) # allow tex rendering


function plot_ts(model; fontsize=16, 
                   figname="figures/inventory_sim_1.pdf",
                   savefig=false)
    (; S, s, p, ϕ, h) = model
    X = sim_inventories(model)
    fig, ax = plt.subplots(figsize=(9, 5.2))
    ax.plot(X, label=L"X_t", lw=3, alpha=0.6)
    ax.set_xlabel(L"t", fontsize=fontsize)
    ax.set_ylabel("inventory", fontsize=fontsize)
    ax.legend(fontsize=fontsize, frameon=false)
    ax.set_ylim(0, S + s + 20)

    if savefig == true
        fig.savefig(figname)
    end
end


function plot_hist(model; fontsize=16, 
                   figname="figures/inventory_sim_2.pdf",
                   savefig=false)
    (; S, s, p, ϕ, h) = model
    state_values, ψ_star = compute_stationary_dist(model) 
    X = sim_inventories(model; ts_length=1_000_000)
    histogram = [mean(X .== i) for i in state_values]

    fig, ax = plt.subplots(figsize=(9, 5.2))
    ax.plot(state_values, ψ_star, "k-",  lw=3, alpha=0.7, label=L"\psi^*")
    ax.bar(state_values, histogram, alpha=0.7, label="frequency")
    ax.set_xlabel("state", fontsize=fontsize)

    ax.legend(fontsize=fontsize, frameon=false)
    ax.set_ylim(0, 0.015)

    if savefig == true
        fig.savefig(figname)
    end
end
ArgumentError: Package Distributions not found in current path.
- Run `import Pkg; Pkg.add("Distributions")` to install the Distributions package.

Stacktrace:
 [1] macro expansion
   @ ./loading.jl:1630 [inlined]
 [2] macro expansion
   @ ./lock.jl:267 [inlined]
 [3] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1611
model = create_inventory_model()
UndefVarError: `create_inventory_model` not defined

Stacktrace:
 [1] top-level scope
   @ In[3]:1
plot_ts(model; savefig=true)
UndefVarError: `plot_ts` not defined

Stacktrace:
 [1] top-level scope
   @ In[4]:1
plot_hist(model; savefig=true)
UndefVarError: `plot_hist` not defined

Stacktrace:
 [1] top-level scope
   @ In[5]:1

is_irreducible.jl#

Hide code cell source
using QuantEcon
P = [0.1 0.9;
     0.0 1.0]
mc = MarkovChain(P)
print(is_irreducible(mc))
ArgumentError: Package QuantEcon [fcd29c91-0bd7-5a09-975d-7ac3f643a60c] is required but does not seem to be installed:
 - Run `Pkg.instantiate()` to install all recorded dependencies.


Stacktrace:
 [1] _require(pkg::Base.PkgId, env::String)
   @ Base ./loading.jl:1774
 [2] _require_prelocked(uuidkey::Base.PkgId, env::String)
   @ Base ./loading.jl:1660
 [3] macro expansion
   @ ./loading.jl:1648 [inlined]
 [4] macro expansion
   @ ./lock.jl:267 [inlined]
 [5] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1611

laborer_sim.jl#

Hide code cell source
function create_laborer_model(; α=0.3, β=0.2)
    return (; α, β)
end

function laborer_update(x, model)  # update X from t to t+1
    (; α, β) = model
    if x == 1    
        x′ = rand() < α ? 2 : 1
    else 
        x′ = rand() < β ? 1 : 2
    end
    return x′
end

function sim_chain(k, p, model)
    X = Array{Int32}(undef, k)
    X[1] = rand() < p ? 1 : 2
    for t in 1:(k-1)
        X[t+1] = laborer_update(X[t], model)
    end
    return X
end

function test_convergence(; k=10_000_000, p=0.5)
    model = create_laborer_model()
    (; α, β) = model
    ψ_star = (1/(α + β)) * [β α]

    X = sim_chain(k, p, model)
    ψ_e = (1/k) * [sum(X .== 1)  sum(X .== 2)]
    error = maximum(abs.(ψ_star - ψ_e))
    approx_equal = isapprox(ψ_star, ψ_e, rtol=0.01)
    println("Sup norm deviation is $error")
    println("Approximate equality is $approx_equal")
 end
test_convergence (generic function with 1 method)

markov_js.jl#

Hide code cell source
"""
Infinite-horizon job search with Markov wage draws.

"""

using QuantEcon, LinearAlgebra
include("s_approx.jl")

"Creates an instance of the job search model with Markov wages."
function create_markov_js_model(;
        n=200,       # wage grid size
        ρ=0.9,       # wage persistence
        ν=0.2,       # wage volatility
        β=0.98,      # discount factor
        c=1.0        # unemployment compensation
    )
    mc = tauchen(n, ρ, ν)
    w_vals, P = exp.(mc.state_values), mc.p
    return (; n, w_vals, P, β, c)
end

" The Bellman operator Tv = max{e, c + β P v} with e(w) = w / (1-β)."
function T(v, model)
    (; n, w_vals, P, β, c) = model
    h = c .+ β * P * v
    e = w_vals ./ (1 - β)
    return max.(e, h)
end

" Get a v-greedy policy."
function get_greedy(v, model)
    (; n, w_vals, P, β, c) = model
    σ = w_vals / (1 - β) .>= c .+ β * P * v
    return σ
end

"Solve the infinite-horizon Markov job search model by VFI."
function vfi(model) 
    v_init = zero(model.w_vals)  
    v_star = successive_approx(v -> T(v, model), v_init)
    σ_star = get_greedy(v_star, model)
    return v_star, σ_star
end

        

# == Policy iteration == #

"Get the value of policy σ."
function get_value(σ, model)
    (; n, w_vals, P, β, c) = model
    e = w_vals ./ (1 - β)
    K_σ = β .* (1 .- σ) .* P
    r_σ = σ .* e .+ (1 .- σ) .* c
    return (I - K_σ) \ r_σ
end


    
"Howard policy iteration routine."
function policy_iteration(model)
    σ = Vector{Bool}(undef, model.n)
    i, error = 0, 1.0
    while error > 0
        v_σ = get_value(σ, model)
        σ_new = get_greedy(v_σ, model)
        error = maximum(abs.(σ_new - σ))
        σ = σ_new
        i = i + 1
        println("Concluded loop $i with error $error.")
    end
    return σ
end


# == Plots == #

using PyPlot
using LaTeXStrings
PyPlot.matplotlib[:rc]("text", usetex=true) # allow tex rendering
fontsize=16

default_model = create_markov_js_model()


function plot_main(; model=default_model,
                     method="vfi", 
                     savefig=false, 
                     figname="figures/markov_js_1.pdf")
    (; n, w_vals, P, β, c) = model


    if method == "vfi"
        v_star, σ_star = vfi(model)
    else
        σ_star = policy_iteration(model)
        v_star = get_value(σ_star, model)
    end

    h_star = c .+ β * P * v_star
    e = w_vals / (1 - β)

    fig, ax = plt.subplots(figsize=(9, 5.2))
    ax.plot(w_vals, h_star, lw=4, ls="--", alpha=0.4, label=L"h^*(w)")
    ax.plot(w_vals, e, lw=4, ls="--", alpha=0.4, label=L"w/(1-\beta)")
    ax.plot(w_vals, max.(e, h_star), "k-", alpha=0.7, label=L"v^*(w)")
    ax.legend(frameon=false, fontsize=fontsize)
    ax.set_xlabel(L"w", fontsize=fontsize)
    if savefig
        fig.savefig(figname)
    end
end
ArgumentError: Package QuantEcon [fcd29c91-0bd7-5a09-975d-7ac3f643a60c] is required but does not seem to be installed:
 - Run `Pkg.instantiate()` to install all recorded dependencies.


Stacktrace:
 [1] _require(pkg::Base.PkgId, env::String)
   @ Base ./loading.jl:1774
 [2] _require_prelocked(uuidkey::Base.PkgId, env::String)
   @ Base ./loading.jl:1660
 [3] macro expansion
   @ ./loading.jl:1648 [inlined]
 [4] macro expansion
   @ ./lock.jl:267 [inlined]
 [5] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1611
plot_main(savefig=true)
UndefVarError: `plot_main` not defined

Stacktrace:
 [1] top-level scope
   @ In[9]:1

markov_js_with_sep.jl#

Hide code cell source
"""
Infinite-horizon job search with Markov wage draws and separation.

"""

include("s_approx.jl")
using QuantEcon, LinearAlgebra

"Creates an instance of the job search model with separation."
function create_js_with_sep_model(;
        n=200,          # wage grid size
        ρ=0.9, ν=0.2,   # wage persistence and volatility
        β=0.98, α=0.1,  # discount factor and separation rate
        c=1.0)          # unemployment compensation
    mc = tauchen(n, ρ, ν)
    w_vals, P = exp.(mc.state_values), mc.p
    return (; n, w_vals, P, β, c, α)
end

" The Bellman operator for the value of being unemployed."
function T(v, model)
    (; n, w_vals, P, β, c, α) = model
    d = 1 / (1 - β * (1 - α))
    accept = d * (w_vals + α * β * P * v)
    reject = c .+ β * P * v
    return max.(accept, reject)
end

" Get a v-greedy policy."
function get_greedy(v, model)
    (; n, w_vals, P, β, c, α) = model
    d = 1 / (1 - β * (1 - α))
    accept = d * (w_vals + α * β * P * v)
    reject = c .+ β * P * v
    σ = accept .>= reject
    return σ
end

"Solve by VFI."
function vfi(model) 
    v_init = zero(model.w_vals)  
    v_star = successive_approx(v -> T(v, model), v_init)
    σ_star = get_greedy(v_star, model)
    return v_star, σ_star
end


# == Plots == #

using PyPlot
using LaTeXStrings
PyPlot.matplotlib[:rc]("text", usetex=true) # allow tex rendering
fontsize=16

default_model = create_js_with_sep_model()


function plot_main(; model=default_model,
                     method="vfi", 
                     savefig=false, 
                     figname="figures/markov_js_with_sep_1.pdf")
    (; n, w_vals, P, β, c, α) = model
    v_star, σ_star = vfi(model)

    d = 1 / (1 - β * (1 - α))
    accept = d * (w_vals + α * β * P * v_star)
    h_star = c .+ β * P * v_star

    w_star = Inf
    for (i, w) in enumerate(w_vals)
        if accept[i]  h_star[i]
            w_star = w
            break
        end
    end
    @assert w_star < Inf "Agent never accepts"

    fig, ax = plt.subplots(figsize=(9, 5.2))
    ax.plot(w_vals, h_star, lw=4, ls="--", alpha=0.4, label="continuation value")
    ax.plot(w_vals, accept, lw=4, ls="--", alpha=0.4, label="stopping value")
    ax.plot(w_vals, v_star, "k-", alpha=0.7, label=L"v_u^*(w)")
    ax.legend(frameon=false, fontsize=fontsize)
    ax.set_xlabel(L"w", fontsize=fontsize)
    if savefig
        fig.savefig(figname)
    end
end

function plot_w_stars(; α_vals=LinRange(0.0, 1.0, 10),
                        savefig=false, 
                        figname="figures/markov_js_with_sep_2.pdf")

    w_star_vec = similar(α_vals)
    for (i_α, α) in enumerate(α_vals)
        print(i_α, α)
        model = create_js_with_sep_model(α=α)
        (; n, w_vals, P, β, c, α) = model
        v_star, σ_star = vfi(model)

        d = 1 / (1 - β * (1 - α))
        accept = d * (w_vals + α * β * P * v_star)
        h_star = c .+ β * P * v_star

        w_star = Inf
        for (i_w, w) in enumerate(w_vals)
            if accept[i_w]  h_star[i_w]
                w_star = w
                break
            end
        end
        @assert w_star < Inf "Agent never accepts"
        w_star_vec[i_α] = w_star
    end

    fig, ax = plt.subplots(figsize=(9, 5.2))
    ax.plot(α_vals, w_star_vec, lw=2, alpha=0.6, label="reservation wage")
    ax.legend(frameon=false, fontsize=fontsize)
    ax.set_xlabel(L"\alpha", fontsize=fontsize)
    ax.set_xlabel(L"w", fontsize=fontsize)
    if savefig
        fig.savefig(figname)
    end
end
ArgumentError: Package QuantEcon [fcd29c91-0bd7-5a09-975d-7ac3f643a60c] is required but does not seem to be installed:
 - Run `Pkg.instantiate()` to install all recorded dependencies.


Stacktrace:
 [1] _require(pkg::Base.PkgId, env::String)
   @ Base ./loading.jl:1774
 [2] _require_prelocked(uuidkey::Base.PkgId, env::String)
   @ Base ./loading.jl:1660
 [3] macro expansion
   @ ./loading.jl:1648 [inlined]
 [4] macro expansion
   @ ./lock.jl:267 [inlined]
 [5] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1611
plot_main(savefig=true)
UndefVarError: `plot_main` not defined

Stacktrace:
 [1] top-level scope
   @ In[11]:1
plot_w_stars(savefig=true)
UndefVarError: `plot_w_stars` not defined

Stacktrace:
 [1] top-level scope
   @ In[12]:1