Beispiel #1
0
def ncpsolve(f,
             a,
             b,
             x,
             tol=1e-8,
             maxit=100,
             infos=False,
             verbose=False,
             jactype="serial"):
    def fcmp(z):

        [val, dval] = f(z)

        # revert convention
        val = -val
        dval = -dval

        [val, dval] = smooth(z, a, b, val, dval, jactype=jactype)

        return [val, dval]

    [sol, nit] = newton(fcmp,
                        x,
                        tol=tol,
                        maxit=maxit,
                        verbose=verbose,
                        jactype=jactype)

    return [sol, nit]
Beispiel #2
0
def ncpsolve(f, a, b, x, tol=1e-8, maxit=100, infos=False, verbose=False, jactype='serial'):

    def fcmp(z):

        [val, dval] = f(z)
        [val, dval] = smooth(z, a, b, val, dval, jactype=jactype)

        return [val, dval]

    [sol, nit] = newton(fcmp, x, tol=tol, maxit=maxit, verbose=verbose, jactype=jactype)

    return [sol, nit]
Beispiel #3
0
def ncpsolve(f, a, b, x, tol=1e-8, maxit=100, infos=False, verbose=False, jactype="serial"):
    def fcmp(z):

        [val, dval] = f(z)

        # revert convention
        val = -val
        dval = -dval

        [val, dval] = smooth(z, a, b, val, dval, jactype=jactype)

        return [val, dval]

    [sol, nit] = newton(fcmp, x, tol=tol, maxit=maxit, verbose=verbose, jactype=jactype)

    return [sol, nit]
Beispiel #4
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}
    )
