示例#1
0
def det_residual(model,
                 guess,
                 start,
                 final,
                 shocks,
                 diff=True,
                 jactype='sparse'):
    '''
    Computes the residuals, the derivatives of the stacked-time system.
    :param model: an fga model
    :param guess: the guess for the simulated values. An `(n_s.n_x) x N` array, where n_s is the number of states,
    n_x the number of controls, and `N` the length of the simulation.
    :param start: initial boundary condition (initial value of the states)
    :param final: final boundary condition (last value of the controls)
    :param shocks: values for the exogenous shocks
    :param diff: if True, the derivatives are computes
    :return: a list with two elements:
        - an `(n_s.n_x) x N` array with the residuals of the system
        - a `(n_s.n_x) x N x (n_s.n_x) x N` array representing the jacobian of the system
    '''

    # TODO: compute a sparse derivative and ensure the solvers can deal with it

    n_s = len(model.symbols['states'])
    n_x = len(model.symbols['controls'])

    n_e = len(model.symbols['shocks'])
    N = guess.shape[0]

    p = model.calibration['parameters']

    from dolo.algos.convert import get_fg_functions
    [f, g] = get_fg_functions(model)

    vec = guess[:-1, :]
    vec_f = guess[1:, :]

    s = vec[:, :n_s]
    x = vec[:, n_s:]
    S = vec_f[:, :n_s]
    X = vec_f[:, n_s:]

    e = shocks[:-1, :]
    E = shocks[1:, :]

    if diff:
        SS, SS_s, SS_x, SS_e = g(s, x, e, p, diff=True)
        R, R_s, R_x, R_e, R_S, R_X = f(s, x, E, S, X, p, diff=True)
    else:
        SS = g(s, x, e, p)
        R = f(s, x, E, S, X, p)

    res_s = SS - S
    res_x = R

    res = numpy.zeros((N, n_s + n_x))

    res[1:, :n_s] = res_s
    res[:-1, n_s:] = res_x

    res[0, :n_s] = -(guess[0, :n_s] - start)
    res[-1, n_s:] = -(guess[-1, n_s:] - guess[-2, n_s:])

    if not diff:
        return res
    else:

        sparse_jac = False
        if not sparse_jac:

            # we compute the derivative matrix

            from dolo.numeric.serial_operations import serial_multiplication as smult
            res_s_s = SS_s
            res_s_x = SS_x

            # next block is probably very inefficient
            jac = numpy.zeros((N, n_s + n_x, N, n_s + n_x))
            for i in range(N - 1):
                jac[i, n_s:, i, :n_s] = R_s[i, :, :]
                jac[i, n_s:, i, n_s:] = R_x[i, :, :]
                jac[i, n_s:, i + 1, :n_s] = R_S[i, :, :]
                jac[i, n_s:, i + 1, n_s:] = R_X[i, :, :]
                jac[i + 1, :n_s, i, :n_s] = SS_s[i, :, :]
                jac[i + 1, :n_s, i, n_s:] = SS_x[i, :, :]
                jac[i + 1, :n_s, i + 1, :n_s] = -numpy.eye(n_s)
                # jac[i,n_s:,i,:n_s] = R_s[i,:,:]
                # jac[i,n_s:,i,n_s:] = R_x[i,:,:]
                # jac[i+1,n_s:,i,:n_s] = R_S[i,:,:]
                # jac[i+1,n_s:,i,n_s:] = R_X[i,:,:]
                # jac[i,:n_s,i+1,:n_s] = SS_s[i,:,:]
                # jac[i,:n_s,i+1,n_s:] = SS_x[i,:,:]
                # jac[i+1,:n_s,i+1,:n_s] = -numpy.eye(n_s)
            jac[0, :n_s, 0, :n_s] = -numpy.eye(n_s)
            jac[-1, n_s:, -1, n_s:] = -numpy.eye(n_x)
            jac[-1, n_s:, -2, n_s:] = +numpy.eye(n_x)
            nn = jac.shape[0] * jac.shape[1]
            res = res.ravel()
            jac = jac.reshape((nn, nn))

        if jactype == 'sparse':
            from scipy.sparse import csc_matrix, csr_matrix
            jac = csc_matrix(jac)
            # scipy bug ? I don't get the same with csr

        return [res, jac]
