Exemple #1
0
    def __init__(self, values, model=None):

        from dolang.symbolic import sanitize, stringify

        exogenous = model.symbols['exogenous']
        states = model.symbols['states']
        controls = model.symbols['controls']
        parameters = model.symbols['parameters']

        preamble = dict([(s, values[s]) for s in values.keys()
                         if s not in controls])
        equations = [values[s] for s in controls]

        variables = exogenous + states + controls + [*preamble.keys()]

        preamble_str = dict()

        for k in [*preamble.keys()]:
            v = preamble[k]
            if '(' not in k:
                vv = f'{k}(0)'
            else:
                vv = k

            preamble_str[stringify(vv)] = stringify(sanitize(v, variables))

        # let's reorder the preamble
        from dolang.triangular_solver import get_incidence, triangular_solver
        incidence = get_incidence(preamble_str)
        sol = triangular_solver(incidence)
        kk = [*preamble_str.keys()]
        preamble_str = dict([(kk[k], preamble_str[kk[k]]) for k in sol])

        equations = [
            dolang.symbolic.sanitize(eq, variables) for eq in equations
        ]
        equations_strings = [
            dolang.stringify(eq, variables) for eq in equations
        ]

        args = dict([('m', [(e, 0) for e in exogenous]),
                     ('s', [(e, 0) for e in states]),
                     ('p', [e for e in parameters])])

        args = dict([(k, [stringify_symbol(e) for e in v])
                     for k, v in args.items()])

        targets = [stringify_symbol((e, 0)) for e in controls]

        eqs = dict([(targets[i], eq)
                    for i, eq in enumerate(equations_strings)])

        fff = FlatFunctionFactory(preamble_str, eqs, args, 'custom_dr')

        fun, gufun = make_method_from_factory(fff)

        self.p = model.calibration['parameters']
        self.exo_grid = model.exogenous.discretize()  # this is never used
        self.endo_grid = model.get_grid()
        self.gufun = gufun
Exemple #2
0
def timeshift(expr, variables, date):
    from sympy import Symbol
    from dolang import stringify
    d = {
        Symbol(stringify_symbol((v, 0))): Symbol(stringify_symbol((v, date)))
        for v in variables
    }
    return expr.subs(d)
Exemple #3
0
def timeshift(expr, variables, date):
    from sympy import Symbol
    from dolang import stringify
    d = {
        Symbol(stringify_symbol((v, 0))): Symbol(stringify_symbol((v, date)))
        for v in variables
    }
    return expr.subs(d)
Exemple #4
0
def eval_formula(expr: str, dataframe=None, context=None):
    '''
    expr: string
        Symbolic expression to evaluate.
        Example: `k(1)-delta*k(0)-i`
    table: (optional) pandas dataframe
        Each column is a time series, which can be indexed with dolo notations.
    context: dict or CalibrationDict
    '''

    print("Evaluating: {}".format(expr))
    if context is None:
        dd = {}  # context dictionary
    elif isinstance(context, CalibrationDict):
        dd = context.flat.copy()
    else:
        dd = context.copy()

    # compat since normalize form for parameters doesn't match calib dict.
    for k in [*dd.keys()]:
        dd[stringify_symbol(k)] = dd[k]

    expr_ast = parse_string(expr).value
    variables = list_variables(expr_ast)
    nexpr = stringify(expr_ast)
    print(expr)
    print(variables)

    dd['log'] = log
    dd['exp'] = exp

    if dataframe is not None:

        import pandas as pd
        for (k, t) in variables:
            dd[stringify_symbol((k, t))] = dataframe[k].shift(t)
        dd['t'] = pd.Series(dataframe.index, index=dataframe.index)

    expr = to_source(nexpr)
    print(expr)
    print(dd.keys())
    res = eval(expr, dd)

    return res
