示例#1
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
示例#2
0
def approximate_controls(model,
                         verbose=False,
                         steady_state=None,
                         eigmax=1.0 - 1e-6,
                         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.")

    f = model.functions['arbitrage']
    g = model.functions['transition']

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

    if solve_steady_state:
        calib = find_deterministic_equilibrium(model)

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

    distrib = model.get_distribution()
    sigma = distrib.sigma

    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])])

    [S, T, Q, Z, eigval] = qzordered(A, B, 1.0 - 1e-8)

    Q = Q.real  # is it really necessary ?
    Z = Z.real

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

    tol_geneigvals = 1e-10

    try:
        ok = sum((abs(diag_S) < tol_geneigvals) *
                 (abs(diag_T) < tol_geneigvals)) == 0
        assert (ok)
    except Exception as e:
        raise GeneralizedEigenvaluesError(diag_S=diag_S, diag_T=diag_T)

    if max(eigval[:n_s]) >= 1 and min(eigval[n_s:]) < 1:
        # BK conditions are met
        pass
    else:
        eigval_s = sorted(eigval, reverse=True)
        ev_a = eigval_s[n_s - 1]
        ev_b = eigval_s[n_s]
        cutoff = (ev_a - ev_b) / 2
        if not ev_a > ev_b:
            raise GeneralizedEigenvaluesSelectionError(A=A,
                                                       B=B,
                                                       eigval=eigval,
                                                       cutoff=cutoff,
                                                       diag_S=diag_S,
                                                       diag_T=diag_T,
                                                       n_states=n_s)
        import warnings
        if cutoff > 1:
            warnings.warn("Solution is not convergent.")
        else:
            warnings.warn(
                "There are multiple convergent solutions. The one with the smaller eigenvalues was selected."
            )
        [S, T, Q, Z, eigval] = qzordered(A, B, cutoff)

    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
    # P = (solve(S11.T, Z11.T).T @ solve(Z11.T, T11.T).T)
    C = solve(Z11.T, Z21.T).T
    Q = g_e

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

    A = g_s + 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 perturbate(model,
               order=1,
               return_dr=True,
               steady_state=None,
               verbose=True):

    from dolo.numeric.processes import IIDProcess

    # here we should check that exogenous don't appear with time t-1 in transition
    # and with time t+1 in arbitrage.
    assert isinstance(model.exogenous, IIDProcess)

    import numpy

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

    [f, g] = get_model_derivatives(model, order=order, calibration=calibration)
    sigma = model.exogenous.Sigma

    problem = PerturbationProblem(f, g, sigma)
    print(len(problem.f))

    pert_sol = state_perturb(problem, verbose=verbose)

    controls_ss = calibration['controls']
    states_ss = calibration['states']

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

    if order == 1:
        if return_dr:
            S_bar = numpy.array(states_ss)
            X_bar = numpy.array(controls_ss)
            # add transitions of states to the d.r.

            X_s = pert_sol[0]
            A = g[1][:, :n_s] + numpy.dot(g[1][:, n_s:n_s + n_c], X_s)
            B = g[1][:, n_s + n_c:]
            dr = CDR(S_bar, X_bar, X_s)
            dr.A = A
            dr.B = B
            dr.sigma = sigma
            return dr

        return [controls_ss] + pert_sol

    if order == 2:
        [[X_s, X_ss], [X_tt]] = pert_sol
        X_bar = controls_ss + X_tt / 2
        if return_dr:
            S_bar = states_ss
            S_bar = numpy.array(S_bar)
            X_bar = numpy.array(X_bar)
            dr = CDR(S_bar, X_bar, X_s, X_ss)
            A = g[1][:, :n_s] + numpy.dot(g[1][:, n_s:n_s + n_c], X_s)
            B = g[1][:, n_s + n_c:]
            dr.sigma = sigma
            dr.A = A
            dr.B = B
            return dr
        return [X_bar, X_s, X_ss]

    if order == 3:
        [[X_s, X_ss, X_sss], [X_tt, X_stt]] = pert_sol
        X_bar = controls_ss + X_tt / 2
        X_s = X_s + X_stt / 2
        if return_dr:
            S_bar = states_ss
            dr = CDR(S_bar, X_bar, X_s, X_ss, X_sss)
            dr.sigma = sigma
            return dr
        return [X_bar, X_s, X_ss, X_sss]
def perturb(model, order=1, return_dr=True, steady_state=None, verbose=True):

    from dolo.numeric.processes import IIDProcess

    # here we should check that exogenous don't appear with time t-1 in transition
    # and with time t+1 in arbitrage.
    assert isinstance(model.exogenous, IIDProcess)

    import numpy

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

    [f, g] = get_model_derivatives(model, order=order, calibration=calibration)
    sigma = model.exogenous.Sigma

    problem = PerturbationProblem(f,g,sigma)
    print(len(problem.f))

    pert_sol = state_perturb(problem, verbose=verbose)

    controls_ss = calibration['controls']
    states_ss = calibration['states']

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

    if order == 1:
        if return_dr:
            S_bar = numpy.array(states_ss)
            X_bar = numpy.array(controls_ss)
            # add transitions of states to the d.r.

            X_s = pert_sol[0]
            A = g[1][:, :n_s] + numpy.dot(g[1][:, n_s:n_s+n_c], X_s)
            B = g[1][:, n_s+n_c:]
            dr = CDR(S_bar, X_bar, X_s)
            dr.A = A
            dr.B = B
            dr.sigma = sigma
            return dr

        return [controls_ss] + pert_sol

    if order == 2:
        [[X_s, X_ss], [X_tt]] = pert_sol
        X_bar = controls_ss + X_tt/2
        if return_dr:
            S_bar = states_ss
            S_bar = numpy.array(S_bar)
            X_bar = numpy.array(X_bar)
            dr = CDR(S_bar, X_bar, X_s, X_ss)
            A = g[1][:, :n_s] + numpy.dot(g[1][:, n_s:n_s+n_c], X_s)
            B = g[1][:, n_s+n_c:]
            dr.sigma = sigma
            dr.A = A
            dr.B = B
            return dr
        return [X_bar, X_s, X_ss]

    if order == 3:
        [[X_s, X_ss, X_sss], [X_tt, X_stt]] = pert_sol
        X_bar = controls_ss + X_tt/2
        X_s = X_s + X_stt/2
        if return_dr:
            S_bar = states_ss
            dr = CDR(S_bar, X_bar, X_s, X_ss, X_sss)
            dr.sigma = sigma
            return dr
        return [X_bar, X_s, X_ss, X_sss]