Found a minor bug in grid interpolation layer that triggered in a model I am using, but was not noticeable in any other model I had used previously. I am mid-fix now, just posting for anyone who is interested.
When I wrote the grid interpolation layer code, I thought carefully about what happens if one of the two coarse grid points we want to interpolate between involves a next period V was a minus -Inf, and made sure the linear interpolation is based on conservatively assuming the region in between this point and the next is all -Inf. I also thought about when ReturnFn was -Inf at one of the two coarse grid points, but since I evaluate ReturnFn exactly (rather than interpolate) we can just ignore these when. We get the most accurate Policy with this approach, while still being conservative and avoiding anything that should perhaps be a -Inf.
The agent distribution iteration then involves moving all agents back onto the coarse grid, and this was done by turning the fine index into a weight and using those weights to move agents to the two course grid points either side of the fine index.
Individually these are both perfectly good choices, but the combination of the two causes an issue in some niche cases.
Specifically, I realised that because of how the ReturnFn being -Inf is handled, interacting this with the simulation/iteration taking place on the coarse grid causes an error that results in agents leaking into infeasible situations. Specifically, when you have that a neighbouring coarse ReturnFn point is -Inf and you choose a point on the fine grid, while the Policy is fine, I was then putting a non-zero weight on the neighbouring coarse grid point during simulation/interpolation, which was like saying that with a non-zero probability you had chosen a -Inf ReturnFn.
One solution would simply to be to rule out the Policy from using fine grid if the neighbouring grid point is ReturnFn of -Inf. But this is rather crude, as we loose a lot of accuracy from Policy. Instead, I think it is more accurate that I keep the fine grid index when next to a ReturnFn of -Inf, but we record a flag to say that the the probability weight assigned to the neighbouring point will be zero during simulation/iteration.
In this way, we can keep the fine grid in Policy, giving more accurate plots for Policy, and more accurate stats when we use FnsToEvaluate, while at the same time eliminating any âleakageâ from the agent distribution into these âinfeasible statesâ.
To implement this, I am adding an additional row to Policy whenever grid interpolation layer is being used. This row contains the flag: 2 is the usual use of fine index to create the weights, 1 is all weight to lower grid point, 3 is all weight to upper grid point.
As an end user this should make no impact at all to you, with two exceptions. First, on the outside chance you happen to have a model where this kind of leakage was occuring, in which case it will be corrected, you will see a change in results and the new ones are the correct ones. Second, if you have any saved files containing Policy from the old behaviour, these will no longer be usable as they will contain the wrong number of rows.
One way to think about this change is how it handles constraints that tip from being not-binding to being binding in between course grid points. You have to be fuzzy on one side or another of the tipping point, either you allow some fuzziness by breaching the constraint as far as the next grid point, or you allow some fuzziness by enforcing the constraint as far as the previous grid point. The old version was to allow fuzziness by breaching the constraint as far as the next grid point (I did not realise this at the time). Simply ruling out the fine index in these situations would involve fuzziness by enforcing the constraint as far as the previous grid point. The approach taken in the new version is to not impose any fuzziness on the Policy, and to impose fuzziness by enforcing the constraint as far as the previous grid point when doing simulation/iteration of the agent distribution.
Of course, as the number of coarse grid points increases, these differences between the approaches essentially disappear. The question is to find a method that works well when the coarse grid is truly coarse. I think the new approach treads a better balance than the old approach did.
The change to toolkit github will occur later this week, first I have a lot of coding/testing to do. I will post a reply here once the change is done. I will update the pdf on grid interpolation then too.