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

     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?

Related

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.

Using boost geometry to find intersection of line segments

I am trying to use the boost geometry method intersects with my own point class, successfully registered with the boost geometry library.
The boost documentation ( https://www.boost.org/doc/libs/1_73_0/libs/geometry/doc/html/geometry/reference/algorithms/intersection/intersection_3.html ) says that I can use a vector of points as the output parameter. So I wrote this:
#include <iostream>
#include <deque>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
namespace bg = boost::geometry;
using namespace std;
class cxy
{
public:
double x;
double y;
cxy( double X, double Y )
: x( X )
, y( Y )
{
}
/// boost geometry insists on a default constructor
cxy()
: cxy(0,0)
{
}
};
BOOST_GEOMETRY_REGISTER_POINT_2D( cxy, double, bg::cs::cartesian, x, y )
typedef bg::model::segment<cxy> segment_t;
int main()
{
cxy a(0,0);
cxy b(1,1);
cxy c(1,0);
cxy d(0,1) ;
std::vector<cxy> out;
//////////////// this compiles
bg::intersection(segment_t{a, b}, segment_t{c, d}, out);
//////////////// this does not!!!
segment_t ab( a, b );
segment_t cd( c, d );
bg::intersects( ab, cd, out );
return 0;
}
To be clear: my problem was that I was confused between intersection and intersects
The following code compiles and produces the expected results:
#include <iostream>
#include <deque>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
namespace bg = boost::geometry;
using namespace std;
class cxy
{
public:
double x;
double y;
cxy( double X, double Y )
: x( X )
, y( Y )
{
}
/// boost geometry insists on a default constructor
cxy()
: cxy(0,0)
{
}
};
BOOST_GEOMETRY_REGISTER_POINT_2D( cxy, double, bg::cs::cartesian, x, y )
typedef bg::model::segment<cxy> segment_t;
int main()
{
cxy a(0,0);
cxy b(1,1);
cxy c(1,0);
cxy d(0,1) ;
segment_t ab( a, b );
segment_t cd( c, d );
std::vector<cxy> out;
if( ! bg::intersection( ab, cd, out ) ) {
std::cout << "no intersection\n";
return 1;
}
std::cout << "intersection at " << out[0].x <<" " << out[0].y << "\n";
return 0;
}
You're asking "whether a intersects b".
However, your third argument suggests you wanted instead to ask for "the intersection":
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <iostream>
namespace bg = boost::geometry;
using namespace std;
struct cxy {
double x = 0;
double y = 0;
cxy(double X, double Y) : x(X), y(Y) {}
cxy() = default;
};
BOOST_GEOMETRY_REGISTER_POINT_2D(cxy, double, bg::cs::cartesian, x, y)
using segment_t = bg::model::segment<cxy>;
using points_t = bg::model::multi_point<cxy>;
int main() {
cxy a{0, 0}, b{1, 1}, c{1, 0}, d{0, 1};
std::vector<cxy> out;
bg::intersection(segment_t{a, b}, segment_t{c, d}, out);
// for output, use a multipoint model or register your vector as one
points_t pts;
bg::intersection(segment_t{a, b}, segment_t{c, d}, pts);
std::cout << bg::wkt(pts) << "\n";
}
Prints
MULTIPOINT((0.5 0.5))

Incomplete type error (E0409, E0070, E0515)

In my code Main.cpp I have the following shown below. The issue I am running into us with tuple<int, int, int>
I keep getting these three errors
function "sPA" returns incomplete type "trie", incomplete type is not allowed, and
cannot convert to incomplete class "trie"
What am I doing wrong here to make this error?
// Main.cpp
#include <iostream>
#include <string>
using namespace std;
typedef pair<int, int> int_pair;
typedef tuple<int, int, int> trie;
int_pair sum_and_product(int a, int b) {
return int_pair(a + b, a * b);
}
trie sPA(int a, int b, int c) {
trie t{ a + b + c,a * b * c,((a + b + c) / 3) };
return t;
}
void consuming_templates() {
int a = 2, b = 3, c = 4;
auto results = sum_and_product(a,b);
cout << "sum = " << results.first << "|product = " << results.second << endl;
auto r2 = sPA(a, b, c);
}
int main(int argc, char* argv[]) {
consuming_templates();
return 0;
}
idclev 463035818 and M.M has posted the comment to answer my question
You need to do #include <tuple> and #include <utility>

GSL numerical integration for a function with no extra parameters

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;
}
};