让f m x
成为计算上昂贵的函数,它接受两个参数并使用数值算法计算。 f
是differentiable函数,具有f m x
的派生等于f m+1 x
的属性。
为了降低调用此函数的计算成本数千次,我们可以在xk
周围的6项泰勒级数中扩展它,
f(m,x) = f(m,xk + dx) = f(m,xk) -f(m+1,xk)*dx + 0.5*f(m+2,xk)(dx)^2 - 1/6 * f(m+3,xk)(dx)^3 + 1/24 * f(m+4,xk)(dx)^4 + 1/120 * f(m+5,xk)(dx)^5......
f(m+1,xk)
是f m
的第一个派生。
使用泰勒系列,我们可以在xk
维度中生成[0.1, 0.2, ..xk,.. xmax]
点mmax + 6
的网格,其中xmax
和mmax
是{的最大值分别为{1}}和x
。基本上,我们的想法是填充网格的节点,调用昂贵的函数m
,并使用上面的泰勒级数展开计算节点之间函数的值。
可以使用惰性地图
生成此网格f
我们有一个网格,其中每个节点都是昂贵函数import Control.Applicative ((<$>),(<*>))
import Data.Map.Lazy as M
data Fun = Fun Double Double deriving (Ord,Eq) -- data representing the point f m x
generateGrid :: (Double -> Double -> Double)-> Int -> Int -> Double -> Map Fun Double
generateGrid f mMax xmax delta = M.fromList $ zip keys vals
where keys = Fun <$> [fromIntegral x | x <- [0..mMax]] <*> [delta*fromIntegral(i) | i <- [0..xmax]]
vals = fmap (\(Fun m x) -> f m x) keys
funTaylor :: Map Fun Double -> Double -> Double -> Double
funTaylor grid m x = (fun m xk) - (fun (m+1) xk)*dx + 0.5*(fun (m+2) xk)*dx^2 -
(1/6)*(fun (m+3) xk)*dx^3 + (1/24)*(fun (m+4) xk)*dx^4 - (1/120)*(fun (m+5) xk)*dx^5
where delta = 0.1
dx = x-xk
xk = (calcClosestPoint x )* delta
fun = calcutateFun grid
calcClosestPoint r = fromIntegral $ floor $ x /delta
calculateFun :: Map Fun Double -> Double -> Double -> Double
calculateFun = ....
的一部分。现在,每当我们需要计算f
时,我们都会调用f
而不是funTaylor
。
请注意,这是一个虚拟网格,因为我们每次调用f
时,只会评估泰勒系列中涉及的点,而网格的其余部分仍未评估。
现在假设我不知道先验数字funTaylor m x
和xmax
是多少,这个虚拟空间很大,因此猜测极限并产生数百万thunk不是一个好选择。
然后,我们的想法是能够构建网格&#34; 动态&#34;,每次调用funTaylor函数时,新的条目都会添加到Map中。问题是mmax
函数是从我的代码中的几个部分调用的,来自几个并行计算的函数。然后,我需要在调用funTaylor
的所有函数之间共享网格。
另一种方法是创建一个频道或队列,它可以像网格和调用funTaylor
的函数之间的服务器一样工作,每当需要新值funTaylor
时,它就会被发送更新网格的队列,避免了在多个函数之间共享状态网格的问题。
问题是: 在运行中生成网格&#34; 的最佳方法是什么?&#34;