How to read this lecture...

Code should execute sequentially if run in a Jupyter notebook

The McCall Job Search Model

Overview

The McCall search model [McC70] helped transform economists’ way of thinking about labor markets

It did this by casting

  • the loss of a job as a capital loss, and
  • a spell of unemployment as an investment in searching for an acceptable job

To solve the model, we follow McCall in using dynamic programming

Dynamic programming was discussed previously in the lecture on shortest paths

The McCall model is a nice vehicle for readers to start to make themselves more comfortable with this approach to optimization

(More extensive and more formal treatments of dynamic programming are given in later lectures)

The Model

The model concerns the life of an infinitely lived worker and

  • the opportunities he or she (let’s say he to save one character) has to work at different wages
  • exogenous events that destroy his current job
  • his decision making process while unemployed

It is assumed that the worker lives forever

He can be in one of two states: employed or unemployed

He wants to maximize

(1)\[{\mathbb E} \sum_{t=0}^\infty \beta^t u(y_t)\]

which represents the expected value of the discounted utility of his income

The constant \(\beta\) lies in \((0, 1)\) and is called a discount factor

The smaller is \(\beta\), the more the worker discounts future utility relative to current utility

The variable \(y_t\) is

  • his wage \(w_t\) when employed
  • unemployment compensation \(c\) when unemployed

