我有一个二维函数需要从0到无穷大集成一个变量:
library(cubature)
k = 0.5
m = 0.05
integrand = function(variables) {
x = variables[1]
r = variables[2]
p = sqrt(x*(1 - x))*exp((-1/2)*(((k**2)*x*(1 - x)*(r**2)) + ((m**2)/((k**2)*x*(1 - x)))))
d.p = -((x*(1 - x))**(3/2))*(k**2)*r*exp((-1/2)*(((k**2)*x*(1 - x)*(r**2)) + ((m**2)/((k**2)*x*(1 - x)))))
return (2*pi*r*(1/(4*(x**2)*((1 - x)**2)))*(((x**2 + (1 - x)**2)*(d.p**2)) + (m*p)**2))
}
但是, adaptIntegrate
不能将Inf
作为上限,因此我尝试使用大量数据进行集成。从r = 0
到r = 45
下面的图表显示45是一个很好的上限。
但是,以下代码
adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, 45))$integral
没有给我预期的结果。当我增加上限时,结果会减小,直到最终给出0。
我尝试在其他功能上使用较大的上限而不是Inf
,无论我的上限有多高,它似乎都有效。这次是否有这么多失败的原因,有没有办法正确整合这个功能?
答案 0 :(得分:1)
这是hcubature的包装器,它使它接受无限限制:
hcubature.inf <- function() {
cl <- match.call()
cl[[1L]] <- quote(cubature::hcubature)
if(all(is.finite(c(lowerLimit,upperLimit)))) return(eval.parent(cl))
# convert to new coordinates to incorporate infinities
cl[['upperLimit']] <- atan(upperLimit)
cl[['lowerLimit']] <- atan(lowerLimit)
# wrap the coordinate transformation
if(!vectorInterface) {
newfun <- function(x,...) {
z <- tan(x)
jac <- rep(prod(1/cos(x))^2, fDim)
f(z,...) * jac
}
} else {
newfun <- function(x,...) {
z <- tan(x)
jac <- rep(apply(x,2,function(x) prod(1/cos(x)))^2, each=fDim)
f(z,...) * jac
}
}
cl[['f']] <- newfun
eval.parent(cl)
}
formals(hcubature.inf) <- formals(hcubature)
hcubature.inf(integrand, c(0,0), c(1,Inf))$integral
[1] 6.450675
答案 1 :(得分:0)
看来你有一些权威,这个多项式函数应该保持正数。在提供缺少的括号并运行一些测试用例之后,我怀疑你在将表达式转录为R时出错了。
> adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, 45))$integral
[1] 6.3301
> adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, Inf))$integral
[1] NaN
> adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, 300))$integral
[1] 6.4436
> adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, 600))$integral
[1] 6.4436
> adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, 6000))$integral
[1] 2.7391
# backing up a bit .......
> adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, 3000))$integral
[1] 6.4495
看起来你的被积函数在y轴上的3000到6000之间的某个地方过零。看来你的函数在积分网格上评估的许多点上都有NaN的返回值。我用有限值增加,看到结果在第二个限制的宽范围值上保持为0。数字集成有一些固有的局限性,从其有限的性质中脱离出来:
> adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, 1000000000))$integral
[1] 0
我相信我已经读过如果结果的梯度太浅,adaptIntegrate
有时会失败。我似乎记得&#34; adapt&#34; -part的名称意味着它应用一些启发式方法来搜索参数空间的正确切片,这取决于被积函数值的变化。
hcubature method is the default. The help page suggests that using
pcubature`将应用更严格的测试:
> hcubature(integrand, lowerLimit = c(0.00001, 0.1), upperLimit = c(.9999999,360))$integral
[1] 6.4489
> pcubature(integrand, lowerLimit = c(0.00001, 0.1), upperLimit = c(.9999999,360))$integral
[1] 6.4505 # value increased with same arguments
我认为根据这个情节你提议的上限太胆小了:
这是我能做的最好的事情:
pcubature(integrand, lowerLimit = c(0.0000000001, 0.000000001),
upperLimit = c(.99999999999999, 360))$integral
[1] 6.4507
答案 2 :(得分:0)
一种可能的解决方案是,由于您无法确定正确的上限,您可以进行一些数学变换:更改变量以将范围从0更改为Inf到0到1之间。理论上积分应该相同。例如,
library(cubature)
k = 0.5
m = 0.05
integrand = function(variables) {
x = variables[1]
r = variables[2]
p = sqrt(x*(1 - x))*exp((-1/2)*(((k**2)*x*(1 - x)*(r**2)) + ((m**2)/((k**2)*x*(1 - x)))))
d.p = -((x*(1 - x))**(3/2))*(k**2)*r*exp((-1/2)*(((k**2)*x*(1 - x)*(r**2)) + ((m**2)/((k**2)*x*(1 - x)))))
return(2*pi*r*(1/(4*(x**2)*((1 - x)**2)))*(((x**2 + (1 - x)**2)*(d.p**2)) + (m*p)**2))
}
integrand1 <- function(variables){
x <- variables[1]
## y is the variable from 0 to 1
y <- variables[2]
## r is 0 to Inf by this transformation
r <- y / (1 - y)
## the new function will be the original function times the Jacobian
## i.e. the derivative of r = y / (1 - y)
integrand(c(x, r)) / (1 - y) ^ 2
}
## adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, 45))$integral
adaptIntegrate(integrand1, lowerLimit = c(0, 0), upperLimit = c(1, 1))$integral
我得到的结果是6.450692,类似于42的结果,但不接近你想要的结果。