Beispiel #5
0
def deterministic_solve(
    model,
    exogenous=None,
    s0=None,
    m0=None,
    T=100,
    ignore_constraints=False,
    maxit=100,
    initial_guess=None,
    verbose=True,
    solver="ncpsolve",
    keep_steady_state=False,
    s1=None,  # deprecated
    shocks=None,  # deprecated
    tol=1e-6,
):
    """
    Computes a perfect foresight simulation using a stacked-time algorithm.

    Typical simulation exercises are:
    - start from an out-of-equilibrium exogenous and/or endogenous state: specify `s0` and or `m0`. Missing values are taken from the calibration (`model.calibration`).
    - specify an exogenous path for shocks `exogenous`. Initial exogenous state `m0` is then first value of exogenous values. Economy is supposed to have been at the equilibrium for $t<0$, which pins
    down initial endogenous state `s0`. `x0` is a jump variable.

    If $s0$ is not specified it is then set
    equal to the steady-state consistent with the first value

    The initial state is specified either by providing a series of exogenous
    shocks and assuming the model is initially in equilibrium with the first
    value of the shock, or by specifying an initial value for the states.

    Parameters
    ----------
    model : Model
        Model to be solved
    exogenous : array-like, dict, or pandas.DataFrame
        A specification for the path of exogenous variables (aka shocks). Can be any of the
        following (note by "declaration order" below we mean the order
        of `model.symbols["exogenous"]`):

        - A 1d numpy array-like specifying a time series for a single
          exogenous variable, or all exogenous variables stacked into a single array.
        - A 2d numpy array where each column specifies the time series
          for one of the shocks in declaration order. This must be an
          `N` by number of shocks 2d array.
        - A dict where keys are strings found in
          `model.symbols["exogenous"]` and values are a time series of
          values for that shock. For exogenous variables that do not appear in
          this dict, the shock is set to the calibrated value. Note
          that this interface is the most flexible as it allows the user
          to pass values for only a subset of the model shocks and it
          allows the passed time series to be of different lengths.
        - A DataFrame where columns map shock names into time series.
          The same assumptions and behavior that are used in the dict
          case apply here

        If nothing is given here, `exogenous` is set equal to the
        calibrated values found in `model.calibration["exogenous"]` for
        all periods.

        If the length of any time-series in shocks is less than `T`
        (see below) it is assumed that that particular shock will
        remain at the final given value for the duration of the
        simulation.
    s0 : None or ndarray or dict
        If vector with the value of initial states
        If an exogenous timeseries is given for exogenous shocks, `s0` will be computed as the steady-state value that is consistent with its first value.

    T : int
        horizon for the perfect foresight simulation
    maxit : int
        maximum number of iteration for the nonlinear solver
    verbose : boolean
        if True, the solver displays iterations
    tol : float
        stopping criterium for the nonlinear solver
    ignore_constraints : bool
        if True, complementarity constraints are ignored.
    keep_steady_state : bool
        if True, initial steady-states and steady-controls are appended to the simulation with date -1.
    Returns
    -------
    pandas dataframe
        a dataframe with T+1 observations of the model variables along the
        simulation (states, controls, auxiliaries). The  simulation should return to a steady-state
        consistent with the last specified value of the exogenous shocks.

    """

    if shocks is not None:
        import warnings

        warnings.warn(
            "`shocks` argument is deprecated. Use `exogenous` instead.")
        exogenous = shocks

    if s1 is not None:
        import warnings

        warnings.warn("`s1` argument is deprecated. Use `s0` instead.")
        s0 = s1

    # definitions
    n_s = len(model.calibration["states"])
    n_x = len(model.calibration["controls"])
    p = model.calibration["parameters"]

    if exogenous is not None:
        epsilons = _shocks_to_epsilons(model, exogenous, T)
        m0 = epsilons[0, :]
        # get initial steady-state
        from dolo.algos.steady_state import find_steady_state

        start_state = find_steady_state(model, m=m0)
        s0 = start_state["states"]
        x0 = start_state["controls"]
        m1 = epsilons[1, :]
        s1 = model.functions["transition"](m0, s0, x0, m1, p)
    else:
        if s0 is None:
            s0 = model.calibration["states"]
        if m0 is None:
            m0 = model.calibration["exogenous"]
        # if m0 is None:
        #     m0 = np.zeros(len(model.symbols['exogenous']))
        # we should probably do something here with the nature of the exogenous process if specified
        # i.e. compute nonlinear irf
        epsilons = _shocks_to_epsilons(model, exogenous, T)
        x0 = model.calibration["controls"]
        m1 = epsilons[1, :]
        s1 = model.functions["transition"](m0, s0, x0, m1, p)
        s1 = np.array(s1)

    x1_g = model.calibration["controls"]  # we can do better here
    sT_g = model.calibration["states"]  # we can do better here
    xT_g = model.calibration["controls"]  # we can do better here

    if initial_guess is None:
        start = np.concatenate([s1, x1_g])
        final = np.concatenate([sT_g, xT_g])
        initial_guess = np.row_stack(
            [start * (1 - l) + final * l for l in linspace(0.0, 1.0, T + 1)])

    else:
        if isinstance(initial_guess, pd.DataFrame):
            initial_guess = np.array(initial_guess[model.symbols["states"] +
                                                   model.symbols["controls"]])
        initial_guess = initial_guess[1:, :]
        initial_guess = initial_guess[:, :n_s + n_x]

    sh = initial_guess.shape

    if model.x_bounds and not ignore_constraints:
        initial_states = initial_guess[:, :n_s]
        [lb,
         ub] = [u(epsilons[:, :], initial_states, p) for u in model.x_bounds]
        lower_bound = initial_guess * 0 - np.inf
        lower_bound[:, n_s:] = lb
        upper_bound = initial_guess * 0 + np.inf
        upper_bound[:, n_s:] = ub
        test1 = max(lb.max(axis=0) - lb.min(axis=0))
        test2 = max(ub.max(axis=0) - ub.min(axis=0))
        if test1 > 0.00000001 or test2 > 0.00000001:
            msg = "Not implemented: perfect foresight solution requires that "
            msg += "controls have constant bounds."
            raise Exception(msg)
    else:
        ignore_constraints = True
        lower_bound = None
        upper_bound = None

    print(initial_guess.shape)
    print(epsilons.shape)
    det_residual(model, initial_guess, s1, xT_g, epsilons)

    if not ignore_constraints:

        def ff(vec):
            return det_residual(model,
                                vec.reshape(sh),
                                s1,
                                xT_g,
                                epsilons,
                                jactype="sparse")

        v0 = initial_guess.ravel()
        if solver == "ncpsolve":
            sol, nit = ncpsolve(
                ff,
                lower_bound.ravel(),
                upper_bound.ravel(),
                initial_guess.ravel(),
                verbose=verbose,
                maxit=maxit,
                tol=tol,
                jactype="sparse",
            )
        else:
            from dolo.numeric.extern.lmmcp import lmmcp

            sol = lmmcp(
                lambda u: ff(u)[0],
                lambda u: ff(u)[1].todense(),
                lower_bound.ravel(),
                upper_bound.ravel(),
                initial_guess.ravel(),
                verbose=verbose,
            )
            nit = -1

        sol = sol.reshape(sh)

    else:

        def ff(vec):
            ll = det_residual(model,
                              vec.reshape(sh),
                              s1,
                              xT_g,
                              epsilons,
                              diff=True)
            return ll

        v0 = initial_guess.ravel()
        # from scipy.optimize import root
        # sol = root(ff, v0, jac=True)
        # sol = sol.x.reshape(sh)
        from dolo.numeric.optimize.newton import newton

        sol, nit = newton(ff, v0, jactype="sparse")
        sol = sol.reshape(sh)

    # sol = sol[:-1, :]

    if (exogenous is not None) and keep_steady_state:
        sx = np.concatenate([s0, x0])
        sol = np.concatenate([sx[None, :], sol], axis=0)
        epsilons = np.concatenate([epsilons[:1:], epsilons], axis=0)
        index = range(-1, T + 1)
    else:
        index = range(0, T + 1)
    # epsilons = np.concatenate([epsilons[:1,:], epsilons], axis=0)

    if "auxiliary" in model.functions:
        colnames = (model.symbols["states"] + model.symbols["controls"] +
                    model.symbols["auxiliaries"])
        # compute auxiliaries
        y = model.functions["auxiliary"](epsilons, sol[:, :n_s], sol[:, n_s:],
                                         p)
        sol = np.column_stack([sol, y])
    else:
        colnames = model.symbols["states"] + model.symbols["controls"]

    sol = np.column_stack([sol, epsilons])
    colnames = colnames + model.symbols["exogenous"]

    ts = pd.DataFrame(sol, columns=colnames, index=index)
    return ts
