econ-ark/HARK

Solution base class

Opened this issue · 1 comments

It would be good if we create a good Solution base class that makes it easier to write modular code.

@alanlujan91 's ConsumerSolutionLabeled is an example of how to design a Solution base class which takes in data about the policy and continuation using xarray data types.

class ConsumerSolutionLabeled(MetricObject):
"""
Class to allow for solution interpolation using xarray.
Represents a solution object for labeled models.
"""
def __init__(
self,
value: ValueFuncCRRALabeled,
policy: xr.Dataset,
continuation: ValueFuncCRRALabeled,
attrs=None,
):
"""
Consumer Solution for labeled models.
Parameters
----------
value : ValueFuncCRRALabeled
Value function and marginal value function.
policy : xr.Dataset
Policy function.
continuation : ValueFuncCRRALabeled
Continuation value function and marginal value function.
attrs : _type_, optional
Attributes of the solution. The default is None.
"""
if attrs is None:
attrs = dict()
self.value = value # value function
self.policy = policy # policy function
self.continuation = continuation # continuation function
self.attrs = attrs
def distance(self, other: "ConsumerSolutionLabeled"):
"""
Compute the distance between two solutions.
Parameters
----------
other : ConsumerSolutionLabeled
Other solution to compare to.
Returns
-------
float
Distance between the two solutions.
"""
# TODO: is there a faster way to compare two xr.Datasets?
value = self.value.dataset
other_value = other.value.dataset.interp_like(value)
return np.max(np.abs(value - other_value).to_array())

I would suggest generalizing this beyond 'Consumer' problems, and putting it in its own module, like HARK.solution.
Then refactoring the other Consumer model code to use it.

There are a couple other things I would suggest doing with such a class, in part based on my work on something similar in the BARK PR #1186 which I raise for consideration:
https://github.com/econ-ark/HARK/pull/1186/files#diff-5717deef1382756a0fe3790a7fc10d793edd49e1c3b413e62a7f166138552c3cR36-R95

  • The current ConsIndShock solution object maps object attributes to Interpolator objects, which are more flexible than the xaraay default interpolation (which I believe is always linear). (Matt's Interpolators can integrate a variable constraint, such as $c < m$, which I think is pretty important?). A base Solution class could rely on a DataSet for its data, but have more than one interpolation option.
  • For the above reason, the solution perhaps needs to be aware of constraints on actions. (Debatable.)
  • I think it makes sense to bundle the value function transformations (i.e., using the inverse utility function to linearize the value function before interpolation) into the solution object, as an option.
  • If there was an API for adding a known solution point (such as an artificial or natural borrowing constraint) to a solution object, that would save the model solution designer the headache of hand manipulating the xarray, which is awkward.

I'm not 100% on any of those details but I believe something like this would help us further modularize the code and separate model definitions, solution code, and simulation techniques (such as Monte Carlo and transition matrix).

very much in agreement with the spirit of this