Пример #1
0
def time_iteration(model,
                   dr0=None,
                   dprocess=None,
                   with_complementarities=True,
                   verbose=True,
                   grid={},
                   maxit=1000,
                   inner_maxit=10,
                   tol=1e-6,
                   hook=None,
                   details=False,
                   interp_method='cubic'):
    '''
    Finds a global solution for ``model`` using backward time-iteration.

    This algorithm iterates on the residuals of the arbitrage equations

    Parameters
    ----------
    model : Model
        model to be solved
    verbose : boolean
        if True, display iterations
    dr0 : decision rule
        initial guess for the decision rule
    dprocess : DiscretizedProcess (model.exogenous.discretize())
        discretized process to be used
    with_complementarities : boolean (True)
        if False, complementarity conditions are ignored
    grid: grid options
        overload the values set in `options:grid` section
    maxit: maximum number of iterations
    inner_maxit: maximum number of iteration for inner solver
    tol: tolerance criterium for successive approximations
    hook: Callable
        function to be called within each iteration, useful for debugging purposes


    Returns
    -------
    decision rule :
        approximated solution
    '''

    from dolo import dprint

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

    if dprocess is None:
        dprocess = model.exogenous.discretize()

    n_ms = dprocess.n_nodes  # number of exogenous states
    n_mv = dprocess.n_inodes(
        0)  # this assume number of integration nodes is constant

    x0 = model.calibration['controls']
    parms = model.calibration['parameters']
    n_x = len(x0)
    n_s = len(model.symbols['states'])

    endo_grid = model.get_endo_grid(**grid)

    exo_grid = dprocess.grid

    mdr = DecisionRule(exo_grid,
                       endo_grid,
                       dprocess=dprocess,
                       interp_method=interp_method)

    grid = mdr.endo_grid.nodes
    N = grid.shape[0]

    controls_0 = numpy.zeros((n_ms, N, n_x))
    if dr0 is None:
        controls_0[:, :, :] = x0[None, None, :]
    else:
        if isinstance(dr0, AlgoResult):
            dr0 = dr0.dr
        try:
            for i_m in range(n_ms):
                controls_0[i_m, :, :] = dr0(i_m, grid)
        except Exception:
            for i_m in range(n_ms):
                m = dprocess.node(i_m)
                controls_0[i_m, :, :] = dr0(m, grid)

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

    if 'controls_lb' in model.functions and with_complementarities == True:
        lb_fun = model.functions['controls_lb']
        ub_fun = model.functions['controls_ub']
        lb = numpy.zeros_like(controls_0) * numpy.nan
        ub = numpy.zeros_like(controls_0) * numpy.nan
        for i_m in range(n_ms):
            m = dprocess.node(i_m)[None, :]
            p = parms[None, :]
            m = numpy.repeat(m, N, axis=0)
            p = numpy.repeat(p, N, axis=0)

            lb[i_m, :, :] = lb_fun(m, grid, p)
            ub[i_m, :, :] = ub_fun(m, grid, p)

    else:
        with_complementarities = False

    sh_c = controls_0.shape

    controls_0 = controls_0.reshape((-1, n_x))

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

    err = 10
    it = 0

    if with_complementarities:
        lb = lb.reshape((-1, n_x))
        ub = ub.reshape((-1, n_x))

    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)

    import time
    t1 = time.time()

    err_0 = numpy.nan

    verbit = (verbose == 'full')

    while err > tol and it < maxit:

        it += 1

        t_start = time.time()

        mdr.set_values(controls_0.reshape(sh_c))

        fn = lambda x: residuals_simple(f, g, grid, x.reshape(sh_c), mdr,
                                        dprocess, parms).reshape((-1, n_x))
        dfn = SerialDifferentiableFunction(fn)

        res = fn(controls_0)

        if hook:
            hook()

        if with_complementarities:
            [controls, nit] = ncpsolve(dfn,
                                       lb,
                                       ub,
                                       controls_0,
                                       verbose=verbit,
                                       maxit=inner_maxit)
        else:
            [controls, nit] = newton(dfn,
                                     controls_0,
                                     verbose=verbit,
                                     maxit=inner_maxit)

        err = abs(controls - controls_0).max()

        err_SA = err / err_0
        err_0 = err

        controls_0 = controls

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

    controls_0 = controls.reshape(sh_c)

    mdr.set_values(controls_0)

    t2 = time.time()

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

    if not details:
        return mdr

    return TimeIterationResult(
        mdr,
        it,
        with_complementarities,
        dprocess,
        err < tol,  # x_converged: bool
        tol,  # x_tol
        err,  #: float
        None,  # log: object # TimeIterationLog
        None  # trace: object #{Nothing,IterationTrace}
    )
Пример #2
0
def evaluate_policy(model,
                    mdr,
                    tol=1e-8,
                    maxit=2000,
                    grid={},
                    verbose=True,
                    initial_guess=None,
                    hook=None,
                    integration_orders=None,
                    details=False,
                    interp_type='cubic'):
    """Compute value function corresponding to policy ``dr``

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

    model:
        "dtcscc" model. Must contain a 'value' function.

    mdr:
        decision rule to evaluate

    Returns:
    --------

    decision rule:
        value function (a function of the space similar to a decision rule
        object)

    """

    process = model.exogenous
    dprocess = process.discretize()

    n_ms = dprocess.n_nodes()  # number of exogenous states
    n_mv = dprocess.n_inodes(
        0)  # this assume number of integration nodes is constant

    x0 = model.calibration['controls']
    v0 = model.calibration['values']
    parms = model.calibration['parameters']
    n_x = len(x0)
    n_v = len(v0)
    n_s = len(model.symbols['states'])

    endo_grid = model.get_grid(**grid)
    exo_grid = dprocess.grid

    if initial_guess is not None:
        mdrv = initial_guess
    else:
        mdrv = DecisionRule(exo_grid, endo_grid, interp_type=interp_type)

    grid = mdrv.endo_grid.nodes()
    N = grid.shape[0]

    if isinstance(mdr, np.ndarray):
        controls = mdr
    else:
        controls = np.zeros((n_ms, N, n_x))
        for i_m in range(n_ms):
            controls[i_m, :, :] = mdr.eval_is(i_m, grid)

    values_0 = np.zeros((n_ms, N, n_v))
    if initial_guess is None:
        for i_m in range(n_ms):
            values_0[i_m, :, :] = v0[None, :]
    else:
        for i_m in range(n_ms):
            values_0[i_m, :, :] = initial_guess.eval_is(i_m, grid)

    val = model.functions['value']
    g = model.functions['transition']

    sh_v = values_0.shape

    err = 10
    inner_maxit = 50
    it = 0

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

    t1 = time.time()

    err_0 = np.nan

    verbit = (verbose == 'full')

    while err > tol and it < maxit:

        it += 1

        t_start = time.time()

        mdrv.set_values(values_0.reshape(sh_v))
        values = update_value(val, g, grid, controls, values_0, mdr, mdrv,
                              dprocess, parms).reshape((-1, n_v))
        err = abs(values.reshape(sh_v) - values_0).max()

        err_SA = err / err_0
        err_0 = err

        values_0 = values.reshape(sh_v)

        t_finish = time.time()
        elapsed = t_finish - t_start

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

    # values_0 = values.reshape(sh_v)

    t2 = time.time()

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

    if not details:
        return mdrv
    else:
        return EvaluationResult(mdrv, it, tol, err)
