#!/usr/bin/env python
# coding: utf-8
# # Industry Entry-Exit Model
#
#
# **Randall Romero Aguilar, PhD**
#
# This demo is based on the original Matlab demo accompanying the Computational Economics and Finance 2001 textbook by Mario Miranda and Paul Fackler.
#
# Original (Matlab) CompEcon file: **demdp03.m**
#
# Running this file requires the Python version of CompEcon. This can be installed with pip by running
#
# !pip install compecon --upgrade
#
# Last updated: 2022-Oct-10
#
# ## About
#
# A firm operates in an uncertain profit environment. At the beginning of each period, the firm observes its potential short-run operating profit over the coming period $\pi$, which may be negative, and decides whether to operate, making a short-run profit $\pi$, or not operate, making a short-run profit $0$. Although the firm faces no fixed costs, it incurs a shutdown cost $K_0$ when it closes and a start-up cost $K_1$ when it reopens. The short-run profit $\pi$ is an exogenous continuous-valued Markov process
# \begin{equation}
# \pi_{t+1} = h(\pi_t, \epsilon_{t+1})
# \end{equation}
#
# **What is the optimal entry-exit policy?** In particular, how low must the short-run profit be for an operating firm to close, and how high must the short-run profit be for nonoperating firm to reopen?
#
# This is an infinite horizon, stochastic model with time $t$ measured in years. The state variables
# \begin{align}
# \pi &\in (−\infty,\infty)\\
# d &\in \{0, 1\}
# \end{align}
#
# are the current short-run profit, a continuous variable, and the operational status of the firm, a binary variable that equals 1 if the firm is operating and 0 if the firm is not operating. The choice variable
# \begin{equation}
# j \in \{0, 1\}
# \end{equation}
#
# is the operating decision for the coming year, a binary variable that equals 1 if the firm operates and 0 if does not operate. The state transition function is
# \begin{equation}
# g(\pi, d, j, \epsilon) = h(\pi, \epsilon), j)
# \end{equation}
#
# The reward function is
# \begin{equation}
# f(\pi, d, j) = \pi j − K_1(1 − d)j − K_0 d(1 − j)
# \end{equation}
#
# The value of the firm, given that the current short-run profit is $\pi$ and the firm's operational status is $d$, satisfies the Bellman equation
# \begin{equation}
# V(\pi,d) = \max_{j=0,1}\left\{\pi j − K_1(1−d)j − K_0d(1−j) + \delta E_\epsilon V\left(h(\pi,\epsilon),j\right)\right\}
# \end{equation}
#
# In[1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from compecon import BasisSpline, DPmodel,qnwnorm
# ### The reward function
#
# The reward function is
# \begin{equation}
# f(\pi, d, j) = \pi j − K_1(1 − d)j − K_0 d(1 − j)
# \end{equation}
#
# where the exit cost is $K_0=0$ and the entry cost is $K_1=10$.
# In[2]:
K0 = 0.0
K1 = 10
def profit(p, x, d, j):
return p * j - K1 * (1 - d) * j - K0 * d * (1 - j)
# ### The transition function
#
# Assuming that the short-run profit $\pi$ is an exogenous Markov process
# \begin{equation}
# \pi_{t+1} = g(\pi_t,\epsilon_{t+1}) = \bar{\pi} + \gamma(\pi_t − \bar{\pi}) + \epsilon_{t+1}
# \end{equation}
# where $\bar{\pi}=1.0$ and $\gamma=0.7$.
# In[3]:
pbar = 1.0
gamma = 0.7
def transition(p, x, d, j, in_, e):
return pbar + gamma * (p - pbar) + e
# In the transition function $\epsilon_t$ is an i.i.d. normal(0, $σ^2$), with $\sigma=1$. We discretize this distribution by using a discrete distribution, matching the first 10 moments of the normal distribution.
# In[4]:
m = 5 # number of profit shocks
sigma = 1.0
[e,w] = qnwnorm(m,0,sigma **2)
# The collocation method calls for the analyst to select $n$ basis functions $\varphi_j$ and $n$ collocation nodes $(\pi_i,d_i)$, and form the value function approximant $V(\pi,d) \approx \sum_{j=1}^{n} c_j\varphi_j(\pi,d)$ whose coefficients $c_j$ solve the collocation equation
#
# \begin{equation}
# \sum_{j=1}^{n} c_j\varphi_j(\pi_i,d_i) = \max_{x\in\{0,1\}}\left\{\pi_i x − K_1(1−d_i)x − K_0 d_i(1−x) + \delta\sum_{k=1}^{m}\sum_{j=1}^{n}w_k c_j \varphi_j(\hat{\pi}_{ik},x)\right\}
# \end{equation}
#
# where $\hat\pi_{ik}=g(\pi_i,\epsilon_k)$ and where $\epsilon_k$ and $w_k$ represent quadrature nodes and weights for
# the normal shock.
#
# For the approximation, we use a cubic spline basis with $n=250$ nodes between $p_\text{min}=-20$ and $p_\text{max}=20$.
# In[5]:
n = 250
pmin = -20
pmax = 20
basis = BasisSpline(n, pmin, pmax, labels=['profit'])
print(basis)
# Discrete states and discrete actions are
# In[6]:
dstates = ['idle', 'active']
dactions = ['close', 'open']
# The Bellman equation is represeted by a ```DPmodel``` object, where we assume a discount factor of $\delta=0.9$. Notice that the discrete state transition is deterministic, with transition matrix
# \begin{equation}
# h=\begin{bmatrix}0&0\\1&1\end{bmatrix}
# \end{equation}
# In[7]:
model = DPmodel(basis,
profit, transition,
i=dstates,
j=dactions,
discount=0.9, e=e, w=w,
h=[[0, 0], [1, 1]])
# ## SOLUTION
#
# To solve the model, we simply call the ```solve``` method on the ```model``` object.
# In[8]:
S = model.solve(show=True)
S.head()
# ### Plot Action-Contingent Value Functions
# In[9]:
fig1,axs = plt.subplots(1,2,sharey=True, figsize=[12,5])
msgs = ['Profit Entry', 'Profit Exit']
for ax, state in zip(axs, dstates):
subdata = S.loc[state, ['value[close]', 'value[open]']]
ax.plot(subdata)
ax.set(title= f"Value of a currently {state} firm",
xlabel='Potential Profit',
ylabel='Value of Firm')
ax.legend(dactions)
subdata['v.diff'] = subdata['value[open]'] - subdata['value[close]']
pcrit = np.interp(0, subdata['v.diff'], subdata.index)
vcrit = np.interp(pcrit, subdata.index, subdata['value[close]'])
ax.plot(pcrit, vcrit, 'wo')
ax.annotate(f'$p^* = {pcrit:.2f}$', [pcrit, vcrit], fontsize=11, va='top')
# ### Plot Residual
#
# We normalize the residuals as percentage of the value function. Notice the spikes at the "Profit entry" and "Profit exit" points.
# In[10]:
S['resid2'] = 100 * (S.resid / S.value)
fig2, ax = plt.subplots()
ax.plot(S['resid2'].unstack(level=0))
ax.set(title='Bellman Equation Residual',
xlabel='Potential Profit',
ylabel='Percent Residual')
ax.legend(dactions);
# ## SIMULATION
# We simulate the model 50000 times for a time horizon $T=50$, starting with an operating firm ($d=1$) at the long-term profit mean $\bar{\pi}$. To be able to reproduce these results, we set the random seed at an arbitrary value of 945.
# In[11]:
T = 50
nrep = 50000
p0 = np.tile(pbar, (1, nrep))
d0 = 1
data = model.simulate(T, p0, d0, seed=945)
# ### Print Ergodic Moments
# In[12]:
ergodic = pd.DataFrame({
'Ergodic Means' : [data['profit'].mean(), (data['i'] == 'active').mean()],
'Ergodic Standard Deviations': [data['profit'].std(), (data['i'] == 'active').std()]},
index=['Profit Contribution', 'Activity'])
ergodic.round(2)
# ### Plot Simulated and Expected Continuous State Path
# In[13]:
subdata = data.query("_rep < 3").set_index(["time", "_rep"]).unstack()
fig3, ax = plt.subplots()
ax.plot(subdata["profit"])
ax.set(title='Simulated and Expected Profit Contribution',
xlabel='Period',
ylabel='Profit Contribution')
ax.plot(data[['time','profit']].groupby('time').mean(),'k--',label='mean')
ax.legend();
# ### Plot Expected Discrete State Path
# In[14]:
data['ii'] = data['i'] == 'active'
probability_of_active = data[['time','ii']].groupby('time').mean()
fig4, ax = plt.subplots()
ax.plot(probability_of_active)
ax.set(title='Probability of Operation',
xlabel='Period',
ylabel='Probability');