Divergent Integral in R is solvable in Wolfram

前端 未结 3 1257
梦毁少年i
梦毁少年i 2021-01-26 15:37

I know that I asked the same question before, but as I am pretty new here the question was asked poorly and not reproducible. Therefore I try to do it better here. (If I only ed

相关标签:
3条回答
  • 2021-01-26 15:47

    For double integrals, it is better to use the cubature package.

    library(cubature)
    f <- function(x){
      exp(16*x[1] - 8*x[2] - (x[2] + 0.01458757)^2/0.0001126501)
    }
    

    The hcubature function gives a result which is not stable when one decreases the tolerance:

    > hcubature(f, c(-2.5, -2), c(0,2))$integral
    [1] 0.001285129
    > hcubature(f, c(-2.5, -2), c(0,2), tol=1e-10)$integral
    [1] 0.001293842
    

    Contrary to the result of pcubature, which is stable:

    > pcubature(f, c(-2.5, -2), c(0,2))$integral
    [1] 0.001323689
    > pcubature(f, c(-2.5, -2), c(0,2), tol=1e-10)$integral
    [1] 0.001323689
    

    The p-adaptive version, pcubature, repeatedly doubles the degree of the quadrature rules until convergence is achieved, and is based on a tensor product of Clenshaw-Curtis quadrature rules. This algorithm is often superior to h-adaptive integration for smooth integrands in a few (<=3) dimensions, but is a poor choice in higher dimensions or for non-smooth integrands.

    Next, RcppNumerical provides a powerful multiple integration.

    // [[Rcpp::depends(RcppEigen)]]
    // [[Rcpp::depends(RcppNumerical)]]
    #include <RcppNumerical.h>
    #include <cmath>
    using namespace Numer;
    
    class ValegardIntegrand: public MFunc
    {
    public:    
      double operator()(Constvec& x)
      {
        return exp(16*x[0] - 8*x[1] - pow(-x[1] - 0.01458757,2)/0.0001126501);
      }
    };    
    
    // [[Rcpp::export]]
    Rcpp::List Valegard()
    {
      ValegardIntegrand f;  
      Eigen::VectorXd lower(2);
      lower << -2.5, -2;
      Eigen::VectorXd upper(2);
      upper << 0.0, 2.0;
      double err_est;
      int err_code;
      double res = integrate(f, lower, upper, err_est, err_code, 
                             10000000, 1e-14, 1e-14);
      return Rcpp::List::create(
        Rcpp::Named("approximate") = res,
        Rcpp::Named("error_estimate") = err_est,
        Rcpp::Named("error_code") = err_code
      );
    }
    

    It gives the same result as pcubature:

    > Valegard()
    $approximate
    [1] 0.001323689
    
    $error_estimate
    [1] 9.893371e-14
    
    $error_code
    [1] 0
    

    By the way, an exact integration with Mathematica 11 also provides this result:

    Integrate[E^(16 x - 8877.04 (0.0145876 + y)^2 - 8 y), {y, -2, 2}, {x, -2.5, 0}]
    0.00132369
    
    0 讨论(0)
  • 2021-01-26 15:55

    It's also worth noting that in the integrate.c source file, the description for the error message is

    error messages
    ...
    ier = 5 the integral is probably divergent, or
        slowly convergent. it must be noted that
        divergence can occur with any other value of ier.
    

    so despite the fact the message says "probably-divergent" it seems with your code it is more likely to be slowly convergent.

    Also, you can continue to run when you get this message and extract the error if you set stop.on.error=FALSE

    r <- integrate(Vectorize(function(t) 
        integrate(function(g) ff(g,t), -2.5,0)$value
    ), -2, 2, stop.on.error=FALSE); 
    r$value
    

    R doesn't claim to be a fancy mathematical solver like the Wolfram products such as Mathematica. It doesn't do any symbolic simplifications of integrals and that's the kind of stuff that Wolfram's been perfecting over the years. if you're just looking to numerically solve a bunch of double integrals, programs like Mathematica or Maple are probably better choices. That just doesn't seem to be where R spends as much of its development resources.

    0 讨论(0)
  • 2021-01-26 16:00

    Your integrand is significantly nonzero only for a small range around y=0. From ?integrate

    When integrating over infinite intervals do so explicitly, rather than just using a large number as the endpoint. This increases the chance of a correct answer – any function whose integral over an infinite interval is finite must be near zero for most of that interval.

    While you're not strictly integrating over an infinite interval, the same numerical problem applies. And indeed:

    ff <- function(x, y)
    exp(16*x - 8*y - (-y - 0.01458757)^2/0.0001126501)
    
    f <- function(y)
    integrate(ff, lower=-2.5, upper=0, y=y)$value
    
    integrate(Vectorize(f), lower=-Inf, upper=Inf)
    0.001323689 with absolute error < 4.4e-08
    

    It's interesting that the answer is different to that obtained from Wolfram Alpha. I'm not sure who to trust here; on the one hand I've used R's integrate many times and haven't had problems (that I can tell); however as @MrFlick says R isn't a dedicated mathematical solver like Wolfram Alpha.

    You can also set the rel.tol convergence parameter to a more stringent value, say, 1e-7 or 1e-8. This is more important in the inner integral than the outer one, since errors in the former will propagate to the latter. In this case, it didn't make a difference to the final result.

    0 讨论(0)
提交回复
热议问题