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, ¶ms_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;
}
Related
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?
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.
Minimum of non-zero numbers:
#include <iostream>
#include <algorithm>
int main() {
double s1 = 1000;
double s2 = 400;
double s3 = 300;
double s4 = 10;
double minimum = std::min({s1, s2, s3, s4});
std::cout<<minimum<<"\n";
double var = 1/minimum;
std::cout<<var;
}
This works fine and returns:
10
0.1
Problem is when one of the numbers is zero:
#include <iostream>
#include <algorithm>
int main() {
double s1 = 1000;
double s2 = 400;
double s3 = 300;
double s4 = 0;
double minimum = std::min({s1, s2, s3, s4});
std::cout<<minimum<<"\n";
double var = 1/minimum;
std::cout<<var;
}
It returns:
0
inf
Expected results:
300
0.00333333
How can I ignore zero from the calculation?
Or like this
#include <algorithm>
#include <limits>
#include <vector>
template<std::size_t N>
constexpr double min_no_zero(const double (&values)[N])
{
static_assert(N>0,"There must be at least one number");
double min = std::numeric_limits<double>::max();
for (const auto value : values)
{
if ( value != 0.0 )
{
min = std::min(min, value);
}
}
return min;
}
int main()
{
constexpr double s1 = 1000.0;
constexpr double s2 = 400.0;
constexpr double s3 = 0.0;
constexpr double s4 = 10.0;
static_assert( min_no_zero({ s1, s2, s3, s4 }) == 10.0);
}
The std::min works as it should work if you have special requirements, you could pass a compare function with the following signature:
bool cmp(const Type1 &a, const Type2 &b);
as the second std::min function argument (the Compare template parameter):
#include <iostream>
#include <algorithm>
int main()
{
double s1 = 1000;
double s2 = 400;
double s3 = 300;
double s4 = 0;
auto const ignore_zero = [](auto const& a, auto const& b) -> bool {
if(0 == a)
{
return false;
}
else if(0 == b)
{
return true;
}
return a < b;
};
double minimum = std::min({s1, s2, s3, s4}, ignore_zero);
std::cout << minimum << "\n";
}
But it's strange, I suggest you if you have such special requirement with your code:
Try to redesign your program.
Use a function/functor helper:
#include <algorithm>
#include <iostream>
#include <vector>
namespace core::helper
{
template<typename T>
struct special_find final
{
std::vector<T> nums;
explicit special_find(std::initializer_list<T> nums_)
: nums(std::move(nums_))
{
}
auto min() const
{
return *std::min_element(nums.cbegin(), nums.cend());
}
special_find& ignore(T const& value)
{
nums.erase(std::remove_if(nums.begin(), nums.end(), [&value](auto const & item)
{
return item == value;
}), nums.end());
return *this;
}
};
} // namespace core::helper
int main()
{
double s1 = 1000;
double s2 = 400;
double s3 = 300;
double s4 = 0;
auto const min = core::helper::special_find({s1, s2, s3, s4}).ignore(0).min();
std::cout << min << "\n";
}
Make sure that you don't pass the 0s to min. I guess that's the only general answer without knowing how your input looks like.
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;
}
};
I'm trying to create an array of functors at compile time, like so: (complete file):
#include <functional>
using namespace std;
function< float( float tElevation, float pAzimuth )> colorFunctions[] = {
[]( float tElevation, float pAzimuth ) -> float {
return 2.0f ;
},
} ;
int main()
{
}
That works fine.
But as soon as you try to create a local inside the functor block, like this:
function< float( float tElevation, float pAzimuth )> colorFunctions[] = {
[]( float tElevation, float pAzimuth ) -> float {
float v = 2.0f ;
return v ;
},
} ;
You get Error 1 error C1506: unrecoverable block scoping error
How can I declare locals inside these blocks? It doesn't seem to work.
I can reproduce this on MSVC 2010, SP1. VS10 is known for some problems with lambdas and scoping. I've tried around a lot but found nothing beautiful. Ugly, ugly workaround that will have some initialization overhead but else work as intended:
#include <functional>
#include <boost/assign/list_of.hpp>
#include <vector>
using namespace std;
typedef function< float( float tElevation, float pAzimuth )> f3Func;
vector<f3Func const> const colorFunctions = boost::assign::list_of(
f3Func([]( float /*tElevation*/, float /*pAzimuth*/ ) -> float {
float v = 2.0f ;
return v ;
}))
([](float a, float b) -> float {
float someFloat = 3.14f;
return a*b*someFloat;
})
;
#include <iostream>
int main()
{
cout << colorFunctions[1](0.3f,0.4f) << '\n';
}
I compiled the following code on ubuntu 12.04 with the following line:
g++-4.7 -std=c++0x main.cpp
And it worked fine.
What platform and what compiler are you using?
#include <iostream>
#include <functional>
using namespace std;
function<float (float,float)> funcs[] = {
[] (float a, float b) -> float {
float c = 2.0f;
return c;
}
};
int main() {
std::cout << funcs[0](1,2) << std::endl;
}