econ-ark/HARK

What is update? How many terminal solutions?

Closed this issue · 8 comments

Looking at the PortfolioConsumerType I find the following update method:

which calls RiskyConsumerType's update

def update(self):
RiskyAssetConsumerType.update(self)

which calls ConsIndShk's update

def update(self):
IndShockConsumerType.update(self)

which finally updates the terminal solution.

def update(self):
"""
Update the income process, the assets grid, and the terminal solution.
Parameters
----------
None
Returns
-------
None
"""
self.update_income_process()
self.update_assets_grid()
self.update_solution_terminal()

However, when initializing a PortfolioConsumerType, we instantiate the parent RiskyAssetConsumerType

RiskyAssetConsumerType.__init__(self, verbose=verbose, quiet=quiet, **kwds)

which instantiates the parent IndShockConsumerType

IndShockConsumerType.__init__(self, verbose=verbose, quiet=quiet, **kwds)

which itself updates, and calls update_terminal_solution. So, this is the second call to update_terminal_solution

But we are not done....

PortfolioConsumerType has a pre_solve method

def pre_solve(self):
AgentType.pre_solve(self)
self.update_solution_terminal()

so this is the third time we're calling update_terminal_solution by my count!

If we are lucky, it's calling the same update_terminal_solution 3 times. I don't understand this enough but I think I have been in situations where, due to poor inheritance practices, the update_teriminal_solution that I expected is not the one being run, or at least not the last one being run.

This is a big issue that sometimes makes debugging solutions harder than it needs to be.

I think the solution is to remove the following lines

self.update()
def pre_solve(self):
AgentType.pre_solve(self)
self.update_solution_terminal()

but this might not be the only model that does something like this

Why don't we use super?

No I mean in general, super at instantiation

Mv77 commented

Yeah, this is a problem. I think some agent types run the "create income process" from ConsIndShock as much as 3 times each for a single solve. Which can take longer than the solve itself...

Mv77 commented

Maybe a policy for this would be that every agent type should define (not simply inherit) its full update, pre_solve, and post_solve methods? You'd be free to call super.update_whatever(...) in them, but at least you would be doing it consciously?