Exemple #5
0
def get_factory(model, eq_type: str, tshift: int = 0):

    from dolo.compiler.model import decode_complementarity

    from dolo.compiler.recipes import recipes
    from dolang.symbolic import stringify, stringify_symbol

    equations = model.equations

    if eq_type == "auxiliary":
        eqs = [('{}({})'.format(s, 0)) for s in model.symbols['auxiliaries']]
        specs = {
            'eqs': [['exogenous', 0, 'm'], ['states', 0, 's'],
                    ['controls', 0, 'x'], ['parameters', 0, 'p']]
        }
    else:
        eqs = equations[eq_type]
        if eq_type in ('controls_lb', 'controls_ub'):
            specs = {
                'eqs':
                recipes['dtcc']['specs']['arbitrage']['complementarities'][
                    'left-right']
            }
        else:
            specs = recipes['dtcc']['specs'][eq_type]

    specs = shift_spec(specs, tshift=tshift)

    preamble_tshift = set([s[1] for s in specs['eqs'] if s[0] == 'states'])
    preamble_tshift = preamble_tshift.intersection(
        set([s[1] for s in specs['eqs'] if s[0] == 'controls']))

    args = []
    for sg in specs['eqs']:
        if sg[0] == 'parameters':
            args.append([s for s in model.symbols["parameters"]])
        else:
            args.append([(s, sg[1]) for s in model.symbols[sg[0]]])
    args = [[stringify_symbol(e) for e in vg] for vg in args]

    arguments = dict(zip([sg[2] for sg in specs['eqs']], args))

    # temp
    eqs = [eq.replace("==","=").replace("=","==") for eq in eqs]

    if 'target' in specs:
        sg = specs['target']
        targets = [(s, sg[1]) for s in model.symbols[sg[0]]]
        eqs = [eq.split('==')[1] for eq in eqs]
    else:
        eqs = [("({1})-({0})".format(*eq.split('==')) if '==' in eq else eq)
               for eq in eqs]
        targets = [('out{}'.format(i), 0) for i in range(len(eqs))]

    eqs = [str.strip(eq) for eq in eqs]
    eqs = [dolang.parse_string(eq) for eq in eqs]
    es = ExpressionSanitizer(model.variables)
    eqs = [es.visit(eq) for eq in eqs]

    eqs = [time_shift(eq, tshift) for eq in eqs]
    eqs = [stringify(eq) for eq in eqs]
    eqs = [dolang.to_source(eq) for eq in eqs]

    targets = [stringify_symbol(e) for e in targets]

    # sanitize defs ( should be )
    defs = dict()
    for k in model.definitions:
        if '(' not in k:
            s = "{}(0)".format(k)
            val = model.definitions[k]
            val = es.visit(dolang.parse_string(val))
            for t in preamble_tshift:
                s = stringify_symbol((k, t))
                vv = stringify(time_shift(val, t))
                defs[s] = dolang.to_source(vv)

    preamble = reorder_preamble(defs)

    eqs = dict(zip(targets, eqs))
    ff = FlatFunctionFactory(preamble, eqs, arguments, eq_type)

    return ff
