Beispiel #1
0
def compute_expectations_psi( cm, dr_x, dr_z, s, x, p, nodes, weights):

    N = s.shape[1]
    n_s = s.shape[0]
    n_x = x.shape[0]
    n_h = len(cm.model['variables_groups']['expectations'])
    Q = len(weights)

    ss = tile(s, (1,Q))
    xx = tile(x, (1,Q))
    ee = repeat(nodes, N , axis=1)
    SS = cm.g(ss,xx,ee,p)

    xxstart = dr_x(SS)

    ZZ = dr_z(SS)


    ff = lambda xt: cm.f(SS,xt,ZZ,p)
    [XX,nit] = newton_solver(ff , xxstart, numdiff=True,infos=True)

    hh = cm.h(SS,XX,p)
    z = np.zeros( (n_x,N) )
    for i in range(Q):
        z += weights[i] * hh[:,N*i:N*(i+1)]

    return z
Beispiel #2
0
def pea_solve( cm, grid, dr_x, dr_z, p, nodes, weights ):

    tol = 1e-9
    err = 10
    maxit = 500
    it = 0

    x0 = dr_x(grid)
    z0 = dr_z(grid)
#    z0 = compute_expectations_phi( cm, dr_x, grid, x0, p, nodes, weights)

    while err > tol and it < maxit:

        it += 1

        fobj = lambda x: cm.f( grid, x, z0, p )

        x1 = newton_solver( fobj, x0, numdiff=True)
        dr_x.set_values(x1) # I don't really need it

        z1 = compute_expectations_psi(cm, dr_x, dr_h, grid, x1, params, nodes, weights)
        dr_z.set_values(z1)

        err = abs(z1 - z0).max()
        err2 = abs(x1 - x0).max()
        print(err, err2)
        x0 = x1
        z0 = z1

    print('finished in {} iterations'.format(it))

    return [x0,z0]
Beispiel #3
0
def pea_solve(cm, grid, dr_x, dr_z, p, nodes, weights):

    tol = 1e-9
    err = 10
    maxit = 500
    it = 0

    x0 = dr_x(grid)
    z0 = dr_z(grid)
    #    z0 = compute_expectations_phi( cm, dr_x, grid, x0, p, nodes, weights)

    while err > tol and it < maxit:

        it += 1

        fobj = lambda x: cm.f(grid, x, z0, p)

        x1 = newton_solver(fobj, x0, numdiff=True)
        dr_x.set_values(x1)  # I don't really need it

        z1 = compute_expectations_psi(cm, dr_x, dr_h, grid, x1, params, nodes,
                                      weights)
        dr_z.set_values(z1)

        err = abs(z1 - z0).max()
        err2 = abs(x1 - x0).max()
        print(err, err2)
        x0 = x1
        z0 = z1

    print('finished in {} iterations'.format(it))

    return [x0, z0]
Beispiel #4
0
def compute_expectations_psi(cm, dr_x, dr_z, s, x, p, nodes, weights):

    N = s.shape[1]
    n_s = s.shape[0]
    n_x = x.shape[0]
    n_h = len(cm.model['variables_groups']['expectations'])
    Q = len(weights)

    ss = tile(s, (1, Q))
    xx = tile(x, (1, Q))
    ee = repeat(nodes, N, axis=1)
    SS = cm.g(ss, xx, ee, p)

    xxstart = dr_x(SS)

    ZZ = dr_z(SS)

    ff = lambda xt: cm.f(SS, xt, ZZ, p)
    [XX, nit] = newton_solver(ff, xxstart, numdiff=True, infos=True)

    hh = cm.h(SS, XX, p)
    z = np.zeros((n_x, N))
    for i in range(Q):
        z += weights[i] * hh[:, N * i:N * (i + 1)]

    return z