Пример #3
0
def improved_time_iteration(
    model,
    method="jac",
    dr0=None,
    dprocess=None,
    interp_method="cubic",
    mu=2,
    maxbsteps=10,
    verbose=False,
    tol=1e-8,
    smaxit=500,
    maxit=1000,
    complementarities=True,
    compute_radius=False,
    invmethod="iti",
    details=True,
):
    def vprint(*args, **kwargs):
        if verbose:
            print(*args, **kwargs)

    itprint = IterationsPrinter(
        ("N", int),
        ("f_x", float),
        ("d_x", float),
        ("Time_residuals", float),
        ("Time_inversion", float),
        ("Time_search", float),
        ("Lambda_0", float),
        ("N_invert", int),
        ("N_search", int),
        verbose=verbose,
    )
    itprint.print_header("Start Improved Time Iterations.")

    f = model.functions["arbitrage"]
    g = model.functions["transition"]
    x_lb = model.functions["arbitrage_lb"]
    x_ub = model.functions["arbitrage_ub"]

    parms = model.calibration["parameters"]

    if dprocess is not None:
        from dolo.numeric.grids import ProductGrid

        endo_grid = model.domain.discretize()
        grid = ProductGrid(dprocess.grid, endo_grid, names=["exo", "endo"])
    else:
        grid, dprocess = model.discretize()

    endo_grid = grid["endo"]
    exo_grid = grid["exo"]

    n_m = max(dprocess.n_nodes, 1)
    n_s = len(model.symbols["states"])

    if interp_method in ("cubic", "linear"):
        ddr = DecisionRule(
            exo_grid, endo_grid, dprocess=dprocess, interp_method=interp_method
        )
        ddr_filt = DecisionRule(
            exo_grid, endo_grid, dprocess=dprocess, interp_method=interp_method
        )
    else:
        raise Exception("Unsupported interpolation method.")

    # s = ddr.endo_grid
    s = endo_grid.nodes
    N = s.shape[0]
    n_x = len(model.symbols["controls"])
    x0 = (
        model.calibration["controls"][
            None,
            None,
        ]
        .repeat(n_m, axis=0)
        .repeat(N, axis=1)
    )

    if dr0 is not None:
        for i_m in range(n_m):
            x0[i_m, :, :] = dr0.eval_is(i_m, s)
    ddr.set_values(x0)

    steps = 0.5 ** numpy.arange(maxbsteps)

    lb = x0.copy()
    ub = x0.copy()
    for i_m in range(n_m):
        m = dprocess.node(i_m)
        lb[i_m, :] = x_lb(m, s, parms)
        ub[i_m, :] = x_ub(m, s, parms)

    x = x0

    # both affect the precision

    ddr.set_values(x)

    ## memory allocation

    n_im = dprocess.n_inodes(0)  # we assume it is constant for now

    jres = numpy.zeros((n_m, n_im, N, n_x, n_x))
    S_ij = numpy.zeros((n_m, n_im, N, n_s))

    for it in range(maxit):

        jres[...] = 0.0
        S_ij[...] = 0.0

        t1 = time.time()

        # compute derivatives and residuals:
        # res: residuals
        # dres: derivatives w.r.t. x
        # jres: derivatives w.r.t. ~x
        # fut_S: future states

        ddr.set_values(x)
        #
        # ub[ub>100000] = 100000
        # lb[lb<-100000] = -100000
        #
        # sh_x = x.shape
        # rr =euler_residuals(f,g,s,x,ddr,dp,parms, diff=False, with_jres=False,set_dr=True)
        # print(rr.shape)
        #
        # from iti.fb import smooth_
        # jj = smooth_(rr, x, lb, ub)
        #
        # print("Errors with complementarities")
        # print(abs(jj.max()))
        #
        # exit()
        #

        from dolo.numeric.optimize.newton import SerialDifferentiableFunction

        sh_x = x.shape
        ff = SerialDifferentiableFunction(
            lambda u: euler_residuals(
                f,
                g,
                s,
                u.reshape(sh_x),
                ddr,
                dprocess,
                parms,
                diff=False,
                with_jres=False,
                set_dr=False,
            ).reshape((-1, sh_x[2]))
        )
        res, dres = ff(x.reshape((-1, sh_x[2])))
        res = res.reshape(sh_x)
        dres = dres.reshape((sh_x[0], sh_x[1], sh_x[2], sh_x[2]))
        junk, jres, fut_S = euler_residuals(
            f,
            g,
            s,
            x,
            ddr,
            dprocess,
            parms,
            diff=False,
            with_jres=True,
            set_dr=False,
            jres=jres,
            S_ij=S_ij,
        )

        # if there are complementerities, we modify derivatives
        if complementarities:
            res, dres, jres = smooth(res, dres, jres, x - lb)
            res[...] *= -1
            dres[...] *= -1
            jres[...] *= -1
            res, dres, jres = smooth(res, dres, jres, ub - x, pos=-1.0)
            res[...] *= -1
            dres[...] *= -1
            jres[...] *= -1

        err_0 = abs(res).max()

        # premultiply by A
        jres[...] *= -1.0

        for i_m in range(n_m):
            for j_m in range(n_im):
                M = jres[i_m, j_m, :, :, :]
                X = dres[i_m, :, :, :].copy()
                sol = solve_tensor(X, M)

        t2 = time.time()

        # new version
        if invmethod == "gmres":
            ddx = solve_gu(dres.copy(), res.copy())
            L = Operator(jres, fut_S, ddr_filt)
            n0 = L.counter
            L.addid = True
            ttol = err_0 / 100
            sol = scipy.sparse.linalg.gmres(
                L, ddx.ravel(), tol=ttol
            )  # , maxiter=1, restart=smaxit)
            lam0 = 0.01
            nn = L.counter - n0
            tot = sol[0].reshape(ddx.shape)
        else:
            # compute inversion
            tot, nn, lam0 = invert_jac(
                res,
                dres,
                jres,
                fut_S,
                ddr_filt,
                tol=tol,
                maxit=smaxit,
                verbose=(verbose == "full"),
            )

        # lam, lam_max, lambdas = radius_jac(res,dres,jres,fut_S,tol=tol,maxit=1000,verbose=(verbose=='full'),filt=ddr_filt)

        # backsteps
        t3 = time.time()
        for i_bckstps, lam in enumerate(steps):
            new_x = x - tot * lam
            new_err = euler_residuals(
                f, g, s, new_x, ddr, dprocess, parms, diff=False, set_dr=True
            )

            if complementarities:
                new_err = smooth_nodiff(new_err, new_x - lb)
                new_err = smooth_nodiff(-new_err, ub - new_x)

            new_err = abs(new_err).max()
            if new_err < err_0:
                break

        err_2 = abs(tot).max()
        t4 = time.time()
        itprint.print_iteration(
            N=it,
            f_x=err_0,
            d_x=err_2,
            Time_residuals=t2 - t1,
            Time_inversion=t3 - t2,
            Time_search=t4 - t3,
            Lambda_0=lam0,
            N_invert=nn,
            N_search=i_bckstps,
        )
        if err_0 < tol:
            break

        x = new_x

    ddr.set_values(x)

    itprint.print_finished()

    # if compute_radius:
    #     return ddx,L
    #     lam, lam_max, lambdas = radius_jac(res,dres,jres,fut_S,ddr_filt,tol=tol,maxit=smaxit,verbose=(verbose=='full'))
    #     return ddr, lam, lam_max, lambdas
    # else:
    if not details:
        return ddr
    else:
        ddx = solve_gu(dres.copy(), res.copy())
        L = Operator(jres, fut_S, ddr_filt)

        if compute_radius:
            lam = scipy.sparse.linalg.eigs(L, k=1, return_eigenvectors=False)
            lam = abs(lam[0])
        else:
            lam = np.nan
        # lam, lam_max, lambdas = radius_jac(res,dres,jres,fut_S,ddr_filt,tol=tol,maxit=smaxit,verbose=(verbose=='full'))
        return ImprovedTimeIterationResult(
            ddr, it, err_0, err_2, err_0 < tol, complementarities, lam, None, L
        )
