GSL numerical integration for a function with no extra parameters - c++

I have a problem where I need to numerically integrate a univariate function with multiple extra inputs other than the variable that's being integrated over. The integration is from zero to infinity.
I said without extra parameters because I already defined a class with the extra parameters being the private member variables. And then the operator functor is defined to accept just the integration variable (hence, univariate). With this class, I want to use the GSL numerical integration library (gsl/gsl_integration.h) to do the integration. Is there a way to define a member function for this integration inside the class using GSL?
#include <cmath>
#include <Rmath.h>
#include <algorithm>
#include <iterator>
#include <RcppArmadillo.h>
#include <progress.hpp>
#include <progress_bar.hpp>
#include <RcppGSL.h>
#include <gsl/gsl_integration.h>
#include <Rdefines.h>
// [[Rcpp::depends(RcppArmadillo, RcppProgress, RcppGSL)]]
using namespace arma;
class ObservedLik
{
private:
const int& Tk;
const arma::vec& resid;
const arma::mat& ZEREZ_S;
const double& nu;
const double& maxll;
public:
ObservedLik(const int& Tk_,
const arma::vec& resid_,
const arma::mat& ZEREZ_S_,
const double& nu_,
const double& maxll_) : Tk(Tk_), resid(resid_), ZEREZ_S(ZEREZ_S_), nu(nu_), maxll(maxll_) {}
double operator()(const double& lam) const {
double loglik = -M_LN_SQRT_2PI * static_cast<double>(Tk) + (0.5 * nu - 1.0) * lam - 0.5 * nu * lam + 0.5 * nu * (std::log(nu) - M_LN2) - R::lgammafn(0.5 * nu);
double logdet_val;
double logdet_sign;
log_det(logdet_val, logdet_sign, ZEREZ_S);
loglik -= 0.5 * (logdet_val + arma::accu(resid % arma::solve(ZEREZ_S, resid)));
/***********************************
subtract by maximum likelihood value
for numerical stability
***********************************/
return std::exp(loglik - maxll);
}
double integrate() {
/* do the integration here */
gsl_integration_workspace * w
= gsl_integration_workspace_alloc (1000);
double result, error;
gsl_function F;
F.function = &f; // make this the operator()
F.params = α // I don't need this part
gsl_integration_qagiu (&F, 0.0, 0, 1, 0, 1e-7, 1000,
w, &result, &error);
return result;
}
};

I found a solution for this. The solution was to move away from GSL and use the Boost library. There is a Gauss-Kronrod quadrature function in Boost math library so this will do the job.
#include <cmath>
#include <Rmath.h>
#include <algorithm>
#include <iterator>
#include <RcppArmadillo.h>
#include <progress.hpp>
#include <progress_bar.hpp>
#include <boost/math/quadrature/gauss_kronrod.hpp>
#include "dic_nmr.h"
// [[Rcpp::depends(RcppArmadillo, RcppProgress, BH)]]
using namespace arma;
using namespace boost::math::quadrature;
class ObservedLik
{
private:
const int& Tk;
const arma::vec& resid;
const arma::mat& ZEREZ_S;
const double& nu;
const double& maxll;
public:
ObservedLik(const int& Tk_,
const arma::vec& resid_,
const arma::mat& ZEREZ_S_,
const double& nu_,
const double& maxll_) : Tk(Tk_), resid(resid_), ZEREZ_S(ZEREZ_S_), nu(nu_), maxll(maxll_) {}
double integrate_()(double lam) const {
double loglik = -M_LN_SQRT_2PI * static_cast<double>(Tk) + (0.5 * nu - 1.0) * lam - 0.5 * nu * lam + 0.5 * nu * (std::log(nu) - M_LN2) - R::lgammafn(0.5 * nu);
double logdet_val;
double logdet_sign;
log_det(logdet_val, logdet_sign, ZEREZ_S);
loglik -= 0.5 * (logdet_val + arma::accu(resid % arma::solve(ZEREZ_S, resid)));
/***********************************
subtract by maximum likelihood value
for numerical stability
***********************************/
return std::exp(loglik - maxll);
}
double integrate() {
/* do the integration here */
double error;
double Q = gauss_kronrod<double, 31>::integrate(integrate_, 0.0, std::numeric_limits<double>::infinity(), 5, 1e-14, &error);
return Q;
}
};

