问题
I have to calculate the double integral of the function:
> DIntegral <- function(x,y){res <- pnorm(x,1,0.1) * dexp(y-2,1.2)
return(res)
}
The upper limit for x and y are: 10
and Infinity
respectively.
The lower limit for x and y are: 1
and 2
respectively.
How can I do this double integration in RcppNumerical
?
For one dimensional integration my C++ file looks like:
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::depends(RcppNumerical)]]
#include <RcppNumerical.h>
using namespace Numer;
class PDF: public Func
{
private:
double beta;
double M0;
public:
PDF( double beta_, double M0_): beta(beta_), M0(M0_) {};
double operator()(const double& x) const
{
return R::dexp(x-M0,beta,0);
}
};
// [[Rcpp::export]]
double integrate_test2( double beta, double M0, double upper, double lower)
{
PDF f( beta, M0);
double err_est;
int err_code;
double res = integrate ( f, lower, upper,err_est,err_code);
return(res);
}
Code for 2 dimensional integration with finite limits
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::depends(RcppNumerical)]]
#include <RcppNumerical.h>
using namespace Numer;
class PDF: public MFunc
{
private:
double mu;
double sigma;
double beta;
double M0;
public:
PDF( double mu_, double sigma_, double beta_, double M0_): mu(mu_), sigma(sigma_), beta(beta_), M0(M0_) {};
double operator()(Constvec& x)
{
return R::pnorm(x[0],mu,sigma,1,0) * R::dexp(x[1]-M0,beta,0);
}
};
// [[Rcpp::export]]
double integrate_test2( double mu, double sigma, double beta, double M0)
{
Eigen::VectorXd lower(2);
lower << 1, 2;
Eigen::VectorXd upper(2);
upper << 10, 50;
PDF f( mu, sigma, beta, M0);
double err_est;
int err_code;
double err_est2;
int err_code2;
double res = integrate ( f, lower, upper,err_est,err_code);
return(res);
}
回答1:
I have updated your code to take the integration limits as arguments and to return the error code and estimate:
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::depends(RcppNumerical)]]
#include <RcppNumerical.h>
using namespace Numer;
class PDF: public MFunc
{
private:
double mu;
double sigma;
double beta;
double M0;
public:
PDF( double mu_, double sigma_, double beta_, double M0_): mu(mu_), sigma(sigma_), beta(beta_), M0(M0_) {};
double operator()(Constvec& x)
{
return R::pnorm(x[0],mu,sigma,1,0) * R::dexp(x[1]-M0,beta,0);
}
};
// [[Rcpp::export]]
Rcpp::List integrate_test2( double mu, double sigma, double beta, double M0, Eigen::VectorXd lower, Eigen::VectorXd upper)
{
PDF f( mu, sigma, beta, M0);
double err_est;
int err_code;
double res = integrate ( f, lower, upper,err_est,err_code);
return Rcpp::List::create(
Rcpp::Named("result") = res,
Rcpp::Named("error_estimate") = err_est,
Rcpp::Named("error_code") = err_code
);
}
/*** R
integrate_test2(1, 0.1, 1.2, 2, c(1, 2), c(10, 50))
integrate_test2(1, 0.1, 1.2, 2, c(1, 2), c(10, 1e4))
integrate_test2(1, 0.1, 1.2, 2, c(1, 2), c(10, 1e6))
integrate_test2(1, 0.1, 1.2, 2, c(1, 2), c(10, 1e8))
*/
Result:
> Rcpp::sourceCpp('2d_int.cpp')
> integrate_test2(1, 0.1, 1.2, 2, c(1, 2), c(10, 50))
$result
[1] 8.950068
$error_estimate
[1] 0.3570577
$error_code
[1] 1
> integrate_test2(1, 0.1, 1.2, 2, c(1, 2), c(10, 1e4))
$result
[1] 4.787999
$error_estimate
[1] 16.12484
$error_code
[1] 1
> integrate_test2(1, 0.1, 1.2, 2, c(1, 2), c(10, 1e6))
$result
[1] 1.605216e-314
$error_estimate
[1] 4.320299e-313
$error_code
[1] 0
> integrate_test2(1, 0.1, 1.2, 2, c(1, 2), c(10, 1e8))
$result
[1] 0
$error_estimate
[1] 0
$error_code
[1] 0
So for small values the upper limit of y, the integration does not converge. And when it does converge, the result is (nearly) zero. This does not change when one increases the upper limit up to about 1e307
, i.e. almost .Machine$double.xmax
. After that I get NaN
.
However, if I use the cubature
package the result is quite different:
library(cubature)
DIntegral <- function(x){
res <- pnorm(x[1],1,0.1) * dexp(x[2]-2,1.2)
return(res)
}
cubintegrate(f = DIntegral, lower = c(1, 2), upper = c(10, 50), method = "hcubature")
#> $integral
#> [1] 8.961023
#>
#> $error
#> [1] 4.888071e-05
#>
#> $neval
#> [1] 983
#>
#> $returnCode
#> [1] 0
cubintegrate(f = DIntegral, lower = c(1, 2), upper = c(10, 1000), method = "hcubature")
#> $integral
#> [1] 8.960415
#>
#> $error
#> [1] 7.145898e-05
#>
#> $neval
#> [1] 1701611595
#>
#> $returnCode
#> [1] 0
cubintegrate(f = DIntegral, lower = c(1, 2), upper = c(10, Inf), method = "hcubature")
#> $integral
#> [1] 8.960105
#>
#> $error
#> [1] 8.515124e-05
#>
#> $neval
#> [1] 1706522167
#>
#> $returnCode
#> [1] 0
I am not sure what is going on here.
来源:https://stackoverflow.com/questions/53648355/double-integral-in-rcppnumerical