示例#2
0
def approximate_controls(model, verbose=False, steady_state=None, eigmax=1.0, solve_steady_state=False, order=1):
    """Compute first order approximation of optimal controls

    Parameters:
    -----------

    model: NumericModel
        Model to be solved

    verbose: boolean
        If True: displays number of contracting eigenvalues

    steady_state: ndarray
        Use supplied steady-state value to compute the approximation. The routine doesn't check whether it is really
        a solution or not.

    solve_steady_state: boolean
        Use nonlinear solver to find the steady-state

    orders: {1}
        Approximation order. (Currently, only first order is supported).

    Returns:
    --------

    TaylorExpansion:
        Decision Rule for the optimal controls around the steady-state.

    """


    if order>1:
        raise Exception("Not implemented.")

    # get steady_state
    import numpy

    # if model.model_type == 'fga':
    #     model = GModel_fg_from_fga(model)

    # g = model.functions['transition']
    # f = model.functions['arbitrage']
    from dolo.algos.convert import get_fg_functions
    [f,g] = get_fg_functions(model)

    if steady_state is not None:
        calib = steady_state
    else:
        calib = model.calibration

    if solve_steady_state:
        from dolo.algos.steady_state import find_deterministic_equilibrium
        calib = find_deterministic_equilibrium(model)

    p = calib['parameters']
    s = calib['states']
    x = calib['controls']
    e = calib['shocks']

    if model.covariances is not None:
        sigma = model.covariances
    else:
        sigma = numpy.zeros((len(e), len(e)))

    from numpy.linalg import solve


    l = g(s,x,e,p, diff=True)
    [junk, g_s, g_x, g_e] = l[:4] # [el[0,...] for el in l[:4]]

    l = f(s,x,e,s,x,p, diff=True)
    [res, f_s, f_x, f_e, f_S, f_X] = l #[el[0,...] for el in l[:6]]

    n_s = g_s.shape[0]           # number of controls
    n_x = g_x.shape[1]   # number of states
    n_e = g_e.shape[1]
    n_v = n_s + n_x

    A = row_stack([
        column_stack( [ eye(n_s), zeros((n_s,n_x)) ] ),
        column_stack( [ -f_S    , -f_X             ] )
    ])

    B = row_stack([
        column_stack( [ g_s, g_x ] ),
        column_stack( [ f_s, f_x ] )
    ])

    from dolo.numeric.extern.qz import qzordered
    [S,T,Q,Z,eigval] = qzordered(A,B,n_s)
    Q = Q.real # is it really necessary ?
    Z = Z.real

    diag_S = numpy.diag(S)
    diag_T = numpy.diag(T)

    # Check Blanchard=Kahn conditions
    n_big_one = sum(eigval>eigmax)
    n_expected = n_x
    if verbose:
        print( "There are {} eigenvalues greater than {}. Expected: {}.".format( n_big_one, eigmax, n_x ) )
    if n_expected != n_big_one:
        raise BlanchardKahnError(n_big_one, n_expected)


    tol_geneigvals = 1e-10
    try:
        assert( sum(  (abs( diag_S ) < tol_geneigvals) * (abs(diag_T) < tol_geneigvals) ) == 0)
    except Exception as e:
        print e
        print(numpy.column_stack([diag_S, diag_T]))
        # raise GeneralizedEigenvaluesError(diag_S, diag_T)


    Z11 = Z[:n_s,:n_s]
    Z12 = Z[:n_s,n_s:]
    Z21 = Z[n_s:,:n_s]
    Z22 = Z[n_s:,n_s:]
    S11 = S[:n_s,:n_s]
    T11 = T[:n_s,:n_s]

    # first order solution
    C = solve(Z11.T, Z21.T).T
    P = np.dot(solve(S11.T, Z11.T).T , solve(Z11.T, T11.T).T )
    Q = g_e

    s = s.ravel()
    x = x.ravel()

    A = g_s + dot( g_x, C )
    B = g_e

    dr = CDR([s, x, C])
    dr.A = A
    dr.B = B
    dr.sigma = sigma
   
    return dr