Beispiel #5
0
def simulate(cmodel,
             dr,
             s0=None,
             sigma=None,
             n_exp=0,
             horizon=40,
             parms=None,
             seed=1,
             discard=False,
             stack_series=True,
             solve_expectations=False,
             nodes=None,
             weights=None,
             use_pandas=True):
    '''
    :param cmodel: compiled model
    :param dr: decision rule
    :param s0: initial state where all simulations start
    :param sigma: covariance matrix of the normal multivariate distribution describing the random shocks
    :param n_exp: number of draws to simulate. Use 0 for impulse-response functions
    :param horizon: horizon for the simulation
    :param parms: (vector) value for the parameters of the model
    :param seed: used to initialize the random number generator. Use it to replicate exact same results among simulations
    :param discard: (default: False) if True, then all simulations containing at least one non finite value are discarded
    :param stack_series: return simulated series for different types of variables separately (in a list)
    :return: a ``n_s x n_exp x horizon`` array where ``n_s`` is the number of states. The second dimension is omitted if
    n_exp = 0.
    '''

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

    calib = cmodel.calibration

    if parms is None:
        parms = numpy.array(
            calib['parameters'])  # TODO : remove reference to symbolic model

    if sigma is None:
        sigma = numpy.array(calib['covariances'])

    if s0 is None:
        s0 = numpy.array(calib['states'])

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

    x0 = dr(s0)

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

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

    fun = cmodel.functions

    if cmodel.model_type == 'fga':
        ff = fun['arbitrage']
        gg = fun['transition']
        aa = fun['auxiliary']
        g = lambda s, x, e, p: gg(s, x, aa(s, x, p), e, p)
        f = lambda s, x, e, S, X, p: ff(s, x, aa(s, x, p), S, X, aa(S, X, p), p
                                        )
    else:
        f = cmodel.functions['arbitrage']
        g = cmodel.functions['transition']

    numpy.random.seed(seed)

    for i in range(horizon):
        mean = numpy.zeros(sigma.shape[0])
        if irf:
            epsilons = numpy.zeros((sigma.shape[0], 1))
        else:
            epsilons = numpy.random.multivariate_normal(mean, sigma, n_exp).T
        s = s_simul[:, :, i]

        x = dr(s)

        if solve_expectations:
            from dolo.numeric.solver import solver
            from dolo.numeric.newton import newton_solver

            fobj = lambda t: step_residual(
                s, t, dr, f, g, parms, nodes, weights, with_derivatives=False
            )  #
            #            x = solver(fobj, x,  serial_problem=True)
            x = newton_solver(fobj, x, numdiff=True)

        x_simul[:, :, i] = x

        ss = g(s, x, epsilons, parms)

        if i < (horizon - 1):
            s_simul[:, :, i + 1] = ss

    from numpy import any, isnan, all

    if not 'auxiliary' in fun:  # TODO: find a better test than this
        l = [s_simul, x_simul]
        varnames = cmodel.symbols['states'] = cmodel.symbols['controls']
    else:
        aux = fun['auxiliary']
        n_s = s_simul.shape[0]
        n_x = x_simul.shape[0]
        a_simul = aux(s_simul.reshape((n_s, n_exp * horizon)),
                      x_simul.reshape((n_x, n_exp * horizon)), parms)
        n_a = a_simul.shape[0]
        a_simul = a_simul.reshape(n_a, n_exp, horizon)
        l = [s_simul, x_simul, a_simul]
        varnames = cmodel.symbols['states'] + cmodel.symbols[
            'controls'] + cmodel.symbols['auxiliary']
    if not stack_series:
        return l

    else:
        simul = numpy.row_stack(l)

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

    if irf:
        simul = simul[:, 0, :]

        if use_pandas:
            import pandas
            ts = pandas.DataFrame(simul.T, columns=varnames)
            return ts

    return simul
