在 python 中嵌套数值积分

Nesting numerical integrals in python

我目前正在计算 python 中的数值积分,它实际上是四个嵌套的数值积分。每个积分都是不同变量的函数,但我遇到的问题是限制取决于它嵌套在其中的积分(最外面的积分具有适当的浮点范围)。

例如,假设我有一个函数 f(a,b,c,d),其限制为 amin、amax、bmin、bmax、cmin、cmax、dmin、dmax。 amin 和 amax 是浮动的。 bmin和max是a的函数,cmin和cmax是b的函数,dmin和dmax是c的函数。如果 scipy.integrate.quad() 只是一个 for 循环,那么对于每一步,都可以将 a(或 b、c 或 d)的值传递到 limits 中,使它们成为浮点数。

有没有办法用 scipy.integrate.quad 做到这一点?到目前为止,我已经尝试过简单的嵌套:

def int4(func,min1,max1,min2,max2,min3,max3,min4,max4):
    finalfunc = scint.quad(scint.quad(scint.quad(scint.quad(func,min1,max1),min2,max2),min3,max3),min4,max4)
    return finalfunc

在这种情况下,我仍然遇到与 ValueError: Invalid limits given 之前遇到的相同错误,这似乎是因为我有未被整合的符号。我也尝试过使用nquad,但我遇到了同样的错误。

这是我目前尝试向外迭代迭代的过程,只在最后做数字:

def int4(func,var1,var2,var3,min1,max1,min2,max2,min3,max3,min4,max4):
    func2 = sym.integrate(func,(var1,min1,max1)
    func3 = sym.integrate(func2,(var2,min2,max2))
    func4 = sym.integrate(func3,(var3,min3,max3))
    finalfunc = scint.quad(func4,min4,max4) 
    return finalfunc

困难在于 min1、max1 是 var2 的函数,而我实际使用的函数似乎没有解析解。

如果我改为从最外层进入而不是从最内层向外集成,是否也有帮助?

感谢 Kazemakase,他的回答对解决我的问题很有帮助!我使用对他编写的代码稍作修改的代码解决了这个问题,因此我将其包含在此处作为将来遇到类似问题的其他人的参考。

import numpy as np
import scipy.integrate as si

def func(x1, x2, x3, x4):
    return x1**2 - x2**3+x3*x2 - x4*x3**3  

def int1():
    """integrates `int2` over x1"""
    a1, b1 = -1, 3
    def int2(x1):
        """integrates `func` over x2 at given x1.""" 
        #partial_func1 = lambda x2: func(x1, x2)
        b2 = 1 - np.abs(x1)
        a2 = -np.abs(x1**3)
        def int3(x2):
            a3 = x2
            b3 = -a3
            def int4(x3):
                partial_func = lambda x4: func(x1, x2, x3, x4)
                a4 = 1+np.abs(x3)
                b4 = - a4
                return si.quad(partial_func,a4,b4)[0]
            return si.quad(int4, a3, b3)[0]
        return si.quad(int3, a2, b2)[0]     
    return si.quad(int2, a1, b1)[0]

result = int1()  # -22576720.048151683

如果我理解正确,那么 nquad 应该能够处理此集成。请注意,其 ranges 参数允许您指定依赖于其他积分变量值的函数。

例如,要计算 f(x,y)=1 在面积 0 <= y <= 1 和 0 <= x <= y 上的积分(换句话说,我们计算面积单位正方形的左上半三角形):

from scipy.integrate import nquad
def f(x,y): return 1.
def x_integration_boundary(y): return (0,y)
nquad(f,(x_integration_boundary,(0,1)))

这给出了 0.5 的积分值,这是应该的。

嵌套调用 quad 是正确的方法。然而,简单是不够的。传递给 quad 的每个参数都需要是一个函数——而不是先前调用的结果。这是一个在菱形区域 abs(x1) + abs(x2) <= 1.

上积分 f = x1**2 - x2**3 的示例

对于 +/-1.

之间的任何 x1,我们需要能够在 -/+(1 - abs(x1)) 之间集成 x2
import numpy as np
import scipy.integrate as si


def func(x1, x2):
    return x1**2 - x2**3    

def int2(x1):
    """integrates `func` over x2 at given x1.""" 
    partial_func = lambda x2: func(x1, x2)
    b2 = 1 - np.abs(x1)
    a2 = -b2
    return si.quad(partial_func, a2, b2)[0]    

def int1():
    """integrates `int2` over x1"""
    a1, b1 = -1, 1
    return si.quad(int2, a1, b1)[0]

result = int1()  # 0.33333333333333337

您可以使用 nquad 为您进行包装,而不是为每个积分显式编写一个函数。它为每个变量取一个积分范围,它也可以是一个函数,取决于积分的其他变量:

def range1(x2):
    b1 = 1 - np.abs(x2)
    a1 = -b1
    return a1, b1    

result, err = si.nquad(func, [range1, (-1, 1)])
# (0.33333333333333337, 7.401486830834376e-15)