Пример #4
0
def simulate(
    model: Model,
    dr: DecisionRule,
    *,
    process=None,
    N=1,
    T=40,
    s0=None,
    i0=None,
    m0=None,
    driving_process=None,
    seed=42,
    stochastic=True,
):
    """Simulate a model using the specified decision rule.

    Parameters
    ----------

    model: Model

    dr: decision rule

    process:

    s0: ndarray
        initial state where all simulations start

    driving_process: ndarray
        realization of exogenous driving process (drawn randomly if None)

    N: int
        number of simulations
    T: 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

    Returns
    -------
    xarray.DataArray:
        returns a ``T x N x n_v`` array where ``n_v``
           is the number of variables.
    """

    if isinstance(dr, AlgoResult):
        dr = dr.dr

    calib = model.calibration
    parms = numpy.array(calib["parameters"])

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

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

    s_simul = numpy.zeros((T, N, n_s))
    x_simul = numpy.zeros((T, N, n_x))

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

    # are we simulating a markov chain or a continuous process ?
    if driving_process is not None:
        if len(driving_process.shape) == 3:
            m_simul = driving_process
            sim_type = "continuous"
            if m0 is None:
                m0 = model.calibration["exogenous"]
            x_simul[0, :, :] = dr.eval_ms(m0[None, :], s0[None, :])[0, :]
        elif len(driving_process.shape) == 2:
            i_simul = driving_process
            nodes = dr.exo_grid.nodes
            m_simul = nodes[i_simul]
            # inds = i_simul.ravel()
            # m_simul = np.reshape( np.concatenate( [nodes[i,:][None,:] for i in inds.ravel()], axis=0 ), inds.shape + (-1,) )
            sim_type = "discrete"
            x_simul[0, :, :] = dr.eval_is(i0, s0[None, :])[0, :]
        else:
            raise Exception("Incorrect specification of driving values.")
        m0 = m_simul[0, :, :]
    else:
        from dolo.numeric.processes import DiscreteProcess

        if process is None:
            if hasattr(dr, "dprocess") and hasattr(dr.dprocess, "simulate"):
                process = dr.dprocess
            else:
                process = model.exogenous

        # detect type of simulation
        if not isinstance(process, DiscreteProcess):
            sim_type = "continuous"
        else:
            sim_type = "discrete"

        if sim_type == "discrete":
            if i0 is None:
                i0 = 0
            dp = process
            m_simul = dp.simulate(N, T, i0=i0, stochastic=stochastic)
            i_simul = find_index(m_simul, dp.values)
            m0 = dp.node(i0)
            x0 = dr.eval_is(i0, s0[None, :])[0, :]
        else:
            m_simul = process.simulate(N, T, m0=m0, stochastic=stochastic)
            if isinstance(m_simul, xr.DataArray):
                m_simul = m_simul.data
            sim_type = "continuous"
            if m0 is None:
                m0 = model.calibration["exogenous"]
            x0 = dr.eval_ms(m0[None, :], s0[None, :])[0, :]
            x_simul[0, :, :] = x0[None, :]

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

    numpy.random.seed(seed)

    mp = m0
    for i in range(T):
        m = m_simul[i, :, :]
        s = s_simul[i, :, :]
        if sim_type == "discrete":
            i_m = i_simul[i, :]
            xx = [
                dr.eval_is(i_m[ii], s[ii, :][None, :])[0, :] for ii in range(s.shape[0])
            ]
            x = np.row_stack(xx)
        else:
            x = dr.eval_ms(m, s)

        x_simul[i, :, :] = x

        ss = g(mp, s, x, m, parms)
        if i < T - 1:
            s_simul[i + 1, :, :] = ss
        mp = m

    if "auxiliary" not in model.functions:  # TODO: find a better test than this
        l = [s_simul, x_simul]
        varnames = model.symbols["states"] + model.symbols["controls"]
    else:
        aux = model.functions["auxiliary"]
        a_simul = aux(
            m_simul.reshape((N * T, -1)),
            s_simul.reshape((N * T, -1)),
            x_simul.reshape((N * T, -1)),
            parms,
        )
        a_simul = a_simul.reshape(T, N, -1)
        l = [m_simul, s_simul, x_simul, a_simul]
        varnames = (
            model.symbols["exogenous"]
            + model.symbols["states"]
            + model.symbols["controls"]
            + model.symbols["auxiliaries"]
        )

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

    if sim_type == "discrete":
        varnames = ["_i_m"] + varnames
        simul = np.concatenate([i_simul[:, :, None], simul], axis=2)

    data = xr.DataArray(
        simul,
        dims=["T", "N", "V"],
        coords={"T": range(T), "N": range(N), "V": varnames},
    )

    return data
Пример #5
0
def value_iteration(model,
                    grid={},
                    tol=1e-6,
                    maxit=500,
                    maxit_howard=20,
                    verbose=False):
    """
    Solve for the value function and associated Markov decision rule by iterating over
    the value function.

    Parameters:
    -----------
    model :
        "dtmscc" model. Must contain a 'felicity' function.
    grid :
        grid options
    dr :
        decision rule to evaluate

    Returns:
    --------
    mdr : Markov decision rule
        The solved decision rule/policy function
    mdrv: decision rule
        The solved value function
    """

    transition = model.functions['transition']
    felicity = model.functions['felicity']
    controls_lb = model.functions['controls_lb']
    controls_ub = model.functions['controls_ub']

    parms = model.calibration['parameters']
    discount = model.calibration['beta']

    x0 = model.calibration['controls']
    m0 = model.calibration['exogenous']
    s0 = model.calibration['states']
    r0 = felicity(m0, s0, x0, parms)

    process = model.exogenous
    dprocess = process.discretize()

    n_ms = dprocess.n_nodes()  # number of exogenous states
    n_mv = dprocess.n_inodes(
        0)  # this assume number of integration nodes is constant

    endo_grid = model.get_grid(**grid)

    exo_grid = dprocess.grid

    mdrv = DecisionRule(exo_grid, endo_grid)

    grid = mdrv.endo_grid.nodes()
    N = grid.shape[0]
    n_x = len(x0)

    mdr = constant_policy(model)
    controls_0 = np.zeros((n_ms, N, n_x))
    for i_ms in range(n_ms):
        controls_0[i_ms, :, :] = mdr.eval_is(i_ms, grid)

    values_0 = np.zeros((n_ms, N, 1))
    # for i_ms in range(n_ms):
    #     values_0[i_ms, :, :] = mdrv(i_ms, grid)

    mdr = DecisionRule(exo_grid, endo_grid)
    # mdr.set_values(controls_0)

    # THIRD: value function iterations until convergence
    it = 0
    err_v = 100
    err_v_0 = 0
    gain_v = 0.0
    err_x = 100
    err_x_0 = 0
    tol_x = 1e-5
    tol_v = 1e-7

    itprint = IterationsPrinter(
        ('N', int), ('Error_V', float), ('Gain_V', float), ('Error_x', float),
        ('Gain_x', float), ('Eval_n', int), ('Time', float),
        verbose=verbose)
    itprint.print_header('Start value function iterations.')

    while (it < maxit) and (err_v > tol or err_x > tol_x):

        t_start = time.time()
        it += 1

        mdr.set_values(controls_0)
        if it > 2:
            ev = evaluate_policy(model,
                                 mdr,
                                 initial_guess=mdrv,
                                 verbose=False,
                                 details=True)
        else:
            ev = evaluate_policy(model, mdr, verbose=False, details=True)

        mdrv = ev.solution
        for i_ms in range(n_ms):
            values_0[i_ms, :, :] = mdrv.eval_is(i_ms, grid)

        values = values_0.copy()
        controls = controls_0.copy()

        for i_m in range(n_ms):
            m = dprocess.node(i_m)
            for n in range(N):
                s = grid[n, :]
                x = controls[i_m, n, :]
                lb = controls_lb(m, s, parms)
                ub = controls_ub(m, s, parms)
                bnds = [e for e in zip(lb, ub)]

                def valfun(xx):
                    return -choice_value(transition, felicity, i_m, s, xx,
                                         mdrv, dprocess, parms, discount)[0]

                res = scipy.optimize.minimize(valfun, x, bounds=bnds)
                controls[i_m, n, :] = res.x
                values[i_m, n, 0] = -valfun(x)

        # compute error, update value and dr
        err_x = abs(controls - controls_0).max()
        err_v = abs(values - values_0).max()
        t_end = time.time()
        elapsed = t_end - t_start

        values_0 = values
        controls_0 = controls

        gain_x = err_x / err_x_0
        gain_v = err_v / err_v_0

        err_x_0 = err_x
        err_v_0 = err_v

        itprint.print_iteration(N=it,
                                Error_V=err_v,
                                Gain_V=gain_v,
                                Error_x=err_x,
                                Gain_x=gain_x,
                                Eval_n=ev.iterations,
                                Time=elapsed)

    itprint.print_finished()

    mdr = DecisionRule(exo_grid, endo_grid)
    mdr.set_values(controls)
    mdrv.set_values(values_0)

    return mdr, mdrv
