Divergent Integral in R is solvable in Wolfram

前端 未结 3 1316
梦毁少年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 
    #include 
    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
    

提交回复
热议问题