Replies: 11 comments
-
Replies below targeted mainly to persons in the set ***@***.***)
as I think MNW understands my views already.
On Tue, Apr 9, 2024 at 4:11 PM Matthew N. White ***@***.***> wrote:
HARK models as basic as ConsIndShock use some "constructed inputs" for
their solver, by which I mean objects that are passed to the
solve_one_period function but would not have been *manually* specified by
the user. For example, IncShkDstn is a complicated (time-varying) object
that could (in principle) be manually created by a user and assigned to an
instance of IndShockConsumerType, but more reasonably would be
constructed from "primitive parameters" like PermShkStd, TrankShkStd,
UnempPrb, etc. As-is, PermGroFac is expected to be provided by the user,
but it in principle it *could* be constructed on the AgentType instance
given some parametric description of the income growth profile.
Yes, like “flat permanent income growth if you’re older than 65, prior
permanent income is current permanent income / 0.7 for a 65 year old” (to
capture the fact that if you’re going forward in time “permanent income”
falls to 0.7 of its prior value when you retire” etc.
This should be our fundamental “raw” way of creating models — with every
single aspect of the model (not just income growth) up for grabs and
available to change as you move earlier, with the only restriction being
that the end-of-state variables from one state must mesh with the
beginning-of-state variables from its successor.
Each AgentType subclass has "baked in" constructors, which are called from
(or simply part of) an update_X method.
So, these are “backwards” constructors? Like, if you’ve just solved for age
77, the constructor will make the stuff needed to solve the age 76 problem?
The update method itself is supposed to call *all* of those constructors,
as a universal way to bring constructed inputs up-to-date with any changes
made to the primitive parameters. It does so by explicitly calling each
update_X method, sometimes from its parent class.
Seems like the way to do all of this is to allow users to specify “default”
values of everything (say, RRA), and unless their constructor explicitly
constructs RRA the default applies.
As is, if a user wants to have a *different* way of constructing such an
input, they can either a) do it themselves and then drop in the result into
their instances; or b) make a trivial subclass of the AgentType that
overrides that constructor method.
Or c) do what we do now in which you construct everything in advance of
solving anything.
Neither of these are "nice", and there's no organized way for a new user to
find out what the required "primitive inputs" are. I'm going to fix this,
and this issue presents an overview of my proposal for doing so.
------------------------------
I propose that AgentType instances have a new constructors dictionary.
The keys of this dictionary would be the names of inputs to the
solve_one_period function for that class;
This is too rigid - as best I can understand it requires the user to
already know, when they solve the problem of the 120 year old, what the
names of the inputs will be for the problem of the 18 year old who is
deciding whether to go to college.
My (strong) preference is that, in principle, for any age [image: t] we
allow the user to make up anything they want for the [image: t-1] problem,
so long as:
- their [image: t-1] solver requires some subset (probably nonstrict) of
the period-[image: t] beginning-of-period states and functions (like, k
and vFunc_{t}).
- they define a method of simulation that can be invoked to apply the
shocks and decision rules to get from the beginning of [image: t-1] to
the end
I’m very much opposed to any restriction that requires the user to specify
anything about the problem that is not necessary for the period in question
(like, parameters for the 18 year old in the problem of the 120 year old).
the value for each key would be a constructor function whose inputs name
the primitiver (or at least *more primitive*) parameters that are used by
that constructor; those parameters would live as attributes on the instance
(or in the parameters dictionary once that's fully implemented).
1. I think “solve_one_period” should change to “solve_this_stage” to
accommodate the fact that there may be several stages inside a period, and
that the only difference between the last stage of a period and other
stages is that what it needs as an input is a soln_beg_next_prd object
which has in it whatever info is needed to construct the solution.
The top-level AgentType would have a *universal* method (e.g. called
construct) that automatically runs some or all of the functions in the
constructors dictionary. If the user passes one or more strings to this
method, it runs the constructors for the named parameters. If the user
passes nothing to the method, it runs *all* of the constructors. When a
constructor is run by construct, it tries to pull in the parameters named
in its arguments (from the agents or its parameters dictionary), passes
them to the function, and then assigns the output to that key (in the
parameters dictionary or the agent itself, depending on what stage of
development we're at).
This seems like a layer on top of where I think we should start. We should
start with the user being asked to build the solution for every period
backwards from a terminal period. Once we have that working, we can build
“helper tools” like the ones you describe that winnow down the protean
possibilities to ones users are likely to want to entertain.
If construct fails to find the necessary primitive parameters, it flags
that constructor and records the names of the missing parameters. It then
proceeds through the other constructors that have been requested. After it
finishes all of them, if at least one was flagged as incomplete, it *tries
again*, because new data might be available. If construct completes a
"pass" with no constructors being successful, then it quits. The names of
the "missing data" are stored or returned.
This structure makes it much easier and simpler for a user to change the
construction method for a solver input, to make an input constructed, or to
indicate that an input is *not* constructed (just delete its entry from
constructors!). E.g. if a user decided that the income process they want
to use has binary permanent shocks (characterized by the probability and
value of one of the shocks), they can just change *one function name* in
their IndShockConsumerType instances and provide parameters called (e.g.)
LowPermShkVal and LowPermShkPrb rather than PermShkStd, PermShkCount, etc.
It also makes it easier for users to find out what primitive parameters /
data are needed to successfully run construct. We can write a very simple
query method that lists all of the inputs for each constructor, and which
ones are currently missing (as well as related methods for non-constructed
solver inputs).
There are two kinks in the design that I need to work out. First, how to
handle allowing the user to specify that some input is time-varying vs not
time-varying--
It’s time- (or age-) varying if they build it that way. EVERY SINGLE
VARIABLE should be allowed to START being time-varying at any age. So, you
might have constant variance of income shocks after age 65, but age-varying
for earlier ages, AND THE USER NEED NOT DO ANYTHING to accomplish this
until they get to the point of having to solve the problem of the 64 year
old. The variable will be age-varying as a consequence of the fact that the
user builds it backwards to be age-varying for solutions for people younger
than 65.
and how to indicate that the solver will *not function properly* if some
inputs are improperly converted to time-varying
The simplest solution is to enforce at the class level which solver inputs
*can* be time-varying, and require that the user pass a constant list if
they want it to be time-invariant for their purposes (maybe with a method
to handle that automatically).
Second, how to handle situations where it's most natural to construct two
solver inputs simultaneously-- they're biproducts of the same process. I
can think of a slightly clunky and inelegant workaround, but my "slightly
clunky" is others' "hideously bad design".
—
Reply to this email directly, view it on GitHub
<#1408>, or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAKCK75JTKGY64G253KM3PLY4RDOJAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43ASLTON2WKOZSGIZTIMRSGA3DQMI>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
--
- Chris Carroll
|
Beta Was this translation helpful? Give feedback.
-
I do understand your views, and I want to build in those capabilities.
They're useful both for teaching concepts and for the beginning stages of
model development. But a *lot* of the use cases of HARK are "production
stage", where you *can* specify the whole problem structure in advance. We
want to be able to accommodate that and make it useful.
The "construction step" is usually (but not always) a very small portion of
the total solve time. We can have options to only construct solver inputs
for the next-back period ("JIT construction"), but it won't speed things
up, and will often slow them down. In some cases, it's not meaningfully
possible or a pure waste of CPU cycles to attempt it.
Right now, we have a disorganized and hardwired system for making
constructed inputs. I'm just proposing a way to make it more organized for
the typical use case where the user can specify the problem in advance.
This doesn't rule out other use cases in which new periods are constructed
wholly on the fly.
The issue I was raising with time-varying inputs vs time-invariant ones is
that some solver math relies on an assumption of time invariance (e.g.
CRRA). That solver math can be changed or generalized, but some solution
properties will be lost. If we want to make a decision now that we never
want to make any assumptions about future values / concepts, we should talk
about that.
On Tue, Apr 9, 2024, 8:19 PM Christopher Llorracc Carroll <
***@***.***> wrote:
… Replies below targeted mainly to persons in the set ***@***.***)
as I think MNW understands my views already.
On Tue, Apr 9, 2024 at 4:11 PM Matthew N. White ***@***.***>
wrote:
HARK models as basic as ConsIndShock use some "constructed inputs" for
> their solver, by which I mean objects that are passed to the
> solve_one_period function but would not have been *manually* specified
by
> the user. For example, IncShkDstn is a complicated (time-varying) object
> that could (in principle) be manually created by a user and assigned to
an
> instance of IndShockConsumerType, but more reasonably would be
> constructed from "primitive parameters" like PermShkStd, TrankShkStd,
> UnempPrb, etc. As-is, PermGroFac is expected to be provided by the user,
> but it in principle it *could* be constructed on the AgentType instance
> given some parametric description of the income growth profile.
>
Yes, like “flat permanent income growth if you’re older than 65, prior
permanent income is current permanent income / 0.7 for a 65 year old” (to
capture the fact that if you’re going forward in time “permanent income”
falls to 0.7 of its prior value when you retire” etc.
This should be our fundamental “raw” way of creating models — with every
single aspect of the model (not just income growth) up for grabs and
available to change as you move earlier, with the only restriction being
that the end-of-state variables from one state must mesh with the
beginning-of-state variables from its successor.
Each AgentType subclass has "baked in" constructors, which are called from
> (or simply part of) an update_X method.
>
So, these are “backwards” constructors? Like, if you’ve just solved for
age
77, the constructor will make the stuff needed to solve the age 76
problem?
The update method itself is supposed to call *all* of those constructors,
> as a universal way to bring constructed inputs up-to-date with any
changes
> made to the primitive parameters. It does so by explicitly calling each
> update_X method, sometimes from its parent class.
>
Seems like the way to do all of this is to allow users to specify
“default”
values of everything (say, RRA), and unless their constructor explicitly
constructs RRA the default applies.
As is, if a user wants to have a *different* way of constructing such an
> input, they can either a) do it themselves and then drop in the result
into
> their instances; or b) make a trivial subclass of the AgentType that
> overrides that constructor method.
>
Or c) do what we do now in which you construct everything in advance of
solving anything.
Neither of these are "nice", and there's no organized way for a new user
to
> find out what the required "primitive inputs" are. I'm going to fix
this,
> and this issue presents an overview of my proposal for doing so.
> ------------------------------
>
> I propose that AgentType instances have a new constructors dictionary.
> The keys of this dictionary would be the names of inputs to the
> solve_one_period function for that class;
>
This is too rigid - as best I can understand it requires the user to
already know, when they solve the problem of the 120 year old, what the
names of the inputs will be for the problem of the 18 year old who is
deciding whether to go to college.
My (strong) preference is that, in principle, for any age [image: t] we
allow the user to make up anything they want for the [image: t-1] problem,
so long as:
- their [image: t-1] solver requires some subset (probably nonstrict) of
the period-[image: t] beginning-of-period states and functions (like, k
and vFunc_{t}).
- they define a method of simulation that can be invoked to apply the
shocks and decision rules to get from the beginning of [image: t-1] to
the end
I’m very much opposed to any restriction that requires the user to specify
anything about the problem that is not necessary for the period in
question
(like, parameters for the 18 year old in the problem of the 120 year old).
the value for each key would be a constructor function whose inputs name
> the primitiver (or at least *more primitive*) parameters that are used
by
> that constructor; those parameters would live as attributes on the
instance
> (or in the parameters dictionary once that's fully implemented).
>
1. I think “solve_one_period” should change to “solve_this_stage” to
accommodate the fact that there may be several stages inside a period, and
that the only difference between the last stage of a period and other
stages is that what it needs as an input is a soln_beg_next_prd object
which has in it whatever info is needed to construct the solution.
The top-level AgentType would have a *universal* method (e.g. called
> construct) that automatically runs some or all of the functions in the
> constructors dictionary. If the user passes one or more strings to this
> method, it runs the constructors for the named parameters. If the user
> passes nothing to the method, it runs *all* of the constructors. When a
> constructor is run by construct, it tries to pull in the parameters
named
> in its arguments (from the agents or its parameters dictionary), passes
> them to the function, and then assigns the output to that key (in the
> parameters dictionary or the agent itself, depending on what stage of
> development we're at).
>
This seems like a layer on top of where I think we should start. We should
start with the user being asked to build the solution for every period
backwards from a terminal period. Once we have that working, we can build
“helper tools” like the ones you describe that winnow down the protean
possibilities to ones users are likely to want to entertain.
If construct fails to find the necessary primitive parameters, it flags
> that constructor and records the names of the missing parameters. It
then
> proceeds through the other constructors that have been requested. After
it
> finishes all of them, if at least one was flagged as incomplete, it
*tries
> again*, because new data might be available. If construct completes a
> "pass" with no constructors being successful, then it quits. The names
of
> the "missing data" are stored or returned.
>
> This structure makes it much easier and simpler for a user to change the
> construction method for a solver input, to make an input constructed, or
to
> indicate that an input is *not* constructed (just delete its entry from
> constructors!). E.g. if a user decided that the income process they want
> to use has binary permanent shocks (characterized by the probability and
> value of one of the shocks), they can just change *one function name* in
> their IndShockConsumerType instances and provide parameters called
(e.g.)
> LowPermShkVal and LowPermShkPrb rather than PermShkStd, PermShkCount,
etc.
>
> It also makes it easier for users to find out what primitive parameters
/
> data are needed to successfully run construct. We can write a very
simple
> query method that lists all of the inputs for each constructor, and
which
> ones are currently missing (as well as related methods for
non-constructed
> solver inputs).
>
> There are two kinks in the design that I need to work out. First, how to
> handle allowing the user to specify that some input is time-varying vs
not
> time-varying--
>
It’s time- (or age-) varying if they build it that way. EVERY SINGLE
VARIABLE should be allowed to START being time-varying at any age. So, you
might have constant variance of income shocks after age 65, but
age-varying
for earlier ages, AND THE USER NEED NOT DO ANYTHING to accomplish this
until they get to the point of having to solve the problem of the 64 year
old. The variable will be age-varying as a consequence of the fact that
the
user builds it backwards to be age-varying for solutions for people
younger
than 65.
and how to indicate that the solver will *not function properly* if some
> inputs are improperly converted to time-varying
>
The simplest solution is to enforce at the class level which solver inputs
> *can* be time-varying, and require that the user pass a constant list if
> they want it to be time-invariant for their purposes (maybe with a
method
> to handle that automatically).
>
> Second, how to handle situations where it's most natural to construct
two
> solver inputs simultaneously-- they're biproducts of the same process. I
> can think of a slightly clunky and inelegant workaround, but my
"slightly
> clunky" is others' "hideously bad design".
>
> —
> Reply to this email directly, view it on GitHub
> <#1408>, or unsubscribe
> <
https://github.com/notifications/unsubscribe-auth/AAKCK75JTKGY64G253KM3PLY4RDOJAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43ASLTON2WKOZSGIZTIMRSGA3DQMI>
> .
> You are receiving this because you are subscribed to this thread.Message
> ID: ***@***.***>
>
--
- Chris Carroll
—
Reply to this email directly, view it on GitHub
<#1408 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADKRAFKDK7535IOETIM3MN3Y4SASXAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGIZTMMRUHE>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
It might be instructive to look at Dolo for guidance about this, especially
with respect to one thing, which is that Dolo separates the endogenous and
exogenous aspects of a problem.
The exogenous structure can be more complex than IID shocks. AR(1)
processes for example.
I know that income shocks are one thing that will go on the 'constructors'
dictionary with your new plan. What else will? Are they all exogenous?
On Tue, Apr 9, 2024, 9:15 PM Matthew N. White ***@***.***>
wrote:
… I do understand your views, and I want to build in those capabilities.
They're useful both for teaching concepts and for the beginning stages of
model development. But a *lot* of the use cases of HARK are "production
stage", where you *can* specify the whole problem structure in advance. We
want to be able to accommodate that and make it useful.
The "construction step" is usually (but not always) a very small portion
of
the total solve time. We can have options to only construct solver inputs
for the next-back period ("JIT construction"), but it won't speed things
up, and will often slow them down. In some cases, it's not meaningfully
possible or a pure waste of CPU cycles to attempt it.
Right now, we have a disorganized and hardwired system for making
constructed inputs. I'm just proposing a way to make it more organized for
the typical use case where the user can specify the problem in advance.
This doesn't rule out other use cases in which new periods are constructed
wholly on the fly.
The issue I was raising with time-varying inputs vs time-invariant ones is
that some solver math relies on an assumption of time invariance (e.g.
CRRA). That solver math can be changed or generalized, but some solution
properties will be lost. If we want to make a decision now that we never
want to make any assumptions about future values / concepts, we should
talk
about that.
On Tue, Apr 9, 2024, 8:19 PM Christopher Llorracc Carroll <
***@***.***> wrote:
> Replies below targeted mainly to persons in the set ***@***.***)
> as I think MNW understands my views already.
>
> On Tue, Apr 9, 2024 at 4:11 PM Matthew N. White ***@***.***>
> wrote:
>
> HARK models as basic as ConsIndShock use some "constructed inputs" for
> > their solver, by which I mean objects that are passed to the
> > solve_one_period function but would not have been *manually* specified
> by
> > the user. For example, IncShkDstn is a complicated (time-varying)
object
> > that could (in principle) be manually created by a user and assigned
to
> an
> > instance of IndShockConsumerType, but more reasonably would be
> > constructed from "primitive parameters" like PermShkStd, TrankShkStd,
> > UnempPrb, etc. As-is, PermGroFac is expected to be provided by the
user,
> > but it in principle it *could* be constructed on the AgentType
instance
> > given some parametric description of the income growth profile.
> >
> Yes, like “flat permanent income growth if you’re older than 65, prior
> permanent income is current permanent income / 0.7 for a 65 year old”
(to
> capture the fact that if you’re going forward in time “permanent income”
> falls to 0.7 of its prior value when you retire” etc.
>
> This should be our fundamental “raw” way of creating models — with every
> single aspect of the model (not just income growth) up for grabs and
> available to change as you move earlier, with the only restriction being
> that the end-of-state variables from one state must mesh with the
> beginning-of-state variables from its successor.
>
> Each AgentType subclass has "baked in" constructors, which are called
from
> > (or simply part of) an update_X method.
> >
> So, these are “backwards” constructors? Like, if you’ve just solved for
> age
> 77, the constructor will make the stuff needed to solve the age 76
> problem?
>
> The update method itself is supposed to call *all* of those
constructors,
> > as a universal way to bring constructed inputs up-to-date with any
> changes
> > made to the primitive parameters. It does so by explicitly calling
each
> > update_X method, sometimes from its parent class.
> >
> Seems like the way to do all of this is to allow users to specify
> “default”
> values of everything (say, RRA), and unless their constructor explicitly
> constructs RRA the default applies.
>
> As is, if a user wants to have a *different* way of constructing such an
> > input, they can either a) do it themselves and then drop in the result
> into
> > their instances; or b) make a trivial subclass of the AgentType that
> > overrides that constructor method.
> >
> Or c) do what we do now in which you construct everything in advance of
> solving anything.
>
> Neither of these are "nice", and there's no organized way for a new user
> to
> > find out what the required "primitive inputs" are. I'm going to fix
> this,
> > and this issue presents an overview of my proposal for doing so.
> > ------------------------------
> >
> > I propose that AgentType instances have a new constructors dictionary.
> > The keys of this dictionary would be the names of inputs to the
> > solve_one_period function for that class;
> >
> This is too rigid - as best I can understand it requires the user to
> already know, when they solve the problem of the 120 year old, what the
> names of the inputs will be for the problem of the 18 year old who is
> deciding whether to go to college.
>
> My (strong) preference is that, in principle, for any age [image: t] we
> allow the user to make up anything they want for the [image: t-1]
problem,
> so long as:
>
> - their [image: t-1] solver requires some subset (probably nonstrict) of
> the period-[image: t] beginning-of-period states and functions (like, k
> and vFunc_{t}).
> - they define a method of simulation that can be invoked to apply the
> shocks and decision rules to get from the beginning of [image: t-1] to
> the end
>
> I’m very much opposed to any restriction that requires the user to
specify
> anything about the problem that is not necessary for the period in
> question
> (like, parameters for the 18 year old in the problem of the 120 year
old).
>
> the value for each key would be a constructor function whose inputs name
> > the primitiver (or at least *more primitive*) parameters that are used
> by
> > that constructor; those parameters would live as attributes on the
> instance
> > (or in the parameters dictionary once that's fully implemented).
> >
>
> 1. I think “solve_one_period” should change to “solve_this_stage” to
> accommodate the fact that there may be several stages inside a period,
and
> that the only difference between the last stage of a period and other
> stages is that what it needs as an input is a soln_beg_next_prd object
> which has in it whatever info is needed to construct the solution.
>
> The top-level AgentType would have a *universal* method (e.g. called
> > construct) that automatically runs some or all of the functions in the
> > constructors dictionary. If the user passes one or more strings to
this
> > method, it runs the constructors for the named parameters. If the user
> > passes nothing to the method, it runs *all* of the constructors. When
a
> > constructor is run by construct, it tries to pull in the parameters
> named
> > in its arguments (from the agents or its parameters dictionary),
passes
> > them to the function, and then assigns the output to that key (in the
> > parameters dictionary or the agent itself, depending on what stage of
> > development we're at).
> >
> This seems like a layer on top of where I think we should start. We
should
> start with the user being asked to build the solution for every period
> backwards from a terminal period. Once we have that working, we can
build
> “helper tools” like the ones you describe that winnow down the protean
> possibilities to ones users are likely to want to entertain.
>
> If construct fails to find the necessary primitive parameters, it flags
> > that constructor and records the names of the missing parameters. It
> then
> > proceeds through the other constructors that have been requested.
After
> it
> > finishes all of them, if at least one was flagged as incomplete, it
> *tries
> > again*, because new data might be available. If construct completes a
> > "pass" with no constructors being successful, then it quits. The names
> of
> > the "missing data" are stored or returned.
> >
> > This structure makes it much easier and simpler for a user to change
the
> > construction method for a solver input, to make an input constructed,
or
> to
> > indicate that an input is *not* constructed (just delete its entry
from
> > constructors!). E.g. if a user decided that the income process they
want
> > to use has binary permanent shocks (characterized by the probability
and
> > value of one of the shocks), they can just change *one function name*
in
> > their IndShockConsumerType instances and provide parameters called
> (e.g.)
> > LowPermShkVal and LowPermShkPrb rather than PermShkStd, PermShkCount,
> etc.
> >
> > It also makes it easier for users to find out what primitive
parameters
> /
> > data are needed to successfully run construct. We can write a very
> simple
> > query method that lists all of the inputs for each constructor, and
> which
> > ones are currently missing (as well as related methods for
> non-constructed
> > solver inputs).
> >
> > There are two kinks in the design that I need to work out. First, how
to
> > handle allowing the user to specify that some input is time-varying vs
> not
> > time-varying--
> >
> It’s time- (or age-) varying if they build it that way. EVERY SINGLE
> VARIABLE should be allowed to START being time-varying at any age. So,
you
> might have constant variance of income shocks after age 65, but
> age-varying
> for earlier ages, AND THE USER NEED NOT DO ANYTHING to accomplish this
> until they get to the point of having to solve the problem of the 64
year
> old. The variable will be age-varying as a consequence of the fact that
> the
> user builds it backwards to be age-varying for solutions for people
> younger
> than 65.
>
> and how to indicate that the solver will *not function properly* if some
> > inputs are improperly converted to time-varying
> >
> The simplest solution is to enforce at the class level which solver
inputs
> > *can* be time-varying, and require that the user pass a constant list
if
> > they want it to be time-invariant for their purposes (maybe with a
> method
> > to handle that automatically).
> >
> > Second, how to handle situations where it's most natural to construct
> two
> > solver inputs simultaneously-- they're biproducts of the same process.
I
> > can think of a slightly clunky and inelegant workaround, but my
> "slightly
> > clunky" is others' "hideously bad design".
> >
> > —
> > Reply to this email directly, view it on GitHub
> > <#1408>, or unsubscribe
> > <
>
https://github.com/notifications/unsubscribe-auth/AAKCK75JTKGY64G253KM3PLY4RDOJAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43ASLTON2WKOZSGIZTIMRSGA3DQMI>
>
> > .
> > You are receiving this because you are subscribed to this
thread.Message
> > ID: ***@***.***>
> >
> --
> - Chris Carroll
>
> —
> Reply to this email directly, view it on GitHub
> <#1408 (comment)>,
> or unsubscribe
> <
https://github.com/notifications/unsubscribe-auth/ADKRAFKDK7535IOETIM3MN3Y4SASXAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGIZTMMRUHE>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>
—
Reply to this email directly, view it on GitHub
<#1408 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAQZEC745GPURN4WEZ2Z2TY4SHDXAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGI4DGMRUGA>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Everything that would be made by functions `constructors` is "exogenous" in
the sense that it's *inputs* to the solver: data structures needed to
characterize and solve the one period problem. They're not all "exogenous"
in the sense of "exogenous shocks". *Any* of the solver inputs could be
designated as being constructed. You could make the lifecycle sequence of
`LivPrb` be constructed by some function that takes in polynomial
coefficients on age and returns survival probabilities as determined by a
probit or logit formula. I have constructors that make functions for
insurance contracts, based on parameters that characterize the contract.
On Wed, Apr 10, 2024 at 8:09 AM Sebastian Benthall ***@***.***>
wrote:
… It might be instructive to look at Dolo for guidance about this,
especially
with respect to one thing, which is that Dolo separates the endogenous and
exogenous aspects of a problem.
The exogenous structure can be more complex than IID shocks. AR(1)
processes for example.
I know that income shocks are one thing that will go on the 'constructors'
dictionary with your new plan. What else will? Are they all exogenous?
On Tue, Apr 9, 2024, 9:15 PM Matthew N. White ***@***.***>
wrote:
> I do understand your views, and I want to build in those capabilities.
> They're useful both for teaching concepts and for the beginning stages
of
> model development. But a *lot* of the use cases of HARK are "production
> stage", where you *can* specify the whole problem structure in advance.
We
> want to be able to accommodate that and make it useful.
>
> The "construction step" is usually (but not always) a very small portion
> of
> the total solve time. We can have options to only construct solver
inputs
> for the next-back period ("JIT construction"), but it won't speed things
> up, and will often slow them down. In some cases, it's not meaningfully
> possible or a pure waste of CPU cycles to attempt it.
>
> Right now, we have a disorganized and hardwired system for making
> constructed inputs. I'm just proposing a way to make it more organized
for
> the typical use case where the user can specify the problem in advance.
> This doesn't rule out other use cases in which new periods are
constructed
> wholly on the fly.
>
> The issue I was raising with time-varying inputs vs time-invariant ones
is
> that some solver math relies on an assumption of time invariance (e.g.
> CRRA). That solver math can be changed or generalized, but some solution
> properties will be lost. If we want to make a decision now that we never
> want to make any assumptions about future values / concepts, we should
> talk
> about that.
>
> On Tue, Apr 9, 2024, 8:19 PM Christopher Llorracc Carroll <
> ***@***.***> wrote:
>
> > Replies below targeted mainly to persons in the set ***@***.***)
> > as I think MNW understands my views already.
> >
> > On Tue, Apr 9, 2024 at 4:11 PM Matthew N. White ***@***.***>
> > wrote:
> >
> > HARK models as basic as ConsIndShock use some "constructed inputs" for
> > > their solver, by which I mean objects that are passed to the
> > > solve_one_period function but would not have been *manually*
specified
> > by
> > > the user. For example, IncShkDstn is a complicated (time-varying)
> object
> > > that could (in principle) be manually created by a user and assigned
> to
> > an
> > > instance of IndShockConsumerType, but more reasonably would be
> > > constructed from "primitive parameters" like PermShkStd,
TrankShkStd,
> > > UnempPrb, etc. As-is, PermGroFac is expected to be provided by the
> user,
> > > but it in principle it *could* be constructed on the AgentType
> instance
> > > given some parametric description of the income growth profile.
> > >
> > Yes, like “flat permanent income growth if you’re older than 65, prior
> > permanent income is current permanent income / 0.7 for a 65 year old”
> (to
> > capture the fact that if you’re going forward in time “permanent
income”
> > falls to 0.7 of its prior value when you retire” etc.
> >
> > This should be our fundamental “raw” way of creating models — with
every
> > single aspect of the model (not just income growth) up for grabs and
> > available to change as you move earlier, with the only restriction
being
> > that the end-of-state variables from one state must mesh with the
> > beginning-of-state variables from its successor.
> >
> > Each AgentType subclass has "baked in" constructors, which are called
> from
> > > (or simply part of) an update_X method.
> > >
> > So, these are “backwards” constructors? Like, if you’ve just solved
for
> > age
> > 77, the constructor will make the stuff needed to solve the age 76
> > problem?
> >
> > The update method itself is supposed to call *all* of those
> constructors,
> > > as a universal way to bring constructed inputs up-to-date with any
> > changes
> > > made to the primitive parameters. It does so by explicitly calling
> each
> > > update_X method, sometimes from its parent class.
> > >
> > Seems like the way to do all of this is to allow users to specify
> > “default”
> > values of everything (say, RRA), and unless their constructor
explicitly
> > constructs RRA the default applies.
> >
> > As is, if a user wants to have a *different* way of constructing such
an
> > > input, they can either a) do it themselves and then drop in the
result
> > into
> > > their instances; or b) make a trivial subclass of the AgentType that
> > > overrides that constructor method.
> > >
> > Or c) do what we do now in which you construct everything in advance
of
> > solving anything.
> >
> > Neither of these are "nice", and there's no organized way for a new
user
> > to
> > > find out what the required "primitive inputs" are. I'm going to fix
> > this,
> > > and this issue presents an overview of my proposal for doing so.
> > > ------------------------------
> > >
> > > I propose that AgentType instances have a new constructors
dictionary.
> > > The keys of this dictionary would be the names of inputs to the
> > > solve_one_period function for that class;
> > >
> > This is too rigid - as best I can understand it requires the user to
> > already know, when they solve the problem of the 120 year old, what
the
> > names of the inputs will be for the problem of the 18 year old who is
> > deciding whether to go to college.
> >
> > My (strong) preference is that, in principle, for any age [image: t]
we
> > allow the user to make up anything they want for the [image: t-1]
> problem,
> > so long as:
> >
> > - their [image: t-1] solver requires some subset (probably nonstrict)
of
> > the period-[image: t] beginning-of-period states and functions (like,
k
> > and vFunc_{t}).
> > - they define a method of simulation that can be invoked to apply the
> > shocks and decision rules to get from the beginning of [image: t-1] to
> > the end
> >
> > I’m very much opposed to any restriction that requires the user to
> specify
> > anything about the problem that is not necessary for the period in
> > question
> > (like, parameters for the 18 year old in the problem of the 120 year
> old).
> >
> > the value for each key would be a constructor function whose inputs
name
> > > the primitiver (or at least *more primitive*) parameters that are
used
> > by
> > > that constructor; those parameters would live as attributes on the
> > instance
> > > (or in the parameters dictionary once that's fully implemented).
> > >
> >
> > 1. I think “solve_one_period” should change to “solve_this_stage” to
> > accommodate the fact that there may be several stages inside a period,
> and
> > that the only difference between the last stage of a period and other
> > stages is that what it needs as an input is a soln_beg_next_prd object
> > which has in it whatever info is needed to construct the solution.
> >
> > The top-level AgentType would have a *universal* method (e.g. called
> > > construct) that automatically runs some or all of the functions in
the
> > > constructors dictionary. If the user passes one or more strings to
> this
> > > method, it runs the constructors for the named parameters. If the
user
> > > passes nothing to the method, it runs *all* of the constructors.
When
> a
> > > constructor is run by construct, it tries to pull in the parameters
> > named
> > > in its arguments (from the agents or its parameters dictionary),
> passes
> > > them to the function, and then assigns the output to that key (in
the
> > > parameters dictionary or the agent itself, depending on what stage
of
> > > development we're at).
> > >
> > This seems like a layer on top of where I think we should start. We
> should
> > start with the user being asked to build the solution for every period
> > backwards from a terminal period. Once we have that working, we can
> build
> > “helper tools” like the ones you describe that winnow down the protean
> > possibilities to ones users are likely to want to entertain.
> >
> > If construct fails to find the necessary primitive parameters, it
flags
> > > that constructor and records the names of the missing parameters. It
> > then
> > > proceeds through the other constructors that have been requested.
> After
> > it
> > > finishes all of them, if at least one was flagged as incomplete, it
> > *tries
> > > again*, because new data might be available. If construct completes
a
> > > "pass" with no constructors being successful, then it quits. The
names
> > of
> > > the "missing data" are stored or returned.
> > >
> > > This structure makes it much easier and simpler for a user to change
> the
> > > construction method for a solver input, to make an input
constructed,
> or
> > to
> > > indicate that an input is *not* constructed (just delete its entry
> from
> > > constructors!). E.g. if a user decided that the income process they
> want
> > > to use has binary permanent shocks (characterized by the probability
> and
> > > value of one of the shocks), they can just change *one function
name*
> in
> > > their IndShockConsumerType instances and provide parameters called
> > (e.g.)
> > > LowPermShkVal and LowPermShkPrb rather than PermShkStd,
PermShkCount,
> > etc.
> > >
> > > It also makes it easier for users to find out what primitive
> parameters
> > /
> > > data are needed to successfully run construct. We can write a very
> > simple
> > > query method that lists all of the inputs for each constructor, and
> > which
> > > ones are currently missing (as well as related methods for
> > non-constructed
> > > solver inputs).
> > >
> > > There are two kinks in the design that I need to work out. First,
how
> to
> > > handle allowing the user to specify that some input is time-varying
vs
> > not
> > > time-varying--
> > >
> > It’s time- (or age-) varying if they build it that way. EVERY SINGLE
> > VARIABLE should be allowed to START being time-varying at any age. So,
> you
> > might have constant variance of income shocks after age 65, but
> > age-varying
> > for earlier ages, AND THE USER NEED NOT DO ANYTHING to accomplish this
> > until they get to the point of having to solve the problem of the 64
> year
> > old. The variable will be age-varying as a consequence of the fact
that
> > the
> > user builds it backwards to be age-varying for solutions for people
> > younger
> > than 65.
> >
> > and how to indicate that the solver will *not function properly* if
some
> > > inputs are improperly converted to time-varying
> > >
> > The simplest solution is to enforce at the class level which solver
> inputs
> > > *can* be time-varying, and require that the user pass a constant
list
> if
> > > they want it to be time-invariant for their purposes (maybe with a
> > method
> > > to handle that automatically).
> > >
> > > Second, how to handle situations where it's most natural to
construct
> > two
> > > solver inputs simultaneously-- they're biproducts of the same
process.
> I
> > > can think of a slightly clunky and inelegant workaround, but my
> > "slightly
> > > clunky" is others' "hideously bad design".
> > >
> > > —
> > > Reply to this email directly, view it on GitHub
> > > <#1408>, or unsubscribe
> > > <
> >
>
https://github.com/notifications/unsubscribe-auth/AAKCK75JTKGY64G253KM3PLY4RDOJAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43ASLTON2WKOZSGIZTIMRSGA3DQMI>
>
> >
> > > .
> > > You are receiving this because you are subscribed to this
> thread.Message
> > > ID: ***@***.***>
> > >
> > --
> > - Chris Carroll
> >
> > —
> > Reply to this email directly, view it on GitHub
> > <#1408 (comment)>,
> > or unsubscribe
> > <
>
https://github.com/notifications/unsubscribe-auth/ADKRAFKDK7535IOETIM3MN3Y4SASXAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGIZTMMRUHE>
>
> > .
> > You are receiving this because you authored the thread.Message ID:
> > ***@***.***>
> >
>
> —
> Reply to this email directly, view it on GitHub
> <#1408 (comment)>,
> or unsubscribe
> <
https://github.com/notifications/unsubscribe-auth/AAAQZEC745GPURN4WEZ2Z2TY4SHDXAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGI4DGMRUGA>
> .
> You are receiving this because you are subscribed to this thread.Message
> ID: ***@***.***>
>
—
Reply to this email directly, view it on GitHub
<#1408 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADKRAFMYSGKKS7IIRBRWDO3Y4UTV5AVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBXGM3TMMZQGM>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
That's interesting.
If you don't mind, there's still an ambiguity and I'm trying to understand
-- maybe I can ask the question a different way.
'constructor' is a concept in object oriented programming. It's a special
kind of function that creates an object.
'exogeneity' is a concept in social scientific modeling. In our context, a
variable is exogenous if it does not depend on a control variable.
This is when viewing the problem from the perspective of the agent's
problem/solution.
With a different frame of reference in a dynamic system, endogeneity can
have some other meanings.
It sounds like some of what you intend for this new design is the ability
to programmatically create (data) structures that are part of the
environment the agents act in.
But that these may not be probability distributions (i.e, of shocks) but
rather are fixed.
It sounds like you want something that handles both the construction of
probability distributions, for shocks, and these other environmental
factors.
There are many ways to implement exogenous processes, and only some of them
are object oriented.
There may be many ways to implement these other factors, only some of which
are object oriented.
Is it very important for your new design for these to be object-oriented
programming constructs?
Or is it more important that they are playing a consistent role in the
modeling logic, a role that comes prior to solving an agents' problem?
On Wed, Apr 10, 2024 at 9:54 AM Matthew N. White ***@***.***>
wrote:
… Everything that would be made by functions `constructors` is "exogenous"
in
the sense that it's *inputs* to the solver: data structures needed to
characterize and solve the one period problem. They're not all "exogenous"
in the sense of "exogenous shocks". *Any* of the solver inputs could be
designated as being constructed. You could make the lifecycle sequence of
`LivPrb` be constructed by some function that takes in polynomial
coefficients on age and returns survival probabilities as determined by a
probit or logit formula. I have constructors that make functions for
insurance contracts, based on parameters that characterize the contract.
On Wed, Apr 10, 2024 at 8:09 AM Sebastian Benthall ***@***.***>
wrote:
> It might be instructive to look at Dolo for guidance about this,
> especially
> with respect to one thing, which is that Dolo separates the endogenous
and
> exogenous aspects of a problem.
>
> The exogenous structure can be more complex than IID shocks. AR(1)
> processes for example.
>
> I know that income shocks are one thing that will go on the
'constructors'
> dictionary with your new plan. What else will? Are they all exogenous?
>
>
> On Tue, Apr 9, 2024, 9:15 PM Matthew N. White ***@***.***>
> wrote:
>
> > I do understand your views, and I want to build in those capabilities.
> > They're useful both for teaching concepts and for the beginning stages
> of
> > model development. But a *lot* of the use cases of HARK are
"production
> > stage", where you *can* specify the whole problem structure in
advance.
> We
> > want to be able to accommodate that and make it useful.
> >
> > The "construction step" is usually (but not always) a very small
portion
> > of
> > the total solve time. We can have options to only construct solver
> inputs
> > for the next-back period ("JIT construction"), but it won't speed
things
> > up, and will often slow them down. In some cases, it's not
meaningfully
> > possible or a pure waste of CPU cycles to attempt it.
> >
> > Right now, we have a disorganized and hardwired system for making
> > constructed inputs. I'm just proposing a way to make it more organized
> for
> > the typical use case where the user can specify the problem in
advance.
> > This doesn't rule out other use cases in which new periods are
> constructed
> > wholly on the fly.
> >
> > The issue I was raising with time-varying inputs vs time-invariant
ones
> is
> > that some solver math relies on an assumption of time invariance (e.g.
> > CRRA). That solver math can be changed or generalized, but some
solution
> > properties will be lost. If we want to make a decision now that we
never
> > want to make any assumptions about future values / concepts, we should
> > talk
> > about that.
> >
> > On Tue, Apr 9, 2024, 8:19 PM Christopher Llorracc Carroll <
> > ***@***.***> wrote:
> >
> > > Replies below targeted mainly to persons in the set ***@***.***)
> > > as I think MNW understands my views already.
> > >
> > > On Tue, Apr 9, 2024 at 4:11 PM Matthew N. White ***@***.***>
> > > wrote:
> > >
> > > HARK models as basic as ConsIndShock use some "constructed inputs"
for
> > > > their solver, by which I mean objects that are passed to the
> > > > solve_one_period function but would not have been *manually*
> specified
> > > by
> > > > the user. For example, IncShkDstn is a complicated (time-varying)
> > object
> > > > that could (in principle) be manually created by a user and
assigned
> > to
> > > an
> > > > instance of IndShockConsumerType, but more reasonably would be
> > > > constructed from "primitive parameters" like PermShkStd,
> TrankShkStd,
> > > > UnempPrb, etc. As-is, PermGroFac is expected to be provided by the
> > user,
> > > > but it in principle it *could* be constructed on the AgentType
> > instance
> > > > given some parametric description of the income growth profile.
> > > >
> > > Yes, like “flat permanent income growth if you’re older than 65,
prior
> > > permanent income is current permanent income / 0.7 for a 65 year
old”
> > (to
> > > capture the fact that if you’re going forward in time “permanent
> income”
> > > falls to 0.7 of its prior value when you retire” etc.
> > >
> > > This should be our fundamental “raw” way of creating models — with
> every
> > > single aspect of the model (not just income growth) up for grabs and
> > > available to change as you move earlier, with the only restriction
> being
> > > that the end-of-state variables from one state must mesh with the
> > > beginning-of-state variables from its successor.
> > >
> > > Each AgentType subclass has "baked in" constructors, which are
called
> > from
> > > > (or simply part of) an update_X method.
> > > >
> > > So, these are “backwards” constructors? Like, if you’ve just solved
> for
> > > age
> > > 77, the constructor will make the stuff needed to solve the age 76
> > > problem?
> > >
> > > The update method itself is supposed to call *all* of those
> > constructors,
> > > > as a universal way to bring constructed inputs up-to-date with any
> > > changes
> > > > made to the primitive parameters. It does so by explicitly calling
> > each
> > > > update_X method, sometimes from its parent class.
> > > >
> > > Seems like the way to do all of this is to allow users to specify
> > > “default”
> > > values of everything (say, RRA), and unless their constructor
> explicitly
> > > constructs RRA the default applies.
> > >
> > > As is, if a user wants to have a *different* way of constructing
such
> an
> > > > input, they can either a) do it themselves and then drop in the
> result
> > > into
> > > > their instances; or b) make a trivial subclass of the AgentType
that
> > > > overrides that constructor method.
> > > >
> > > Or c) do what we do now in which you construct everything in advance
> of
> > > solving anything.
> > >
> > > Neither of these are "nice", and there's no organized way for a new
> user
> > > to
> > > > find out what the required "primitive inputs" are. I'm going to
fix
> > > this,
> > > > and this issue presents an overview of my proposal for doing so.
> > > > ------------------------------
> > > >
> > > > I propose that AgentType instances have a new constructors
> dictionary.
> > > > The keys of this dictionary would be the names of inputs to the
> > > > solve_one_period function for that class;
> > > >
> > > This is too rigid - as best I can understand it requires the user to
> > > already know, when they solve the problem of the 120 year old, what
> the
> > > names of the inputs will be for the problem of the 18 year old who
is
> > > deciding whether to go to college.
> > >
> > > My (strong) preference is that, in principle, for any age [image: t]
> we
> > > allow the user to make up anything they want for the [image: t-1]
> > problem,
> > > so long as:
> > >
> > > - their [image: t-1] solver requires some subset (probably
nonstrict)
> of
> > > the period-[image: t] beginning-of-period states and functions
(like,
> k
> > > and vFunc_{t}).
> > > - they define a method of simulation that can be invoked to apply
the
> > > shocks and decision rules to get from the beginning of [image: t-1]
to
> > > the end
> > >
> > > I’m very much opposed to any restriction that requires the user to
> > specify
> > > anything about the problem that is not necessary for the period in
> > > question
> > > (like, parameters for the 18 year old in the problem of the 120 year
> > old).
> > >
> > > the value for each key would be a constructor function whose inputs
> name
> > > > the primitiver (or at least *more primitive*) parameters that are
> used
> > > by
> > > > that constructor; those parameters would live as attributes on the
> > > instance
> > > > (or in the parameters dictionary once that's fully implemented).
> > > >
> > >
> > > 1. I think “solve_one_period” should change to “solve_this_stage” to
> > > accommodate the fact that there may be several stages inside a
period,
> > and
> > > that the only difference between the last stage of a period and
other
> > > stages is that what it needs as an input is a soln_beg_next_prd
object
> > > which has in it whatever info is needed to construct the solution.
> > >
> > > The top-level AgentType would have a *universal* method (e.g. called
> > > > construct) that automatically runs some or all of the functions in
> the
> > > > constructors dictionary. If the user passes one or more strings to
> > this
> > > > method, it runs the constructors for the named parameters. If the
> user
> > > > passes nothing to the method, it runs *all* of the constructors.
> When
> > a
> > > > constructor is run by construct, it tries to pull in the
parameters
> > > named
> > > > in its arguments (from the agents or its parameters dictionary),
> > passes
> > > > them to the function, and then assigns the output to that key (in
> the
> > > > parameters dictionary or the agent itself, depending on what stage
> of
> > > > development we're at).
> > > >
> > > This seems like a layer on top of where I think we should start. We
> > should
> > > start with the user being asked to build the solution for every
period
> > > backwards from a terminal period. Once we have that working, we can
> > build
> > > “helper tools” like the ones you describe that winnow down the
protean
> > > possibilities to ones users are likely to want to entertain.
> > >
> > > If construct fails to find the necessary primitive parameters, it
> flags
> > > > that constructor and records the names of the missing parameters.
It
> > > then
> > > > proceeds through the other constructors that have been requested.
> > After
> > > it
> > > > finishes all of them, if at least one was flagged as incomplete,
it
> > > *tries
> > > > again*, because new data might be available. If construct
completes
> a
> > > > "pass" with no constructors being successful, then it quits. The
> names
> > > of
> > > > the "missing data" are stored or returned.
> > > >
> > > > This structure makes it much easier and simpler for a user to
change
> > the
> > > > construction method for a solver input, to make an input
> constructed,
> > or
> > > to
> > > > indicate that an input is *not* constructed (just delete its entry
> > from
> > > > constructors!). E.g. if a user decided that the income process
they
> > want
> > > > to use has binary permanent shocks (characterized by the
probability
> > and
> > > > value of one of the shocks), they can just change *one function
> name*
> > in
> > > > their IndShockConsumerType instances and provide parameters called
> > > (e.g.)
> > > > LowPermShkVal and LowPermShkPrb rather than PermShkStd,
> PermShkCount,
> > > etc.
> > > >
> > > > It also makes it easier for users to find out what primitive
> > parameters
> > > /
> > > > data are needed to successfully run construct. We can write a very
> > > simple
> > > > query method that lists all of the inputs for each constructor,
and
> > > which
> > > > ones are currently missing (as well as related methods for
> > > non-constructed
> > > > solver inputs).
> > > >
> > > > There are two kinks in the design that I need to work out. First,
> how
> > to
> > > > handle allowing the user to specify that some input is
time-varying
> vs
> > > not
> > > > time-varying--
> > > >
> > > It’s time- (or age-) varying if they build it that way. EVERY SINGLE
> > > VARIABLE should be allowed to START being time-varying at any age.
So,
> > you
> > > might have constant variance of income shocks after age 65, but
> > > age-varying
> > > for earlier ages, AND THE USER NEED NOT DO ANYTHING to accomplish
this
> > > until they get to the point of having to solve the problem of the 64
> > year
> > > old. The variable will be age-varying as a consequence of the fact
> that
> > > the
> > > user builds it backwards to be age-varying for solutions for people
> > > younger
> > > than 65.
> > >
> > > and how to indicate that the solver will *not function properly* if
> some
> > > > inputs are improperly converted to time-varying
> > > >
> > > The simplest solution is to enforce at the class level which solver
> > inputs
> > > > *can* be time-varying, and require that the user pass a constant
> list
> > if
> > > > they want it to be time-invariant for their purposes (maybe with a
> > > method
> > > > to handle that automatically).
> > > >
> > > > Second, how to handle situations where it's most natural to
> construct
> > > two
> > > > solver inputs simultaneously-- they're biproducts of the same
> process.
> > I
> > > > can think of a slightly clunky and inelegant workaround, but my
> > > "slightly
> > > > clunky" is others' "hideously bad design".
> > > >
> > > > —
> > > > Reply to this email directly, view it on GitHub
> > > > <#1408>, or unsubscribe
> > > > <
> > >
> >
>
https://github.com/notifications/unsubscribe-auth/AAKCK75JTKGY64G253KM3PLY4RDOJAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43ASLTON2WKOZSGIZTIMRSGA3DQMI>
>
> >
> > >
> > > > .
> > > > You are receiving this because you are subscribed to this
> > thread.Message
> > > > ID: ***@***.***>
> > > >
> > > --
> > > - Chris Carroll
> > >
> > > —
> > > Reply to this email directly, view it on GitHub
> > > <
#1408 (comment)>,
>
> > > or unsubscribe
> > > <
> >
>
https://github.com/notifications/unsubscribe-auth/ADKRAFKDK7535IOETIM3MN3Y4SASXAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGIZTMMRUHE>
>
> >
> > > .
> > > You are receiving this because you authored the thread.Message ID:
> > > ***@***.***>
> > >
> >
> > —
> > Reply to this email directly, view it on GitHub
> > <#1408 (comment)>,
> > or unsubscribe
> > <
>
https://github.com/notifications/unsubscribe-auth/AAAQZEC745GPURN4WEZ2Z2TY4SHDXAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGI4DGMRUGA>
>
> > .
> > You are receiving this because you are subscribed to this
thread.Message
> > ID: ***@***.***>
> >
>
> —
> Reply to this email directly, view it on GitHub
> <#1408 (comment)>,
> or unsubscribe
> <
https://github.com/notifications/unsubscribe-auth/ADKRAFMYSGKKS7IIRBRWDO3Y4UTV5AVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBXGM3TMMZQGM>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>
—
Reply to this email directly, view it on GitHub
<#1408 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAQZEF3GJWJW3P6N4GGVKDY4VABHAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBXGYYTKNZXHE>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
It's not at all important that the constructed inputs be object-oriented.
Some of them will be, and some won't be. The thing that's constructed could
be as simple as a list of numbers, or even just one number. Consider the
following constructor function:
`make_LivPrb_as_polynomial_probit(LivPrb_probit_coeffs, age_0, age_count,
age_incr):`
....`j_vec = np.arange(age_count)*age_incr + age_0`
....`K = len(coeffs)`
....`LivPrb_base = np.zeros(age_count)`
....`for k in range(K):`
........`coeff = LivPrb_probit_coeffs[k]`
........`LivPrb_base += coeff * j_vec**k`
....`LivPrb = norm.cdf(LivPrb_base)`
....`return LivPrb.tolist()`
That returns a list of floats, with each entry representing the survival
probability at some age. For even more simple constructed output, consider
the limiting share in the risky asset as wealth goes to infinity. It can be
calculated from `RiskyDstn` and `CRRA`, but it's just one number. That case
is a little bit special, because there's a *right answer*, but plausibly
different ways to run the calculation to get to the same right answer.
On Thu, Apr 11, 2024 at 10:03 AM Sebastian Benthall <
***@***.***> wrote:
… That's interesting.
If you don't mind, there's still an ambiguity and I'm trying to understand
-- maybe I can ask the question a different way.
'constructor' is a concept in object oriented programming. It's a special
kind of function that creates an object.
'exogeneity' is a concept in social scientific modeling. In our context, a
variable is exogenous if it does not depend on a control variable.
This is when viewing the problem from the perspective of the agent's
problem/solution.
With a different frame of reference in a dynamic system, endogeneity can
have some other meanings.
It sounds like some of what you intend for this new design is the ability
to programmatically create (data) structures that are part of the
environment the agents act in.
But that these may not be probability distributions (i.e, of shocks) but
rather are fixed.
It sounds like you want something that handles both the construction of
probability distributions, for shocks, and these other environmental
factors.
There are many ways to implement exogenous processes, and only some of
them
are object oriented.
There may be many ways to implement these other factors, only some of
which
are object oriented.
Is it very important for your new design for these to be object-oriented
programming constructs?
Or is it more important that they are playing a consistent role in the
modeling logic, a role that comes prior to solving an agents' problem?
On Wed, Apr 10, 2024 at 9:54 AM Matthew N. White ***@***.***>
wrote:
> Everything that would be made by functions `constructors` is "exogenous"
> in
> the sense that it's *inputs* to the solver: data structures needed to
> characterize and solve the one period problem. They're not all
"exogenous"
> in the sense of "exogenous shocks". *Any* of the solver inputs could be
> designated as being constructed. You could make the lifecycle sequence
of
> `LivPrb` be constructed by some function that takes in polynomial
> coefficients on age and returns survival probabilities as determined by
a
> probit or logit formula. I have constructors that make functions for
> insurance contracts, based on parameters that characterize the contract.
>
> On Wed, Apr 10, 2024 at 8:09 AM Sebastian Benthall ***@***.***>
> wrote:
>
> > It might be instructive to look at Dolo for guidance about this,
> > especially
> > with respect to one thing, which is that Dolo separates the endogenous
> and
> > exogenous aspects of a problem.
> >
> > The exogenous structure can be more complex than IID shocks. AR(1)
> > processes for example.
> >
> > I know that income shocks are one thing that will go on the
> 'constructors'
> > dictionary with your new plan. What else will? Are they all exogenous?
> >
> >
> > On Tue, Apr 9, 2024, 9:15 PM Matthew N. White ***@***.***>
> > wrote:
> >
> > > I do understand your views, and I want to build in those
capabilities.
> > > They're useful both for teaching concepts and for the beginning
stages
> > of
> > > model development. But a *lot* of the use cases of HARK are
> "production
> > > stage", where you *can* specify the whole problem structure in
> advance.
> > We
> > > want to be able to accommodate that and make it useful.
> > >
> > > The "construction step" is usually (but not always) a very small
> portion
> > > of
> > > the total solve time. We can have options to only construct solver
> > inputs
> > > for the next-back period ("JIT construction"), but it won't speed
> things
> > > up, and will often slow them down. In some cases, it's not
> meaningfully
> > > possible or a pure waste of CPU cycles to attempt it.
> > >
> > > Right now, we have a disorganized and hardwired system for making
> > > constructed inputs. I'm just proposing a way to make it more
organized
> > for
> > > the typical use case where the user can specify the problem in
> advance.
> > > This doesn't rule out other use cases in which new periods are
> > constructed
> > > wholly on the fly.
> > >
> > > The issue I was raising with time-varying inputs vs time-invariant
> ones
> > is
> > > that some solver math relies on an assumption of time invariance
(e.g.
> > > CRRA). That solver math can be changed or generalized, but some
> solution
> > > properties will be lost. If we want to make a decision now that we
> never
> > > want to make any assumptions about future values / concepts, we
should
> > > talk
> > > about that.
> > >
> > > On Tue, Apr 9, 2024, 8:19 PM Christopher Llorracc Carroll <
> > > ***@***.***> wrote:
> > >
> > > > Replies below targeted mainly to persons in the set ***@***.***)
> > > > as I think MNW understands my views already.
> > > >
> > > > On Tue, Apr 9, 2024 at 4:11 PM Matthew N. White ***@***.***>
> > > > wrote:
> > > >
> > > > HARK models as basic as ConsIndShock use some "constructed inputs"
> for
> > > > > their solver, by which I mean objects that are passed to the
> > > > > solve_one_period function but would not have been *manually*
> > specified
> > > > by
> > > > > the user. For example, IncShkDstn is a complicated
(time-varying)
> > > object
> > > > > that could (in principle) be manually created by a user and
> assigned
> > > to
> > > > an
> > > > > instance of IndShockConsumerType, but more reasonably would be
> > > > > constructed from "primitive parameters" like PermShkStd,
> > TrankShkStd,
> > > > > UnempPrb, etc. As-is, PermGroFac is expected to be provided by
the
> > > user,
> > > > > but it in principle it *could* be constructed on the AgentType
> > > instance
> > > > > given some parametric description of the income growth profile.
> > > > >
> > > > Yes, like “flat permanent income growth if you’re older than 65,
> prior
> > > > permanent income is current permanent income / 0.7 for a 65 year
> old”
> > > (to
> > > > capture the fact that if you’re going forward in time “permanent
> > income”
> > > > falls to 0.7 of its prior value when you retire” etc.
> > > >
> > > > This should be our fundamental “raw” way of creating models — with
> > every
> > > > single aspect of the model (not just income growth) up for grabs
and
> > > > available to change as you move earlier, with the only restriction
> > being
> > > > that the end-of-state variables from one state must mesh with the
> > > > beginning-of-state variables from its successor.
> > > >
> > > > Each AgentType subclass has "baked in" constructors, which are
> called
> > > from
> > > > > (or simply part of) an update_X method.
> > > > >
> > > > So, these are “backwards” constructors? Like, if you’ve just
solved
> > for
> > > > age
> > > > 77, the constructor will make the stuff needed to solve the age 76
> > > > problem?
> > > >
> > > > The update method itself is supposed to call *all* of those
> > > constructors,
> > > > > as a universal way to bring constructed inputs up-to-date with
any
> > > > changes
> > > > > made to the primitive parameters. It does so by explicitly
calling
> > > each
> > > > > update_X method, sometimes from its parent class.
> > > > >
> > > > Seems like the way to do all of this is to allow users to specify
> > > > “default”
> > > > values of everything (say, RRA), and unless their constructor
> > explicitly
> > > > constructs RRA the default applies.
> > > >
> > > > As is, if a user wants to have a *different* way of constructing
> such
> > an
> > > > > input, they can either a) do it themselves and then drop in the
> > result
> > > > into
> > > > > their instances; or b) make a trivial subclass of the AgentType
> that
> > > > > overrides that constructor method.
> > > > >
> > > > Or c) do what we do now in which you construct everything in
advance
> > of
> > > > solving anything.
> > > >
> > > > Neither of these are "nice", and there's no organized way for a
new
> > user
> > > > to
> > > > > find out what the required "primitive inputs" are. I'm going to
> fix
> > > > this,
> > > > > and this issue presents an overview of my proposal for doing so.
> > > > > ------------------------------
> > > > >
> > > > > I propose that AgentType instances have a new constructors
> > dictionary.
> > > > > The keys of this dictionary would be the names of inputs to the
> > > > > solve_one_period function for that class;
> > > > >
> > > > This is too rigid - as best I can understand it requires the user
to
> > > > already know, when they solve the problem of the 120 year old,
what
> > the
> > > > names of the inputs will be for the problem of the 18 year old who
> is
> > > > deciding whether to go to college.
> > > >
> > > > My (strong) preference is that, in principle, for any age [image:
t]
> > we
> > > > allow the user to make up anything they want for the [image: t-1]
> > > problem,
> > > > so long as:
> > > >
> > > > - their [image: t-1] solver requires some subset (probably
> nonstrict)
> > of
> > > > the period-[image: t] beginning-of-period states and functions
> (like,
> > k
> > > > and vFunc_{t}).
> > > > - they define a method of simulation that can be invoked to apply
> the
> > > > shocks and decision rules to get from the beginning of [image:
t-1]
> to
> > > > the end
> > > >
> > > > I’m very much opposed to any restriction that requires the user to
> > > specify
> > > > anything about the problem that is not necessary for the period in
> > > > question
> > > > (like, parameters for the 18 year old in the problem of the 120
year
> > > old).
> > > >
> > > > the value for each key would be a constructor function whose
inputs
> > name
> > > > > the primitiver (or at least *more primitive*) parameters that
are
> > used
> > > > by
> > > > > that constructor; those parameters would live as attributes on
the
> > > > instance
> > > > > (or in the parameters dictionary once that's fully implemented).
> > > > >
> > > >
> > > > 1. I think “solve_one_period” should change to “solve_this_stage”
to
> > > > accommodate the fact that there may be several stages inside a
> period,
> > > and
> > > > that the only difference between the last stage of a period and
> other
> > > > stages is that what it needs as an input is a soln_beg_next_prd
> object
> > > > which has in it whatever info is needed to construct the solution.
> > > >
> > > > The top-level AgentType would have a *universal* method (e.g.
called
> > > > > construct) that automatically runs some or all of the functions
in
> > the
> > > > > constructors dictionary. If the user passes one or more strings
to
> > > this
> > > > > method, it runs the constructors for the named parameters. If
the
> > user
> > > > > passes nothing to the method, it runs *all* of the constructors.
> > When
> > > a
> > > > > constructor is run by construct, it tries to pull in the
> parameters
> > > > named
> > > > > in its arguments (from the agents or its parameters dictionary),
> > > passes
> > > > > them to the function, and then assigns the output to that key
(in
> > the
> > > > > parameters dictionary or the agent itself, depending on what
stage
> > of
> > > > > development we're at).
> > > > >
> > > > This seems like a layer on top of where I think we should start.
We
> > > should
> > > > start with the user being asked to build the solution for every
> period
> > > > backwards from a terminal period. Once we have that working, we
can
> > > build
> > > > “helper tools” like the ones you describe that winnow down the
> protean
> > > > possibilities to ones users are likely to want to entertain.
> > > >
> > > > If construct fails to find the necessary primitive parameters, it
> > flags
> > > > > that constructor and records the names of the missing
parameters.
> It
> > > > then
> > > > > proceeds through the other constructors that have been
requested.
> > > After
> > > > it
> > > > > finishes all of them, if at least one was flagged as incomplete,
> it
> > > > *tries
> > > > > again*, because new data might be available. If construct
> completes
> > a
> > > > > "pass" with no constructors being successful, then it quits. The
> > names
> > > > of
> > > > > the "missing data" are stored or returned.
> > > > >
> > > > > This structure makes it much easier and simpler for a user to
> change
> > > the
> > > > > construction method for a solver input, to make an input
> > constructed,
> > > or
> > > > to
> > > > > indicate that an input is *not* constructed (just delete its
entry
> > > from
> > > > > constructors!). E.g. if a user decided that the income process
> they
> > > want
> > > > > to use has binary permanent shocks (characterized by the
> probability
> > > and
> > > > > value of one of the shocks), they can just change *one function
> > name*
> > > in
> > > > > their IndShockConsumerType instances and provide parameters
called
> > > > (e.g.)
> > > > > LowPermShkVal and LowPermShkPrb rather than PermShkStd,
> > PermShkCount,
> > > > etc.
> > > > >
> > > > > It also makes it easier for users to find out what primitive
> > > parameters
> > > > /
> > > > > data are needed to successfully run construct. We can write a
very
> > > > simple
> > > > > query method that lists all of the inputs for each constructor,
> and
> > > > which
> > > > > ones are currently missing (as well as related methods for
> > > > non-constructed
> > > > > solver inputs).
> > > > >
> > > > > There are two kinks in the design that I need to work out.
First,
> > how
> > > to
> > > > > handle allowing the user to specify that some input is
> time-varying
> > vs
> > > > not
> > > > > time-varying--
> > > > >
> > > > It’s time- (or age-) varying if they build it that way. EVERY
SINGLE
> > > > VARIABLE should be allowed to START being time-varying at any age.
> So,
> > > you
> > > > might have constant variance of income shocks after age 65, but
> > > > age-varying
> > > > for earlier ages, AND THE USER NEED NOT DO ANYTHING to accomplish
> this
> > > > until they get to the point of having to solve the problem of the
64
> > > year
> > > > old. The variable will be age-varying as a consequence of the fact
> > that
> > > > the
> > > > user builds it backwards to be age-varying for solutions for
people
> > > > younger
> > > > than 65.
> > > >
> > > > and how to indicate that the solver will *not function properly*
if
> > some
> > > > > inputs are improperly converted to time-varying
> > > > >
> > > > The simplest solution is to enforce at the class level which
solver
> > > inputs
> > > > > *can* be time-varying, and require that the user pass a constant
> > list
> > > if
> > > > > they want it to be time-invariant for their purposes (maybe with
a
> > > > method
> > > > > to handle that automatically).
> > > > >
> > > > > Second, how to handle situations where it's most natural to
> > construct
> > > > two
> > > > > solver inputs simultaneously-- they're biproducts of the same
> > process.
> > > I
> > > > > can think of a slightly clunky and inelegant workaround, but my
> > > > "slightly
> > > > > clunky" is others' "hideously bad design".
> > > > >
> > > > > —
> > > > > Reply to this email directly, view it on GitHub
> > > > > <#1408>, or unsubscribe
> > > > > <
> > > >
> > >
> >
>
https://github.com/notifications/unsubscribe-auth/AAKCK75JTKGY64G253KM3PLY4RDOJAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43ASLTON2WKOZSGIZTIMRSGA3DQMI>
>
> >
> > >
> > > >
> > > > > .
> > > > > You are receiving this because you are subscribed to this
> > > thread.Message
> > > > > ID: ***@***.***>
> > > > >
> > > > --
> > > > - Chris Carroll
> > > >
> > > > —
> > > > Reply to this email directly, view it on GitHub
> > > > <
> #1408 (comment)>,
> >
> > > > or unsubscribe
> > > > <
> > >
> >
>
https://github.com/notifications/unsubscribe-auth/ADKRAFKDK7535IOETIM3MN3Y4SASXAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGIZTMMRUHE>
>
> >
> > >
> > > > .
> > > > You are receiving this because you authored the thread.Message ID:
> > > > ***@***.***>
> > > >
> > >
> > > —
> > > Reply to this email directly, view it on GitHub
> > > <
#1408 (comment)>,
>
> > > or unsubscribe
> > > <
> >
>
https://github.com/notifications/unsubscribe-auth/AAAQZEC745GPURN4WEZ2Z2TY4SHDXAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGI4DGMRUGA>
>
> >
> > > .
> > > You are receiving this because you are subscribed to this
> thread.Message
> > > ID: ***@***.***>
> > >
> >
> > —
> > Reply to this email directly, view it on GitHub
> > <#1408 (comment)>,
> > or unsubscribe
> > <
>
https://github.com/notifications/unsubscribe-auth/ADKRAFMYSGKKS7IIRBRWDO3Y4UTV5AVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBXGM3TMMZQGM>
>
> > .
> > You are receiving this because you authored the thread.Message ID:
> > ***@***.***>
> >
>
> —
> Reply to this email directly, view it on GitHub
> <#1408 (comment)>,
> or unsubscribe
> <
https://github.com/notifications/unsubscribe-auth/AAAQZEF3GJWJW3P6N4GGVKDY4VABHAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBXGYYTKNZXHE>
> .
> You are receiving this because you commented.Message ID:
> ***@***.***>
>
—
Reply to this email directly, view it on GitHub
<#1408 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADKRAFKB2XCPWNQQZEGRHT3Y42JZVAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBZG43DOMJUGU>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Is there a restricted set of types-of-thing that 'constructed inputs' can be? It sounds like all the examples listed so far are mathematical objects of some kind -- distributions, vectors, scalars. I see now the different meanings of 'construct' in programming and mathematics; I wonder if there's a way to avoid ambiguity. One way might be to name what inputs-to-solutions. Seems to me that these are either parameterizations or definitions of exogenous processes, but maybe I'm missing some counterexample. Clarity about this would also help with making clear the mathematically expressiveness of the library. |
Beta Was this translation helpful? Give feedback.
-
I'm not sure what else it could be except a "mathematical object of some
kind". Constructed inputs can also be representations of functions that are
used directly or indirectly by the solver. Here's a somewhat weird example.
Consider someone with the following utility function:
u(c,m; eta) = c^{1-rho} / (1-rho) + (m/eta)^{1-nu} / (1-nu)
Where c and m are choice variables and eta is a shock (that is observed by
the agent when they're making their decision). Consider the static
optimization problem in which this person has money x to spend, consumption
c costs 1 per unit and medical care m costs pi per unit. In a dynamic model
with this utility function, this static problem needs to be solved millions
(or billions) of times, for reasons that aren't important here. In one of
my projects, I have a constructed solver input that returns solutions to
this static problem instantly. As in:
`(c,m) = solve_static_allocation_problem(x, eta, pi)`
The function `solve_static_allocation_problem` is constructed in advance
(under a different name, obviously) based on rho and nu-- once you tell me
the agent's preferences, I can characterize the solution to the static
optimization problem for any inputs, accurate to an arbitrary degree. That
numeric function is a "mathematical object", but it's not a
parameterization or definition of an exogenous process.
And yes, we want to be able to describe these things in the modeling
language outside of HARK.
…On Thu, Apr 11, 2024 at 10:40 AM Sebastian Benthall < ***@***.***> wrote:
Is there a restricted set of types-of-thing that 'constructed inputs' can
be?
It sounds like all the examples listed so far are mathematical objects of
some kind -- distributions, vectors, scalars.
I see now the different meanings of 'construct' in programming and
mathematics; I wonder if there's a way to avoid ambiguity.
One way might be to name what inputs-to-solutions.
Seems to me that these are either parameterizations or definitions of
exogenous processes, but maybe I'm missing some counterexample.
Clarity about this would also help with making clear the mathematically
expressiveness of the library.
—
Reply to this email directly, view it on GitHub
<#1408 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADKRAFMFVQNUBZGYTCHXP7TY42OHJAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBZHA2TCOJSHA>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Ah, thank you for that example.
I see now that this is something quite different.
It also more directly relates to algorithmic performance because of how the
object is used in the solver.
On Thu, Apr 11, 2024 at 11:03 AM Matthew N. White ***@***.***>
wrote:
… I'm not sure what else it could be except a "mathematical object of some
kind". Constructed inputs can also be representations of functions that
are
used directly or indirectly by the solver. Here's a somewhat weird
example.
Consider someone with the following utility function:
u(c,m; eta) = c^{1-rho} / (1-rho) + (m/eta)^{1-nu} / (1-nu)
Where c and m are choice variables and eta is a shock (that is observed by
the agent when they're making their decision). Consider the static
optimization problem in which this person has money x to spend,
consumption
c costs 1 per unit and medical care m costs pi per unit. In a dynamic
model
with this utility function, this static problem needs to be solved
millions
(or billions) of times, for reasons that aren't important here. In one of
my projects, I have a constructed solver input that returns solutions to
this static problem instantly. As in:
`(c,m) = solve_static_allocation_problem(x, eta, pi)`
The function `solve_static_allocation_problem` is constructed in advance
(under a different name, obviously) based on rho and nu-- once you tell me
the agent's preferences, I can characterize the solution to the static
optimization problem for any inputs, accurate to an arbitrary degree. That
numeric function is a "mathematical object", but it's not a
parameterization or definition of an exogenous process.
And yes, we want to be able to describe these things in the modeling
language outside of HARK.
On Thu, Apr 11, 2024 at 10:40 AM Sebastian Benthall <
***@***.***> wrote:
> Is there a restricted set of types-of-thing that 'constructed inputs'
can
> be?
>
> It sounds like all the examples listed so far are mathematical objects
of
> some kind -- distributions, vectors, scalars.
>
> I see now the different meanings of 'construct' in programming and
> mathematics; I wonder if there's a way to avoid ambiguity.
>
> One way might be to name what inputs-to-solutions.
>
> Seems to me that these are either parameterizations or definitions of
> exogenous processes, but maybe I'm missing some counterexample.
>
> Clarity about this would also help with making clear the mathematically
> expressiveness of the library.
>
> —
> Reply to this email directly, view it on GitHub
> <#1408 (comment)>,
> or unsubscribe
> <
https://github.com/notifications/unsubscribe-auth/ADKRAFMFVQNUBZGYTCHXP7TY42OHJAVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBZHA2TCOJSHA>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>
—
Reply to this email directly, view it on GitHub
<#1408 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAQZEGM7XWGMYIQEF4SKLLY42Q57AVCNFSM6AAAAABF7GUBCGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBZHEYDONBVGI>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
@mnwhite this is very important work. Another trivial example is that, under the current design, it is very cumbersome to solve a portfolio choice model where the return factor is not lognormal. With Matt's proposal, it would be easy. I would like the Agent classes impose as little structure as needed. The |
Beta Was this translation helpful? Give feedback.
-
I think that this is a worthwhile goal that is not that related to the time/age varying debate, I don't think the initiative should get bogged down there. This is an improvement in design that could be amended to accommodate the time/age architecture we land on. |
Beta Was this translation helpful? Give feedback.
-
HARK models as basic as ConsIndShock use some "constructed inputs" for their solver, by which I mean objects that are passed to the
solve_one_period
function but would not have been manually specified by the user. For example,IncShkDstn
is a complicated (time-varying) object that could (in principle) be manually created by a user and assigned to an instance ofIndShockConsumerType
, but more reasonably would be constructed from "primitive parameters" likePermShkStd
,TrankShkStd
,UnempPrb
, etc. As-is,PermGroFac
is expected to be provided by the user, but it in principle it could be constructed on theAgentType
instance given some parametric description of the income growth profile.Each
AgentType
subclass has "baked in" constructors, which are called from (or simply part of) anupdate_X
method. Theupdate
method itself is supposed to call all of those constructors, as a universal way to bring constructed inputs up-to-date with any changes made to the primitive parameters. It does so by explicitly calling eachupdate_X
method, sometimes from its parent class.As is, if a user wants to have a different way of constructing such an input, they can either a) do it themselves and then drop in the result into their instances; or b) make a trivial subclass of the
AgentType
that overrides that constructor method. Neither of these are "nice", and there's no organized way for a new user to find out what the required "primitive inputs" are. I'm going to fix this, and this issue presents an overview of my proposal for doing so.I propose that
AgentType
instances have a newconstructors
dictionary. The keys of this dictionary would be the names of inputs to thesolve_one_period
function for that class; the value for each key would be a constructor function whose inputs name the primitiver (or at least more primitive) parameters that are used by that constructor; those parameters would live as attributes on the instance (or in theparameters
dictionary once that's fully implemented).The top-level
AgentType
would have a universal method (e.g. calledconstruct
) that automatically runs some or all of the functions in theconstructors
dictionary. If the user passes one or more strings to this method, it runs the constructors for the named parameters. If the user passes nothing to the method, it runs all of the constructors.When a constructor is run by
construct
, it tries to pull in the parameters named in its arguments (from the agents or itsparameters
dictionary), passes them to the function, and then assigns the output to that key (in theparameters
dictionary or the agent itself, depending on what stage of development we're at).If
construct
fails to find the necessary primitive parameters, it flags that constructor and records the names of the missing parameters. It then proceeds through the other constructors that have been requested. After it finishes all of them, if at least one was flagged as incomplete, it tries again, because new data might be available. Ifconstruct
completes a "pass" with no constructors being successful, then it quits. The names of the "missing data" are stored or returned.This structure makes it much easier and simpler for a user to change the construction method for a solver input, to make an input constructed, or to indicate that an input is not constructed (just delete its entry from
constructors
!). E.g. if a user decided that the income process they want to use has binary permanent shocks (characterized by the probability and value of one of the shocks), they can just change one function name in theirIndShockConsumerType
instances and provide parameters called (e.g.)LowPermShkVal
andLowPermShkPrb
rather thanPermShkStd
,PermShkCount
, etc.It also makes it easier for users to find out what primitive parameters / data are needed to successfully run
construct
. We can write a very simple query method that lists all of the inputs for each constructor, and which ones are currently missing (as well as related methods for non-constructed solver inputs).There are two kinks in the design that I need to work out. First, how to handle allowing the user to specify that some input is time-varying vs not time-varying-- and how to indicate that the solver will not function properly if some inputs are improperly converted to time-varying. The simplest solution is to enforce at the class level which solver inputs can be time-varying, and require that the user pass a constant list if they want it to be time-invariant for their purposes (maybe with a method to handle that automatically).
Second, how to handle situations where it's most natural to construct two solver inputs simultaneously-- they're biproducts of the same process. I can think of a slightly clunky and inelegant workaround, but my "slightly clunky" is others' "hideously bad design".
Beta Was this translation helpful? Give feedback.
All reactions