Пример #6
0
def evaluate_policy(
    model,
    mdr,
    tol=1e-8,
    maxit=2000,
    grid={},
    verbose=True,
    dr0=None,
    hook=None,
    integration_orders=None,
    details=False,
    interp_method="cubic",
):
    """Compute value function corresponding to policy ``dr``

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

    model:
        "dtcscc" model. Must contain a 'value' function.

    mdr:
        decision rule to evaluate

    Returns:
    --------

    decision rule:
        value function (a function of the space similar to a decision rule
        object)

    """

    process = model.exogenous
    grid, dprocess = model.discretize()
    endo_grid = grid["endo"]
    exo_grid = grid["exo"]

    n_ms = dprocess.n_nodes  # number of exogenous states
    n_mv = dprocess.n_inodes(
        0)  # this assume number of integration nodes is constant

    x0 = model.calibration["controls"]
    v0 = model.calibration["values"]
    parms = model.calibration["parameters"]
    n_x = len(x0)
    n_v = len(v0)
    n_s = len(model.symbols["states"])

    if dr0 is not None:
        mdrv = dr0
    else:
        mdrv = DecisionRule(exo_grid, endo_grid, interp_method=interp_method)

    s = mdrv.endo_grid.nodes
    N = s.shape[0]

    if isinstance(mdr, np.ndarray):
        controls = mdr
    else:
        controls = np.zeros((n_ms, N, n_x))
        for i_m in range(n_ms):
            controls[i_m, :, :] = mdr.eval_is(i_m, s)

    values_0 = np.zeros((n_ms, N, n_v))
    if dr0 is None:
        for i_m in range(n_ms):
            values_0[i_m, :, :] = v0[None, :]
    else:
        for i_m in range(n_ms):
            values_0[i_m, :, :] = dr0.eval_is(i_m, s)

    val = model.functions["value"]
    g = model.functions["transition"]

    sh_v = values_0.shape

    err = 10
    inner_maxit = 50
    it = 0

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

    t1 = time.time()

    err_0 = np.nan

    verbit = verbose == "full"

    while err > tol and it < maxit:

        it += 1

        t_start = time.time()

        mdrv.set_values(values_0.reshape(sh_v))
        values = update_value(val, g, s, controls, values_0, mdr, mdrv,
                              dprocess, parms).reshape((-1, n_v))
        err = abs(values.reshape(sh_v) - values_0).max()

        err_SA = err / err_0
        err_0 = err

        values_0 = values.reshape(sh_v)

        t_finish = time.time()
        elapsed = t_finish - t_start

        if verbose:
            print("|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |".format(
                it, err, err_SA, elapsed))

    # values_0 = values.reshape(sh_v)

    t2 = time.time()

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

    if not details:
        return mdrv
    else:
        return EvaluationResult(mdrv, it, tol, err)
Пример #7
0
def time_iteration(model,
                   initial_guess=None,
                   with_complementarities=True,
                   verbose=True,
                   grid={},
                   maxit=1000,
                   inner_maxit=10,
                   tol=1e-6,
                   hook=None):
    '''
    Finds a global solution for ``model`` using backward time-iteration.

    This algorithm iterates on the residuals of the arbitrage equations

    Parameters
    ----------
    model : NumericModel
        "dtmscc" model to be solved
    verbose : boolean
        if True, display iterations
    initial_dr : decision rule
        initial guess for the decision rule
    with_complementarities : boolean (True)
        if False, complementarity conditions are ignored
    grid: grid options
    maxit: maximum number of iterations
    inner_maxit: maximum number of iteration for inner solver
    tol: tolerance criterium for successive approximations

    Returns
    -------
    decision rule :
        approximated solution
    '''

    from dolo import dprint

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

    process = model.exogenous
    dprocess = process.discretize()

    n_ms = dprocess.n_nodes()  # number of exogenous states
    n_mv = dprocess.n_inodes(
        0)  # this assume number of integration nodes is constant

    x0 = model.calibration['controls']
    parms = model.calibration['parameters']
    n_x = len(x0)
    n_s = len(model.symbols['states'])

    endo_grid = model.get_grid(**grid)

    interp_type = 'cubic'

    exo_grid = dprocess.grid

    mdr = DecisionRule(exo_grid, endo_grid)

    grid = mdr.endo_grid.nodes()
    N = grid.shape[0]

    controls_0 = numpy.zeros((n_ms, N, n_x))
    if initial_guess is None:
        controls_0[:, :, :] = x0[None, None, :]
    else:
        for i_m in range(n_ms):
            controls_0[i_m, :, :] = initial_guess(i_m, grid)

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

    if 'controls_lb' in model.functions and with_complementarities == True:
        lb_fun = model.functions['controls_lb']
        ub_fun = model.functions['controls_ub']
        lb = numpy.zeros_like(controls_0) * numpy.nan
        ub = numpy.zeros_like(controls_0) * numpy.nan
        for i_m in range(n_ms):
            m = dprocess.node(i_m)[None, :]
            p = parms[None, :]
            m = numpy.repeat(m, N, axis=0)
            p = numpy.repeat(p, N, axis=0)

            lb[i_m, :, :] = lb_fun(m, grid, p)
            ub[i_m, :, :] = ub_fun(m, grid, p)

    else:
        with_complementarities = False

    sh_c = controls_0.shape

    controls_0 = controls_0.reshape((-1, n_x))

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

    err = 10
    it = 0

    if with_complementarities:
        vprint("Solving WITH complementarities.")
        lb = lb.reshape((-1, n_x))
        ub = ub.reshape((-1, n_x))

    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)

    import time
    t1 = time.time()

    err_0 = numpy.nan

    verbit = (verbose == 'full')

    while err > tol and it < maxit:

        it += 1

        t_start = time.time()

        mdr.set_values(controls_0.reshape(sh_c))

        fn = lambda x: residuals_simple(f, g, grid, x.reshape(sh_c), mdr,
                                        dprocess, parms).reshape((-1, n_x))
        dfn = SerialDifferentiableFunction(fn)

        res = fn(controls_0)

        if hook:
            hook()

        if with_complementarities:
            [controls, nit] = ncpsolve(dfn,
                                       lb,
                                       ub,
                                       controls_0,
                                       verbose=verbit,
                                       maxit=inner_maxit)
        else:
            [controls, nit] = newton(dfn,
                                     controls_0,
                                     verbose=verbit,
                                     maxit=inner_maxit)

        err = abs(controls - controls_0).max()

        err_SA = err / err_0
        err_0 = err

        controls_0 = controls

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

    controls_0 = controls.reshape(sh_c)

    t2 = time.time()

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

    return mdr
Пример #8
0
def evaluate_policy(model,
                    mdr,
                    tol=1e-8,
                    maxit=2000,
                    grid={},
                    verbose=True,
                    initial_guess=None,
                    hook=None,
                    integration_orders=None,
                    details=False,
                    interp_type='cubic'):
    """Compute value function corresponding to policy ``dr``

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

    model:
        "dtcscc" model. Must contain a 'value' function.

    mdr:
        decision rule to evaluate

    Returns:
    --------

    decision rule:
        value function (a function of the space similar to a decision rule
        object)

    """

    process = model.exogenous
    dprocess = process.discretize()

    n_ms = dprocess.n_nodes()  # number of exogenous states
    n_mv = dprocess.n_inodes(
        0)  # this assume number of integration nodes is constant

    x0 = model.calibration['controls']
    v0 = model.calibration['values']
    parms = model.calibration['parameters']
    n_x = len(x0)
    n_v = len(v0)
    n_s = len(model.symbols['states'])

    endo_grid = model.get_grid(**grid)
    exo_grid = dprocess.grid

    if initial_guess is not None:
        mdrv = initial_guess
    else:
        mdrv = DecisionRule(exo_grid, endo_grid, interp_type=interp_type)

    grid = mdrv.endo_grid.nodes()
    N = grid.shape[0]

    if isinstance(mdr, np.ndarray):
        controls = mdr
    else:
        controls = np.zeros((n_ms, N, n_x))
        for i_m in range(n_ms):
            controls[i_m, :, :] = mdr.eval_is(i_m, grid)

    values_0 = np.zeros((n_ms, N, n_v))
    if initial_guess is None:
        for i_m in range(n_ms):
            values_0[i_m, :, :] = v0[None, :]
    else:
        for i_m in range(n_ms):
            values_0[i_m, :, :] = initial_guess.eval_is(i_m, grid)

    val = model.functions['value']
    g = model.functions['transition']

    sh_v = values_0.shape

    err = 10
    inner_maxit = 50
    it = 0

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

    t1 = time.time()

    err_0 = np.nan

    verbit = (verbose == 'full')

    while err > tol and it < maxit:

        it += 1

        t_start = time.time()

        mdrv.set_values(values_0.reshape(sh_v))
        values = update_value(val, g, grid, controls, values_0, mdr, mdrv,
                              dprocess, parms).reshape((-1, n_v))
        err = abs(values.reshape(sh_v) - values_0).max()

        err_SA = err / err_0
        err_0 = err

        values_0 = values.reshape(sh_v)

        t_finish = time.time()
        elapsed = t_finish - t_start

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

    # values_0 = values.reshape(sh_v)

    t2 = time.time()

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

    if not details:
        return mdrv
    else:
        return EvaluationResult(mdrv, it, tol, err)