Beispiel #6
0
def deterministic_solve(model,
                        shocks=None,
                        s1=None,
                        T=100,
                        ignore_constraints=False,
                        maxit=100,
                        initial_guess=None,
                        verbose=True,
                        solver='ncpsolve',
                        tol=1e-6):
    """
    Computes a perfect foresight simulation using a stacked-time algorithm.

    The initial state is specified either by providing a series of exogenous
    shocks and assuming the model is initially in equilibrium with the first
    value of the shock, or by specifying an initial value for the states.

    Parameters
    ----------
    model : Model
        Model to be solved
    shocks : array-like, dict, or pandas.DataFrame
        A specification of the shocks to the model. Can be any of the
        following (note by "declaration order" below we mean the order
        of `model.symbols["shocks"]`):

        - A 1d numpy array-like specifying a time series for a single
          shock, or all shocks stacked into a single array.
        - A 2d numpy array where each column specifies the time series
          for one of the shocks in declaration order. This must be an
          `N` by number of shocks 2d array.
        - A dict where keys are strings found in
          `model.symbols["shocks"]` and values are a time series of
          values for that shock. For model shocks that do not appear in
          this dict, the shock is set to the calibrated value. Note
          that this interface is the most flexible as it allows the user
          to pass values for only a subset of the model shocks and it
          allows the passed time series to be of different lengths.
        - A DataFrame where columns map shock names into time series.
          The same assumptions and behavior that are used in the dict
          case apply here

        If nothing is given here, `shocks` is set equal to the
        calibrated values found in `model.calibration["shocks"]` for
        all periods.

        If the length of any time-series in shocks is less than `T`
        (see below) it is assumed that that particular shock will
        remain at the final given value for the duration of the
        simulaiton.
    s1 : ndarray or dict
        a vector with the value of initial states
    T : int
        horizon for the perfect foresight simulation
    maxit : int
        maximum number of iteration for the nonlinear solver
    verbose : boolean
        if True, the solver displays iterations
    tol : float
        stopping criterium for the nonlinear solver
    ignore_constraints : bool
        if True, complementarity constraints are ignored.

    Returns
    -------
    pandas dataframe
        a dataframe with T+1 observations of the model variables along the
        simulation (states, controls, auxiliaries). The first observation is
        the steady-state corresponding to the first value of the shocks. The
        simulation should return to a steady-state corresponding to the last
        value of the exogenous shocks.

    """

    # definitions
    n_s = len(model.calibration['states'])
    n_x = len(model.calibration['controls'])
    p = model.calibration['parameters']

    epsilons = _shocks_to_epsilons(model, shocks, T)

    m0 = epsilons[0, :]

    # get initial steady-state
    from dolo.algos.steady_state import find_steady_state
    # TODO: use initial_guess for steady_state
    # TODO:

    if s1 is None:
        start_state = find_steady_state(model, m=m0)
        s0 = start_state['states']
        x0 = start_state['controls']
        m1 = epsilons[1, :]
        s1 = model.functions['transition'](m0, s0, x0, m1, p)
    else:
        s0 = model.calibration['states'] * np.nan
        x0 = model.calibration['controls'] * np.nan
        s1 = np.array(s1)

    x1_g = model.calibration['controls']  # we can do better here
    sT_g = model.calibration['states']  # we can do better here
    xT_g = model.calibration['controls']  # we can do better here

    if initial_guess is None:
        start = np.concatenate([s1, x1_g])
        final = np.concatenate([sT_g, xT_g])
        initial_guess = np.row_stack(
            [start * (1 - l) + final * l for l in linspace(0.0, 1.0, T)])

    else:
        if isinstance(initial_guess, pd.DataFrame):
            initial_guess = np.array(initial_guess[model.symbols['states'] +
                                                   model.symbols['controls']])
        initial_guess = initial_guess[1:, :]
        initial_guess = initial_guess[:, :n_s + n_x]

    sh = initial_guess.shape

    if model.x_bounds and not ignore_constraints:
        initial_states = initial_guess[:, :n_s]
        [lb,
         ub] = [u(epsilons[1:, :], initial_states, p) for u in model.x_bounds]
        lower_bound = initial_guess * 0 - np.inf
        lower_bound[:, n_s:] = lb
        upper_bound = initial_guess * 0 + np.inf
        upper_bound[:, n_s:] = ub
        test1 = max(lb.max(axis=0) - lb.min(axis=0))
        test2 = max(ub.max(axis=0) - ub.min(axis=0))
        if test1 > 0.00000001 or test2 > 0.00000001:
            msg = "Not implemented: perfect foresight solution requires that "
            msg += "controls have constant bounds."
            raise Exception(msg)
    else:
        ignore_constraints = True
        lower_bound = None
        upper_bound = None

    if not ignore_constraints:

        def ff(vec):
            return det_residual(model,
                                vec.reshape(sh),
                                s1,
                                xT_g,
                                epsilons[1:, :],
                                jactype='sparse')

        v0 = initial_guess.ravel()
        if solver == 'ncpsolve':
            sol, nit = ncpsolve(ff,
                                lower_bound.ravel(),
                                upper_bound.ravel(),
                                initial_guess.ravel(),
                                verbose=verbose,
                                maxit=maxit,
                                tol=tol,
                                jactype='sparse')
        else:
            from dolo.numeric.extern.lmmcp import lmmcp
            sol = lmmcp(lambda u: ff(u)[0],
                        lambda u: ff(u)[1].todense(),
                        lower_bound.ravel(),
                        upper_bound.ravel(),
                        initial_guess.ravel(),
                        verbose=verbose)
            nit = -1

        sol = sol.reshape(sh)

    else:

        def ff(vec):
            ll = det_residual(model,
                              vec.reshape(sh),
                              s1,
                              xT_g,
                              epsilons[1:, :],
                              diff=True)
            return (ll)

        v0 = initial_guess.ravel()
        # from scipy.optimize import root
        # sol = root(ff, v0, jac=True)
        # sol = sol.x.reshape(sh)
        from dolo.numeric.optimize.newton import newton
        sol, nit = newton(ff, v0, jactype='sparse')
        sol = sol.reshape(sh)

    sx = np.concatenate([s0, x0])
    # sol = sol[:-1, :]

    sol = np.concatenate([sx[None, :], sol], axis=0)
    # epsilons = np.concatenate([epsilons[:1,:], epsilons], axis=0)

    if 'auxiliary' in model.functions:
        colnames = (model.symbols['states'] + model.symbols['controls'] +
                    model.symbols['auxiliaries'])
        # compute auxiliaries
        y = model.functions['auxiliary'](epsilons, sol[:, :n_s], sol[:, n_s:],
                                         p)
        sol = np.column_stack([sol, y])
    else:
        colnames = model.symbols['states'] + model.symbols['controls']

    sol = np.column_stack([sol, epsilons])
    colnames = colnames + model.symbols['exogenous']

    ts = pd.DataFrame(sol, columns=colnames)
    return ts