示例#3
0
def find_deterministic_equilibrium(model, constraints=None, return_jacobian=False):
    '''
    Finds the steady state calibration.

    Parameters
    ----------
    model: NumericModel
        an "fg" model.
    constraints: dict
        a dictionaries with forced values. Use it to set shocks to non-zero values or to add additional constraints to avoid unit roots.

    Returns:
    --------
    dict:
        calibration dictionary
    '''

    from dolo.algos.convert import get_fg_functions

    [f,g] = get_fg_functions(model)
    
    s0 = model.calibration['states']
    x0 = model.calibration['controls']
    p = model.calibration['parameters']
    if 'shocks' in model.calibration:
        e0 = model.calibration['shocks'].copy()
    else:
        e0 = numpy.zeros( len(model.symbols['shocks']) )
    n_e = len(e0)
    
    z = numpy.concatenate([s0, x0, e0])

    symbs = model.symbols['states'] + model.symbols['controls']
    addcons_ind = []
    addcons_val = []
    if constraints is None: constraints = dict()
    for k in constraints:
        if k in symbs:
            i = symbs.index(k)
            addcons_ind.append(i)
            addcons_val.append(constraints[k])
        elif k in model.symbols['shocks']:
            i = model.symbols['shocks'].index(k)
            e0[i] = constraints[k]
        else:
            raise Exception("Invalid symbol '{}' for steady_state constraint".format(k))
    def fobj(z):
        s = z[:len(s0)]
        x = z[len(s0):-n_e]
        e = z[-n_e:]

        S = g(s,x,e,p)
        r = f(s,x,e,s,x,p)
        d_e = e - e0
        d_sx = z[addcons_ind] - addcons_val
        res = numpy.concatenate([S-s, r, d_e, d_sx ])
        return res

    from dolo.numeric.misc import MyJacobian
    jac = MyJacobian(fobj)( z )
    if return_jacobian:
        return jac


    rank = numpy.linalg.matrix_rank(jac)
    if rank < len(z):
        import warnings
        warnings.warn("There are {} equilibrium variables to find, but the jacobian matrix is only of rank {}. The solution is indeterminate.".format(len(z),rank))

    from scipy.optimize import root
    sol = root(fobj, z, method='lm')
    steady_state = sol.x

    
   
    s = steady_state[:len(s0)]
    x = steady_state[len(s0):-n_e]
    e = steady_state[-n_e:]

    calib = OrderedDict(
        states = s,
        controls = x,
        shocks = e,
        parameters = p.copy()
    )
    
    if 'auxiliary' in model.functions:
        a = model.functions['auxiliary'](s,x,p)
        calib['auxiliaries'] = a
    
    return calib
示例#4
0
def find_deterministic_equilibrium(model,
                                   constraints=None,
                                   return_jacobian=False):
    '''
    Finds the steady state calibration.

    Parameters
    ----------
    model: NumericModel
        an "fg" model.
    constraints: dict
        a dictionaries with forced values. Use it to set shocks to non-zero values or to add additional constraints to avoid unit roots.

    Returns:
    --------
    dict:
        calibration dictionary
    '''

    from dolo.algos.convert import get_fg_functions

    [f, g] = get_fg_functions(model)

    s0 = model.calibration['states']
    x0 = model.calibration['controls']
    p = model.calibration['parameters']
    if 'shocks' in model.calibration:
        e0 = model.calibration['shocks'].copy()
    else:
        e0 = numpy.zeros(len(model.symbols['shocks']))
    n_e = len(e0)

    z = numpy.concatenate([s0, x0, e0])

    symbs = model.symbols['states'] + model.symbols['controls']
    addcons_ind = []
    addcons_val = []
    if constraints is None: constraints = dict()
    for k in constraints:
        if k in symbs:
            i = symbs.index(k)
            addcons_ind.append(i)
            addcons_val.append(constraints[k])
        elif k in model.symbols['shocks']:
            i = model.symbols['shocks'].index(k)
            e0[i] = constraints[k]
        else:
            raise Exception(
                "Invalid symbol '{}' for steady_state constraint".format(k))

    def fobj(z):
        s = z[:len(s0)]
        x = z[len(s0):-n_e]
        e = z[-n_e:]

        S = g(s, x, e, p)
        r = f(s, x, e, s, x, p)
        d_e = e - e0
        d_sx = z[addcons_ind] - addcons_val
        res = numpy.concatenate([S - s, r, d_e, d_sx])
        return res

    from dolo.numeric.misc import MyJacobian
    jac = MyJacobian(fobj)(z)
    if return_jacobian:
        return jac

    rank = numpy.linalg.matrix_rank(jac)
    if rank < len(z):
        import warnings
        warnings.warn(
            "There are {} equilibrium variables to find, but the jacobian matrix is only of rank {}. The solution is indeterminate."
            .format(len(z), rank))

    from scipy.optimize import root
    sol = root(fobj, z, method='lm')
    steady_state = sol.x

    s = steady_state[:len(s0)]
    x = steady_state[len(s0):-n_e]
    e = steady_state[-n_e:]

    calib = OrderedDict(states=s, controls=x, shocks=e, parameters=p.copy())

    if 'auxiliary' in model.functions:
        a = model.functions['auxiliary'](s, x, p)
        calib['auxiliaries'] = a

    return calib
