예제 #1
0
    def update(self):
        # Unpack parameters
        A, alpha, beta, delta, gamma, rho, sigma = self._unpack_params()
        ns, Qn = self.ncgm.ns, self.ncgm.Qn
        ncgm, grid = self.ncgm, self.ncgm.grid
        k, z = grid[:, 0], grid[:, 1]

        # Evaluate RHS of EE
        temp = np.empty((n_complete(2, self.degree), ns))
        rhs_ee = 0.0
        for iz1 in range(Qn):
            # Build t+1 decisions
            zp = ncgm.z1[:, iz1]
            _complete_poly_impl(np.vstack([self.KP, zp]), self.degree, temp)

            # Compute k_{t+2} and the corresponding c_{t+1}
            kpp = self.k_coeffs @ temp
            cp = expendables_t(self.KP, zp, A, alpha, delta) - kpp
            foo = beta * ncgm.weights[iz1] * (1.0 - delta +
                                              df(self.KP, zp, A, alpha))
            foo *= du(cp, gamma)
            rhs_ee += foo

        # Determine c_t using euler equation
        c = duinv(rhs_ee, gamma)
        kp = expendables_t(k, z, A, alpha, delta) - c
        VF = u(c, gamma) + beta * self.compute_EV(kp=kp)

        return kp, VF
예제 #2
0
def test_complete_vec_vs_mat():
    # Matrix for allocation
    temp = np.ones(n_complete(2, 3)) * 5.0
    temp_mat = np.ones((n_complete(2, 3), 3))

    # Point at which to evaluate
    z = np.array([0.9, 1.05])
    z_mat = np.array([[0.9, 0.95, 1.0], [1.05, 1.0, 0.95]])

    foo = complete_polynomial(z, 2)
    bar = complete_polynomial(z_mat, 2)[:, 0]
    assert np.allclose(foo, bar)

    foo = complete_polynomial_der(z, 2, 0)
    bar = complete_polynomial_der(z_mat, 2, 0)[:, 0]
    assert np.allclose(foo, bar)

    foo = complete_polynomial_der(z, 4, 0)
    bar = complete_polynomial_der(z_mat, 4, 0)[:, 0]
    assert np.allclose(foo, bar)
예제 #3
0
def test_complete_derivative():

    # Test derivative vector
    z = np.array([1, 2, 3])
    sol_vec = np.array([0.0, 1.0, 0.0, 0.0, 2.0, 2.0, 3.0, 0.0, 0.0, 0.0])
    out_vec = np.empty(n_complete(3, 2))
    _complete_poly_der_impl_vec(z, 2, 0, out_vec)
    assert (abs(out_vec - sol_vec).max() < 1e-10)

    # Test derivative matrix
    z = np.arange(1, 7).reshape(3, 2)
    out_mat = complete_polynomial_der(z, 2, 1)
    assert (abs(out_mat[0, :]).max() < 1e-10)
    assert (abs(out_mat[2, :] - np.ones(2)).max() < 1e-10)
    assert (abs(out_mat[-2, :] - np.array([5.0, 6.0])).max() < 1e-10)
예제 #4
0
def test_complete_derivative():

    # TODO: Currently if z has a 0 value then it breaks because occasionally
    #       tries to raise 0 to a negative power -- This can be fixed by
    #       checking whether coefficient is 0 before trying to do anything...

    # Test derivative vector
    z = np.array([1, 2, 3])
    sol_vec = np.array([0.0, 1.0, 0.0, 0.0, 2.0, 2.0, 3.0, 0.0, 0.0, 0.0])
    out_vec = np.empty(n_complete(3, 2))
    _complete_poly_der_impl_vec(z, 2, 0, out_vec)
    assert (abs(out_vec - sol_vec).max() < 1e-10)

    # Test derivative matrix
    z = np.arange(1, 7).reshape(3, 2)
    out_mat = complete_polynomial_der(z, 2, 1)
    assert (abs(out_mat[0, :]).max() < 1e-10)
    assert (abs(out_mat[2, :] - np.ones(2)).max() < 1e-10)
    assert (abs(out_mat[-2, :] - np.array([5.0, 6.0])).max() < 1e-10)