Beispiel #7
0
def solve_mfg_model(model, maxit=1000, initial_guess=None, with_complementarities=True, verbose=True, orders=None, output_type='dr'):

    assert(model.model_type == 'mfga')

    [P, Q] = model.markov_chain

    n_ms = P.shape[0]   # number of markov states
    n_mv = P.shape[1] # number of markov variables

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

    approx = model.options['approximation_space']
    a = approx['a']
    b = approx['b']
    if orders is None:
        orders = approx['orders']

    from dolo.numeric.decision_rules_markov import MarkovDecisionRule

    mdr = MarkovDecisionRule(n_ms, a, b, orders)

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



#    if isinstance(initial_guess, numpy.ndarray):
#        print("Using initial guess (1)")
#        controls = initial_guess
#    elif isinstance(initial_guess, dict):
#        print("Using initial guess (2)")
#        controls_0 = initial_guess['controls']
#        ap_space = initial_guess['approximation_space']
#        if False in (approx['orders']==orders):
#            print("Interpolating initial guess")
#            old_dr = MarkovDecisionRule(controls_0.shape[0], ap_space['smin'], ap_space['smax'], ap_space['orders'])
#            old_dr.set_values(controls_0)
#            controls_0 = numpy.zeros( (n_ms, N, n_x) )
#            for i in range(n_ms):
#                e = old_dr(i,grid)
#                controls_0[i,:,:] = e
#    else:
#        controls_0 = numpy.zeros((n_ms, N, n_x))



    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):
            m = P[i_m,:][None,:]
            controls_0[i_m,:,:] = initial_guess(i_m, grid)

    ff = model.functions['arbitrage']
    gg = model.functions['transition']
    aa = model.functions['auxiliary']

    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 = P[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


    f = lambda m,s,x,M,S,X,p: ff(m,s,x,aa(m,s,x,p),M,S,X,aa(M,S,X,p),p)
    g = lambda m,s,x,M,p: gg(m,s,x,aa(m,s,x,p),M,p)

    # mdr.set_values(controls)

    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
    tol = 1e-8
    inner_maxit = 50
    it = 0


    if with_complementarities:
        print("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(f, g, grid, x.reshape(sh_c), mdr, P, Q, parms).reshape((-1,n_x))
        dfn = SerialDifferentiableFunction(fn)

        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 output_type == 'dr':
        return mdr
    elif output_type == 'controls':
        return controls_0
    else:
        raise Exception("Unsupported ouput type {}.".format(output_type))
Beispiel #8
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
Beispiel #9
0
def time_iteration(model,
                   initial_guess=None,
                   with_complementarities=True,
                   verbose=True,
                   orders=None,
                   output_type='dr',
                   maxit=1000,
                   inner_maxit=10,
                   tol=1e-6,
                   hook=None):

    assert (model.model_type == 'dtmscc')

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

    [P, Q] = model.markov_chain

    n_ms = P.shape[0]  # number of markov states
    n_mv = P.shape[1]  # number of markov variables

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

    approx = model.options['approximation_space']
    a = approx['a']
    b = approx['b']
    if orders is None:
        orders = approx['orders']

    from dolo.numeric.decision_rules_markov import MarkovDecisionRule

    mdr = MarkovDecisionRule(n_ms, a, b, orders)

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

    #    if isinstance(initial_guess, numpy.ndarray):
    #        print("Using initial guess (1)")
    #        controls = initial_guess
    #    elif isinstance(initial_guess, dict):
    #        print("Using initial guess (2)")
    #        controls_0 = initial_guess['controls']
    #        ap_space = initial_guess['approximation_space']
    #        if False in (approx['orders']==orders):
    #            print("Interpolating initial guess")
    #            old_dr = MarkovDecisionRule(controls_0.shape[0], ap_space['smin'], ap_space['smax'], ap_space['orders'])
    #            old_dr.set_values(controls_0)
    #            controls_0 = numpy.zeros( (n_ms, N, n_x) )
    #            for i in range(n_ms):
    #                e = old_dr(i,grid)
    #                controls_0[i,:,:] = e
    #    else:
    #        controls_0 = numpy.zeros((n_ms, N, n_x))

    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):
            m = P[i_m, :][None, :]
            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 = P[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

    # mdr.set_values(controls)

    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(f, g, grid, x.reshape(sh_c), mdr, P, Q, parms
                                 ).reshape((-1, n_x))
        dfn = SerialDifferentiableFunction(fn)

        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 output_type == 'dr':
        return mdr
    elif output_type == 'controls':
        return controls_0
    else:
        raise Exception("Unsupported ouput type {}.".format(output_type))
Beispiel #10
0
def time_iteration(model,
                   initial_guess=None,
                   with_complementarities=True,
                   verbose=True,
                   grid={},
                   output_type='dr',
                   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
    '''

    assert (model.model_type == 'dtmscc')

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

    [P, Q] = model.markov_chain

    n_ms = P.shape[0]  # number of markov states
    n_mv = P.shape[1]  # number of markov variables

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

    approx = model.get_grid(**grid)
    a = approx.a
    b = approx.b
    orders = approx.orders
    interp_type = approx.interpolation  # unused

    from dolo.numeric.decision_rules_markov import MarkovDecisionRule

    mdr = MarkovDecisionRule(n_ms, a, b, orders)

    grid = mdr.grid
    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):
            m = P[i_m, :][None, :]
            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 = P[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

    # mdr.set_values(controls)

    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(f, g, grid, x.reshape(sh_c), mdr, P, Q, parms
                                 ).reshape((-1, n_x))
        dfn = SerialDifferentiableFunction(fn)

        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 output_type == 'dr':
        return mdr
    elif output_type == 'controls':
        return controls_0
    else:
        raise Exception("Unsupported ouput type {}.".format(output_type))
Beispiel #11
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}
    )
Beispiel #12
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}
    )