예제 #1
0
    def test_spli_shape(self):
        n, a, b = 35, -3, 3
        basis = BasisSpline(n, a, b)
        assert_equal(basis.nodes.size, n)
        assert_equal(basis.Phi().shape, (n, n))
        assert_equal(basis._diff(0, 2).shape, (n - 2, n))
        assert_equal(basis._diff(0, -3).shape, (n + 3, n))
        assert_equal(basis().shape, (n, ))

        nx = 24
        x = np.linspace(a, b, nx)
        assert_equal(basis.Phi(x).shape, (nx, n))
        assert_equal(basis.Phi(x, 1).shape, (nx, n))
        assert_equal(basis.Phi(x, -1).shape, (nx, n))
        assert_equal(basis(x).shape, (nx, ))
예제 #2
0
    def test_cheb_2d(self):
        n, a, b = [5, 9], -3, 3
        s = 2
        nn = n[0] * n[1]
        basis = BasisSpline(n, a, b, s=s)
        assert_equal(basis.nodes.shape, (len(n), nn))
        assert_equal(basis.Phi().shape, (nn, nn))
        assert_equal(basis._diff(0, 2).shape, (n[0] - 2, n[0]))
        assert_equal(basis._diff(1, -3).shape, (n[1] + 3, n[1]))
        assert_equal(basis().shape, (s, nn))

        nx = [15, 16]
        nnx = nx[0] * nx[1]
        x = gridmake([np.linspace(a, b, j) for j in nx])
        assert_equal(basis.Phi(x).shape, (nnx, nn))
        assert_equal(basis.Phi(x, [[1], [0]]).shape, (nnx, nn))
        assert_equal(basis.Phi(x, [[0], [-1]]).shape, (nnx, nn))
        assert_equal(basis(x).shape, (s, nnx))
예제 #3
0
# The critical exercise price is the price at which the value of exercising the option $K-\exp(p)$ equals the discounted expected value of keeping the option one more period $\delta E_\epsilon V(p + \epsilon)$. To find it, we set it as a nonlinear rootfinding problem by using the ```NLP``` class; here we assume that the option strike price is $K=1$ and that the discount factor is $\delta=0.9998$

# In[5]:

K = 1.0
delta = 0.9998
f = NLP(lambda p: K - np.exp(p) - delta * Value(p))

# Notice that we have not defined the ```Value(p)``` function yet. This function is unknown, so we are going to approximate it with a cubic spline, setting 500 nodes between -1 and 1. Since the basis is expressed in terms of log-prices, this interval corresponds to prices between 0.3679 and 2.7183.

# In[6]:

n = 500
pmin = -1  # minimum log price
pmax = 1  # maximum log price
Value = BasisSpline(n, pmin, pmax, labels=['logprice'], l=['value'])
print(Value)

# In the last expression, by passing the option `l` with a one-element list we are telling the ```BasisSpline``` class that we a single function named "value". On creation, the function will be set by default to $V(p)=0$ for all values of $p$, which conveniently corresponds to the terminal condition of this problem.

# ## Finding the critical exercise prices
#
# We are going to find the prices recursively, starting form a option in the expiration date. Notice that the solution to this problem is trivial: since next-period value is zero, the exercise price is $K$. Either way, we can find it numerically by calling the ```zero``` method on the `f` object.

# In[7]:

pcrit[0] = f.zero(0.0)

# Next, for each possible price shock, we compute next period log-price by adding the shock to current log-prices (the nodes of the Value object). Then, we use each next-period price to compute the expected value of an option with one-period to maturity (save the values in ```v```). We update the value function to reflect the new time-to-maturity and use ```broyden``` to solve for the critical value. We repeat this procedure until we reach the $T=300$ horizon.

# In[8]:
예제 #4
0
# Model Parameters
pbar = 1.0  # long-run mean profit
gamma = 0.7  # profit autoregressive coefficient
kappa = 10  # cost of reopenning idle firm
sigma = 1.0  # standard deviation of profit shock
delta = 0.9  # discount factor

# Continuous State Shock Distribution
m = 5  # number of profit shocks
[e, w] = qnwnorm(m, 0, sigma**2)  # profit shocks and probabilities

# Approximation Structure
n = 250  # number of collocation nodes
pmin = -20  # minimum profit
pmax = 20  # maximum profit
basis = BasisSpline(n, pmin, pmax)  # basis functions


def profit(p, x, i, j):
    return p * j - kappa * (1 - i) * j


def transition(p, x, i, j, in_, e):
    return pbar + gamma * (p - pbar) + e


