econ-ark / HARK

Heterogenous Agents Resources & toolKit
Apache License 2.0
331 stars 198 forks source link

replace AgentType.sim_one_period with a generic Monte Carlo simulator that consumes equations #1295

Open sbenthall opened 1 year ago

sbenthall commented 1 year ago

This can more explicitly take in equations, and be removed to a HARK.simulation.monte_carlo module

https://github.com/econ-ark/HARK/blob/master/HARK/core.py#L432-L479

This will help with the whiteboard problem #889

cf. #1292

sbenthall commented 1 year ago

The FrameAgentType was an attempt at this. The problem with it, noted by @mnwhite , is that the configuration of the FrameAgentType is too complex.

https://github.com/econ-ark/HARK/blob/master/examples/FrameAgentType/FrameModels.ipynb

Something simpler, like a dictionary of lambdas, would be easier to read and write.

mnwhite commented 1 year ago

Here's the off-the-top-of-my-head draft of a format to specify the mechanics of ConsIndShock:

inter = [aNrm, pLvl] control = [cNrm] discrete = [] exog = [psi, theta] param = [gamma, omega, R, J]

dynamics = [ G = gamma * psi, Rnrm = R / G, bNrm = Rnrm * aNrm, mNrm = bNrm + theta, cNrm = policy(mNrm), aNrm = mNrm - cNrm, die(omega), old = j >= J, die(old) ]

auxiliary = [ pLvl = G * pLvl, mLvl = mNrm * pLvl, cLvl = cNrm * pLvl, aLvl = aNrm * pLvl, MPC = policy.der(mNrm) ]

The simulator should be able to take a statement like this and implement it. The inter variables specify what must exist for an agent when it is initialized. The control variables specify the variables that the simulator should expect to exist, probably named like cNrmFunc or stored in policy['cNrm'].

The discrete variables are those that the code should expect to be whole numbers, not continuous values, which might matter for evaluating policy(d, mNrm) where d is discrete.

The exog variables name variables that come from some process exogenous to the agent-- maybe RVs, maybe chosen by someone else, maybe an aggregate. The code just needs to know to expect to be given some way to get or generate things named in exog, which will not be found within dynamics.

Variables named in param are parameters to be pulled from the agent's data, common to a "type". Whether or not each one is time/age-varying is irrelevant for the mechanics of the model. Each instance of an AgentType using this model can specify its own vary list to indicate how parameters should be looked up. In our standard ConsIndShock lifecycle model, omega and gamma would be in vary, while R and J would not.

Note what's not here: state variables. It might be that we need to name the variables that are used as "states" in the sense of "inputs to a policy function", but it might be enough to have them implicit in the dynamics statement.

The statements in dynamics should be self-explanatory. It's a start to finish description of what happens to each agent in one period. The parameter J is the maximum age beyond which an agent can't live.

The contents of auxiliary are optional variables that can be computed along the way, but don't need to be as a required part of simulating the model. Each of these lines would be executed if and only if the accompanying variable is requested in track, with dependencies automatically generated and handled.

There are some additional complications for things like jointly determined variables, but those don't appear in any of our models so far.

mnwhite commented 1 year ago

Oh, and j is used to mean "age". There would also be t for absolute time, if needed.

sbenthall commented 1 year ago

Ok, I think it's possible to move incrementally in this direction.

The hardest part is the Python object for equations, I think.

I've got a few aesthetic quibbles but let's start getting the functionality in.

I think I can get part of the way there with #1292 and refactoring the Frame code, as discussed.

llorracc commented 1 year ago

I very much hope that @William Du @.***> 's implementation of the "shuffling" method is included in the generic Monte Carlo simulator.

On Thu, Jun 29, 2023 at 1:07 AM Sebastian Benthall @.***> wrote:

Ok, I think it's possible to move incrementally in this direction.

The hardest part is the Python object for equations, I think.

I've got a few aesthetic quibbles but let's start getting the functionality in.

I think I can get part of the way there with #1292 https://github.com/econ-ark/HARK/pull/1292 and refactoring the Frame code, as discussed.

— Reply to this email directly, view it on GitHub https://github.com/econ-ark/HARK/issues/1295#issuecomment-1612223273, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKCK76WDRCLQDI4PIAIMMTXNS2K3ANCNFSM6AAAAAAZXOKJ5A . You are receiving this because you are subscribed to this thread.Message ID: @.***>

--

sbenthall commented 1 year ago

dynamics = [ G = gamma * psi, Rnrm = R / G, bNrm = Rnrm * aNrm, mNrm = bNrm + theta, cNrm = policy(mNrm), aNrm = mNrm - cNrm, die(omega), old = j >= J, die(old) ]

As we've discussed, one tricky part about this proposal is the syntax for these sorts of 'equations'. Without a symbolic library, it's hard to do this very cleanly in Python.

This commit is the most lightweight way I can think of doing this without a symbolic library: https://github.com/econ-ark/HARK/pull/1292/commits/d09eb303ebc01d85cd8e5c00d875b4384830a6ee

It is possible to use inspect.signature to pull out the parameter names and bind them in simulation. https://docs.python.org/3/library/inspect.html#inspect.signature

mnwhite commented 1 year ago

I'm not attached to anything about the notation, especially specifics. This was more about specifying what is the kind of information specifies the basic consumption saving model's mechanics, up to distributional and/or functional assumptions (other than basic accounting arithmetic).

My general point was that it's a very "light" set of information, human readable, and easy-ish to interpret. The programming of how that gets passed into Python is a different question.

On Fri, Jun 30, 2023, 3:24 PM Sebastian Benthall @.***> wrote:

dynamics = [ G = gamma psi, Rnrm = R / G, bNrm = Rnrm aNrm, mNrm = bNrm + theta, cNrm = policy(mNrm), aNrm = mNrm - cNrm, die(omega), old = j >= J, die(old) ]

As we've discussed, one tricky part about this proposal is the syntax for these sorts of 'equations'. Without a symbolic library, it's hard to do this very cleanly in Python.

This commit is the most lightweight way I can think of doing this without a symbolic library: d09eb30 https://github.com/econ-ark/HARK/commit/d09eb303ebc01d85cd8e5c00d875b4384830a6ee

It is possible to use inspect.signature to pull out the parameter names and bind them in simulation. https://docs.python.org/3/library/inspect.html#inspect.signature

— Reply to this email directly, view it on GitHub https://github.com/econ-ark/HARK/issues/1295#issuecomment-1615104403, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADKRAFMK7SSFNHZVDHAXDUTXN4RWBANCNFSM6AAAAAAZXOKJ5A . You are receiving this because you were mentioned.Message ID: @.***>

sbenthall commented 1 year ago

Got it. Please see #1296 for an example implementation.

mnwhite commented 1 year ago

Passed --> parsed. Ducking autocorrect.

On Fri, Jun 30, 2023, 4:14 PM Sebastian Benthall @.***> wrote:

Got it. Please see #1296 https://github.com/econ-ark/HARK/pull/1296 for an example implementation.

— Reply to this email directly, view it on GitHub https://github.com/econ-ark/HARK/issues/1295#issuecomment-1615150101, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADKRAFMP4ZMWCSV5AADWDK3XN4XSHANCNFSM6AAAAAAZXOKJ5A . You are receiving this because you were mentioned.Message ID: @.***>