Пример #9
0
def value_iteration(
    model: Model,
    *,
    verbose: bool = False,  #
    details: bool = True,  #
    tol=1e-6,
    maxit=500,
    maxit_howard=20,
) -> ValueIterationResult:
    """
    Solve for the value function and associated Markov decision rule by iterating over
    the value function.

    Parameters:
    -----------
    model :
        model to be solved
    dr :
        decision rule to evaluate

    Returns:
    --------
    mdr : Markov decision rule
        The solved decision rule/policy function
    mdrv: decision rule
        The solved value function
    """

    transition = model.functions["transition"]
    felicity = model.functions["felicity"]
    controls_lb = model.functions["controls_lb"]
    controls_ub = model.functions["controls_ub"]

    parms = model.calibration["parameters"]
    discount = model.calibration["beta"]

    x0 = model.calibration["controls"]
    m0 = model.calibration["exogenous"]
    s0 = model.calibration["states"]
    r0 = felicity(m0, s0, x0, parms)

    process = model.exogenous

    grid, dprocess = model.discretize()
    endo_grid = grid["endo"]
    exo_grid = grid["exo"]

    n_ms = dprocess.n_nodes  # number of exogenous states
    n_mv = dprocess.n_inodes(
        0)  # this assume number of integration nodes is constant

    mdrv = DecisionRule(exo_grid, endo_grid)

    s = mdrv.endo_grid.nodes
    N = s.shape[0]
    n_x = len(x0)

    mdr = constant_policy(model)

    controls_0 = np.zeros((n_ms, N, n_x))
    for i_ms in range(n_ms):
        controls_0[i_ms, :, :] = mdr.eval_is(i_ms, s)

    values_0 = np.zeros((n_ms, N, 1))
    # for i_ms in range(n_ms):
    #     values_0[i_ms, :, :] = mdrv(i_ms, grid)

    mdr = DecisionRule(exo_grid, endo_grid)
    # mdr.set_values(controls_0)

    # THIRD: value function iterations until convergence
    it = 0
    err_v = 100
    err_v_0 = 0
    gain_v = 0.0
    err_x = 100
    err_x_0 = 0
    tol_x = 1e-5
    tol_v = 1e-7

    itprint = IterationsPrinter(
        ("N", int),
        ("Error_V", float),
        ("Gain_V", float),
        ("Error_x", float),
        ("Gain_x", float),
        ("Eval_n", int),
        ("Time", float),
        verbose=verbose,
    )
    itprint.print_header("Start value function iterations.")

    while (it < maxit) and (err_v > tol or err_x > tol_x):

        t_start = time.time()
        it += 1

        mdr.set_values(controls_0)
        if it > 2:
            ev = evaluate_policy(model,
                                 mdr,
                                 dr0=mdrv,
                                 verbose=False,
                                 details=True)
        else:
            ev = evaluate_policy(model, mdr, verbose=False, details=True)

        mdrv = ev.solution
        for i_ms in range(n_ms):
            values_0[i_ms, :, :] = mdrv.eval_is(i_ms, s)

        values = values_0.copy()
        controls = controls_0.copy()

        for i_m in range(n_ms):
            m = dprocess.node(i_m)
            for n in range(N):
                s_ = s[n, :]
                x = controls[i_m, n, :]
                lb = controls_lb(m, s_, parms)
                ub = controls_ub(m, s_, parms)
                bnds = [e for e in zip(lb, ub)]

                def valfun(xx):
                    return -choice_value(
                        transition,
                        felicity,
                        i_m,
                        s_,
                        xx,
                        mdrv,
                        dprocess,
                        parms,
                        discount,
                    )[0]

                res = scipy.optimize.minimize(valfun, x, bounds=bnds)
                controls[i_m, n, :] = res.x
                values[i_m, n, 0] = -valfun(x)

        # compute error, update value and dr
        err_x = abs(controls - controls_0).max()
        err_v = abs(values - values_0).max()
        t_end = time.time()
        elapsed = t_end - t_start

        values_0 = values
        controls_0 = controls

        gain_x = err_x / err_x_0
        gain_v = err_v / err_v_0

        err_x_0 = err_x
        err_v_0 = err_v

        itprint.print_iteration(
            N=it,
            Error_V=err_v,
            Gain_V=gain_v,
            Error_x=err_x,
            Gain_x=gain_x,
            Eval_n=ev.iterations,
            Time=elapsed,
        )

    itprint.print_finished()

    mdr = DecisionRule(exo_grid, endo_grid)

    mdr.set_values(controls)
    mdrv.set_values(values_0)

    if not details:
        return mdr, mdrv
    else:
        return ValueIterationResult(
            mdr,  #:AbstractDecisionRule
            mdrv,  #:AbstractDecisionRule
            it,  #:Int
            dprocess,  #:AbstractDiscretizedProcess
            err_x < tol_x,  #:Bool
            tol_x,  #:Float64
            err_x,  #:Float64
            err_v < tol_v,  #:Bool
            tol_v,  #:Float64
            err_v,  #:Float64
            None,  # log:     #:ValueIterationLog
            None,  # trace:   #:Union{Nothing,IterationTrace
        )