# Model
model = DPmodel(BasisSpline(n, pmin, pmax, labels=['profit']),
                profit,
                transition,
                i=['idle', 'active'],
예제 #5
0
# In[5]:

sigma = 5
m = 15
e, w = qnwnorm(m, 0, sigma**2)

# ### Approximation Structure
#
# To discretize the continuous state variable, we use a cubic spline basis with $n=150$ nodes between $w_\min=0$ and $w_\max=200$.

# In[6]:

n = 150
wmin = 0
wmax = 200
basis = BasisSpline(n, wmin, wmax, labels=['wage'])

# ## SOLUTION
#
# To represent the model, we create an instance of ```DPmodel```. Here, we assume a discout factor of $\delta=0.95$.

# In[7]:

model = DPmodel(basis,
                reward,
                transition,
                i=['unemployed', 'employed'],
                j=['idle', 'active'],
                discount=0.95,
                e=e,
                w=w,
예제 #6
0
from compecon import BasisSpline, DPmodel
from compecon.quad import qnwlogn
from demos.setup import np, plt, demo

## FORMULATION

# Model Parameters
a = [6, 0.8]  # demand function parameters
b = [7, 1.0]  # cost function parameters
delta = 0.9  # discount factor

# Approximation Structure
n = 51  # number of collocation nodes
smin = 0  # minimum state
smax = 10  # maximum state
basis = BasisSpline(n, smin, smax, labels=['stock'])  # basis functions


def bounds(s, i, j):
    return np.zeros_like(s), s.copy()


def reward(s, q, i, j):
    a0, a1 = a
    b0, b1 = b
    f = (a0 - b0 + b1 * s) * q - (a1 + b1 / 2) * q**2
    fx = (a0 - b0 + b1 * s) - 2 * (a1 + b1 / 2) * q
    fxx = -2 * (a1 + b1 / 2) * np.ones_like(s)
    return f, fx, fxx

예제 #7
0
Phi = np.array([x**j for j in np.arange(n)])
basisplot(x, Phi, 'Monomial Basis Functions on [0,1]')

# ### % Plot Chebychev basis functions and nodes

# In[7]:

B = BasisChebyshev(n, a, b)
basisplot(x, B.Phi(x).T, 'Chebychev Polynomial Basis Functions on [0,1]')
nodeplot(B.nodes, 'Chebychev Nodes on [0,1]')

# ### % Plot linear spline basis functions and nodes

# In[8]:

L = BasisSpline(n, a, b, k=1)
basisplot(x, L.Phi(x).T.toarray(), 'Linear Spline Basis Functions on [0,1]')
nodeplot(L.nodes, 'Linear Spline Standard Nodes on [0,1]')

# ### % Plot cubic spline basis functions and nodes

# In[9]:

C = BasisSpline(n, a, b, k=3)
basisplot(x, C.Phi(x).T.toarray(), 'Cubic Spline Basis Functions on [0,1]')
nodeplot(C.nodes, 'Cubic Spline Standard Nodes on [0,1]')

# In[10]:

demo.savefig(figures)
예제 #8
0
off = 0.05
xlims = [xmin - off, xmax + off]
n = 401
x = np.linspace(xmin, xmax, n)
y = f(x)
ymin, ymax = y.min(), y.max()
ywid = ymax - ymin
ylims = [ymin - 0.5*ywid, ymax + 0.1*ywid]


# In[4]:


figs = []
for nnode in 3, 5, 9:
    F = BasisSpline(nnode, xmin, xmax, k=1, f=f)
    xnodes = F.nodes[0]

    xx = np.r_[x, xnodes]
    xx.sort()

    figs.append(demo.figure('Linear Spline with %d nodes' % nnode, '', '', 
                xlims, ylims, figsize=[10,5]))
    plt.plot(xx, f(xx), lw=3)  # true function
    plt.plot(xx, F(xx), 'r', lw=1) # approximation
    plt.yticks(ylims, ['', ''])
    xe = ['$x_{%d}$' % k for k in range(nnode)]
    xe[0], xe[-1] = '$x_0=a$', '$x_{%d}=b$' % (nnode-1)
    plt.xticks(xnodes, xe, fontsize=18)
    for i, xi in enumerate(xnodes):
        plt.vlines(xi, ylims[0], F(xi), 'gray','--')
예제 #9
0
delta = 0.9  # discount factor

# Deterministic Steady-State
sstar = (pbar - beta[0]) / beta[1]  # deterministic steady-state state

# Continuous State Shock Distribution
m = 3  # number of market price shocks
mu = np.log(pbar) - sigma**2 / 2  # mean log price
p, w = qnwlogn(m, mu, sigma**2)  # market price shocks and probabilities
q = np.tile(w, (m, 1))  # market price transition probabilities

# Approximation Structure
n = 50  # number of collocation nodes
smin = 0  # minimum state
smax = 20  # maximum state
basis = BasisSpline(n, smin, smax,
                    labels=['lagged production'])  # basis functions


def bounds(s, i, j):
    return np.zeros_like(s), np.full(s.shape, np.inf)


def reward(s, q, i, j):
    f = p[i] * q - (beta[0] * q + 0.5 * beta[1] * q**2) - 0.5 * alpha * (
        (q - s)**2)
    fx = p[i] - beta[0] - beta[1] * q - alpha * (q - s)
    fxx = (-beta[1] - alpha) * np.ones_like(s)
    return f, fx, fxx


def transition(s, q, i, j, in_, e):
예제 #10
0
# In[3]:


def h(s): return np.array(s + gamma*(smax - s))


# ## SOLUTION
# 
# ### Code the approximant and the residual

# In[4]:


ns = 200
vhat = BasisSpline(ns,0,smax,k=3)


# In[5]:


def vhat1(s): return price*s - kappa + delta * vhat(h(0))
def vhat0(s): return delta * vhat(h(s))


# In[6]:


def resid(c,s=vhat.nodes):
    vhat.c = c
    return vhat(s) - np.maximum(vhat0(s), vhat1(s))
예제 #11
0
n = 10  # order of interpolatioin

# Construct refined uniform grid for error ploting
x = nodeunif(1001, a, b)

# Compute actual and fitted values on grid
y, d, s = f(x)  # actual

# Construct and evaluate Chebychev interpolant
C = BasisChebyshev(n, a, b, f=f)  # chose basis functions
yc = C(x)  # values
dc = C(x, 1)  # first derivative
sc = C(x, 2)  # second derivative

# Construct and evaluate cubic spline interpolant
S = BasisSpline(n, a, b, f=f)  # chose basis functions
ys = S(x)  # values
ds = S(x, 1)  # first derivative
ss = S(x, 2)  # second derivative

# Plot function approximation error
plt.figure()
plt.subplot(2, 1, 1),
plt.plot(x, y - yc[0])
plt.ylabel('Chebychev')
plt.title('Function Approximation Error')

plt.subplot(2, 1, 2)
plt.plot(x, y - ys[0])
plt.ylabel('Cubic Spline')
plt.xlabel('x')
예제 #12
0
demo.figure('Chebychev Approximation Error for exp(-x)', 'x', 'Error')
plt.plot(xgrid, yapp - yact)
plt.plot(xgrid, np.zeros(ngrid), 'k--', linewidth=2)

# The plot indicates that an order 10 Chebychev approximation scheme, produces approximation errors
# no bigger in magnitude than 6x10^-10. The approximation error exhibits the "Chebychev equioscillation
# property", oscilating relatively uniformly throughout the approximation domain.
#
# This commonly occurs when function being approximated is very smooth, as is the case here but should not
# be expected when the function is not smooth.  Further notice how the approximation error is exactly 0 at the
# approximation nodes --- which is true by contruction.

# Let us repeat the approximation exercise, this time constructing a
# 21-function cubic spline approximant:
n = 21  # order of approximation
S = BasisSpline(n, a, b, f=f)  # define basis
yapp = S(xgrid)  # approximant values at grid nodes

demo.figure('Cubic Spline Approximation Error for exp(-x)', 'x', 'Error')
plt.plot(xgrid, yapp - yact)
plt.plot(xgrid, np.zeros(ngrid), 'k--', linewidth=2)

# The plot indicates that an order 21 cubic spline approximation scheme produces approximation errors
#  no bigger in magnitude than 1.2x10^-6, about four orders of magnitude worse than with Chebychev polynomials.

# Let us repeat the approximation exercise, this time constructing a
# 31-function linear spline approximant:
n = 31  # order of approximation
L = BasisSpline(n, a, b, k=1, f=f)  # define basis functions
yapp = L(xgrid)  # fitted values at grid nodes
demo.figure('Linear Spline Approximation Error for exp(-x)', 'x',
예제 #13
0
smax  = 0.5
gamma = 0.1
delta = 0.9


# ### State Space
# The state variable is the stand biomass, $s\in [0,s_{\max}]$.  
# 
# Here, we represent it with a cubic spline basis, with $n=200$ nodes.
# 

# In[3]:


n = 200
basis = BasisSpline(n, 0, smax, labels=['biomass'])


# ### Action Space
# The action variable is $j\in\{0:\text{'keep'},\quad 1:\text{'clear cut'}\}$.
# 

# In[4]:


options = ['keep', 'clear-cut']


# ### Reward function
# If the farmer clears the stand, the profit is the value of selling the biomass $ps$ minus the cost of clearing and replanting $\kappa$, otherwise the profit is zero.
예제 #14
0
x = nodeunif(2001, a, b)


def subfig(k, x, y, xlim, ylim, title):
    plt.subplot(2, 2, k)
    plt.plot(x, y)
    plt.xlim(xlim)
    plt.ylim(ylim)
    plt.title(title)


for ifunc, ff in enumerate(funcs):

    # Construct interpolants
    C = BasisChebyshev(n, a, b, f=ff)
    S = BasisSpline(n, a, b, f=ff)
    L = BasisSpline(n, a, b, k=1, f=ff)

    # Compute actual and fitted values on grid
    y = ff(x)  # actual
    yc = C(x)  # Chebychev approximant
    ys = S(x)  # cubic spline approximant
    yl = L(x)  # linear spline approximant

    # Plot function approximations
    plt.figure()
    ymin = np.floor(y.min())
    ymax = np.ceil(y.max())
    xlim = [a, b]
    ylim = [-0.2, 1.2] if ifunc == 2 else [ymin, ymax]
예제 #15
0
#
# \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_{\min}=-20$ and $p_\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]:
예제 #16
0
#     smax    stand carrying capacity
#     gamma   biomass growth parameter
#     delta   discount factor

## FORMULATION

# Model Parameters
price = 1.0 / 2  # unit price of biomass
kappa = 0.2  # clearcut-replant cost
smax = 0.5  # stand carrying capacity
gamma = 0.1  # biomass growth parameter
delta = 0.9  # discount factor

# Approximation Structure
n = 200  # number of collocation nodes
basis = BasisSpline(n, 0, smax, labels=['stand biomass'])  # basis functions

# Model Structure


def reward(s, x, i, j):
    return (price * s - kappa) * j


def transition(s, x, i, j, in_, e):
    if j:
        return np.full_like(s, gamma * smax)
    else:
        return s + gamma * (smax - s)

예제 #17
0
                cstride=1,
                cmap=cm.coolwarm,
                linewidth=0,
                antialiased=False)
ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
ax.set_zlabel('error')
plt.title('Chebychev Approximation Error')

# The plot indicates that an order 11 by 11 Chebychev approximation scheme
# produces approximation errors no bigger in magnitude than 1x10^-10.

# Let us repeat the approximation exercise, this time constructing an order
# 21 by 21 cubic spline approximation scheme:
n = [21, 21]  # order of approximation
S = BasisSpline(n, a, b, f=f)
yapp = S(X)  # approximant values at grid nodes
error = (yapp - yact).reshape(nplot)
ax = fig.add_subplot(1, 2, 2, projection='3d')
ax.plot_surface(X1,
                X2,
                error,
                rstride=1,
                cstride=1,
                cmap=cm.coolwarm,
                linewidth=0,
                antialiased=False)
ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
ax.set_zlabel('error')
plt.title('Cubic Spline Approximation Error')
예제 #18
0
sigma   = 0.15                             # standard deviation of unit profit shock
delta   = 0.9                              # discount factor 

# Continuous State Shock Distribution
m = 5                                      # number of unit profit shocks
[e,w] = qnwnorm(m,0,sigma ** 2)               # unit profit shocks and probabilities

# Deterministic Discrete State Transitions
h = np.zeros((2, A))
h[0, :-1] = np.arange(1, A)

# Approximation Structure
n  = 200                                   # number of collocation nodes
pmin = 0                                   # minimum unit profit
pmax = 2                                   # maximum unit profit
basis = BasisSpline(n, pmin, pmax, labels=['unit profit'])        # basis functions

# Model Structure

def profit(p, x, i, j):
    a = i + 1
    if j or a == A:
        return p * 50 - kappa
    else:
        return p * (alpha[0] + alpha[1] * a + alpha[2] * a ** 2 )

def transition(p, x, i, j, in_, e):
    return pbar + gamma * (p - pbar) + e

model = DPmodel(basis, profit, transition,
                # i=['a={}'.format(a+1) for a in range(A)],
예제 #19
0
m = 15  # number of wage shocks
e, w = qnwnorm(m, 0, sigma**2)  # wage shocks

# Stochastic Discrete State Transition Probabilities
q = np.zeros((2, 2, 2))
q[1, 0, 1] = p0
q[1, 1, 1] = p1
q[:, :, 0] = 1 - q[:, :, 1]

# Model Structure

# Approximation Structure
n = 150  # number of collocation nodes
wmin = 0  # minimum wage
wmax = 200  # maximum wage
basis = BasisSpline(n, wmin, wmax, labels=['wage'])  # basis functions


def reward(w, x, employed, active):
    if active:
        return w.copy() if employed else np.full_like(
            w, u
        )  # the copy is critical!!! otherwise it passes the pointer to w!!
    else:
        return np.full_like(w, v)


def transition(w, x, i, j, in_, e):
    return wbar + gamma * (w - wbar) + e