Beispiel #6
0
def simulate(cmodel, dr, s0=None, sigma=None, n_exp=0, horizon=40, parms=None, seed=1, discard=False, stack_series=True,
             solve_expectations=False, nodes=None, weights=None, use_pandas=True):

    '''
    :param cmodel: compiled model
    :param dr: decision rule
    :param s0: initial state where all simulations start
    :param sigma: covariance matrix of the normal multivariate distribution describing the random shocks
    :param n_exp: number of draws to simulate. Use 0 for impulse-response functions
    :param horizon: horizon for the simulation
    :param parms: (vector) value for the parameters of the model
    :param seed: used to initialize the random number generator. Use it to replicate exact same results among simulations
    :param discard: (default: False) if True, then all simulations containing at least one non finite value are discarded
    :param stack_series: return simulated series for different types of variables separately (in a list)
    :return: a ``n_s x n_exp x horizon`` array where ``n_s`` is the number of states. The second dimension is omitted if
    n_exp = 0.
    '''


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



    calib = cmodel.calibration

    if parms is None:
        parms = numpy.array( calib['parameters'] ) # TODO : remove reference to symbolic model

    if sigma is None:
        sigma = numpy.array( calib['covariances'] )

    if s0 is None:
        s0 = numpy.array( calib['states'] )

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

    x0 = dr(s0)

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

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

    fun = cmodel.functions

    if cmodel.model_type == 'fga':
        ff = fun['arbitrage']
        gg = fun['transition']
        aa = fun['auxiliary']
        g = lambda s,x,e,p : gg(s,x,aa(s,x,p),e,p)
        f = lambda s,x,e,S,X,p : ff(s,x,aa(s,x,p),S,X,aa(S,X,p),p)
    else:
        f = cmodel.functions['arbitrage']
        g = cmodel.functions['transition']


    numpy.random.seed(seed)

    for i in range(horizon):
        mean = numpy.zeros(sigma.shape[0])
        if irf:
            epsilons = numpy.zeros( (sigma.shape[0],1) )
        else:
            epsilons = numpy.random.multivariate_normal(mean, sigma, n_exp).T
        s = s_simul[:,:,i]

        x = dr(s)

        if solve_expectations:
            from dolo.numeric.solver import solver
            from dolo.numeric.newton import newton_solver

            fobj = lambda t: step_residual(s, t, dr, f, g, parms, nodes, weights, with_derivatives=False) #
#            x = solver(fobj, x,  serial_problem=True)
            x = newton_solver(fobj, x, numdiff=True)

        x_simul[:,:,i] = x

        ss = g(s,x,epsilons,parms)

        if i<(horizon-1):
            s_simul[:,:,i+1] = ss

    from numpy import any,isnan,all

    if not 'auxiliary' in fun: # TODO: find a better test than this
        l = [s_simul, x_simul]
        varnames = cmodel.symbols['states'] = cmodel.symbols['controls']
    else:
        aux = fun['auxiliary']
        n_s = s_simul.shape[0]
        n_x = x_simul.shape[0]
        a_simul = aux( s_simul.reshape((n_s,n_exp*horizon)), x_simul.reshape( (n_x,n_exp*horizon) ), parms)
        n_a = a_simul.shape[0]
        a_simul = a_simul.reshape(n_a,n_exp,horizon)
        l = [s_simul, x_simul, a_simul]
        varnames = cmodel.symbols['states'] + cmodel.symbols['controls'] + cmodel.symbols['auxiliary']
    if not stack_series:
        return l

    else:
        simul = numpy.row_stack(l)

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

    if irf:
        simul = simul[:,0,:]

        if use_pandas:
            import pandas
            ts = pandas.DataFrame(simul.T, columns=varnames)
            return ts

    return simul
