# IndShockConsumerTypeNumba

Since the last post I’ve worked on a `numba`

version of `IndShockConsumerType`

in IndShockNumbaModel.py. The class `IndShockConsumerTypeNumba`

is the same as `IndShockConsumerType`

, but now I use a “flat” `numba`

optimized solvers called `ConsIndShockNumbaSolverBasic`

and `ConsIndSchockSolverNumba`

.

`ConsIndShockNumbaSolverBasic`

The method `prepareToSolve`

implements the machinery of `ConsIndShockSetup`

. Beyond the steps that have been described before to translate code from standard python to `numba`

, this method didn’t need much alteration.

`solveConsIndShockNumba`

in `ConsIndShockNumbaSolverBasic`

The method `solve`

implements the machinery of `ConsIndShockSolverBasic`

. I will describe the few modifications that were needed in detail.

The first hurdle was due to the fact that `numba`

does not yet have optimized implementations of `np.tile`

and `np.insert`

. With the hopes that these methods are implemented in the future, I wrote two basic ‘placeholders’ that take the same parameters in the exact same format, and instead uses a combination of other `numpy`

methods that `numba`

does support. For example, the way `np.insert`

is being used is to insert `values`

into `array`

before index 0, which can be done instead by converting `values`

to an array, then appending `array`

at the end. If and when `numba`

implements these two methods, the code can be changed by adding `np.-`

back to the call.

The next big hurdle was to replace the call to `vPfuncNext`

, a HARK object, in `calcEndOfPrdvP`

. After inspection, it appears that `vPfuncNext`

is a `MargValueFunc`

, which is itself an instance of `LowerEnvelope`

. What `MargValueFunc`

does is take a `cFunc`

and apply the function `c**-gam`

, so I can just do that myself, assuming I can calculate `c`

first. This is where `LowerEnvelope `

comes into place, since `cFunc`

is an instance of `LowerEnvelope`

and thus composed of several functions. Assuming I can get `cFunc.x_list`

and `cFunc.y_list`

(for now, will touch on this later), I can linearly interpolate `cFuncNext`

given `mNrmNext`

, using `interp`

from interpolation.py.

Doing this, however, was not as easy as expected. I may have found a bug (or perhaps a feature request) on the method `interp`

. Calling `interp(x_list,y_list,values)`

where `values`

is an `ndarray`

(more than 1 dimension), returned only an array output (1 dimension) which appeared to only interpolate along the first value of axis 0. More clearly, if `values.shape = (x,y)`

, then `output.shape = (x,)`

. Clearly, this is not what I need, so to fix this issue, I flatten `values`

, then `reshape`

the output. The final code looks like this:

```
cFuncNext = interp(sn_cFunc_x_list, sn_cFunc_y_list, mNrmNext.flatten())
vPfuncNext = (cFuncNext ** -CRRA).reshape(mNrmNext.shape)
```

As I mentioned before, I assumed the existence of `cFunc.x_list`

and `cFunc.y_list`

, which are inputs to the `solveConsIndShockNumba`

method. Since `cFunc`

is an instance of `LowerEnvelope`

, these attributes do not exist directly, therefore, I need to create them. For `cFunc.x_list`

, I simply used `self.aXtraGrid`

, which is the resource grid. For `cFunc.y_list`

I unfortunately need to call `cFunc(cFunc_x_list)`

, which uses the internals of `LowerEnvelope`

to linearly interpolate over `cFunc_x_list`

. This linear interpolation is not `numba`

optimized, and may be a bottleneck to the code.