예제 #5
0
def jit_ee(params, degree, v_coeffs, nodes, weights, ks, zs):
    # Unpack parameters
    A, alpha, beta, delta, gamma, rho, sigma = param_unpack(params)

    # Allocate space for temporary vector to fill with complete polynomials
    temp = np.empty(n_complete(2, degree))
    T = ks.size
    Qn = weights.size

    # Allocate space to store euler errors
    ee = np.empty(T)

    # Iterate over all ks and zs
    for t in range(T):
        # Current states
        k, z = ks[t], zs[t]

        # Compute decision for kp and implied c
        k1 = env_cond_kp(temp, params, degree, v_coeffs, k, z)
        c = expendables_t(k, z, A, alpha, delta) - k1

        # Compute euler error for period t
        lhs = du(c, gamma)
        rhs = 0.0
        for i in range(Qn):
            # Get productivity tomorrow
            z1 = z**rho * np.exp(nodes[i])

            # Compute decision for kpp and implied c
            k2 = env_cond_kp(temp, params, degree, v_coeffs, k1, z1)
            c1 = expendables_t(k1, z1, A, alpha, delta) - k2
            rhs = rhs + weights[i] * du(
                c1, gamma) * (1 - delta + df(k1, z1, A, alpha))

        ee[t] = np.abs(1.0 - beta * rhs / lhs)

    return ee
예제 #6
0
def jit_simulate_ncgm(params, degree, v_coeffs, T, nburn, shocks):
    "Simulates economy using envelope condition as policy rule"
    # Unpack parameters
    A, alpha, beta, delta, gamma, rho, sigma = param_unpack(params)

    # Allocate space for output
    ksim = np.empty(T + nburn)
    zsim = np.empty(T + nburn)
    ksim[0], zsim[0] = 1.0, 1.0

    # Allocate space for temporary vector to fill with complete polynomials
    temp = np.empty(n_complete(2, degree))

    # Simulate
    for t in range(1, T + nburn):
        # Evaluate policy for today given yesterdays state
        kp = env_cond_kp(temp, params, degree, v_coeffs, ksim[t - 1],
                         zsim[t - 1])

        # Draw new z and update k using policy from above
        zsim[t] = zsim[t - 1]**rho * np.exp(sigma * shocks[t])
        ksim[t] = kp

    return ksim[nburn:], zsim[nburn:]