Exemple #6
0
def model_to_fg(model, order=2):
    # compile f, g function at higher order

    all_variables = sum(
        [model.symbols[e] for e in model.symbols if e != "parameters"], [])
    all_dvariables = ([(d, 0) for d in all_variables] +
                      [(d, 1)
                       for d in all_variables] + [(d, -1)
                                                  for d in all_variables])
    psyms = [(e, 0) for e in model.symbols["parameters"]]

    definitions = model.definitions

    d = dict()

    for k in definitions:
        v = parse_equation(definitions[k], all_variables, to_sympy=True)
        kk = stringify_symbol((k, 0))
        kk_m1 = stringify_symbol((k, -1))
        kk_1 = stringify_symbol((k, 1))
        d[sympy.Symbol(kk)] = v
        d[sympy.Symbol(kk_m1)] = timeshift(v, all_variables, -1)
        d[sympy.Symbol(kk_1)] = timeshift(v, all_variables, 1)

    f_eqs = model.equations["arbitrage"]
    f_eqs = [parse_equation(eq, all_variables, to_sympy=True) for eq in f_eqs]
    f_eqs = [eq.subs(d) for eq in f_eqs]

    g_eqs = model.equations["transition"]
    g_eqs = [
        parse_equation(eq, all_variables, to_sympy=True, substract_lhs=False)
        for eq in g_eqs
    ]
    # solve_recursively
    dd = dict()
    for eq in g_eqs:
        dd[eq[0]] = eq[1].subs(dd).subs(d)
    g_eqs = dd.values()

    f_syms = ([(e, 0) for e in model.symbols["states"]] +
              [(e, 0) for e in model.symbols["controls"]] +
              [(e, 1) for e in model.symbols["states"]] +
              [(e, 1) for e in model.symbols["controls"]])

    g_syms = ([(e, -1) for e in model.symbols["states"]] +
              [(e, -1) for e in model.symbols["controls"]] +
              [(e, 0) for e in model.symbols["exogenous"]])

    params = model.symbols["parameters"]

    f = compile_higher_order_function(
        f_eqs,
        f_syms,
        params,
        order=order,
        funname="f",
        return_code=False,
        compile=False,
    )

    g = compile_higher_order_function(
        g_eqs,
        g_syms,
        params,
        order=order,
        funname="g",
        return_code=False,
        compile=False,
    )
    # cache result
    model.__higher_order_functions__ = dict(f=f, g=g)
    model.__highest_order__ = order

    return [f, g]
def compile_higher_order_function(eqs,
                                  syms,
                                  params,
                                  order=2,
                                  funname='anonymous',
                                  return_code=False,
                                  compile=False):
    '''From a list of equations and variables, define a multivariate functions with higher order derivatives.'''

    from dolang.symbolic import stringify, stringify_symbol

    vars = [s[0] for s in syms]
    # TEMP: compatibility fix when eqs is an Odict:
    eqs = [eq for eq in eqs]

    if isinstance(eqs[0], str):
        # elif not isinstance(eqs[0], sympy.Basic):
        # assume we have ASTs
        eqs = list([ast.parse(eq).body[0] for eq in eqs])
        eqs_std = list([stringify_symbol(eq, variables=vars) for eq in eqs])
        eqs_sym = list([ast_to_sympy(eq) for eq in eqs_std])
    else:
        eqs_sym = eqs

    symsd = list([stringify_symbol((a, b)) for a, b in syms])
    paramsd = list([stringify_symbol(a) for a in params])
    D = higher_order_diff(eqs_sym, symsd, order=order)

    txt = """def {funname}(x, p, order=1):

    import numpy
    from numpy import log, exp, tan, sqrt
    from numpy import pi as pi_
    from numpy import inf as inf_
    from scipy.special import erfc

""".format(funname=funname)

    for i in range(len(syms)):
        txt += "    {} = x[{}]\n".format(symsd[i], i)

    txt += "\n"

    for i in range(len(params)):
        txt += "    {} = p[{}]\n".format(paramsd[i], i)

    txt += "\n    out = numpy.zeros({})".format(len(eqs))

    for i in range(len(eqs)):
        txt += "\n    out[{}] = {}".format(i, D[0][i])

    txt += """

    if order == 0:
        return out

"""
    if order >= 1:
        # Jacobian
        txt += "    out_1 = numpy.zeros(({},{}))\n".format(len(eqs), len(syms))

        for i in range(len(eqs)):
            for j in range(len(syms)):
                val = D[1][i, j]
                if val != 0:
                    txt += "    out_1[{},{}] = {}\n".format(i, j, D[1][i, j])

        txt += """

    if order == 1:
        return [out, out_1]

"""

    if order >= 2:
        # Hessian
        txt += "    out_2 = numpy.zeros(({},{},{}))\n".format(
            len(eqs), len(syms), len(syms))

        for n in range(len(eqs)):
            for i in range(len(syms)):
                for j in range(len(syms)):
                    val = D[2][n, i, j]
                    if val is not None:
                        if val != 0:
                            txt += "    out_2[{},{},{}] = {}\n".format(
                                n, i, j, D[2][n, i, j])
                    else:
                        i1, j1 = sorted((i, j))
                        if D[2][n, i1, j1] != 0:
                            txt += "    out_2[{},{},{}] = out_2[{},{},{}]\n".format(
                                n, i, j, n, i1, j1)

        txt += """

    if order == 2:
        return [out, out_1, out_2]

"""

    if order >= 3:
        # Hessian
        txt += "    out_3 = numpy.zeros(({},{},{},{}))\n".format(
            len(eqs), len(syms), len(syms), len(syms))

        for n in range(len(eqs)):
            for i in range(len(syms)):
                for j in range(len(syms)):
                    for k in range(len(syms)):
                        val = D[3][n, i, j, k]
                        if val is not None:
                            if val != 0:
                                txt += "    out_3[{},{},{},{}] = {}\n".format(
                                    n, i, j, k, D[3][n, i, j, k])
                        else:
                            i1, j1, k1 = sorted((i, j, k))
                            if D[3][n, i1, j1, k1] != 0:
                                txt += "    out_3[{},{},{},{}] = out_3[{},{},{},{}]\n".format(
                                    n, i, j, k, n, i1, j1, k1)

        txt += """

    if order == 3:
        return [out, out_1, out_2, out_3]
    """

    if return_code:
        return txt
    else:
        d = {}

        exec(txt, d)
        fun = d[funname]

        if compile:
            raise Exception("Not implemented.")

        return fun