Beispiel #7
0
def solver(fobj,
           x0,
           lb=None,
           ub=None,
           jac=None,
           method='lmmcp',
           infos=False,
           serial_problem=False,
           verbose=False,
           options={}):

    in_shape = x0.shape

    if serial_problem:
        ffobj = fobj
    else:
        ffobj = lambda x: fobj(x.reshape(in_shape)).flatten()

    # standardize jacobian
    if jac is not None:
        if not serial_problem:
            pp = np.prod(in_shape)

            def Dffobj(t):
                tt = t.reshape(in_shape)
                dval = jac(tt)
                return dval.reshape((pp, pp))
        else:
            Dffobj = jac
    elif serial_problem:
        from dolo.numeric.newton import SerialDifferentiableFunction
        Dffobj = SerialDifferentiableFunction(fobj, in_shape)
    else:
        Dffobj = MyJacobian(ffobj)

    if lb == None:
        lb = -np.inf * np.ones(len(x0.flatten()))
    if ub == None:
        ub = np.inf * np.ones(len(x0.flatten())).flatten()

    if not serial_problem:
        lb = lb.flatten()
        ub = ub.flatten()

    if not serial_problem:
        x0 = x0.flatten()

    if method == 'fsolve':
        import scipy.optimize as optimize
        factor = options.get('factor')
        factor = factor if factor else 1
        [sol, infodict, ier, msg] = optimize.fsolve(ffobj,
                                                    x0,
                                                    fprime=Dffobj,
                                                    factor=factor,
                                                    full_output=True,
                                                    xtol=1e-10,
                                                    epsfcn=1e-9)
        if ier != 1:
            print(msg)

    elif method == 'newton':
        from dolo.numeric.newton import serial_newton as newton_solver
        fun = lambda x: [ffobj(x), Dffobj(x)]
        [sol, nit] = newton_solver(fun, x0, verbose=verbose)

    elif method == 'lmmcp':
        from dolo.numeric.extern.lmmcp import lmmcp
        sol = lmmcp(lambda t: -ffobj(t),
                    lambda u: -Dffobj(u),
                    x0,
                    lb,
                    ub,
                    verbose=verbose,
                    options=options)

    elif method == 'ncpsolve':
        from dolo.numeric.ncpsolve import ncpsolve
        fun = lambda x: [ffobj(x), Dffobj(x)]
        if serial_problem:
            jactype = 'serial'
        [sol, nit] = ncpsolve(fun,
                              lb,
                              ub,
                              x0,
                              verbose=verbose,
                              infos=True,
                              jactype='serial')

    else:
        raise Exception('Unknown method : ' + str(method))
    sol = sol.reshape(in_shape)

    if infos:
        return [sol, nit]
    else:
        return sol
Beispiel #8
0
def simulate(cmodel, dr, s0=None, sigma=None, n_exp=0, horizon=40, parms=None, seed=1, discard=False, stack_series=True,
             solve_expectations=False, nodes=None, weights=None):

    '''
    :param cmodel: compiled model
    :param dr: decision rule
    :param s0: initial state where all simulations start
    :param sigma: covariance matrix of the normal multivariate distribution describing the random shocks
    :param n_exp: number of draws to simulate. Use 0 for impulse-response functions
    :param horizon: horizon for the simulation
    :param parms: (vector) value for the parameters of the model
    :param seed: used to initialize the random number generator. Use it to replicate exact same results among simulations
    :param discard: (default: False) if True, then all simulations containing at least one non finite value are discarded
    :param stack_series: return simulated series for different types of variables separately (in a list)
    :return: a ``n_s x n_exp x horizon`` array where ``n_s`` is the number of states. The second dimension is omitted if
    n_exp = 0.
    '''

    from dolo.compiler.compiler_global import CModel
    from dolo.symbolic.model import Model

    if isinstance(cmodel, Model):
        from dolo.symbolic.model import Model
        model = cmodel
        cmodel = CModel(model)
        [y,x,parms] = model.read_calibration()
    else:
        cmodel = cmodel.as_type('fg')

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



    calib = cmodel.model.calibration

    if parms is None:
        parms = numpy.array( calib['parameters'] ) # TODO : remove reference to symbolic model

    if sigma is None:
        sigma = numpy.array( calib['sigma'] )

    if s0 is None:
        s0 = numpy.array( calib['steady_state']['states'] )

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

    x0 = dr(s0)

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

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

    numpy.random.seed(seed)

    for i in range(horizon):
        mean = numpy.zeros(sigma.shape[0])
        if irf:
            epsilons = numpy.zeros( (sigma.shape[0],1) )
        else:
            epsilons = numpy.random.multivariate_normal(mean, sigma, n_exp).T
        s = s_simul[:,:,i]

        x = dr(s)

        if solve_expectations:
            from dolo.numeric.solver import solver
            from dolo.numeric.newton import newton_solver

            fobj = lambda t: step_residual(s, t, dr, cmodel.f, cmodel.g, parms, nodes, weights, with_derivatives=False) #