예제 #7
0
파일: gssa.py 프로젝트: dvillacreses/dolo
def gssa(model, maxit=100, tol=1e-8, initial_dr=None, verbose=False,
         n_sim=10000, deg=3, damp=0.1, seed=42):
    """
    Sketch of algorithm:

    0. Choose levels for the initial states and the simulation length (n_sim)
    1. Obtain an initial decision rule -- here using first order perturbation
    2. Draw a sequence of innovations epsilon
    3. Iterate on the following steps:
        - Use the epsilons, initial states, and proposed decision rule to
          simulate model forward. Will leave us with time series of states and
          controls
        - Evaluate expectations using quadrature
        - Use direct response to get alternative proposal for controls
        - Regress updated controls on the simulated states to get proposal
          coefficients. New coefficients are convex combination of previous
          coefficients and proposal coefficients. Weights controlled by damp,
          where damp is the weight on the old coefficients. This should be
          fairly low to increase chances of convergence.
        - Check difference between the simulated series of controls and the
          direct response version of controls

    """
    # verify input arguments
    if deg < 0 or deg > 5:
        raise ValueError("deg must be in [1, 5]")

    if damp < 0 or damp > 1:
        raise ValueError("damp must be in [0, 1]")

    t1 = time.time()

    # extract model functions and parameters
    g = model.__original_functions__['transition']
    g_gu = model.__original_gufunctions__['transition']
    h_gu = model.__original_gufunctions__['expectation']
    d_gu = model.__original_gufunctions__['direct_response']
    p = model.calibration['parameters']
    n_s = len(model.symbols["states"])
    n_x = len(model.symbols["controls"])
    n_z = len(model.symbols["expectations"])
    n_eps = len(model.symbols["shocks"])
    s0 = model.calibration["states"]
    x0 = model.calibration["controls"]

    # construct initial decision rule if not supplied
    if initial_dr is None:
        drp = approximate_controls(model)
    else:
        drp = initial_dr

    # set up quadrature weights and nodes
    distrib = model.get_distribution()
    nodes, weights = distrib.discretize()

    # draw sequence of innovations
    np.random.seed(seed)
    distrib = model.get_distribution()
    sigma = distrib.sigma
    epsilon = np.random.multivariate_normal(np.zeros(n_eps), sigma, n_sim)

    # simulate initial decision rule and do initial regression for coefs
    init_sim = simulate(model, drp, horizon=n_sim, return_array=True,
                        forcing_shocks=epsilon)
    s_sim = init_sim[:, 0, 0:n_s]
    x_sim = init_sim[:, 0, n_s:n_s + n_x]
    Phi_sim = complete_polynomial(s_sim.T, deg).T
    coefs = np.ascontiguousarray(lstsq(Phi_sim, x_sim)[0])

    # NOTE: the ascontiguousarray above was needed for numba to compile the
    #       `np.dot` in the simulation function in no python mode. Appearantly
    #       the array returned from lstsq is not C-contiguous

    # allocate for simulated series of expectations and next period states
    z_sim = np.empty((n_sim, n_z))
    S = np.empty_like(s_sim)
    X = np.empty_like(x_sim)
    H = np.empty_like(z_sim)
    new_x = np.empty_like(x_sim)

    # set initial states and controls
    s_sim[0, :] = s0
    x_sim[0, :] = x0

    Phi_t = np.empty(n_complete(n_s, deg))  # buffer array for simulation

    # create jitted function that will simulate states and controls, using
    # the epsilon shocks from above (define here as closure over all data
    # above).
    @jit(nopython=True)
    def simulate_states_controls(s, x, Phi_t, coefs):
        for t in range(1, n_sim):
            g(s[t - 1, :], x[t - 1, :], epsilon[t, :], p, s[t, :])

            # fill Phi_t with new complete poly version of s[t, :]
            _complete_poly_impl_vec(s[t, :], deg, Phi_t)

            # do inner product to get new controls
            x[t, :] = Phi_t @coefs

    it = 0
    err = 10.0
    err_0 = 10

    if verbose:
        headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |'
        headline = headline.format('N', ' Error', 'Gain', 'Time')
        stars = '-' * len(headline)
        print(stars)
        print(headline)
        print(stars)

        # format string for within loop
        fmt_str = '|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'

    while err > tol and it <= maxit:
        t_start = time.time()

        # simulate with new coefficients
        simulate_states_controls(s_sim, x_sim, Phi_t, coefs)

        # update expectations of z
        # update_expectations(s_sim, x_sim, z_sim, Phi_sim)
        z_sim[:, :] = 0.0
        for i in range(weights.shape[0]):
            e = nodes[i, :]  # extract nodes
            # evaluate future states at each node (stores in S)
            g_gu(s_sim, x_sim, e, p, S)

            # evaluate future controls at each future state
            _complete_poly_impl(S.T, deg, Phi_sim.T)
            np.dot(Phi_sim, coefs, out=X)

            # compute expectation (stores in H)
            h_gu(S, X, p, H)
            z_sim += weights[i] * H

        # get controls on the simulated points from direct_resposne
        # (stores in new_x)
        d_gu(s_sim, z_sim, p, new_x)

        # update basis matrix and do regression of new_x on s_sim to get
        # updated coefficients
        _complete_poly_impl(s_sim.T, deg, Phi_sim.T)
        new_coefs = np.ascontiguousarray(lstsq(Phi_sim, new_x)[0])

        # check whether they differ from the preceding guess
        err = (abs(new_x - x_sim).max())

        # update the series of controls and coefficients
        x_sim[:, :] = new_x
        coefs = (1 - damp) * new_coefs + damp * coefs

        if verbose:
            # update error and print if `verbose`
            err_SA = err / err_0
            err_0 = err
            t_finish = time.time()
            elapsed = t_finish - t_start
            if verbose:
                print(fmt_str.format(it, err, err_SA, elapsed))

        it += 1

    if it == maxit:
        warnings.warn(UserWarning("Maximum number of iterations reached"))

    # compute final fime and do final printout if `verbose`
    t2 = time.time()
    if verbose:
        print(stars)
        print('Elapsed: {} seconds.'.format(t2 - t1))
        print(stars)

    cp = CompletePolynomial(deg, len(s0))
    cp.fit_values(s_sim, x_sim)
    return cp