Avoid repeated calls to Interpolation
Asked Answered
A

3

8

I want to interpolate a function in mathematica.

The function depends on a parameter a, in fact it is the inverse of a function F which also depends on a, so I build my approximation as follows,

approx = Interpolation[Table[{F[0.1 n, a], 0.1 n}, {n, -100, 100}]]

now I can simply call approx[x] to evaluate the inverse function at a point.

Instead I would like to do something like this: Define a function which takes a parameter,

G[x_,a_] = "construct the interpolating function,
            and return the value of the function at x"

Then write G[x,a] to evaluate the function. Otherwise I would have to repeat the interpolation for all the parameters I am interested in and have lots of variables lying around. I have tried putting the Interpolation[] call inside a module but that just constructs the interpolation every time I call G[x,a]! How would I avoid this?

Thanks for reading.

Askew answered 16/10, 2011 at 2:34 Comment(0)
D
6

Try something along these lines:

G[a_]:=G[a]=Interpolation[Table[{F[0.1 n, a], 0.1 n}, {n, -100, 100}]]

G[0.2]  (* particular value of G[a] *)

G[0.2][0.3] (* the value you want *)

You will only evaluate G the first time you call it for each particular value of a.

Deterioration answered 16/10, 2011 at 4:34 Comment(2)
This approach seems to be the simplest approach over the others provided. Maybe there is a draw back to this scheme over the explicit caching as described in the other answers. But I'm not enough of an expert to know the difference.Askew
The other answers deal with how to release memory stored in the cache symbol when it grows too big. The caching idea of these is the same as in this answer. If your code is not too memory intensive it's ok to not really care of releasing the memory of the current session, but it can be useful if you do big computations.Barrows
V
12

The first step is to parameterize approx with a:

approx[a_] := Interpolation[Table[{F[0.1 n,a],0.1 n},{n,-100,100}]]

With this definition, G can then be defined thus:

G[x_, a_] := approx[a][x]

But, as observed in the question, this ends up reconstructing the interpolation every time G is called. One way to avoid this is to redefine approx using memoization:

m: approx[a_] := m = Interpolation[Table[{F[0.1 n,a],0.1 n},{n,-100,100}]]

Now, approx will save the interpolation function for any given a, avoiding reconstruction in subsequent calls with the same a. Of course, this uses up memory so if there are a large number of distinct values of a then memory could run short. It is possible to localize the cache used by approx by associating the saved values with another symbol (cache in this case):

approx[a_] := cache[a] /.
  _cache :> (cache[a] = Interpolation[Table[{F[0.1` n,a],0.1` n},{n,-100,100}]])

With this version of approx, cache can be localized using Block, e.g.:

Block[{cache}
, Table[G[x, a], {x, 0, 5}, {a, 0, 1, 0.1}]
]

The interpolation functions are still temporarily stored for each distinct value of a, but now those saved definitions are released after the Block exits.

For more information about functions with memory in Mathematica, see the SO questions:

The best way to construct a function with memory

Dynamic Programming in Mathematica: how to automatically localize and / or clear memoized function's definitions

Virginia answered 16/10, 2011 at 4:30 Comment(1)
Thank you for your answer, it has motivated me to go learn more mathematica!Askew
D
6

Try something along these lines:

G[a_]:=G[a]=Interpolation[Table[{F[0.1 n, a], 0.1 n}, {n, -100, 100}]]

G[0.2]  (* particular value of G[a] *)

G[0.2][0.3] (* the value you want *)

You will only evaluate G the first time you call it for each particular value of a.

Deterioration answered 16/10, 2011 at 4:34 Comment(2)
This approach seems to be the simplest approach over the others provided. Maybe there is a draw back to this scheme over the explicit caching as described in the other answers. But I'm not enough of an expert to know the difference.Askew
The other answers deal with how to release memory stored in the cache symbol when it grows too big. The caching idea of these is the same as in this answer. If your code is not too memory intensive it's ok to not really care of releasing the memory of the current session, but it can be useful if you do big computations.Barrows
B
6

You could use the definition of CacheIndex I posted in What is in your Mathematica tool bag?. One good thing about using this function is that you can cache values or portions of code without having to define a new function (although we do here to be in line with the example).

G[x_,a_] :=
   CacheIndex[a,
      Pause[3];
      Interpolation[Table[{F[0.1 n,a],0.1 n},{n,-100,100}]]
   ][x];

I added Pause[3] just to make it clear that the definition of Interpolation is cached for each a after it has been computed once.

You could then delete the cached Interpolation values in CacheIndex using

DeleteCachedValues[CacheIndex] (*or*) 
DeleteCachedValues[CacheIndex,1].

I adapted my Cache and CacheIndex functions to make them compatible with the idea of WReach of using a separate symbol defined in a Block. One thing not practical here is that you have to define Hold attributes to the symbol used as cache, but the idea is still interesting.

Here is the definition of CacheSymbol

SetAttributes[CacheSymbol,HoldAll];
CacheSymbol[cacheSymbol_,expr_]:=cacheSymbol[expr]/.(_cacheSymbol:>(cacheSymbol[expr]=expr));

You can test this implementation using the following instructions, in a real example cache would be defined in a Block.

ClearAll[cache]
SetAttributes[cache,HoldFirst] 
CacheSymbol[cache,Pause[3];2+2]
?cache
CacheSymbol[cache,Pause[3];2+2]

Here is the definition of CacheSymbolIndex

SetAttributes[CacheIndexSymbol,HoldAll];
CacheIndexSymbol[cacheSymbol_,index_,expr_]:=cacheSymbol[index,expr]/.(_cacheSymbol:>(cacheSymbol[index,expr]=expr));

You can test this implementation using the following instructions, in a real example cache would be defined in a Block.

ClearAll[cache] 
SetAttributes[cache,HoldRest]
CacheIndexSymbol[cache,2+2,Pause[3];2+2]
?cache
CacheIndexSymbol[cache,2+2,Pause[3];2+2]

and similarly to the example of WReach we would have

G[x_,a_] :=
   CacheIndexSymbol[cache,a,
      Print["Caching"];
      Interpolation[Table[{F[0.1 n,a],0.1 n},{n,-100,100}]]
   ][x]

Block[{cache}, 
   SetAttributes[cache,HoldRest];
   Table[G[x, a], {x, 0, 5}, {a, 0, 1, 0.1}]
]
Barrows answered 16/10, 2011 at 14:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.