示例#5
0
def time_iteration(model,
                   bounds=None,
                   verbose=False,
                   initial_dr=None,
                   pert_order=1,
                   with_complementarities=True,
                   interp_type='smolyak',
                   smolyak_order=3,
                   interp_orders=None,
                   maxit=500,
                   tol=1e-8,
                   integration='gauss-hermite',
                   integration_orders=None,
                   T=200,
                   n_s=3,
                   hook=None):
    """Finds a global solution for ``model`` using backward time-iteration.

    Parameters:
    -----------

    model: NumericModel
        "fg" or "fga" model to be solved

    bounds: ndarray
        boundaries for approximations. First row contains minimum values. Second row contains maximum values.

    verbose: boolean
        if True, display iterations

    initial_dr: decision rule
        initial guess for the decision rule

    pert_order: {1}
        if no initial guess is supplied, the perturbation solution at order ``pert_order`` is used as initial guess

    with_complementarities: boolean (True)
        if False, complementarity conditions are ignored

    interp_type: {`smolyak`, `spline`}
        type of interpolation to use for future controls

    smolyak_orders: int
        parameter ``l`` for Smolyak interpolation

    interp_orders: 1d array-like
        list of integers specifying the number of nods in each dimension if ``interp_type="spline" ``


    Returns:
    --------
    decision rule object (SmolyakGrid or MultivariateSplines)
    """
    def vprint(t):
        if verbose:
            print(t)

    parms = model.calibration['parameters']
    sigma = model.covariances

    if initial_dr == None:
        if pert_order == 1:
            from dolo.algos.perturbations import approximate_controls
            initial_dr = approximate_controls(model)

        if pert_order > 1:
            raise Exception("Perturbation order > 1 not supported (yet).")

        if interp_type == 'perturbations':
            return initial_dr

    if bounds is not None:
        pass

    elif model.options and 'approximation_space' in model.options:

        vprint('Using bounds specified by model')

        approx = model.options['approximation_space']
        a = approx['a']
        b = approx['b']

        bounds = numpy.row_stack([a, b])
        bounds = numpy.array(bounds, dtype=float)

    else:
        vprint('Using asymptotic bounds given by first order solution.')

        from dolo.numeric.timeseries import asymptotic_variance
        # this will work only if initial_dr is a Taylor expansion
        Q = asymptotic_variance(initial_dr.A.real,
                                initial_dr.B.real,
                                initial_dr.sigma,
                                T=T)

        devs = numpy.sqrt(numpy.diag(Q))
        bounds = numpy.row_stack([
            initial_dr.S_bar - devs * n_s,
            initial_dr.S_bar + devs * n_s,
        ])

    if interp_orders == None:
        interp_orders = [5] * bounds.shape[1]

    if interp_type == 'smolyak':
        from dolo.numeric.interpolation.smolyak import SmolyakGrid
        dr = SmolyakGrid(bounds[0, :], bounds[1, :], smolyak_order)
    elif interp_type == 'spline':
        from dolo.numeric.interpolation.splines import MultivariateSplines
        dr = MultivariateSplines(bounds[0, :], bounds[1, :], interp_orders)
    elif interp_type == 'multilinear':
        from dolo.numeric.interpolation.multilinear import MultilinearInterpolator
        dr = MultilinearInterpolator(bounds[0, :], bounds[1, :], interp_orders)

    if integration == 'optimal_quantization':
        from dolo.numeric.discretization import quantization_nodes
        # number of shocks
        [epsilons, weights] = quantization_nodes(N_e, sigma)
    elif integration == 'gauss-hermite':
        from dolo.numeric.discretization import gauss_hermite_nodes
        if not integration_orders:
            integration_orders = [3] * sigma.shape[0]
        [epsilons, weights] = gauss_hermite_nodes(integration_orders, sigma)

    vprint('Starting time iteration')

    # TODO: transpose

    grid = dr.grid

    xinit = initial_dr(grid)
    xinit = xinit.real  # just in case...

    from dolo.algos.convert import get_fg_functions

    f, g = get_fg_functions(model)

    import time

    fun = lambda x: step_residual(grid, x, dr, f, g, parms, epsilons, weights)

    ##
    t1 = time.time()
    err = 1
    x0 = xinit
    it = 0

    verbit = True if verbose == 'full' else False

    if with_complementarities:
        lbfun = model.functions['arbitrage_lb']
        ubfun = model.functions['arbitrage_ub']
        lb = lbfun(grid, parms)
        ub = ubfun(grid, parms)
    else:
        lb = None
        ub = None

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

    err_0 = 1

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

        dr.set_values(x0)

        from dolo.numeric.optimize.newton import serial_newton, SerialDifferentiableFunction
        from dolo.numeric.optimize.ncpsolve import ncpsolve
        sdfun = SerialDifferentiableFunction(fun)

        if with_complementarities:
            [x, nit] = ncpsolve(sdfun, lb, ub, x0, verbose=verbit)

        else:
            [x, nit] = serial_newton(sdfun, x0, verbose=verbit)

        err = abs(x - x0).max()
        err_SA = err / err_0
        err_0 = err

        t_finish = time.time()
        elapsed = t_finish - t_start
        if verbose:
            print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} | {4:3} |'.format(
                it, err, err_SA, elapsed, nit))

        x0 = x0 + (x - x0)
        if hook:
            hook(dr, it, err)
        if False in np.isfinite(x0):
            print('iteration {} failed : non finite value')
            return [x0, x]

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

    t2 = time.time()
    if verbose:
        print(stars)
        print('Elapsed: {} seconds.'.format(t2 - t1))
        print(stars)

    return dr
