# ConsIndShockFastModel

In this post I will go over my latest PR on econ-ark/HARK.

The goal of this PR is to create a mirror to `ConsIndShockModel.py`

, but that implements faster solutions using `numba`

just-in-time compiling and optimization.

`PerfForesightSolution`

The first step is to create a solution object called `PerfForesightSolution`

that contains only python primitives and `numba`

arrays. This object takes the place of `ConsumerSolution`

, which creates additional HARK objects and can lead to unnecessary time overhead in the solution iteration. The `distance_criteria`

for this solution is `["cNrm", "mNrm"]`

, which is identical to the `distance_criteria`

for `ConsumerSolution`

but more straight forward. This `ConsumerSolution`

replacement is faster because instead of having to create HARK objects such as `cFunc`

, `vFunc`

, etc. as `LinearInterpolator`

s for every solution iteration, the solution method or algorithm only really needs the primitives that compose these objects. Below I will describe in more detail how this object is used in the solver.

`ConsPerfForesightFastSolver`

The next step is to create a solver that replaces `ConsPerfForesightSolver`

, aptly called `ConsPerfForesightFastSolver`

. The object uses a `numba`

-optimized helper function called `solveConsPerfForesightNumba`

. In this implementation, the outputs of this helper method are packaged into a `PerfForesightSolution`

object instead of a `ConsumerSolution`

object. As I mentioned, this avoids the needless creation of other HARK objects in the iteration, leaving the creation of a proper HARK solution to the end of the iteration. An additional feature that has been removed from the solution iteration is the searching of steady-state normalized market resources with `addSSmNrm()`

. As the iteration does not depend on this result as an intermediate input, this can be safely moved to the end of the solution method, or rather to `postSolve()`

.

`PerfForesightFastConsumerType`

Finally, I create an agent that can use the above solution method called `PerfForesightFastConsumerType`

. Since now the solution iteration uses `PerfForesightSolution`

, I first override `solution_terminal_ = PerfForesightSolution()`

. Then, on `__init__`

, I override `solveOnePeriod`

to `ConsPerfForesightFastSolver`

. Since I am overriding the solution_terminal_, I might still need a `ConsumerSolution`

terminal in the case of a non-infinite problem. So, I override the method `updateSolutionTerminal()`

to save an internal `ConsumerSolution`

version of the `solution_terminal`

. The final step is to implement a `postSolve()`

method to wrap every `PerfForesightSolution`

parameter into a HARK object and to run `addSSmNrmNumba()`

only on the final solution. As I had mentioned, there is no need to create these objects at every iteration step of the solution, and it is thus more efficient to leave them to `postSolve()`

. Now, ideally, the output of `solve()`

is the same between the standard HARK approach and the fast approach, a list of `ConsumerSolution`

objects with `cFunc`

, `vFunc`

, etc. as HARK `LinearInterpolator`

s.

### Checking for Equality

Having proposed a new agent type and solution that should be equivalent, or ideally identical, I then focus on implementing `__eq__`

methods for `==`

comparison. In the class definition of `ConsumerSolution`

in `ConsIndShockModel.py`

, I add this method. The logic is that if the solution is a subclass of a `HARKobject`

(which I presume all solutions should be), and if one of the solutions is a subclass of the other (for the two solutions being compared), and if the other solution has an attribute called `"tolerance"`

, then if the `distance`

between both solutions is smaller than the `tolerance`

of both solutions, then the solutions are `equal`

, otherwise they are not. For this, I had to create a dummy attribute for `ConsumerSolution`

as `tolerance = 0.000001`

, although I argue that the solution should inherit “solution method parameters” such as `tolerance`

, `solution_distance`

, and `completed_cycles`

. Although this works for comparing standard HARK approach and fast approach, there might be other cases where this should be revised.

For comparing whether two models are the same, I added an `__eq__`

method to `PerfForesightConsumerType`

. The logic is that if the corresponding agent being compared to is a subclass of `AgentType`

, and if one of the models is a subclass of the other (for the two models being compared), and if the other agent has an attribute called `"params"`

, then the models are equal if the `params`

dictionaries are the same, where equality between dictionaries is built in. For this, I had to make `params`

an attribute of `PerfForesightConsumerType`

, and additionally I had to add cycles to `params`

, to differentiate between finite and infinite horizon models with otherwise identical parameters.