Related

How to use ceres-solver to solve high dimensional non-linear problem?

     I need to solve the optimization problem: . A and b are known. I use Zero to represent A and b to facilate the expression in the following code. The error is caused by problem.AddResidualBlock(cost_function, nullptr, &X); because the third argument needs to be double type and X is a vector with 50 elements. Can you give me some advice?
#include <cmath>
#include <ceres/ceres.h>
#include <Eigen/Core>
#include <Eigen/Eigen>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/StdVector>
#define PhaseNums 25
using namespace std;
using namespace ceres;
using namespace Eigen;
struct GammaResidual
{
GammaResidual(const MatrixXf A, const VectorXf b) : A_(A), b_(b) {}
template <typename T>
bool operator()(const T* const x, T* residual) const {
residual[0] = (A_ * x[0] - b_).transpose() * (A_ * x[0] - b_);
return true;
}
private:
const MatrixXf A_;
const VectorXf b_;
};
int main()
{
MatrixXf A = MatrixXf::Zero(2 * PhaseNums, 2 * PhaseNums);
VectorXf b = VectorXf::Zero(2 * PhaseNums);
VectorXf X = VectorXf::Zero(2 * PhaseNums);
Problem problem;
CostFunction* cost_function = new AutoDiffCostFunction<GammaResidual, 1, 1>(
new GammaResidual(A, b));
problem.AddResidualBlock(cost_function, nullptr, &X);
ceres::Solver::Options options;
options.minimizer_progress_to_stdout = true;
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
cout << summary.BriefReport() << endl;
}
I guess that If your X is a vector, you need to loop through it and add a residual a residual block for each x. Makes sense?

Numerical integration gives very different result from analytical expression

I'm trying to compute some thermal-averaged integral as defined in this reference. For the sake of the discussion, let's assume that the average of a quantity X looks like:
where M and T are parameters. Using Cubature, a simple C-package for adaptive multidimensional integration, I was able to implement these integrals.
The simplest case, X(k)=1, has the following analytical approximation I want to cross-check with my numerical integration:
where K2 is a modified Bessel function. Mathematica corroborated the approximation. The implementation of these numerical integrals (see below) seem to work well for dummy examples:
./main_nNeq 30 100
0.3 | 1.77268e+06 | 1.95712e+06
but my actual code would require very extreme values, where both values are quite different:
/main_nNeq 1e12 7.11258e17
1.40596e-06 | 4.92814e+46 | 7.19634e+53
Question: What could be the underlying issue here? Thanks!
My code (written in C++ for no particula reason) looks like this:
//
// COMPILING INSTRUCTIONS:
// g++ -o main_nNeq nNeq.cpp cubature-master/hcubature.c -lgsl -lm -lgslcblas -lgmp -std=c++11
//
// MORE INFO: http://ab-initio.mit.edu/wiki/index.php/Cubature_(Multi-dimensional_integration)
//
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <chrono>
#include <cmath>
#include <complex>
#include "cubature-master/cubature.h"
#include <gsl/gsl_sf_dilog.h>
#include <gsl/gsl_math.h>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/math/special_functions/bessel.hpp>
using namespace std;
#define SQR(x) ((x)*(x)) //x^2
#define CUB(x) ((x)*(x)*(x)) //x^3
#define K1(x) (boost::math::cyl_bessel_k(1.0, x)) //BesselK(1, x)
#define K2(x) (boost::math::cyl_bessel_k(2.0, x)) //BesselK(2, x)
//Momentum grid
const double log_kmin = -2;
const double log_kmax = 25;
const int Ngrid = 2000;
//Numerical constants
const double gw = 2.0;
const double PI = M_PI;
const double a_int = 0.0;
//Cosmological parameters
const double g_star = 106.75;
const double Mpl = 1.22e19; //GeV
const double aR = Mpl/2.0*sqrt(45.0/CUB(PI)/g_star); //as in Eq. (83), arXiv:1812.02651
const double Tcom = aR;
#define aa(eta) (aR*eta) //as in Eq. (82), arXiv:1812.02651
//f_F
double f_F(long double k, long double T, long double M){
long double root = SQR(k) + SQR(M);
root = isinf(root) ? k : sqrt(root);
long double expo = exp(root/T);
return isinf(expo) ? 0.0 : 1.0/(expo+1.0);
}
//n_N_eq
long double n_N_eq(double T, double M){
return SQR(M)*T*K2(M/T);
}
//integrand
double integrand__n_N_eq(double k, double T, double M){
return SQR(k)*f_F(k, T, M);
}
//integrator
struct fparams {
double M;
double T;
};
//function to be integrated
int inf_n_N_eq(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval){
struct fparams * fp = (struct fparams *)fdata;
//(void)(dim); /* avoid unused parameter warnings */
//(void)(params);
double M = fp->M;
double T = fp->T;
double t = x[0];
double aux = integrand__n_N_eq(a_int+t*pow(1.0-t, -1.0), T, M)*pow(1.0-t, -2.0);
if (!isnan(aux) && !isinf(aux))
{
fval[0] = aux;
}
else
{
fval[0] = 0.0;
}
return 0;
}
int main (int argc, char* argv[])
{
//Defining variables (M, T)
double M = stof(argv[1]); //command line argument
double T = stof(argv[2]); //command line argument
//range integration 1D
double xl[1] = { 0 };
double xu[1] = { 1 };
double nNeq, nNeq_ERR;
struct fparams params_nNeq = {M, T};
hcubature(1, inf_n_N_eq, &params_nNeq, 1, xl, xu, 0, 0, 1e-4, ERROR_INDIVIDUAL, &nNeq, &nNeq_ERR);
cout << M/T << " | " << nNeq << " | " << n_N_eq(T, M) << '\n';
return 0;
}

