diff --git a/Documentation/CHANGELOG.md b/Documentation/CHANGELOG.md index be3f00680..49b860a50 100644 --- a/Documentation/CHANGELOG.md +++ b/Documentation/CHANGELOG.md @@ -8,13 +8,14 @@ For more information on HARK, see [our Github organization](https://github.com/e ## Changes -### 0.15.2 (in development) +### 0.16.0 (in development) Release Date: TBD #### Major Changes -none +- Allows structural equations in model files to be provided in string form [#1427](https://github.com/econ-ark/HARK/pull/1427) +- Introduces `HARK.parser' module for parsing configuration files into models [#1427](https://github.com/econ-ark/HARK/pull/1427) #### Minor Changes @@ -50,7 +51,7 @@ This release drops support for Python 3.8 and 3.9, consistent with SPEC 0, and a - Object-oriented solver code has been moved to /HARK/ConsumptionSaving/LegacyOOsolvers.py, for legacy support of downstream projects. - AgentTypeMonteCarloSimulator now requires model shock, parameter, and dynamics information to be organized into 'blocks'. The DBlock object is introduced. [#1411](https://github.com/econ-ark/HARK/pull/1411) - RBlock object allows for recursive composition of DBlocks in models, as demonstrated by the AgentTypeMonteCarloSimulator [#1417](https://github.com/econ-ark/HARK/pull/1417/) -- Transtion, reward, state-rulle value function, decision value function, and arrival value function added to DBlock [#1417](https://github.com/econ-ark/HARK/pull/1417/) +- Transtion, reward, state-rule value function, decision value function, and arrival value function added to DBlock [#1417](https://github.com/econ-ark/HARK/pull/1417/) - All methods that construct inputs for solvers are now functions that are specified in the dictionary attribute `constructors`. [#1410](https://github.com/econ-ark/HARK/pull/1410) - Such constructed inputs can use alternate parameterizations / formats by changing the `constructor` function and providing its arguments in `parameters`. - Move `HARK.datasets` to `HARK.Calibration` for better organization of data and calibration tools. [#1430](https://github.com/econ-ark/HARK/pull/1430) diff --git a/HARK/model.py b/HARK/model.py index c97a2ad76..1816460fd 100644 --- a/HARK/model.py +++ b/HARK/model.py @@ -11,6 +11,7 @@ ) from inspect import signature import numpy as np +from HARK.parser import math_text_to_lambda from typing import Any, Callable, Mapping, List, Union @@ -143,7 +144,16 @@ class DBlock: Parameters ---------- - ... + shocks: Mapping(str, Distribution) + A mapping from variable names to Distribution objects, + representing exogenous shocks. + + dynamics: Mapping(str, str or callable) + A dictionary mapping variable names to mathematical expressions. + These expressions can be simple functions, in which case the + argument names should match the variable inputs. + Or these can be strings, which are parsed into functions. + """ name: str = "" @@ -152,6 +162,11 @@ class DBlock: dynamics: dict = field(default_factory=dict) reward: dict = field(default_factory=dict) + def __post_init__(self): + for v in self.dynamics: + if isinstance(self.dynamics[v], str): + self.dynamics[v] = math_text_to_lambda(self.dynamics[v]) + def get_shocks(self): return self.shocks diff --git a/HARK/models/consumer.py b/HARK/models/consumer.py index bee7b102a..148c81457 100644 --- a/HARK/models/consumer.py +++ b/HARK/models/consumer.py @@ -53,7 +53,7 @@ "b": lambda k, R, PermGroFac: k * R / PermGroFac, "m": lambda b, theta: b + theta, "c": Control(["m"]), - "a": lambda m, c: m - c, + "a": "m - c", }, "reward": {"u": lambda c, CRRA: c ** (1 - CRRA) / (1 - CRRA)}, } diff --git a/HARK/parser.py b/HARK/parser.py new file mode 100644 index 000000000..61fcba539 --- /dev/null +++ b/HARK/parser.py @@ -0,0 +1,26 @@ +from sympy.utilities.lambdify import lambdify +from sympy.parsing.sympy_parser import parse_expr + + +class Expression: + def __init__(self, text): + self.txt + self.expr = parse_expr(text) + self.npf = self.func() + + # first derivatives. + self.grad = { + sym.__str__(): self.expr.diff(sym) for sym in list(self.expr.free_symbols) + } + + def func(self): + return lambdify(list(self.expr.free_symbols), self.expr, "numpy") + + +def math_text_to_lambda(text): + """ + Returns a function represented by the given mathematical text. + """ + expr = parse_expr(text) + func = lambdify(list(expr.free_symbols), expr, "numpy") + return func