示例#6
0
def simulate(model, dr, s0=None, n_exp=0, horizon=40, seed=1, discard=False, solve_expectations=False, nodes=None, weights=None, forcing_shocks=None):
    '''Simulate a model using the specified decision rule.

    Parameters
    ---------
    model: NumericModel
        an "fg" or "fga" model

    dr: decision rule

    s0: ndarray
        initial state where all simulations start
    n_exp: int
        number of simulations. Use 0 for impulse-response functions
    horizon: int
        horizon for the simulations
    seed: int
        used to initialize the random number generator. Use it to replicate exact same results among simulations
    discard: boolean (False)
        if True, then all simulations containing at least one non finite value are discarded
    solve_expectations: boolean (False)
        if True, Euler equations are solved at each step using the controls to form expectations
    nodes: ndarray
        if `solve_expectations` is True use ``nodes`` for integration
    weights: ndarray
        if `solve_expectations` is True use ``weights`` for integration
    forcing_shocks: ndarray
        specify an exogenous process of shocks (requires ``n_exp<=1``)

    Returns
    -------
    ndarray or pandas.Dataframe:
         if `n_exp<=1` returns a DataFrame object
         if `n_exp>1` returns a ``horizon x n_exp x n_v`` array where ``n_v`` is the number of variables.
    '''


    if n_exp ==0:
        irf = True
        n_exp = 1
    else:
        irf = False



    calib = model.calibration

    parms = numpy.array( calib['parameters'] )

    sigma = model.covariances

    if s0 is None:
        s0 = calib['states']

    # s0 = numpy.atleast_2d(s0.flatten()).T

    x0 = dr(s0)

    s_simul = numpy.zeros( (horizon, n_exp, s0.shape[0]) )
    x_simul = numpy.zeros( (horizon, n_exp, x0.shape[0]) )

    s_simul[0,:,:] = s0[None,:]
    x_simul[0,:,:] = x0[None,:]

    fun = model.functions

    if model.model_type == 'fga':

       from dolo.algos.convert import get_fg_functions
       [f,g] = get_fg_functions(model)
    else:
        f = model.functions['arbitrage']
        g = model.functions['transition']


    numpy.random.seed(seed)

    for i in range(horizon):
        mean = numpy.zeros(sigma.shape[0])
        if irf:
            if forcing_shocks is not None and i<forcing_shocks.shape[0]:
                epsilons = forcing_shocks[i,:] 
            else:
                epsilons = numpy.zeros( (1,sigma.shape[0]) )
        else:
            epsilons = numpy.random.multivariate_normal(mean, sigma, n_exp)
        s = s_simul[i,:,:]
        
        x = dr(s)

        if solve_expectations:

            lbfun = model.functions['arbitrage_lb']
            ubfun = model.functions['arbitrage_ub']
            lb = lbfun(s, parms)
            ub = ubfun(s, parms)

            from dolo.numeric.optimize.newton import newton as newton_solver, SerialDifferentiableFunction
            from dolo.numeric.optimize.ncpsolve import ncpsolve


            fobj = lambda t: step_residual(s, t, dr, f, g, parms, nodes, weights)
            dfobj = SerialDifferentiableFunction(fobj)
            # [x,nit] = newton_solver(dfobj, x)
            [x,nit] = ncpsolve(dfobj, lb, ub, x)


        x_simul[i,:,:] = x
    
        ss = g(s,x,epsilons,parms)
        if i<(horizon-1):
            s_simul[i+1,:,:] = ss

    from numpy import isnan,all

    if not 'auxiliary' in fun: # TODO: find a better test than this
        l = [s_simul, x_simul]
        varnames = model.symbols['states'] + model.symbols['controls']
    else:
        aux = fun['auxiliary']
    
        a_simul = aux( s_simul.reshape((n_exp*horizon,-1)), x_simul.reshape( (n_exp*horizon,-1) ), parms)    
        a_simul = a_simul.reshape(horizon, n_exp, -1)

        l = [s_simul, x_simul, a_simul]
        varnames = model.symbols['states'] + model.symbols['controls'] + model.symbols['auxiliaries']

    simul = numpy.concatenate(l, axis=2)

    if discard:
        iA = -isnan(x_simul)
        valid = all( all( iA, axis=0 ), axis=1 )
        simul = simul[:,valid,:]
        n_kept = s_simul.shape[1]
        if n_exp > n_kept:
            print( 'Discarded {}/{}'.format(n_exp-n_kept,n_exp))

    if irf or (n_exp==1):
        simul = simul[:,0,:]

        import pandas
        ts = pandas.DataFrame(simul, columns=varnames)
        return ts

    return simul