Exemple #8
0
exo_vars = [e['name'] for e in data['modfile']['exogenous']]
parameters = [e['name'] for e in data['modfile']['parameters']]

variables = endo_vars + exo_vars  # all variables with time-index

equations = [f"{e['rhs']} - ({e['lhs']})" for e in data['modfile']['model']]
equations = [dolang.symbolic.sanitize(eq, variables) for eq in equations]
equations_strings = [dolang.stringify(eq, variables) for eq in equations]

args = dict([('y_f', [(e, 1) for e in endo_vars]),
             ('y', [(e, 0) for e in endo_vars]),
             ('y_p', [(e, -1) for e in endo_vars]),
             ('e', [(e, 0) for e in exo_vars]),
             ('p', [e for e in parameters])])

args = dict([(k, [stringify_symbol(e) for e in v]) for k, v in args.items()])

from dolang.symbolic import stringify_symbol
from dolang.factory import FlatFunctionFactory

eqs = dict([(f"equation_{i+1}", eq) for i, eq in enumerate(equations_strings)])

fff = FlatFunctionFactory(dict(), eqs, args, 'f_dynamic')

from dolang.function_compiler import make_method_from_factory

fun, gufun = make_method_from_factory(fff, vectorize=True, debug=True)

calibration = dict()
data['modfile']['statements']
Exemple #9
0
def model_to_fg(model, order=2):
    # compile f, g function at higher order

    all_variables = sum(
        [model.symbols[e] for e in model.symbols if e != 'parameters'], [])
    all_dvariables = ([(d, 0) for d in all_variables] + [
        (d, 1) for d in all_variables
    ] + [(d, -1) for d in all_variables])
    psyms = [(e, 0) for e in model.symbols['parameters']]

    definitions = model.definitions

    d = dict()

    for k in definitions:
        v = parse_equation(definitions[k], all_variables, to_sympy=True)
        kk = stringify_symbol((k, 0))
        kk_m1 = stringify_symbol((k, -1))
        kk_1 = stringify_symbol((k, 1))
        d[sympy.Symbol(kk)] = v
        d[sympy.Symbol(kk_m1)] = timeshift(v, all_variables, -1)
        d[sympy.Symbol(kk_1)] = timeshift(v, all_variables, 1)

    f_eqs = model.equations['arbitrage']
    f_eqs = [parse_equation(eq, all_variables, to_sympy=True) for eq in f_eqs]
    f_eqs = [eq.subs(d) for eq in f_eqs]

    g_eqs = model.equations['transition']
    g_eqs = [
        parse_equation(eq, all_variables, to_sympy=True, substract_lhs=False)
        for eq in g_eqs
    ]
    #solve_recursively
    dd = dict()
    for eq in g_eqs:
        dd[eq[0]] = eq[1].subs(dd).subs(d)
    g_eqs = dd.values()

    f_syms = [(e,0) for e in model.symbols['states']] + \
                [(e,0) for e in model.symbols['controls']] + \
                [(e,1) for e in model.symbols['states']] + \
                [(e,1) for e in model.symbols['controls']]

    g_syms = [(e,-1) for e in model.symbols['states']] + \
                [(e,-1) for e in model.symbols['controls']] + \
                [(e,0) for e in model.symbols['exogenous']]

    params = model.symbols['parameters']

    f = compile_higher_order_function(
        f_eqs,
        f_syms,
        params,
        order=order,
        funname='f',
        return_code=False,
        compile=False)

    g = compile_higher_order_function(
        g_eqs,
        g_syms,
        params,
        order=order,
        funname='g',
        return_code=False,
        compile=False)
    # cache result
    model.__higher_order_functions__ = dict(f=f, g=g)
    model.__highest_order__ = order

    return [f, g]