UnitTest C++ in VS (expected and actual values are the same but it's showing the mistake)

Why is it showing that the test failed, but the expected and actual values are the same? What is the problem?
#include "pch.h"
#include "CppUnitTest.h"
#include "../Lab 5_3/Lab 5_3.cpp"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace UnitTest53
{
TEST_CLASS(UnitTest53)
{
public:
TEST_METHOD(TestMethod1)
{
double t, g;
g = 1;
t = p(p(1 - 2 * g) + pow(p(1 - p(1) + (p(2 * g) * p(2 * g))), 2));
Assert::AreEqual(t, 0.320469);
}
};
}
Basically problems is that there is a rounding issue for floating point types. For details see this linked SO question.
Results of calculation should not be compared by equal operator, but some tolerance must be applied.
Now CppUnitTestFramework takes this into account and gives you a chance to provide this tolerance. So fix your test like this:
#include "pch.h"
#include "CppUnitTest.h"
#include "../Lab 5_3/Lab 5_3.cpp"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace UnitTest53
{
TEST_CLASS(UnitTest53)
{
public:
TEST_METHOD(TestMethod1)
{
double t, g;
g = 1;
t = p(p(1 - 2 * g) + pow(p(1 - p(1) + (p(2 * g) * p(2 * g))), 2));
Assert::AreEqual(t, 0.320469, 0.000001);
}
};
}
Reference: CppUnitTestFramework API documentation
Verify that two doubles are equal
static void Assert::AreEqual(
double expected,
double actual,
double tolerance,
const wchar_t* message = NULL,
const __LineInfo* pLineInfo = NULL)
Since you used only 2 arguments for AreEqual your code used this template:
template<typename T>
static void Assert::AreEqual(
const T& expected,
const T& actual,
const wchar_t* message = NULL,
const __LineInfo* pLineInfo = NULL)
which just uses equal operator.

ODEINT output to txt file instead of console

Is there a way to write the outputs of t and x of this example to a txt file instead of the console. Thanks!
This is the example I copied from Odeint website.
#include <iostream>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
/* we solve the simple ODE x' = 3/(2t^2) + x/(2t)
* with initial condition x(1) = 0.
* Analytic solution is x(t) = sqrt(t) - 1/t
*/
void rhs( const double x , double &dxdt , const double t )
{
dxdt = 3.0/(2.0*t*t) + x/(2.0*t);
}
void write_cout( const double &x , const double t )
{
cout << t << '\t' << x << endl;
}
// state_type = double
typedef runge_kutta_dopri5< double > stepper_type;
int main()
{
double x = 0.0;
integrate_adaptive( make_controlled( 1E-12 , 1E-12 , stepper_type() ) ,
rhs , x , 1.0 , 10.0 , 0.1 , write_cout );
}
you can simply pipe the output of this example into a text file
$ ./lorenz > data.txt
Otherwise you can use a C++ ofstreams to write the output directly into a file, e.g. described there: http://www.cplusplus.com/doc/tutorial/files/
just replace cout with object of ofstream.
#include <iostream>
#include <fstream>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
ofstream data("data.txt");
/* we solve the simple ODE x' = 3/(2t^2) + x/(2t)
* with initial condition x(1) = 0.
* Analytic solution is x(t) = sqrt(t) - 1/t
*/
void rhs(const double x, double &dxdt, const double t)
{
dxdt = 3.0 / (2.0*t*t) + x / (2.0*t);
}
void write_cout(const double &x, const double t)
{
data << t << '\t' << x << endl;
}
// state_type = double
typedef runge_kutta_dopri5< double > stepper_type;
int main()
{
double x = 0.0;
integrate_adaptive(make_controlled(1E-12, 1E-12, stepper_type()),
rhs, x, 1.0, 10.0, 0.1, write_cout);
}

GSL: Solving ODEs with time-dependent coefficients

I have an ODE of type:
x'(t) = a(t)x+g(t)
Which I am trying to solve. The only GSL ODE example isn't very helpful because the only coefficient (\mu) is not time dependent.
This question has been answered on the GSL mailing list however the answer is very unclear - g(t) is ignored and it has not been explained how to incorporate a(t) into func ( should it be passed in *params?).
Is there any example I can see where such an ODE is solved using GSL?
UPDATE: As has been pointed out below, this has been answered on the GSL mailing list. Here is a full example program of how this is done:
#include <stdio.h>
#include <math.h>
#include "gsl/gsl_errno.h"
#include "gsl/gsl_matrix.h"
#include "gsl/gsl_odeiv2.h"
int func(double t, const double y[], double f[], void *params) {
f[0] = -t* y[0];
return GSL_SUCCESS;
}
int jac(double t, const double y[], double *dfdy, double dfdt[], void
*params) {
gsl_matrix_view dfdy_mat = gsl_matrix_view_array(dfdy, 1, 1);
gsl_matrix * m = &dfdy_mat.matrix;
gsl_matrix_set(m, 0, 0, -t);
dfdt[0] = -1;
return GSL_SUCCESS;
}
int main(void) {
double mu = 0;
gsl_odeiv2_system sys = { func, jac, 1, &mu };
gsl_odeiv2_driver * d = gsl_odeiv2_driver_alloc_y_new(&sys,
gsl_odeiv2_step_rk1imp, 1e-7, 1e-7, 0.0);
int i;
double t = 0.0, t1 = 2.0;
const double x0 = 1.0;
double y[1] = {x0};
const int N = 100;
printf("time\t \tapprox solution \t exact solution\n");
for (i = 0; i <= N; i++) {
double ti = i * (t1 / N);
int status = gsl_odeiv2_driver_apply(d, &t, ti, y);
if (status != GSL_SUCCESS) {
printf("error, return value=%d\n", status);
break;
}
printf("%.5e\t%.5e\t\t%.5e\n", t, y[0], x0*exp(-0.5*t*t));
}
gsl_odeiv2_driver_free(d);
printf("\n...and done!\n");
return 0;
}
If you are not restricted to the GSL and/or C you can use http://odeint.com - a modern C++ library for ODEs. Odeint is part of boost, so it might be already installed on your system or can easily be installed be most of the package managers for Linux distributions.
You can simply define your coefficients and the ODE and use for example the RK4 method:
double coef_a( double t ) { /* return a(t) */ };
double coef_g( double t ) { /* return b(t) */ };
typedef std::array< double , 1 > state_type;
double ode( state_type const &x , state_type &dxdt , double )
{
dxdt[0] = coef_a( t ) * x[0] + coef_g( t );
}
state_type x;
double t_state , t_end , dt;
// initialize x
integrate_const( runge_kutta< state_type >() , ode , x , t_start , dt , t_end );