示例#7
0
文件: accuracy.py 项目: sglyon/dolo
def omega(model, dr, n_exp=10000, orders=None, bounds=None,
          n_draws=100, seed=0, horizon=50, s0=None,
          solve_expectations=False, time_discount=None):

    assert(model.model_type =='fga')

    [f,g] = get_fg_functions(model)

    sigma = model.covariances
    parms = model.calibration['parameters']

    mean = numpy.zeros(sigma.shape[0])

    numpy.random.seed(seed)
    epsilons = numpy.random.multivariate_normal(mean, sigma, n_draws)
    weights = np.ones(epsilons.shape[0])/n_draws

    if bounds is None:
        approx = model.options['approximation_space']
        a = approx['a']
        b = approx['b']
        bounds = numpy.row_stack([a,b])
    else:
        a,b =numpy.row_stack(bounds)

    if orders is None:
        orders = [100]*len(a)

    domain = RectangularDomain(a, b, orders)

    grid = domain.grid

    n_s = len(model.symbols['states'])

    errors = test_residuals( grid, dr, f, g, parms, epsilons, weights )
    errors = abs(errors)

    if s0 is None:
        s0 = model.calibration['states']

    from dolo.algos.simulations import simulate
    simul = simulate(model, dr, s0, n_exp=n_exp, horizon=horizon+1,
                     discard=True, solve_expectations=solve_expectations)

    s_simul = simul[:,:,:n_s]

    densities = [domain.compute_density(s_simul[t,:,:]) for t in range(horizon)]
    ergo_dens = densities[-1]

    max_error = numpy.max(errors,axis=0)        # maximum errors
    ergo_error = numpy.dot(ergo_dens,errors)    # weighted by ergodic distribution

    d = dict(
            errors = errors,
            densities = densities,
            bounds = bounds,
            max_errors = max_error,
            ergodic = ergo_error,
            domain = domain
        )

    if time_discount is not None:
        beta = time_discount
        time_weighted_errors = max_error*0
        for i in range(horizon):
            err = numpy.dot(densities[i], errors)
            time_weighted_errors += beta**i * err
        time_weighted_errors /= (1-beta**(horizon-1))/(1-beta)
        d['time_weighted'] = time_weighted_errors


    return EulerErrors(d)