def compile_higher_order_function(eqs, syms, params, order=2, funname='anonymous',
    return_code=False, compile=False):
    '''From a list of equations and variables, define a multivariate functions with higher order derivatives.'''

    from dolang.symbolic import stringify, stringify_symbol

    vars = [s[0] for s in syms]
    # TEMP: compatibility fix when eqs is an Odict:
    eqs = [eq for eq in eqs]

    if isinstance(eqs[0], str):
    # elif not isinstance(eqs[0], sympy.Basic):
    # assume we have ASTs
        eqs = list([ast.parse(eq).body[0] for eq in eqs])
        eqs_std = list( [stringify_symbol(eq, variables=vars) for eq in eqs] )
        eqs_sym = list( [ast_to_sympy(eq) for eq in eqs_std] )
    else:
        eqs_sym = eqs

    symsd = list( [stringify_symbol((a,b)) for a,b in syms] )
    paramsd = list( [stringify_symbol(a) for a in params] )
    D = higher_order_diff(eqs_sym, symsd, order=order)

    txt = """def {funname}(x, p, order=1):

    import numpy
    from numpy import log, exp, tan, sqrt
    from numpy import pi as pi_
    from numpy import inf as inf_
    from scipy.special import erfc

""".format(funname=funname)

    for i in range(len(syms)):
        txt += "    {} = x[{}]\n".format(symsd[i], i)

    txt += "\n"

    for i in range(len(params)):
        txt += "    {} = p[{}]\n".format(paramsd[i], i)

    txt += "\n    out = numpy.zeros({})".format(len(eqs))

    for i in range(len(eqs)):
        txt += "\n    out[{}] = {}".format(i, D[0][i])

    txt += """

    if order == 0:
        return out

"""
    if order >= 1:
        # Jacobian
        txt += "    out_1 = numpy.zeros(({},{}))\n".format(len(eqs), len(syms))

        for i in range(len(eqs)):
            for j in range(len(syms)):
                val = D[1][i,j]
                if val != 0:
                    txt += "    out_1[{},{}] = {}\n".format(i,j,D[1][i,j])

        txt += """

    if order == 1:
        return [out, out_1]

"""

    if order >= 2:
        # Hessian
        txt += "    out_2 = numpy.zeros(({},{},{}))\n".format(len(eqs), len(syms), len(syms))

        for n in range(len(eqs)):
            for i in range(len(syms)):
                for j in range(len(syms)):
                    val = D[2][n,i,j]
                    if val is not None:
                        if val != 0:
                            txt += "    out_2[{},{},{}] = {}\n".format(n,i,j,D[2][n,i,j])
                    else:
                        i1, j1 = sorted( (i,j) )
                        if D[2][n,i1,j1] != 0:
                            txt += "    out_2[{},{},{}] = out_2[{},{},{}]\n".format(n,i,j,n,i1,j1)

        txt += """

    if order == 2:
        return [out, out_1, out_2]

"""


    if order >= 3:
        # Hessian
        txt += "    out_3 = numpy.zeros(({},{},{},{}))\n".format(len(eqs), len(syms), len(syms), len(syms))

        for n in range(len(eqs)):
            for i in range(len(syms)):
                for j in range(len(syms)):
                    for k in range(len(syms)):
                        val = D[3][n,i,j,k]
                        if val is not None:
                            if val != 0:
                                txt += "    out_3[{},{},{},{}] = {}\n".format(n,i,j,k,D[3][n,i,j,k])
                        else:
                            i1, j1, k1 = sorted( (i,j,k) )
                            if D[3][n,i1,j1,k1] != 0:
                                txt += "    out_3[{},{},{},{}] = out_3[{},{},{},{}]\n".format(n,i,j,k,n,i1,j1,k1)

        txt += """

    if order == 3:
        return [out, out_1, out_2, out_3]
    """

    if return_code:
        return txt
    else:
        d = {}

        exec(txt, d)
        fun = d[funname]

        if compile:
            raise Exception("Not implemented.")

        return fun
