4维积分计算:nquad获非零小值qmc_quad得零值的问题排查
4维积分nquad正常但qmc_quad返回零值的问题分析
1. 核心错误:函数向量化处理不当
qmc_quad要求被积函数能处理批量采样点——当输入是形状为(4, n_points)的数组时,输出必须是形状为(n_points,)的数组,每个元素对应一个采样点的函数值。
你的G函数里,np.prod(values)会把20个采样点数组的所有元素全部相乘,最终得到一个标量,而不是每个采样点对应的函数值数组。这直接导致qmc_quad无法正确计算每个采样点的贡献,积分结果自然异常。
正确的写法是沿着第0轴对每个采样点的20个PDF值取乘积:
result = np.prod(values, axis=0)
2. 采样点没命中窄峰值区域
被积函数是20个正态分布PDF的乘积,只有当M1, Mn, S1, Sn恰好让每个正态分布的均值/标准差匹配对应x值时,函数值才会显著非零。这个峰值区域在你设置的[-100,100]^2 × [0.0001,100]^24维空间里占比极小:
- nquad是自适应积分,会自动找到并集中采样峰值区域,所以能算出非零结果;
- qmc_quad是均匀覆盖整个区间的准蒙特卡洛采样,204800个点分摊到4维空间,每个维度仅约21个采样点(
204800^(1/4)≈21),几乎不可能碰到窄峰值,采样到的函数值全为0,积分结果就是0。
3. 积分区间太宽泛
M1, Mn设为[-100,100],但你的XX数据集中在2-15之间,M是M1和Mn的线性组合,显然M1, Mn的合理范围应该接近[0,20]。过大的区间进一步降低了采样点命中峰值的概率。
修复方案
- 修正向量化代码:把
G函数里的np.prod(values)改成np.prod(values, axis=0); - 缩小积分区间:将
M1, Mn的范围调整为[0,20],S1, Sn调整为[0.1,20](更符合实际标准差的范围); - 增加采样点数量:4维积分至少需要百万级别的采样点才有可能覆盖峰值,可尝试
n_points=1000000; - 变量替换优化:把
S1, Sn换成对数变量(比如log_S1 = np.log(S1)),将正半轴积分转成实数域,提升采样效率。
修复后的G函数示例:
def G(args): M1, Mn, S1, Sn = args x = XX[1:] i = number_i[1:] values = [F(M1, Mn, S1, Sn, i_val, 20, x_val) for i_val, x_val in zip(i, x)] # 对每个采样点的20个值取乘积 result = np.prod(values, axis=0) return result
内容的提问来源于stack exchange,提问作者Alexey_Proz
相关产品推荐
相关产品推荐