Пример #10
0
def value_iteration(model,
                    grid={},
                    tol=1e-6,
                    maxit=500,
                    maxit_howard=20,
                    verbose=False,
                    details=True):
    """
    Solve for the value function and associated Markov decision rule by iterating over
    the value function.

    Parameters:
    -----------
    model :
        "dtmscc" model. Must contain a 'felicity' function.
    grid :
        grid options
    dr :
        decision rule to evaluate

    Returns:
    --------
    mdr : Markov decision rule
        The solved decision rule/policy function
    mdrv: decision rule
        The solved value function
    """

    transition = model.functions['transition']
    felicity = model.functions['felicity']
    controls_lb = model.functions['controls_lb']
    controls_ub = model.functions['controls_ub']

    parms = model.calibration['parameters']
    discount = model.calibration['beta']

    x0 = model.calibration['controls']
    m0 = model.calibration['exogenous']
    s0 = model.calibration['states']
    r0 = felicity(m0, s0, x0, parms)

    process = model.exogenous
    dprocess = process.discretize()

    n_ms = dprocess.n_nodes()  # number of exogenous states
    n_mv = dprocess.n_inodes(
        0)  # this assume number of integration nodes is constant

    endo_grid = model.get_grid(**grid)

    exo_grid = dprocess.grid

    mdrv = DecisionRule(exo_grid, endo_grid)

    grid = mdrv.endo_grid.nodes()
    N = grid.shape[0]
    n_x = len(x0)

    mdr = constant_policy(model)
    
    controls_0 = np.zeros((n_ms, N, n_x))
    for i_ms in range(n_ms):
        controls_0[i_ms, :, :] = mdr.eval_is(i_ms, grid)

    values_0 = np.zeros((n_ms, N, 1))
    # for i_ms in range(n_ms):
    #     values_0[i_ms, :, :] = mdrv(i_ms, grid)

    mdr = DecisionRule(exo_grid, endo_grid)
    # mdr.set_values(controls_0)

    # THIRD: value function iterations until convergence
    it = 0
    err_v = 100
    err_v_0 = 0
    gain_v = 0.0
    err_x = 100
    err_x_0 = 0
    tol_x = 1e-5
    tol_v = 1e-7

    itprint = IterationsPrinter(
        ('N', int), ('Error_V', float), ('Gain_V', float), ('Error_x', float),
        ('Gain_x', float), ('Eval_n', int), ('Time', float),
        verbose=verbose)
    itprint.print_header('Start value function iterations.')

    while (it < maxit) and (err_v > tol or err_x > tol_x):

        t_start = time.time()
        it += 1

        mdr.set_values(controls_0)
        if it > 2:
            ev = evaluate_policy(
                model, mdr, initial_guess=mdrv, verbose=False, details=True)
        else:
            ev = evaluate_policy(model, mdr, verbose=False, details=True)

        mdrv = ev.solution
        for i_ms in range(n_ms):
            values_0[i_ms, :, :] = mdrv.eval_is(i_ms, grid)

        values = values_0.copy()
        controls = controls_0.copy()

        for i_m in range(n_ms):
            m = dprocess.node(i_m)
            for n in range(N):
                s = grid[n, :]
                x = controls[i_m, n, :]
                lb = controls_lb(m, s, parms)
                ub = controls_ub(m, s, parms)
                bnds = [e for e in zip(lb, ub)]

                def valfun(xx):
                    return -choice_value(transition, felicity, i_m, s, xx,
                                         mdrv, dprocess, parms, discount)[0]

                res = scipy.optimize.minimize(valfun, x, bounds=bnds)
                controls[i_m, n, :] = res.x
                values[i_m, n, 0] = -valfun(x)

        # compute error, update value and dr
        err_x = abs(controls - controls_0).max()
        err_v = abs(values - values_0).max()
        t_end = time.time()
        elapsed = t_end - t_start

        values_0 = values
        controls_0 = controls

        gain_x = err_x / err_x_0
        gain_v = err_v / err_v_0

        err_x_0 = err_x
        err_v_0 = err_v

        itprint.print_iteration(
            N=it,
            Error_V=err_v,
            Gain_V=gain_v,
            Error_x=err_x,
            Gain_x=gain_x,
            Eval_n=ev.iterations,
            Time=elapsed)

    itprint.print_finished()

    mdr = DecisionRule(exo_grid, endo_grid)
    mdr.set_values(controls)
    mdrv.set_values(values_0)

    if not details:
        return mdr, mdrv
    else:
        return ValueIterationResult(
            mdr,             #:AbstractDecisionRule
            mdrv,            #:AbstractDecisionRule
            it,              #:Int
            dprocess,        #:AbstractDiscretizedProcess
            err_x<tol_x,     #:Bool
            tol_x,           #:Float64
            err_x,           #:Float64
            err_v<tol_v,     #:Bool
            tol_v,           #:Float64
            err_v,           #:Float64
            None,            #log:     #:ValueIterationLog
            None             #trace:   #:Union{Nothing,IterationTrace
        )
Пример #11
0
def improved_time_iteration(model,
                            method='jac',
                            initial_dr=None,
                            interp_type='spline',
                            mu=2,
                            maxbsteps=10,
                            verbose=False,
                            tol=1e-8,
                            smaxit=500,
                            maxit=1000,
                            complementarities=True,
                            compute_radius=False,
                            invmethod='gmres',
                            details=True):
    def vprint(*args, **kwargs):
        if verbose:
            print(*args, **kwargs)

    itprint = IterationsPrinter(
        ('N', int), ('f_x', float), ('d_x', float), ('Time_residuals', float),
        ('Time_inversion', float), ('Time_search', float), ('Lambda_0', float),
        ('N_invert', int), ('N_search', int),
        verbose=verbose)
    itprint.print_header('Start Improved Time Iterations.')

    f = model.functions['arbitrage']
    g = model.functions['transition']
    x_lb = model.functions['controls_lb']
    x_ub = model.functions['controls_ub']

    parms = model.calibration['parameters']

    dp = model.exogenous.discretize()

    n_m = max(dp.n_nodes(), 1)

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

    grid = model.get_grid()

    if interp_type == 'spline':
        ddr = DecisionRule(dp.grid, grid)
        ddr_filt = DecisionRule(dp.grid, grid)
    elif interp_type == 'smolyak':
        ddr = SmolyakDecisionRule(n_m, grid.min, grid.max, mu)
        ddr_filt = SmolyakDecisionRule(n_m, grid.min, grid.max, mu)
        derivative_type = 'numerical'

    # s = ddr.endo_grid
    s = grid.nodes()
    N = s.shape[0]
    n_x = len(model.symbols['controls'])
    x0 = model.calibration['controls'][None,
                                       None, ].repeat(n_m,
                                                      axis=0).repeat(N, axis=1)

    if initial_dr is not None:
        for i_m in range(n_m):
            x0[i_m, :, :] = initial_dr.eval_is(i_m, s)
    ddr.set_values(x0)

    steps = 0.5**numpy.arange(maxbsteps)

    lb = x0.copy()
    ub = x0.copy()
    for i_m in range(n_m):
        m = dp.node(i_m)
        lb[i_m, :] = x_lb(m, s, parms)
        ub[i_m, :] = x_ub(m, s, parms)

    x = x0

    # both affect the precision

    ddr.set_values(x)

    ## memory allocation

    n_im = dp.n_inodes(0)  # we assume it is constant for now

    jres = numpy.zeros((n_m, n_im, N, n_x, n_x))
    S_ij = numpy.zeros((n_m, n_im, N, n_s))

    for it in range(maxit):

        jres[...] = 0.0
        S_ij[...] = 0.0

        t1 = time.time()

        # compute derivatives and residuals:
        # res: residuals
        # dres: derivatives w.r.t. x
        # jres: derivatives w.r.t. ~x
        # fut_S: future states

        ddr.set_values(x)
        #
        # ub[ub>100000] = 100000
        # lb[lb<-100000] = -100000
        #
        # sh_x = x.shape
        # rr =euler_residuals(f,g,s,x,ddr,dp,parms, diff=False, with_jres=False,set_dr=True)
        # print(rr.shape)
        #
        # from iti.fb import smooth_
        # jj = smooth_(rr, x, lb, ub)
        #
        # print("Errors with complementarities")
        # print(abs(jj.max()))
        #
        # exit()
        #

        from dolo.numeric.optimize.newton import SerialDifferentiableFunction
        sh_x = x.shape
        ff = SerialDifferentiableFunction(
            lambda u: euler_residuals(f,
                                      g,
                                      s,
                                      u.reshape(sh_x),
                                      ddr,
                                      dp,
                                      parms,
                                      diff=False,
                                      with_jres=False,
                                      set_dr=False).reshape((-1, sh_x[2])))
        res, dres = ff(x.reshape((-1, sh_x[2])))
        res = res.reshape(sh_x)
        dres = dres.reshape((sh_x[0], sh_x[1], sh_x[2], sh_x[2]))
        junk, jres, fut_S = euler_residuals(f,
                                            g,
                                            s,
                                            x,
                                            ddr,
                                            dp,
                                            parms,
                                            diff=False,
                                            with_jres=True,
                                            set_dr=False,
                                            jres=jres,
                                            S_ij=S_ij)

        # if there are complementerities, we modify derivatives
        if complementarities:
            res, dres, jres = smooth(res, dres, jres, x - lb)
            res[...] *= -1
            dres[...] *= -1
            jres[...] *= -1
            res, dres, jres = smooth(res, dres, jres, ub - x, pos=-1.0)
            res[...] *= -1
            dres[...] *= -1
            jres[...] *= -1

        err_0 = (abs(res).max())

        # premultiply by A
        jres[...] *= -1.0

        for i_m in range(n_m):
            for j_m in range(n_im):
                M = jres[i_m, j_m, :, :, :]
                X = dres[i_m, :, :, :].copy()
                sol = solve_tensor(X, M)

        t2 = time.time()

        # new version
        if invmethod == 'gmres':
            import scipy.sparse.linalg
            ddx = solve_gu(dres.copy(), res.copy())
            L = Operator(jres, fut_S, ddr_filt)
            n0 = L.counter
            L.addid = True
            ttol = err_0 / 100
            sol = scipy.sparse.linalg.gmres(
                L, ddx.ravel(), tol=ttol)  #, maxiter=1, restart=smaxit)
            lam0 = 0.01
            nn = L.counter - n0
            tot = sol[0].reshape(ddx.shape)
        else:
            # compute inversion
            tot, nn, lam0 = invert_jac(res,
                                       dres,
                                       jres,
                                       fut_S,
                                       ddr_filt,
                                       tol=tol,
                                       maxit=smaxit,
                                       verbose=(verbose == 'full'))

        # lam, lam_max, lambdas = radius_jac(res,dres,jres,fut_S,tol=tol,maxit=1000,verbose=(verbose=='full'),filt=ddr_filt)

        # backsteps
        t3 = time.time()
        for i_bckstps, lam in enumerate(steps):
            new_x = x - tot * lam
            new_err = euler_residuals(f,
                                      g,
                                      s,
                                      new_x,
                                      ddr,
                                      dp,
                                      parms,
                                      diff=False,
                                      set_dr=True)

            if complementarities:
                new_err = smooth_nodiff(new_err, new_x - lb)
                new_err = smooth_nodiff(-new_err, ub - new_x)

            new_err = abs(new_err).max()
            if new_err < err_0:
                break

        err_2 = abs(tot).max()
        t4 = time.time()
        itprint.print_iteration(N=it,
                                f_x=err_0,
                                d_x=err_2,
                                Time_residuals=t2 - t1,
                                Time_inversion=t3 - t2,
                                Time_search=t4 - t3,
                                Lambda_0=lam0,
                                N_invert=nn,
                                N_search=i_bckstps)
        if err_0 < tol:
            break

        x = new_x

    ddr.set_values(x)

    itprint.print_finished()

    # if compute_radius:
    #     return ddx,L
    #     lam, lam_max, lambdas = radius_jac(res,dres,jres,fut_S,ddr_filt,tol=tol,maxit=smaxit,verbose=(verbose=='full'))
    #     return ddr, lam, lam_max, lambdas
    # else:
    if not details:
        return ddr
    else:
        ddx = solve_gu(dres.copy(), res.copy())
        L = Operator(jres, fut_S, ddr_filt)
        lam = scipy.sparse.linalg.eigs(L, k=1, return_eigenvectors=False)
        lam = abs(lam[0])
        # lam, lam_max, lambdas = radius_jac(res,dres,jres,fut_S,ddr_filt,tol=tol,maxit=smaxit,verbose=(verbose=='full'))
        return ImprovedTimeIterationResult(ddr, it, err_0, err_2, err_0 < tol,
                                           complementarities, lam, None, L)