示例#8
0
def det_residual(model, guess, start, final, shocks, diff=True, jactype='sparse'):
    '''
    Computes the residuals, the derivatives of the stacked-time system.
    :param model: an fga model
    :param guess: the guess for the simulated values. An `(n_s.n_x) x N` array, where n_s is the number of states,
    n_x the number of controls, and `N` the length of the simulation.
    :param start: initial boundary condition (initial value of the states)
    :param final: final boundary condition (last value of the controls)
    :param shocks: values for the exogenous shocks
    :param diff: if True, the derivatives are computes
    :return: a list with two elements:
        - an `(n_s.n_x) x N` array with the residuals of the system
        - a `(n_s.n_x) x N x (n_s.n_x) x N` array representing the jacobian of the system
    '''

    # TODO: compute a sparse derivative and ensure the solvers can deal with it

    n_s = len( model.symbols['states'] )
    n_x = len( model.symbols['controls'] )

    n_e = len( model.symbols['shocks'] )
    N = guess.shape[0]

    p = model.calibration['parameters']

    from dolo.algos.convert import get_fg_functions
    [f,g] = get_fg_functions(model)

    vec = guess[:-1,:]
    vec_f = guess[1:,:]

    s = vec[:,:n_s]
    x = vec[:,n_s:]
    S = vec_f[:,:n_s]
    X = vec_f[:,n_s:]

    e = shocks[:-1,:]
    E = shocks[1:,:]

    if diff:
        SS, SS_s, SS_x, SS_e = g(s,x,e,p, diff=True)
        R, R_s, R_x, R_e, R_S, R_X = f(s,x,E,S,X,p,diff=True)
    else:
        SS = g(s,x,e,p)
        R = f(s,x,E,S,X,p)

    res_s = SS - S
    res_x = R

    res = numpy.zeros( (N, n_s+n_x) )

    res[1:,:n_s] = res_s
    res[:-1,n_s:] = res_x

    res[0,:n_s] = - (guess[0,:n_s] - start)
    res[-1,n_s:] = - (guess[-1,n_s:] - guess[-2,n_s:] )

    if not diff:
        return res
    else:

        sparse_jac=False
        if not sparse_jac:

            # we compute the derivative matrix

            from dolo.numeric.serial_operations import serial_multiplication as smult
            res_s_s = SS_s
            res_s_x = SS_x

            # next block is probably very inefficient
            jac = numpy.zeros( (N, n_s+n_x, N, n_s+n_x) )
            for i in range(N-1):
                jac[i,n_s:,i,:n_s] = R_s[i,:,:]
                jac[i,n_s:,i,n_s:] = R_x[i,:,:]
                jac[i,n_s:,i+1,:n_s] = R_S[i,:,:]
                jac[i,n_s:,i+1,n_s:] = R_X[i,:,:]
                jac[i+1,:n_s,i,:n_s] = SS_s[i,:,:]
                jac[i+1,:n_s,i,n_s:] = SS_x[i,:,:]
                jac[i+1,:n_s,i+1,:n_s] = -numpy.eye(n_s)
                # jac[i,n_s:,i,:n_s] = R_s[i,:,:]
                # jac[i,n_s:,i,n_s:] = R_x[i,:,:]
                # jac[i+1,n_s:,i,:n_s] = R_S[i,:,:]
                # jac[i+1,n_s:,i,n_s:] = R_X[i,:,:]
                # jac[i,:n_s,i+1,:n_s] = SS_s[i,:,:]
                # jac[i,:n_s,i+1,n_s:] = SS_x[i,:,:]
                # jac[i+1,:n_s,i+1,:n_s] = -numpy.eye(n_s)
            jac[ 0,:n_s,0,:n_s] = - numpy.eye(n_s)
            jac[-1,n_s:,-1,n_s:] = - numpy.eye(n_x)
            jac[-1,n_s:,-2,n_s:] = + numpy.eye(n_x)
            nn = jac.shape[0]*jac.shape[1]
            res = res.ravel()
            jac = jac.reshape((nn,nn))


        if jactype == 'sparse':
            from scipy.sparse import csc_matrix, csr_matrix
            jac = csc_matrix(jac)
            # scipy bug ? I don't get the same with csr

        return [res,jac]