Exemple #11
0
def get_factory(model, eq_type: str, tshift: int = 0):

    from dolo.compiler.model import decode_complementarity

    from dolo.compiler.recipes import recipes
    from dolang.symbolic import stringify, stringify_symbol

    equations = model.equations

    if eq_type == "auxiliary":
        eqs = ["{}".format(s) for s in model.symbols["auxiliaries"]]
        specs = {
            "eqs": [
                ["exogenous", 0, "m"],
                ["states", 0, "s"],
                ["controls", 0, "x"],
                ["parameters", 0, "p"],
            ]
        }
    else:
        eqs = equations[eq_type]
        if eq_type in ("arbitrage_lb", "arbitrage_ub"):
            specs = {
                "eqs":
                recipes["dtcc"]["specs"]["arbitrage"]["complementarities"]
                ["left-right"]
            }
        else:
            specs = recipes["dtcc"]["specs"][eq_type]

    specs = shift_spec(specs, tshift=tshift)

    preamble_tshift = set([s[1] for s in specs["eqs"] if s[0] == "states"])
    preamble_tshift = preamble_tshift.intersection(
        set([s[1] for s in specs["eqs"] if s[0] == "controls"]))

    args = []
    for sg in specs["eqs"]:
        if sg[0] == "parameters":
            args.append([s for s in model.symbols["parameters"]])
        else:
            args.append([(s, sg[1]) for s in model.symbols[sg[0]]])
    args = [[stringify_symbol(e) for e in vg] for vg in args]

    arguments = dict(zip([sg[2] for sg in specs["eqs"]], args))

    # temp
    eqs = [eq.split("⟂")[0].strip() for eq in eqs]

    if "target" in specs:
        sg = specs["target"]
        targets = [(s, sg[1]) for s in model.symbols[sg[0]]]
        eqs = [eq.split("=")[1] for eq in eqs]
    else:
        eqs = [("({1})-({0})".format(*eq.split("=")) if "=" in eq else eq)
               for eq in eqs]
        targets = [("out{}".format(i), 0) for i in range(len(eqs))]

    eqs = [str.strip(eq) for eq in eqs]

    eqs = [dolang.parse_string(eq) for eq in eqs]
    es = Sanitizer(variables=model.variables)
    eqs = [es.transform(eq) for eq in eqs]

    eqs = [time_shift(eq, tshift) for eq in eqs]

    eqs = [stringify(eq) for eq in eqs]

    eqs = [str_expression(eq) for eq in eqs]

    targets = [stringify_symbol(e) for e in targets]

    # sanitize defs ( should be )
    defs = dict()

    for k in model.definitions:
        val = model.definitions[k]
        # val = es.transform(dolang.parse_string(val))
        for t in preamble_tshift:
            s = stringify(time_shift(k, t))
            if isinstance(val, str):
                vv = stringify(time_shift(val, t))
            else:
                vv = str(val)
            defs[s] = vv

    preamble = reorder_preamble(defs)

    eqs = dict(zip(targets, eqs))
    ff = FlatFunctionFactory(preamble, eqs, arguments, eq_type)

    return ff