Пример #12
0
def egm(
    model: Model,
    dr0: DecisionRule = None,
    verbose: bool = False,
    details: bool = True,
    a_grid=None,
    η_tol=1e-6,
    maxit=1000,
    grid=None,
    dp=None,
):
    """
    a_grid: (numpy-array) vector of points used to discretize poststates; must be increasing
    """

    assert len(model.symbols["states"]) == 1
    assert (len(model.symbols["controls"]) == 1
            )  # we probably don't need this restriction

    from dolo.numeric.processes import IIDProcess

    iid_process = isinstance(model.exogenous, IIDProcess)

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

    p = model.calibration["parameters"]

    if grid is None and dp is None:
        grid, dp = model.discretize()

    s = grid["endo"].nodes

    funs = model.__original_gufunctions__
    h = funs["expectation"]
    gt = funs["half_transition"]
    τ = funs["direct_response_egm"]
    aτ = funs["reverse_state"]
    lb = funs["arbitrage_lb"]
    ub = funs["arbitrage_ub"]

    if dr0 is None:
        x0 = model.calibration["controls"]
        dr0 = lambda i, s: x0[None, :].repeat(s.shape[0], axis=0)

    n_m = dp.n_nodes
    n_x = len(model.symbols["controls"])

    if a_grid is None:
        raise Exception("You must supply a grid for the post-states.")

    assert a_grid.ndim == 1
    a = a_grid[:, None]
    N_a = a.shape[0]

    N = s.shape[0]

    n_h = len(model.symbols["expectations"])

    xa = np.zeros((n_m, N_a, n_x))
    sa = np.zeros((n_m, N_a, 1))
    xa0 = np.zeros((n_m, N_a, n_x))
    sa0 = np.zeros((n_m, N_a, 1))

    z = np.zeros((n_m, N_a, n_h))

    if verbose:
        headline = "|{0:^4} | {1:10} |".format("N", " Error")
        stars = "-" * len(headline)
        print(stars)
        print(headline)
        print(stars)

    for it in range(0, maxit):

        if it == 0:
            drfut = dr0

        else:

            def drfut(i, ss):
                if iid_process:
                    i = 0
                m = dp.node(i)
                l_ = lb(m, ss, p)
                u_ = ub(m, ss, p)
                x = eval_linear((sa0[i, :, 0], ), xa0[i, :, 0], ss)[:, None]
                x = np.minimum(x, u_)
                x = np.maximum(x, l_)
                return x

        z[:, :, :] = 0

        for i_m in range(n_m):
            m = dp.node(i_m)
            for i_M in range(dp.n_inodes(i_m)):
                w = dp.iweight(i_m, i_M)
                M = dp.inode(i_m, i_M)
                S = gt(m, a, M, p)
                print(it, i_m, i_M)
                X = drfut(i_M, S)
                z[i_m, :, :] += w * h(M, S, X, p)
            xa[i_m, :, :] = τ(m, a, z[i_m, :, :], p)
            sa[i_m, :, :] = aτ(m, a, xa[i_m, :, :], p)

        if it > 1:
            η = abs(xa - xa0).max() + abs(sa - sa0).max()
        else:
            η = 1

        vprint("|{0:4} | {1:10.3e} |".format(it, η))

        if η < η_tol:
            break

        sa0[...] = sa
        xa0[...] = xa

    # resample the result on the standard grid
    endo_grid = grid["endo"]
    exo_grid = grid["exo"]
    mdr = DecisionRule(exo_grid, endo_grid, dprocess=dp, interp_method="cubic")

    mdr.set_values(
        np.concatenate([drfut(i, s)[None, :, :] for i in range(n_m)], axis=0))

    sol = EGMResult(mdr, it, dp, (η < η_tol), η_tol, η)

    return sol