The function \(u\) is a utility function satisfying \(u'> 0\) and \(u'' < 0\)

Timing and Decisions

Let’s consider what happens at the start of a given period (e.g., a month, if the timing of the model is monthly)

If currently employed, the worker consumes his wage \(w\), receiving utility \(u(w)\)

If currently unemployed, he

  • receives and consumes unemployment compensation \(c\)
  • receives an offer to start work next period at a wage \(w'\) drawn from a known distribution \(p\)

He can either accept or reject the offer

If he accepts the offer, he enters next period employed with wage \(w'\)

If he rejects the offer, he enters next period unemployed

(Note that we do not allow for job search while employed—this topic is taken up in a later lecture)

Job Termination

When employed, he faces a constant probability \(\alpha\) of becoming unemployed at the end of the period

Solving the Model using Dynamic Programming

As promised, we shall solve the McCall search model using dynamic programming

Dynamic programming is an ingenious method for solving a problem that starts by

  1. assuming that you know the answer,
  2. writing down some natural conditions that the answer must satisfy, then
  3. solving those conditions to find the answer

So here goes

Let

  • \(V(w)\) be the total lifetime value accruing to a worker who enters the current period employed with wage \(w\)
  • \(U\) be the total lifetime value accruing to a worker who is unemployed this period

Here value means the value of the objective function (1) when the worker makes optimal decisions now and at all future points in time

Suppose for now that the worker can calculate the function \(V\) and the constant \(U\) and use them in his decision making

In this case, a little thought will convince you that \(V\) and \(U\) should satisfy

(2)\[V(w) = u(w) + \beta [(1-\alpha)V(w) + \alpha U ]\]

and

(3)\[U = u(c) + \beta \sum_{w'} \max \left\{ U, V(w') \right\} p(w')\]

The sum is over all possible wage values, which we assume for convenience is finite

Let’s interpret these two equations in light of the fact that today’s tomorrow is tomorrow’s today

  • The left hand sides of equations (2) and (3) are the values of a worker in a particular situation today
  • The right hand sides of the equations are the discounted (by \(\beta\)) expected values of the possible situations that worker can be in tomorrow
  • But tomorrow the worker can be in only one of the situations whose values today are on the left sides of our two equations

Equation (3) incorporates the fact that a currently unemployed worker will maximize his own welfare

In particular, if his next period wage offer is \(w'\), he will choose to remain unemployed unless \(U < V(w')\)

Equations (2) and (3) are called Bellman equations after the mathematician Richard Bellman

It turns out that equations (2) and (3) provide enough information to solve out for both \(V\) and \(U\)

Before discussing this, however, let’s make a small extension to the model

Stochastic Offers

Let’s suppose now that unemployed workers don’t always receive job offers

Instead, let’s suppose that unemployed workers only receive an offer with probability \(\gamma\)

If our worker does receive an offer, the wage offer is drawn from \(p\) as before

He either accepts or rejects the offer

Otherwise the model is the same

With some thought, you will be able to convince yourself that \(V\) and \(U\) should now satisfy

(4)\[V(w) = u(w) + \beta [(1-\alpha)V(w) + \alpha U ]\]

and

(5)\[U = u(c) + \beta (1 - \gamma) U + \beta \gamma \sum_{w'} \max \left\{ U, V(w') \right\} p(w')\]

Solving the Bellman Equations

The Bellman equations are nonlinear in \(U\) and \(V\), and hence not trivial to solve

One way to solve them is to

  1. make guesses for \(U\) and \(V\)
  2. plug these guesses into the right hand sides of (4) and (5)
  3. update the left hand sides from this rule and then repeat

In other words, we are iterating using the rules

(6)\[V_{n+1} (w) = u(w) + \beta [(1-\alpha)V_n (w) + \alpha U_n ]\]

and

(7)\[U_{n+1} = u(c) + \beta (1 - \gamma) U_n + \beta \gamma \sum_{w'} \max \{ U_n, V_n(w') \} p(w')\]

starting from some initial conditions \(U_0, V_0\)

This procedure is called iterating on the Bellman equations

It turns out that these iterations are guaranteed to converge to the \(V\) and \(U\) that solve (4) and (5)

We discuss the theory behind this property extensively in later lectures (see, e.g., the discussion in this lecture)

For now let’s try implementing the iteration scheme to see what the solutions look like

Implementation

Code to iterate on the Bellman equations can be found in mccall_bellman_iteration.jl

We repeat it here for convenience

In the code you’ll see that we use a type to store the various parameters and other objects associated with a given model

This helps to tidy up the code and provides an object that’s easy to pass to functions

The default utility function is a CRRA utility function

using Distributions

# A default utility function

function u(c::Real, sigma::Real)
    if c > 0
        return (c^(1 - sigma) - 1) / (1 - sigma)
    else
        return -10e6
    end
end

# default wage vector with probabilities

const n = 60                                   # n possible outcomes for wage
const default_w_vec = linspace(10, 20, n)   # wages between 10 and 20
const a, b = 600, 400                          # shape parameters
const dist = BetaBinomial(n-1, a, b)
const default_p_vec = pdf(dist)

mutable struct McCallModel{TF <: AbstractFloat,
                           TAV <: AbstractVector{TF},
                           TAV2 <: AbstractVector{TF}}
    alpha::TF        # Job separation rate
    beta::TF         # Discount rate
    gamma::TF        # Job offer rate
    c::TF            # Unemployment compensation
    sigma::TF        # Utility parameter
    w_vec::TAV # Possible wage values
    p_vec::TAV2 # Probabilities over w_vec

    McCallModel(alpha::TF=0.2,
                beta::TF=0.98,
                gamma::TF=0.7,
                c::TF=6.0,
                sigma::TF=2.0,
                w_vec::TAV=default_w_vec,
                p_vec::TAV2=default_p_vec) where {TF, TAV, TAV2} =
        new{TF, TAV, TAV2}(alpha, beta, gamma, c, sigma, w_vec, p_vec)
end

"""
A function to update the Bellman equations.  Note that V_new is modified in
place (i.e, modified by this function).  The new value of U is returned.

"""
function update_bellman!(mcm::McCallModel, V::AbstractVector,
                         V_new::AbstractVector, U::Real)
    # Simplify notation
    alpha, beta, sigma, c, gamma = mcm.alpha, mcm.beta, mcm.sigma, mcm.c, mcm.gamma

    for (w_idx, w) in enumerate(mcm.w_vec)
        # w_idx indexes the vector of possible wages
        V_new[w_idx] = u(w, sigma) + beta * ((1 - alpha) * V[w_idx] + alpha * U)
    end

    U_new = u(c, sigma) + beta * (1 - gamma) * U +
                    beta * gamma * dot(max.(U, V), mcm.p_vec)

    return U_new
end


function solve_mccall_model(mcm::McCallModel;
                            tol::AbstractFloat=1e-5, max_iter::Integer=2000)

    V = ones(length(mcm.w_vec))  # Initial guess of V
    V_new = similar(V)           # To store updates to V
    U = 1.0                        # Initial guess of U
    i = 0
    error = tol + 1

    while error > tol && i < max_iter
        U_new = update_bellman!(mcm, V, V_new, U)
        error_1 = maximum(abs, V_new - V)
        error_2 = abs(U_new - U)
        error = max(error_1, error_2)
        V[:] = V_new
        U = U_new
        i += 1
    end

    return V, U
end

The approch is to iterate until successive iterates are closer together than some small tolerance level

We then return the current iterate as an approximate solution

Let’s plot the approximate solutions \(U\) and \(V\) to see what they look like

We’ll use the default parameterizations found in the code above

using Plots, LaTeXStrings
pyplot()


mcm = McCallModel()
V, U = solve_mccall_model(mcm)
U_vec = U .* ones(length(mcm.w_vec))

plot(mcm.w_vec, 
        [V U_vec],
        lw=2, 
        alpha=0.7, 
        label=[L"$V$" L"$U$"])

Here’s the plot this code produces

../_images/mccall_vf_plot1.png

The value \(V\) is increasing because higher \(w\) generates a higher wage flow conditional on staying employed

The Reservation Wage

Once \(V\) and \(U\) are known, the agent can use them to make decisions in the face of a given wage offer

If \(V(w) > U\), then working at wage \(w\) is preferred to unemployment

If \(V(w) < U\), then remaining unemployed will generate greater lifetime value

Suppose in particular that \(V\) crosses \(U\) (as it does in the preceding figure)

Then, since \(V\) is increasing, there is a unique smallest \(w\) in the set of possible wages such that \(V(w) \geq U\)

We denote this wage \(\bar w\) and call it the reservation wage

Optimal behavior for the worker is characterized by \(\bar w\)

  • if the wage offer \(w\) in hand is greater than or equal to \(\bar w\), then the worker accepts
  • if the wage offer \(w\) in hand is less than \(\bar w\), then the worker rejects

Here’s a function called compute_reservation_wage that takes an instance of a McCall model and returns the reservation wage associated with a given model

It uses np.searchsorted to obtain the first \(w\) in the set of possible wages such that \(V(w) > U\)

If \(V(w) < U\) for all \(w\), then the function returns np.inf

"""
Computes the reservation wage of an instance of the McCall model
by finding the smallest w such that V(w) > U.

If V(w) > U for all w, then the reservation wage w_bar is set to
the lowest wage in mcm.w_vec.

If v(w) < U for all w, then w_bar is set to np.inf.

Parameters
----------
mcm : an instance of McCallModel
return_values : bool (optional, default=false)
    Return the value functions as well

Returns
-------
w_bar : scalar
    The reservation wage

"""
function compute_reservation_wage(mcm::McCallModel; return_values::Bool=false)

    V, U = solve_mccall_model(mcm)
    w_idx = searchsortedfirst(V - U, 0)

    if w_idx == length(V)
        w_bar = Inf
    else
        w_bar = mcm.w_vec[w_idx]
    end

    if return_values == false
        return w_bar
    else
        return w_bar, V, U
    end

end

Let’s use it to look at how the reservation wage varies with parameters

In each instance below we’ll show you a figure and then ask you to reproduce it in the exercises

The Reservation Wage and Unemployment Compensation

First, let’s look at how \(\bar w\) varies with unemployment compensation

In the figure below, we use the default parameters in the McCallModel type, apart from c (which takes the values given on the horizonal axis)

../_images/mccall_resw_c.png

As expected, higher unemployment compensation causes the worker to hold out for higher wages

In effect, the cost of continuing job search is reduced

The Reservation Wage and Discounting

Next let’s investigate how \(\bar w\) varies with the discount rate

The next figure plots the reservation wage associated with different values of \(\beta\)

../_images/mccall_resw_beta.png

Again, the results are intuitive: More patient workers will hold out for higher wages

The Reservation Wage and Job Destruction

Finally, let’s look at how \(\bar w\) varies with the job separation rate \(\alpha\)

Higher \(\alpha\) translates to a greater chance that a worker will face termination in each period once employed

../_images/mccall_resw_alpha.png

Once more, the results are in line with our intuition

If the separation rate is high, then the benefit of holding out for a higher wage falls

Hence the reservation wage is lower

Exercises

Exercise 1

Reproduce all the reservation wage figures shown above

Exercise 2

Plot the reservation wage against the job offer rate \(\gamma\)

Use

grid_size = 25
gamma_vals = linspace(0.05, 0.95, grid_size)

Interpret your results

Solutions

Exercise 1

Using the compute_reservation_wage function mentioned earlier in the lecture, we can create an array for reserveration wages for different values of \(c\), \(\beta\) and \(\alpha\) and plot the results like so

using Plots, LaTeXStrings
pyplot()


grid_size = 25  
c_vals = linspace(2, 12, grid_size)  
w_bar_vals = similar(c_vals)

mcm = McCallModel()

for (i, c) in enumerate(c_vals)
    mcm.c = c
    w_bar = compute_reservation_wage(mcm)
    w_bar_vals[i] = w_bar
end

plot(c_vals, 
    w_bar_vals, 
    lw=2, 
    alpha=0.7, 
    xlabel="unemployment compensation",
    ylabel="reservation wage",
    label=L"$\bar w$ as a function of $c$")

Exercise 2

Similar to above, we can plot \(\bar w\) against \(\gamma\) as follows

grid_size = 25  
gamma_vals = linspace(0.05, 0.95, grid_size)  
w_bar_vals = similar(gamma_vals)

mcm = McCallModel()

for (i, gamma) in enumerate(gamma_vals)
    mcm.gamma = gamma
    w_bar = compute_reservation_wage(mcm)
    w_bar_vals[i] = w_bar
end

plot(gamma_vals, 
    w_bar_vals, 
    lw=2, 
    alpha=0.7, 
    xlabel="job offer rate",
    ylabel="reservation wage",
    label=L"$\bar w$ as a function of $\gamma$")
../_images/mccall_model_solutions_ex2_jl.png

As expected, the reservation wage increases in \(\gamma\)

This is because higher \(\gamma\) translates to a more favorable job search environment

Hence workers are less willing to accept lower offers