#            x = solver(fobj, x,  serial_problem=True)
            x = newton_solver(fobj, x, numdiff=True)

        x_simul[:,:,i] = x

        ss = cmodel.g(s,x,epsilons,parms)

        if i<(horizon-1):
            s_simul[:,:,i+1] = ss

    from numpy import any,isnan,all

    if not hasattr(cmodel,'__a__'): # TODO: find a better test than this
        l = [s_simul, x_simul]
    else:
        n_s = s_simul.shape[0]
        n_x = x_simul.shape[0]
        a_simul = cmodel.a( s_simul.reshape((n_s,n_exp*horizon)), x_simul.reshape( (n_x,n_exp*horizon) ), parms)
        n_a = a_simul.shape[0]
        a_simul = a_simul.reshape(n_a,n_exp,horizon)
        l = [s_simul, x_simul, a_simul]

    if not stack_series:
        return l

    else:
        simul = numpy.row_stack(l)

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

    if irf:
        simul = simul[:,0,:]

    return simul
Beispiel #9
0
def solver(fobj, x0, lb=None, ub=None, jac=None, method='lmmcp', infos=False, serial_problem=False, verbose=False, options={}):


    in_shape = x0.shape

    if serial_problem:
        ffobj = fobj
    else:
        ffobj = lambda x: fobj(x.reshape(in_shape)).flatten()


    # standardize jacobian
    if jac is not None:
        if not serial_problem:
            pp = np.prod(in_shape)
            def Dffobj(t):
                tt = t.reshape(in_shape)
                dval = jac(tt)
                return dval.reshape( (pp,pp) )
        else:
            Dffobj = jac
    elif serial_problem:
        Dffobj = MySerialJacobian(fobj, in_shape)
    else:
        Dffobj = MyJacobian(ffobj)


    if lb == None:
        lb = -np.inf*np.ones(len(x0.flatten()))
    if ub == None:
        ub = np.inf*np.ones(len(x0.flatten())).flatten()

    if not serial_problem:
         lb = lb.flatten()
         ub = ub.flatten()

    if not serial_problem:
        x0 = x0.flatten()


    if method == 'fsolve':
        import scipy.optimize as optimize
        factor = options.get('factor')
        factor = factor if factor else 1
        [sol,infodict,ier,msg] = optimize.fsolve(ffobj, x0, fprime=Dffobj, factor=factor, full_output=True, xtol=1e-10, epsfcn=1e-9)
        if ier != 1:
            print(msg)

    elif method == 'newton':
        from dolo.numeric.newton import newton_solver
        fun = lambda x: [ffobj(x), Dffobj(x) ]
        [sol,nit] = newton_solver(fun,x0, verbose=verbose, infos=True)

    elif method == 'lmmcp':
        from dolo.numeric.extern.lmmcp import lmmcp
        sol = lmmcp(lambda t: -ffobj(t), lambda u: -Dffobj(u),x0,lb,ub,verbose=verbose,options=options)

    elif method == 'ncpsolve':
        from dolo.numeric.ncpsolve import ncpsolve
        fun = lambda x: [ffobj(x), Dffobj(x) ]
        [sol,nit] = ncpsolve(fun,lb,ub,x0, verbose=verbose, infos=True, serial=serial_problem)


    sol = sol.reshape(in_shape)

    if infos:
        return [sol, nit]
    else:
        return sol