示例#9
0
def time_iteration(model,  bounds=None, verbose=False, initial_dr=None,
                 pert_order=1, with_complementarities=True,
                 interp_type='smolyak', smolyak_order=3, interp_orders=None,
                 maxit=500, tol=1e-8,
                 integration='gauss-hermite', integration_orders=None,
                 T=200, n_s=3, hook=None):

    """Finds a global solution for ``model`` using backward time-iteration.

    Parameters:
    -----------

    model: NumericModel
        "fg" or "fga" model to be solved

    bounds: ndarray
        boundaries for approximations. First row contains minimum values. Second row contains maximum values.

    verbose: boolean
        if True, display iterations

    initial_dr: decision rule
        initial guess for the decision rule

    pert_order: {1}
        if no initial guess is supplied, the perturbation solution at order ``pert_order`` is used as initial guess

    with_complementarities: boolean (True)
        if False, complementarity conditions are ignored

    interp_type: {`smolyak`, `spline`}
        type of interpolation to use for future controls

    smolyak_orders: int
        parameter ``l`` for Smolyak interpolation

    interp_orders: 1d array-like
        list of integers specifying the number of nods in each dimension if ``interp_type="spline" ``


    Returns:
    --------
    decision rule object (SmolyakGrid or MultivariateSplines)
    """

    def vprint(t):
        if verbose:
            print(t)

    parms = model.calibration['parameters']
    sigma = model.covariances

    if initial_dr == None:
        if pert_order==1:
            from dolo.algos.perturbations import approximate_controls
            initial_dr = approximate_controls(model)

        if pert_order>1:
            raise Exception("Perturbation order > 1 not supported (yet).")

        if interp_type == 'perturbations':
            return initial_dr

    if bounds is not None:
        pass

    elif model.options and 'approximation_space' in model.options:

        vprint('Using bounds specified by model')

        approx = model.options['approximation_space']
        a = approx['a']
        b = approx['b']

        bounds = numpy.row_stack([a, b])
        bounds = numpy.array(bounds, dtype=float)

    else:
        vprint('Using asymptotic bounds given by first order solution.')

        from dolo.numeric.timeseries import asymptotic_variance
        # this will work only if initial_dr is a Taylor expansion
        Q = asymptotic_variance(initial_dr.A.real, initial_dr.B.real, initial_dr.sigma, T=T)

        devs = numpy.sqrt(numpy.diag(Q))
        bounds = numpy.row_stack([
            initial_dr.S_bar - devs * n_s,
            initial_dr.S_bar + devs * n_s,
        ])

    if interp_orders == None:
        interp_orders = [5] * bounds.shape[1]

    if interp_type == 'smolyak':
        from dolo.numeric.interpolation.smolyak import SmolyakGrid
        dr = SmolyakGrid(bounds[0, :], bounds[1, :], smolyak_order)
    elif interp_type == 'spline':
        from dolo.numeric.interpolation.splines import MultivariateSplines
        dr = MultivariateSplines(bounds[0, :], bounds[1, :], interp_orders)
    elif interp_type == 'multilinear':
        from dolo.numeric.interpolation.multilinear import MultilinearInterpolator
        dr = MultilinearInterpolator(bounds[0, :], bounds[1, :], interp_orders)

    if integration == 'optimal_quantization':
        from dolo.numeric.discretization import quantization_nodes
        # number of shocks
        [epsilons, weights] = quantization_nodes(N_e, sigma)
    elif integration == 'gauss-hermite':
        from dolo.numeric.discretization import gauss_hermite_nodes
        if not integration_orders:
            integration_orders = [3] * sigma.shape[0]
        [epsilons, weights] = gauss_hermite_nodes(integration_orders, sigma)


    vprint('Starting time iteration')

    # TODO: transpose

    grid = dr.grid

    xinit = initial_dr(grid)
    xinit = xinit.real  # just in case...


    from dolo.algos.convert import get_fg_functions

    f,g = get_fg_functions(model)


    import time

    fun = lambda x: step_residual(grid, x, dr, f, g, parms, epsilons, weights)

    ##
    t1 = time.time()
    err = 1
    x0 = xinit
    it = 0

    verbit = True if verbose=='full' else False

    if with_complementarities:
        lbfun = model.functions['arbitrage_lb']
        ubfun = model.functions['arbitrage_ub']
        lb = lbfun(grid, parms)
        ub = ubfun(grid, parms)
    else:
        lb = None
        ub = None

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

    err_0 = 1

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

        dr.set_values(x0)

        from dolo.numeric.optimize.newton import serial_newton, SerialDifferentiableFunction
        from dolo.numeric.optimize.ncpsolve import ncpsolve
        sdfun = SerialDifferentiableFunction(fun)

        if with_complementarities:
            [x,nit] = ncpsolve(sdfun, lb, ub, x0, verbose=verbit)

        else:
            [x,nit] = serial_newton(sdfun, x0, verbose=verbit)

        err = abs(x-x0).max()
        err_SA = err/err_0
        err_0 = err

        t_finish = time.time()
        elapsed = t_finish - t_start
        if verbose:
            print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} | {4:3} |'.format( it, err, err_SA, elapsed, nit  ))

        x0 = x0 + (x-x0)
        if hook:
            hook(dr,it,err)
        if False in np.isfinite(x0):
            print('iteration {} failed : non finite value')
            return [x0, x]

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


    t2 = time.time()
    if verbose:
        print(stars)
        print('Elapsed: {} seconds.'.format(t2 - t1))
        print(stars)

    return dr