Пример #13
0
def time_iteration(
    model: Model,
    *,  #
    dr0: DecisionRule = None,  #
    verbose: bool = True,  #
    details: bool = True,  #
    ignore_constraints: bool = False,  #
    trace: bool = False,  #
    dprocess=None,
    maxit=1000,
    inner_maxit=10,
    tol=1e-6,
    hook=None,
    interp_method="cubic",
    # obsolete
    with_complementarities=None,
) -> TimeIterationResult:
    """Finds a global solution for ``model`` using backward time-iteration.


    This algorithm iterates on the residuals of the arbitrage equations

    Parameters
    ----------
    model : Model
        model to be solved
    verbose : bool
        if True, display iterations
    dr0 : decision rule
        initial guess for the decision rule
    with_complementarities : bool (True)
        if False, complementarity conditions are ignored
    maxit: maximum number of iterations
    inner_maxit: maximum number of iteration for inner solver
    tol: tolerance criterium for successive approximations
    hook: Callable
        function to be called within each iteration, useful for debugging purposes


    Returns
    -------
    decision rule :
        approximated solution
    """

    # deal with obsolete options
    if with_complementarities is not None:
        # TODO warn
        pass
    else:
        with_complementarities = not ignore_constraints

    if trace:
        trace_details = []
    else:
        trace_details = None

    from dolo import dprint

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

    grid, dprocess_ = model.discretize()

    if dprocess is None:
        dprocess = dprocess_

    n_ms = dprocess.n_nodes  # number of exogenous states
    n_mv = dprocess.n_inodes(
        0)  # this assume number of integration nodes is constant

    x0 = model.calibration["controls"]
    parms = model.calibration["parameters"]
    n_x = len(x0)
    n_s = len(model.symbols["states"])

    endo_grid = grid["endo"]
    exo_grid = grid["exo"]

    mdr = DecisionRule(exo_grid,
                       endo_grid,
                       dprocess=dprocess,
                       interp_method=interp_method)

    s = mdr.endo_grid.nodes
    N = s.shape[0]

    controls_0 = numpy.zeros((n_ms, N, n_x))
    if dr0 is None:
        controls_0[:, :, :] = x0[None, None, :]
    else:
        if isinstance(dr0, AlgoResult):
            dr0 = dr0.dr
        try:
            for i_m in range(n_ms):
                controls_0[i_m, :, :] = dr0(i_m, s)
        except Exception:
            for i_m in range(n_ms):
                m = dprocess.node(i_m)
                controls_0[i_m, :, :] = dr0(m, s)

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

    if "arbitrage_lb" in model.functions and with_complementarities == True:
        lb_fun = model.functions["arbitrage_lb"]
        ub_fun = model.functions["arbitrage_ub"]
        lb = numpy.zeros_like(controls_0) * numpy.nan
        ub = numpy.zeros_like(controls_0) * numpy.nan
        for i_m in range(n_ms):
            m = dprocess.node(i_m)[None, :]
            p = parms[None, :]
            m = numpy.repeat(m, N, axis=0)
            p = numpy.repeat(p, N, axis=0)

            lb[i_m, :, :] = lb_fun(m, s, p)
            ub[i_m, :, :] = ub_fun(m, s, p)

    else:
        with_complementarities = False

    sh_c = controls_0.shape

    controls_0 = controls_0.reshape((-1, n_x))

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

    err = 10
    it = 0

    if with_complementarities:
        lb = lb.reshape((-1, n_x))
        ub = ub.reshape((-1, n_x))

    itprint = IterationsPrinter(
        ("N", int),
        ("Error", float),
        ("Gain", float),
        ("Time", float),
        ("nit", int),
        verbose=verbose,
    )
    itprint.print_header("Start Time Iterations.")

    import time

    t1 = time.time()

    err_0 = numpy.nan

    verbit = verbose == "full"

    while err > tol and it < maxit:

        it += 1

        t_start = time.time()

        mdr.set_values(controls_0.reshape(sh_c))

        if trace:
            trace_details.append({"dr": copy.deepcopy(mdr)})

        fn = lambda x: residuals_simple(f, g, s, x.reshape(sh_c), mdr,
                                        dprocess, parms).reshape((-1, n_x))
        dfn = SerialDifferentiableFunction(fn)

        res = fn(controls_0)

        if hook:
            hook()

        if with_complementarities:
            [controls, nit] = ncpsolve(dfn,
                                       lb,
                                       ub,
                                       controls_0,
                                       verbose=verbit,
                                       maxit=inner_maxit)
        else:
            [controls, nit] = newton(dfn,
                                     controls_0,
                                     verbose=verbit,
                                     maxit=inner_maxit)

        err = abs(controls - controls_0).max()

        err_SA = err / err_0
        err_0 = err

        controls_0 = controls

        t_finish = time.time()
        elapsed = t_finish - t_start

        itprint.print_iteration(N=it,
                                Error=err_0,
                                Gain=err_SA,
                                Time=elapsed,
                                nit=nit),

    controls_0 = controls.reshape(sh_c)

    mdr.set_values(controls_0)
    if trace:
        trace_details.append({"dr": copy.deepcopy(mdr)})

    itprint.print_finished()

    if not details:
        return mdr

    return TimeIterationResult(
        mdr,
        it,
        with_complementarities,
        dprocess,
        err < tol,  # x_converged: bool
        tol,  # x_tol
        err,  #: float
        None,  # log: object # TimeIterationLog
        trace_details,  # trace: object #{Nothing,IterationTrace}
    )
Пример #14
0
def time_iteration(model, initial_guess=None, dprocess=None, with_complementarities=True,
                        verbose=True, grid={},
                        maxit=1000, inner_maxit=10, tol=1e-6, hook=None, details=False):

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

    This algorithm iterates on the residuals of the arbitrage equations

    Parameters
    ----------
    model : Model
        model to be solved
    verbose : boolean
        if True, display iterations
    initial_guess : decision rule
        initial guess for the decision rule
    dprocess : DiscretizedProcess (model.exogenous.discretize())
        discretized process to be used
    with_complementarities : boolean (True)
        if False, complementarity conditions are ignored
    grid: grid options
        overload the values set in `options:grid` section
    maxit: maximum number of iterations
    inner_maxit: maximum number of iteration for inner solver
    tol: tolerance criterium for successive approximations
    hook: Callable
        function to be called within each iteration, useful for debugging purposes


    Returns
    -------
    decision rule :
        approximated solution
    '''

    from dolo import dprint
    def vprint(t):
        if verbose:
            print(t)

    if dprocess is None:
        dprocess = model.exogenous.discretize()

    n_ms = dprocess.n_nodes() # number of exogenous states
    n_mv = dprocess.n_inodes(0) # this assume number of integration nodes is constant

    x0 = model.calibration['controls']
    parms = model.calibration['parameters']
    n_x = len(x0)
    n_s = len(model.symbols['states'])

    endo_grid = model.get_grid(**grid)

    exo_grid = dprocess.grid

    mdr = DecisionRule(exo_grid, endo_grid)

    grid = mdr.endo_grid.nodes()
    N = grid.shape[0]

    controls_0 = numpy.zeros((n_ms, N, n_x))
    if initial_guess is None:
        controls_0[:, :, :] = x0[None,None,:]
    else:
        if isinstance(initial_guess, AlgoResult):
            initial_guess = initial_guess.dr
        try:
            for i_m in range(n_ms):
                controls_0[i_m, :, :] = initial_guess(i_m, grid)
        except Exception:
            for i_m in range(n_ms):
                m = dprocess.node(i_m)
                controls_0[i_m, :, :] = initial_guess(m, grid)

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

    if 'controls_lb' in model.functions and with_complementarities==True:
        lb_fun = model.functions['controls_lb']
        ub_fun = model.functions['controls_ub']
        lb = numpy.zeros_like(controls_0)*numpy.nan
        ub = numpy.zeros_like(controls_0)*numpy.nan
        for i_m in range(n_ms):
            m = dprocess.node(i_m)[None,:]
            p = parms[None,:]
            m = numpy.repeat(m, N, axis=0)
            p = numpy.repeat(p, N, axis=0)

            lb[i_m,:,:] = lb_fun(m, grid, p)
            ub[i_m,:,:] = ub_fun(m, grid, p)

    else:
        with_complementarities = False

    sh_c = controls_0.shape

    controls_0 = controls_0.reshape( (-1,n_x) )

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

    err = 10
    it = 0

    if with_complementarities:
        vprint("Solving WITH complementarities.")
        lb = lb.reshape((-1,n_x))
        ub = ub.reshape((-1,n_x))


    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)

    import time
    t1 = time.time()

    err_0 = numpy.nan

    verbit = (verbose == 'full')

    while err>tol and it<maxit:

        it += 1

        t_start = time.time()

        mdr.set_values(controls_0.reshape(sh_c))

        fn = lambda x: residuals_simple(f, g, grid, x.reshape(sh_c), mdr, dprocess, parms).reshape((-1,n_x))
        dfn = SerialDifferentiableFunction(fn)

        res = fn(controls_0)

        if hook:
            hook()

        if with_complementarities:
            [controls,nit] = ncpsolve(dfn, lb, ub, controls_0, verbose=verbit, maxit=inner_maxit)
        else:
            [controls, nit] = newton(dfn, controls_0, verbose=verbit, maxit=inner_maxit)

        err = abs(controls-controls_0).max()

        err_SA = err/err_0
        err_0 = err

        controls_0 = controls

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

    controls_0 = controls.reshape(sh_c)

    t2 = time.time()

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

    if not details:
        return mdr

    return TimeIterationResult(
        mdr,
        it,
        with_complementarities,
        dprocess,
        err<tol, # x_converged: bool
        tol, # x_tol
        err, #: float
        None,  # log: object # TimeIterationLog
        None   # trace: object #{Nothing,IterationTrace}
    )