R在R中的整合上限不起作用吗?

时间:2017-06-22 17:39:40

标签: r numerical-integration

我有一个二维函数需要从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 = 0r = 45下面的图表显示45是一个很好的上限。

enter image description here

但是,以下代码

adaptIntegrate(integrand, lowerLimit = c(0, 0), upperLimit = c(1, 45))$integral

没有给我预期的结果。当我增加上限时,结果会减小,直到最终给出0。

我尝试在其他功能上使用较大的上限而不是Inf,无论我的上限有多高,它似乎都有效。这次是否有这么多失败的原因,有没有办法正确整合这个功能?

3 个答案:

答案 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

我认为根据这个情节你提议的上限太胆小了:

enter image description here

这是我能做的最好的事情:

 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的结果,但不接近你想要的结果。