Избегайте повторных вызовов Интерполяции

Я хочу интерполировать функцию в математике.

Функция зависит от параметра 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]! Как мне избежать этого?

Спасибо за чтение.

Ответ 1

Попробуйте что-то в этом направлении:

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 при первом вызове для каждого конкретного значения a.

Ответ 2

Первым шагом является параметризация approx с помощью a:

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

С помощью этого определения G можно определить таким образом:

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

Но, как замечено в вопросе, это заканчивает реконструкцию интерполяции каждый раз, когда вызывается G. Один из способов избежать этого - переопределить approx с помощью memoization:

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

Теперь approx сохранит функцию интерполяции для любого заданного a, избегая реконструкции в последующих вызовах с тем же a. Конечно, это использует память, поэтому, если имеется большое количество различных значений a, тогда память может работать коротко. Локализовать кеш, используемый approx, можно локализовать, связав сохраненные значения с другим символом (cache в этом случае):

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

С помощью этой версии approx, cache можно локализовать, используя Block, например:

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

Функции интерполяции по-прежнему временно сохраняются для каждого отдельного значения a, но теперь эти сохраненные определения освобождаются после выхода Block.

Для получения дополнительной информации о функциях с памятью в Mathematica см. вопросы SO:

Лучший способ построения функции с памятью

Динамическое программирование в Mathematica: как автоматически локализовать и/или очистить имена замеченных функций

Ответ 3

Вы можете использовать определение CacheIndex, которое я разместил в Что входит в сумку для инструментов Mathematica?. Одна из хороших особенностей использования этой функции заключается в том, что вы можете кэшировать значения или части кода без необходимости определять новую функцию (хотя мы здесь, чтобы соответствовать этому примеру).

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

Я адаптировал функции Cache и 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}]
]