def time_iteration(
    grid,
    interp,
    xinit,
    f,
    g,
    parms,
    epsilons,
    weights,
    x_bounds=None,
    options={},
    serial_grid=True,
    verbose=True,
    method="lmmcp",
    maxit=500,
    nmaxit=5,
    backsteps=10,
    hook=None,
):

    from dolo.numeric.solver import solver
    from dolo.numeric.newton import newton_solver

    if serial_grid:
        # fun = lambda x: step_residual(grid, x, interp, f, g, parms, epsilons, weights, x_bounds=x_bounds, with_derivatives=False)[0]
        # dfun = lambda x: step_residual(grid, x, interp, f, g, parms, epsilons, weights, x_bounds=x_bounds)[1]
        fun = lambda x: step_residual(grid, x, interp, f, g, parms, epsilons, weights, x_bounds=x_bounds)
    else:
        fun = lambda x: step_residual(
            grid,
            x,
            interp,
            f,
            g,
            parms,
            epsilons,
            weights,
            x_bounds=x_bounds,
            serial_grid=False,
            with_derivatives=False,
        )[0]
        dfun = lambda x: step_residual(
            grid, x, interp, f, g, parms, epsilons, weights, x_bounds=x_bounds, serial_grid=False
        )[1]

    #
    tol = 1e-8
    ##
    import time

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

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

    if x_bounds:
        [lb, ub] = x_bounds(grid, parms)
    else:
        lb = None
        ub = None

    if verbose:
        s = "|Iteration\t|\tStep\t\t\t|\tTime (s)\t|"
        nnn = len(s.replace("\t", " " * 4))
        print("-" * nnn)
        print(s)
        print("-" * nnn)

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

        if serial_grid:
            [x, nit] = newton_solver(fun, x0, lb=lb, ub=ub, infos=True, backsteps=backsteps, maxit=nmaxit)
        else:
            x = solver(fun, x0, lb=lb, ub=ub, method=method, jac=dfun, verbose=verbit, options=options)
            nit = 0
            # we restrict the solution to lie inside the boundaries
        if x_bounds:
            x = np.maximum(np.minimum(ub, x), lb)
        #        res = abs(fun(x)).max()
        err = abs(x - x0).max()
        t_finish = time.time()
        elapsed = t_finish - t_start
        if verbose:
            print("\t\t{}\t|\t{:e}\t|\t{:f}\t|\t{}".format(it, err, elapsed, nit))
        x0 = x0 + (x - x0)
        if hook:
            hook(interp, it, err)
        if False in np.isfinite(x0):
            print("iteration {} failed : non finite value")
            return [x0, x]

    if it == maxit:
        import warnings

        warnings.warn(UserWarning("Maximum number of iterations reached"))

    t2 = time.time()
    print("Elapsed: {}".format(t2 - t1))

    return interp
Beispiel #11
0
def time_iteration(grid, interp, xinit, f, g, parms, epsilons, weights, x_bounds=None, options={}, serial_grid=True, verbose=True, method='lmmcp', maxit=500, nmaxit=5, backsteps=10, hook=None):

    from dolo.numeric.solver import solver
    from dolo.numeric.newton import newton_solver

    if serial_grid:
        #fun = lambda x: step_residual(grid, x, interp, f, g, parms, epsilons, weights, x_bounds=x_bounds, with_derivatives=False)[0]
        #dfun = lambda x: step_residual(grid, x, interp, f, g, parms, epsilons, weights, x_bounds=x_bounds)[1]
        fun = lambda x: step_residual(grid, x, interp, f, g, parms, epsilons, weights, x_bounds=x_bounds)
    else:
        fun = lambda x: step_residual(grid, x, interp, f, g, parms, epsilons, weights, x_bounds=x_bounds, serial_grid=False, with_derivatives=False)[0]
        dfun = lambda x: step_residual(grid, x, interp, f, g, parms, epsilons, weights, x_bounds=x_bounds, serial_grid=False)[1]

    #
    tol = 1e-8
    ##
    import time
    t1 = time.time()
    err = 1
    x0 = xinit
    it = 0

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

    if x_bounds:
        [lb,ub] = x_bounds(grid,parms)
    else:
        lb = None
        ub = None

    if verbose:
        s = "|Iteration\t|\tStep\t\t\t|\tTime (s)\t|"
        nnn = len(s.replace('\t',' '*4))
        print('-'*nnn)
        print(s)
        print('-'*nnn)



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

        if serial_grid:
            [x,nit] = newton_solver(fun,x0,lb=lb,ub=ub,infos=True, backsteps=backsteps, maxit=nmaxit)
        else:
            x = solver(fun, x0, lb=lb, ub=ub, method=method, jac=dfun, verbose=verbit, options=options)
            nit = 0
            # we restrict the solution to lie inside the boundaries
        if x_bounds:
            x = np.maximum(np.minimum(ub,x),lb)
        #        res = abs(fun(x)).max()
        err = abs(x-x0).max()
        t_finish = time.time()
        elapsed = t_finish - t_start
        if verbose:
            print("\t\t{}\t|\t{:e}\t|\t{:f}\t|\t{}".format(it,err,elapsed,nit))
        x0 = x0 + (x-x0)
        if hook:
            hook(interp,it,err)
        if False in np.isfinite(x0):
            print('iteration {} failed : non finite value')
            return [x0, x]

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


    t2 = time.time()
    print('Elapsed: {}'.format(t2 - t1))

    return interp