Indexed and array-valued interpolations

Indexed is hardly well-documented, so it is hard to say what is or what is not a bug. However, I will argue that what you encountered is not a bug. The basis of my argument is that what documentation there is indicates the first argument given to Indexed should be an expression that is a valid first argument for Part. An interpolation function does not meet this condition.

f = NDSolve[{y'[t] == y[t], y[0] == {1, 2}}, y, {t, 0, 1}][[1, 1, 2]]
Table[Part[f[t], i], {i, 2}]

Part::partw: Part 2 of InterpolatingFunction[{{0.,1.}},{5,3,1,{26},{4},0,0,0,0,Automatic,{},{},False},{{<<1>>}},{{{1.,2.},{1.,2.}},<<24>>,{{2.71828,5.43656},{2.71828,<<19>>}}},{Automatic}][t] does not exist. >>

I am arguing that one can only use Indexed safely in situations where

 Indexed`[<expression>, <index>] /. Indexed -> Part

produces a valid result.


[Ref: Please see The clearest way to represent Mathematica's evaluation sequence for WReach's traceView2 function, which I will use to trace evaluation.]

I'm a little more confused than I like to be when I answer. Perhaps sharing what I think I know will prompt others who better understand evaluation in Mathematica to contribute.

One of the mysterious things about Mathematica is how it determines when to evaluate an expression as it moves through the digestion process of evaluation. No doubt it's perfectly clear to those who know the internal workings. What I mean is that, putting held expressions and so forth aside, once Mathematica has evaluated an InterpolatingFunction or an Integrate that results in the same (or even a different) expression, it does not need to reevaluate it -- unless something changes which either does or might lead to a different result. There must be something like a been-there-done-that flag associated with the expression, but however it is done, I have to hope and treat it like it does not matter, because I don't how it's done.

Working answer: What seems to be happening is that inside Indexed something happens that suggests to Mathematica that something changed that might lead to a different result for the InterpolatingFunction. The InterpolatingFunction is reevaluated and that causes Indexed to be reevaluated. This leads to an infinite loop, since inside Indexed, once again the InterpolatingFunction is reevaluated, etc.

If you wish to explore this, here is a minimal example:

if = Interpolation[Range@2, InterpolationOrder -> 1];
Indexed[if, 2]

Unlike the example in the OP, using Indexed this way does not make sense; however, it does give the same $IterationLimit::itlim behavior as the original with a minimal-sized trace.

You might first want to see the evaluation process that constructs an InterpolatingFunction. First Interpolation constructs an InterpolatingFunction expression: The standard evaluation sequence, head Interpolation, first argument Range@2, etc. results in

InterpolatingFunction[{{1, 2}}, {5, 3, 0, {2}, {2}, 0, 0, 0, 0, 
  Automatic, {}, {}, False}, {{1, 2}}, {{1}, {2}}, {Automatic}]

which is itself evaluated in six steps.

traceView2[Interpolation[Range@2, InterpolationOrder -> 1]]

Mathematica graphics

The final result has the same input form, but is formatted(!). I don't know for sure why it is formatted, but it seems consistent that it is formatted when Mathematica is done evaluating the expression. I have assumed this and used it as a key in interpreting the trace of the evaluation.

The evaluation of InterpolatingFunction[..] also follows the standard evaluation sequence and results in an expression with the same input form, although now that it is evaluated, it will be formatted when returned as seen above.

Mathematica graphics

Another trick to help read the trace output is to replace all InterpolationFunction[..] expressions by "IFN". You lose the formatting, but the output is smaller and easier to deal with. Since the expressions in a trace are wrapped in HoldForm, this replacement does not cause reevaluation of the trace output.

Here we can see the start of the infinite loop described in the working answer. After if is evaluated, Indexed[IFN, 2] evaluates to Indexed[IFN, {2}], which begins the loop. Note that the InterpolatingFunction is reevaluated (the 7-step block, not expanded). So after the head Indexed and the arguments IFN and {2}, Indexed[IFN, {2}] is evaluated. Instead of evaluation stopping at this point, as it should, the evaluation process is repeated.

Block[{$IterationLimit = 20},
  traceView2[Indexed[if, 2]]
  ] /. i_InterpolatingFunction :> "IFN"

$IterationLimit::itlim: Iteration limit of 20 exceeded. >>

Mathematica graphics

I haven't found another function with this problem, so far. Only 5000 more to check. :)


This is an extended comment, not an answer.

After running into problems similar to yours with evaluations that returned rules involving interpolation functions, I decided to cut the Gordian knot and simply extract the interpolation function(s) for use in any further computations. I have never regretted adopting this strategy and it certainly works well for this problem.

f = NDSolve[{y'[t] == y[t], y[0] == {1, 2}}, y, {t, 0, 1}][[1, 1, 2]];
Plot[f[t], {t, 0., 1.}]

plot

Voila, no fuss, no muss, no bother (old tv commercial catch phrase).

Update

Addressing an issue raised in a comment.

{f1, f2} = Table[With[{i = i}, f[#][[i]] &], {i, 2}];
Plot[{f1[t], f2[t]}, {t, 0., 1.}]

color-plot