ReplaceAll in an expression including large InterpolatingFunction

I have a large InterpolatingFunction that I'm transforming to another basis with a few simple multiplications and additions by (symbolic) constants. The transformation is quick to compute. However, when I later want to replace the symbolic constants with real numbers for plotting purposes, a call to ReplaceAll grinds for an exceptionally long time on the expression.

Why? Is there a way to avoid this without replacing in the transformation itself (an alternative I'd like to avoid for procedural reasons).

I would provide code, but I don't know a short snippet that can generate a large interpolating function. Perhaps someone can provide a good example.

-
I am afraid that without code, you significantly reduce your chances to get a good answer. Try to simplify your real case to a minimal example exhibiting this behavior. – Leonid Shifrin May 20 '14 at 21:20
@LeonidShifrin, I was able to work around it by replacing the variables before transforming the basis. I found the issue unreliable to reproduce, with some lists of replacement rules computing ReplaceAll quickly, and others taken a very long time. – Rico Picone May 20 '14 at 21:30
The problem is that until you could provide a reproducible example, we can only guess. One such guess is that this might be related to unpacking of packed arrays. You can switch the monitoring of packing on, by calling On["Packing"] (or Off["Packing"] to switch this off, and see if the long timings correlate with unpacking messages. – Leonid Shifrin May 20 '14 at 21:33
I think you're right. I'm getting messages like DeveloperFromPackedArray::punpack1: Unpacking array with dimensions {1010} for the calls to ReplaceAll that take a long time and no such messages for others. – Rico Picone May 20 '14 at 21:39
Then the thing you are observing is similar to what was happening here. Here is the cure: whatever your rules are, say {a->1, b->2}, add the following rule in front: arr_List?DeveloperPackedArrayQ :> arr (so for my example, you'd have {arr_List?DeveloperPackedArrayQ :> arr,a->1, b->2}). The added rule is instructing to be idle on packed arrays, which would prevent them from unpacking. – Leonid Shifrin May 20 '14 at 22:18

What's happening is that ReplaceAll unpacks packed arrays during rule application, as a part of the pattern-matching procedure. This happens because for general patterns, there is no automatic way to exclude packed arrays in advance (to know that they or their elements won't match a given pattern).

The way to handle this situation is to use the fact that only the first matching rule applies for any given expression. Therefore, all you have to do is to add an idle rule like the following:

arr_List?DeveloperPackedArrayQ :> arr


{a->1, b->2}


then the new rule set will look like

{arr_List?DeveloperPackedArrayQ :> arr,a->1, b->2}


This will ensure that any packed array encountered by the pattern-matcher in ReplaceAll will be left untouched (and, in particular, unpacked). Note that this only works for ReplaceAll, because it is breadth-first, and goes from expressions to sub-expressions.

Most replacement functions are depth-first (the similar situation with Cases` was considered here), and there isn't such a simple solution in that case (because for depth-first traversal, unpacking happens as a part of the traversal, rather than part of the pattern-matching. There, lists are unpacked even before the pattern-matcher has a chance to "see" them as a whole).

-