Currying和多重积分

时间:2013-01-16 19:49:20

标签: f# functional-programming numerical-methods currying

我有兴趣学习一种优雅的方法,在函数式编程语言中使用currying来数值评估多个积分。我选择的语言是F#。

如果我想在区域f(x,y,z)=8xyz上整合[0,1]x[0,1]x[0,1],我首先写下差异格式8xyz dx dy dz的三重积分。在某种意义上,这是三个有序参数的函数:(float -> float -> float -> float)

我接受第一个积分,问题减少到4xy dx dy[0,1]x[0,1]的双积分。从概念上讲,我们已将该函数调整为(float -> float -> float)

在第二个积分后,我将在单位间隔内取2x dx的积分(float -> float)

在三次积分之后,我留下结果,数字为1.0

忽略数字集成的优化,我怎么能简洁地执行这个?我想写一些类似的东西:

let diffForm = (fun x y z -> 8 * x * y * z)

let result =
    diffForm
    |> Integrate 0.0 1.0
    |> Integrate 0.0 1.0
    |> Integrate 0.0 1.0

这是否可行,如果可能不切实际?我喜欢这种关于如何以数学方式捕捉正在发生的事情的想法。

2 个答案:

答案 0 :(得分:3)

我不完全确定你将如何以正常方式实现这一点,所以这可能无法完全解决问题,但这里有一些想法。

要进行数值积分,你(我认为?)需要在管道中diffForm调用指定的各个点调用原始函数Integrate - 但实际上你需要在范围的产品中调用它 - 所以如果我只想在边界处调用它,我仍然需要将其称为2x2x2次以涵盖所有可能的组合(diffForm 0 0 0diffForm 0 0 1,{{ 1}}等等,然后对你得到的8个结果做一些计算。

以下示例(至少)显示了如何使用您指定的参数值的所有组合来编写调用指定函数的类似代码。

这个想法是使用 continuations ,可以多次调用(因此当我们得到一个函数时,我们可以在多个不同的点重复调用它)。

diffForm 0 1 0

这可能会让人感到困惑(因为延续会花费很多时间来习惯),但也许你(或其他人在这里?)可以找到一种方法将这个第一次尝试变成真正的数值积分: - )< / p>

答案 1 :(得分:2)

  

我喜欢这种能够在多大程度上捕捉数学上正在发生的事情的想法。

我担心你的前提是错误的:管道运算符通过一系列函数来线程化一个值,并且与函数组成密切相关。然而,在 n 维度域上进行集成类似于 n 嵌套循环,即在您的情况下类似

for x in x_grid_nodes do
    for y in y_grid_nodes do
        for z in z_grid_nodes do
            integral <- integral + ... // details depend on integration scheme

您无法轻松将其映射到三个独立调用链到一些Integrate函数的链接,因此组合integrate x1 x2 >> integrate y1 y2 >> integrate z1 z2实际上您在整合时所执行的操作{{ 1}}。这就是为什么Tomas的解决方案 - 如果我理解正确(并且我不确定那个......) - 基本上在隐式定义的3D网格上评估你的函数并将其传递给集成函数。我怀疑这与你原来的问题一样接近。

你没有要求它,但是如果你想在实践中评估一个 n - 维积分,那么看看蒙特卡罗积分,它避免了另一个通常被称为“维数诅咒”的问题“,即使用经典集成方案, n 所需采样点数呈指数增长的事实。

更新

您可以实现迭代集成,但不能使用单个f函数,因为要集成的函数类型对于集成的每个步骤都是不同的(即每个步骤变为 n -ary函数到( n - 1) - 一个):

integrate

使用示例函数let f = fun x y z -> 8.0 * x * y * z // numerically integrate f on [x1, x2] let trapRule f x1 x2 = (x2 - x1) * (f x1 + f x2) / 2.0 // uniform step size for simplicity let h = 0.1 // integrate an unary function f on a given discrete grid let integrate grid f = let mutable integral = 0.0 for x1, x2 in Seq.zip grid (Seq.skip 1 grid) do integral <- integral + trapRule f x1 x2 integral // integrate a 3-ary function f with respect to its last argument let integrate3 lower upper f = let grid = seq { lower .. h .. upper } fun x y -> integrate grid (f x y) // integrate a 2-ary function f with respect to its last argument let integrate2 lower upper f = let grid = seq { lower .. h .. upper } fun x -> integrate grid (f x) // integrate an unary function f on [lower, upper] let integrate1 lower upper f = integrate (seq { lower .. h .. upper }) f

f

收益率1.0。