2011-10-16 101 views
8

我想在mathematica中内插一个函数。避免重复调用插值

功能取决于参数a,实际上它是一个功能F这也取决于a的倒数,所以我建立我的近似值如下,

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

现在我可以简单地叫approx[x]到评估一个点的反函数。

相反,我愿做这样的事情:定义一个函数,它接受一个参数,

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

然后写G [X,A]评估功能。否则,我将不得不重复所有我感兴趣的参数的插值,并且存在很多变量。我已经尝试在模块内插入Interpolation []函数,但每次我调用G [x,a]时都会构造插值!我将如何避免这种情况?

感谢您的阅读。

回答

6

沿着这些路线试试:

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 *) 

你只会评估G您第一次为每个特定值调用它时。

+0

这种方法似乎是其他方法提供的最简单的方法。如其他答案中所述,也许在这个方案上隐藏了显式缓存。但我不够专业知道这种差异。 – mark

+3

其他答案处理如何释放存储在缓存符号中的内存,当它变得太大时。这些缓存的想法与这个答案中的一样。如果你的代码不是太内存密集型的,可以不关心释放当前会话的内存,但是如果你做大的计算,它会很有用。 – faysou

+0

@Faysal Aberkane ......谢谢 – mark

12

的第一步是参数化approxa

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

利用这个定义,G然后可以这样定义:

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

但是,正如在问题观察到的,这最终每调用一次G就重构插值。避免这种情况的一种方法是使用记忆化重新定义approx

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

现在,approx将节省插值功能对于任何给定a,避免在后续调用重建具有相同a。当然,这会消耗内存,所以如果有大量不同的值a,那么内存可能会不足。它可以通过将保存的值与另一个符号(cache在这种情况下)相关联的本地化由approx使用的高速缓存:

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

在这个版本中的approxcache可使用Block是局部的,例如:

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

对于每个不同的值a,内插函数仍暂时存储,但现在这些保存的定义在Block退出后被释放。

有关职能与Mathematica的内存的详细信息,请参阅SO问题:

The best way to construct a function with memory

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

+0

谢谢你的回答,它促使我去学习更多的数学! – mark

6

您可以使用的定义CacheIndex我发布在What is in your Mathematica tool bag?。使用这个函数的一个好处是你可以缓存值或部分代码,而不必定义一个新的函数(尽管我们在这里要与示例一致)。

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

我添加了Pause [3],以便明确说明Interpolation的定义在每个a被计算一次之后被缓存。

你可以在CacheIndex使用

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

我适应我的缓存和CacheIndex功能,以使它们与WReach的使用在一个块中定义一个单独的符号的理念一致,然后删除缓存的插值结果。这里不实际的一点是你必须将Hold属性定义为用作缓存的符号,但这个想法仍然很有趣。

这里是定义CacheSymbol

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

您可以测试使用下面的指令在此执行,在一个真实的例子高速缓存将在一个块定义。

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

这里是CacheSymbolIndex的定义

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

您可以按以下说明测试这个实现,在一个真实的例子高速缓存将在一个块定义。

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

和类似WReach的例子中,我们将有

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}] 
]