Optimising multi-dimensional functions with Ceres - c++

I want to use Ceres to optimise a function of n parameters. How to find the gradient of this function is unclear, although I do have a well defined cost. I have been using GSL so far, with numeric differentiation, but I thought I would try to use Ceres with automatic diff.
I have had a look at the toy example helloworld_analytic_diff.cc in which they use AutoDiff to minimise the function f(x) = 0.5 (10 - x)^2 and read the tutorial, so I thought I would try and extend this to the two dimensional function f(x,y) = (10-x)^2 +(20- y)^2, which has a global minimum at x, y = 10, 20. But I am getting a little stuck on this:
#include "ceres/ceres.h"
#include "glog/logging.h"
using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solver;
using ceres::Solve;
struct CostFunctor {
template <typename T> bool operator()(const T* const x, T* residual) const {
const T x1 = x[0];
const T y1 = x[1];
residual[0] = (10.0-x[0]) + (20.0-x[1]);
return true;
}
};
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
double x[2] = {0.5, -3.0};
const double initial_x[2] = {0.5, -3.0};
Problem problem;
CostFunction* cost_function = new AutoDiffCostFunction<CostFunctor, 1, 2>(new CostFunctor);
problem.AddResidualBlock(cost_function, NULL, &x[0]);
// Run the solver!
Solver::Options options;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
std::cout << "x : " << initial_x[0] << ", " << initial_x[0]
<< " -> " << x[0] << ", " << x[1]<< "\n";
return 0;
}
If I run this however, it winds up converging to something incorrect, depending on the initial guess:
Ceres Solver Report: Iterations: 3, Initial cost: 5.281250e+02, Final cost: 3.667046e-16, Termination: CONVERGENCE
x : 0.5, 0.5 -> 16.75, 13.25
Any ideas on what I've done wrong here?
Many thanks!

Your cost functor is wrong.
the optimization problem you are solving is
[(10.0-x) + (20.0-y)]^2
and not
(10-x)^2 +(20- y)^2,
what you should do here is to have two cost functors, something like as follows:
struct CostFunctor1 {
template <typename T> bool operator()(const T* const x, T* residual) const {
residual[0] = 10.0-x[0];
return true;
}
};
struct CostFunctor2 {
template <typename T> bool operator()(const T* const x, T* residual) const {
residual[0] = 20.0-x[1];
return true;
}
};
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
double x[2] = {0.5, -3.0};
const double initial_x[2] = {0.5, -3.0};
Problem problem;
problem.AddResidualBlock(new AutoDiffCostFunction<CostFunctor1, 1, 2>(new
CostFunctor1), NULL, &x[0]);
problem.AddResidualBlock(new AutoDiffCostFunction<CostFunctor2, 1, 2>(new
CostFunctor2), NULL, &x[0]);
// Run the solver!
Solver::Options options;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
std::cout << "x : " << initial_x[0] << ", " << initial_x[0]
<< " -> " << x[0] << ", " << x[1]<< "\n";
return 0;
}

Related

How to solve the following problem when I use Ceres Solver

When I run the following code in tutorial of ceres solver,I met some problem.
Here is the code:
#include <iostream>
#include "ceres/ceres.h"
#include "glog/logging.h"
using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solve;
using ceres::Solver;
struct CostFunctor {
template <typename T>
bool operator()(const T* const x, T* residual) const {
residual[0] = 10.0 - x[0];
return true;
}
};
int main(int argc, char *argv[])
{
double x = 0.5;
const double initial_x = x;
Problem problem;
CostFunction* cost_function =
new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, nullptr, &x);
Solver::Options options;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
std::cout << "x : " << initial_x << " -> " << x << "\n";
}
And I got the problem:
E:\study_materials\Computer Version\ceres\ceres-solver-2.0.0\internal\ceres\solver.cc:505 Terminating: Can't use SPARSE_NORMAL_CHOLESKY with Solver::Options::sparse_linear_algebra_library_type = SUITE_SPARSE, because support was not enabled when Ceres Solver was built.
I don't know how to enable this support,any assistance will be appreciated.
what version of ceres solver is this? if a sparse linear algebra library is not available, it should default to using a dense solver (DENSE_QR). So this looks like a bug in the way defaults are setup in ceres solver.

Generating floating point limits at compile time via template arguments and constexpr semantics:

I'm working on a set of classes. My Function class will take a Functor class which stores a function pointer to some defined function which has an operator that will invoke the function call from the function pointer. It uses a Limit class that currently takes <int,int> for its upper and lower bounds. It has nothing but static constexpr functions to return the bounds and to calculate the number of elements between those bounds. If the lower bounds = 1 and upper bounds = 5 it will generate 5 for the number of elements to be evaluated for that function...
Here is what I'm doing with these classes:
First I declare a function such as f(x) = x, f(x) = x^2, or f(x) = cos(x), etc.
Then I instantiate a Functor object based on the above function(s) parameter types both for the return and for its parameter-argument types...
Next, I assign the function to my Functor class's member variable.
Then I instantiate a Function object giving it the data-type and the Lower & Upper limits for the range of the function.
The Function class upon construction automatically generates the data points of that function from [lower,upper] and stores the generated values in its internal array.
The Function class also contains an operator that will allow the user to get any value from any given input.
Pseudo Example:
f(x) = x^2;
Functor<T,T> functor;
functor.member = &f(x);
Function<T,Lower,Upper,T> function(functor);
// If T=int, Lower = -4, and Upper = 4 then the internal data set will be
// (-4,16) (-3,9), (-2,4), (-1,1), (0,0), (1,1), (2,4), (3,9), (4,16)
// The user can also use it's operator to call function(9) and it will return 81
Here is my working program that is generating datasets of values from my classes using various functions:
main.cpp
#include <cmath>
#include <exception>
#include <iostream>
#include "Function.h"
int main() {
try {
pipes::Functor<int, int> functor1;
functor1.FuncPtr = &square;
pipes::Function<int, -10, 10, int> func1( functor1 );
auto data1{ func1.data() };
for (auto& p : data1)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func1(25) << "\n\n";
pipes::Functor<int, int> functor2;
functor2.FuncPtr = &linear;
pipes::Function<int, -10, 10, int> func2(functor2);
auto data2{ func2.data() };
for (auto& p : data2)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func2(25) << "\n\n";
pipes::Functor<double, double> functor3;
functor3.FuncPtr = &cosine;
pipes::Function<double, -7, 7, double> func3(functor3);
auto data3{ func3.data() };
for (auto& p : data3)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";
}
catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Function.h
#pragma once
#include <array>
namespace pipes {
template<typename Ret, typename... Args>
struct Functor {
Ret(*FuncPtr)(Args...);
Ret operator()(Args... args) { return FuncPtr(args...); }
};
template<int Lower, int Upper>
class Limits {
public:
static constexpr unsigned lower_bound() { return Lower; }
static constexpr unsigned upper_bound() { return Upper; }
static constexpr unsigned element_count() { return (Upper - Lower + 1); }
};
template<typename T, int Lower, int Upper, typename... Args>
class Function {
std::array<std::pair<T, T>, Limits<Lower,Upper>::element_count()> data_points_;
Functor<T,Args...> functor_;
public:
Function(Functor<T,Args...> func) {
functor_ = func;
for (unsigned i = 0; i < Limits<Lower,Upper>::element_count(); i++) {
data_points_[i].first = ((T)i + (T)Lower);
data_points_[i].second = functor_(data_points_[i].first);
}
}
T operator()(Args... args) const {
return functor_.FuncPtr(args...);
}
constexpr auto lower() const { return Lower; }
constexpr auto upper() const { return Upper; }
constexpr auto count() const { return Limits<Lower,Upper>::element_count(); }
constexpr auto data() const { return data_points_; }
};
} // namespace pipes
When I run the program it is generating this output which appears to be correct:
Output
(-10,100)
(-9,81)
(-8,64)
(-7,49)
(-6,36)
(-5,25)
(-4,16)
(-3,9)
(-2,4)
(-1,1)
(0,0)
(1,1)
(2,4)
(3,9)
(4,16)
(5,25)
(6,36)
(7,49)
(8,64)
(9,81)
(10,100)
f(25) = 625
(-10,-10)
(-9,-9)
(-8,-8)
(-7,-7)
(-6,-6)
(-5,-5)
(-4,-4)
(-3,-3)
(-2,-2)
(-1,-1)
(0,0)
(1,1)
(2,2)
(3,3)
(4,4)
(5,5)
(6,6)
(7,7)
(8,8)
(9,9)
(10,10)
f(25) = 25
(-7,0.753902)
(-6,0.96017)
(-5,0.283662)
(-4,-0.653644)
(-3,-0.989992)
(-2,-0.416147)
(-1,0.540302)
(0,1)
(1,0.540302)
(2,-0.416147)
(3,-0.989992)
(4,-0.653644)
(5,0.283662)
(6,0.96017)
(7,0.753902)
f(25) = 0.991203
And now for my question where this becomes the tricky part...
With my code currently the way it is, everything is fine as long as my bounds [-a,b] are of an integral type...
Let's suppose on my last example such as with cos, what if I want to have my bounds from [-2pi,2pi] where the lower and upper limits are of floating-point types...
The Issue:
Currently in C++ this is non-standard and in most cases won't compile:
template<float val> // or template<double>
struct foo() {
constexpr float operator()() {
return val;
}
};
And the above prevents me from doing something like this:
constexpr double PI{ 6.28318531 };
pipes::Functor<double, double> functor3;
functor3.FuncPtr = &cosine;
pipes::Function<double, -PI, PI, double> func3(functor3);
auto data3{ func3.data() };
for (auto& p : data3)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";
So if I want to be able to support floating-point types for my intervals of my Limits or Range class... What kind of alternative would there be if such a thing is currently possible in c++? Or would I just have to simply restructure the way my class templates are designed?
If the above is possible in some way during compile time via templates and constexpr semantics, then there is another issue that arises that will have to be taken into consideration and that would be the stepping interval for use with floating-point types to know how many data points there will be within the dataset... (basically calculating dx based on some stepping value which would be defined by the user, for example: (0.1, 0.001, etc...) and the number of data points would be calculated by the number of these divisions between [lower, upper]... However, if the stepping value is known at compile-time, then calculating the divisions should be simple enough... that's not a major concern. The bigger concern is being able to express floating-point constants at compile time for template evaluation...
Currently, with the way my code is with its design, I have hit a limit on its functionality... I'm not sure how to provide a similar interface to support a floating-point range that can be calculated and generated at compile time! Any bit of help or suggestions is welcomed!
I think the closest you can get to a construct like yours is:
#include <iostream>
#include <array>
constexpr const double PI_2{ 6.28318531 };
template<double const &lower, double const &upper>
void foo() {
static_assert(lower<upper, "invalid lower and upper value");
constexpr size_t size = (upper-lower);
std::array<int, size> test;
std::cout << lower << " " << upper << " " << test.size() << std::endl;
}
template<double const &V>
struct neg {
static constexpr double value = -V;
};
int main()
{
foo<neg<PI_2>::value, PI_2>();
return 0;
}
If you can always specify the type as first template argument you could have something like this:
template<typename T, T const &lower, T const &upper>
void foo() {
std::cout << lower << " " << upper << std::endl;
}
I didn't fully think it through, how to get the floating-point part and the other together, but I think it should be possible.
In modern C++ and how templates are currently designed, I had to slightly restructure my code. It's forcing me to have to use std::vector instead of std::array, because we can't use floating-point types as constant template arguments... So I ended up having to change two of my classes... I had to change my Limits class, and my Function class.
My Limits class now accepts a Type instead of constant-integral-type and it stores 3 member variables. It also has a default constructor and a user constructor. The functions are now just constexpr instead of being static.
My Function class now stores a Limits class object and data_points_ is no longer an std::array as it is now std::vector. It's constructor now also takes in a Limits object.
I had also taken into account for the step size for floating-point ranges.
Here is what my modified code looks like with its given output:
main.cpp
#include <cmath>
#include <iostream>
#include <exception>
#include "Function.h"
constexpr int square(int x) {
return x * x;
}
constexpr int linear(int x) {
return x;
}
double cosine(double x) {
return cos(x);
}
//template<float val>
struct foo {
float operator()(float val) { return val; }
};
int main() {
try {
pipes::Functor<int, int> functor1;
pipes::Limits<int> limit1(-10, 10, 1);
functor1.FuncPtr = &square;
pipes::Function<int, int, int> func1( limit1, functor1 );
auto data1{ func1.data() };
for (auto& p : data1)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func1(25) << "\n\n";
pipes::Functor<int,int> functor2;
pipes::Limits<int> limit2(-10, 10, 1);
functor2.FuncPtr = &linear;
pipes::Function<int, int, int> func2(limit2, functor2);
auto data2{ func2.data() };
for (auto& p : data2)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func2(25) << "\n\n";
constexpr double PI{ 6.28318531 };
pipes::Functor<double, double> functor3;
pipes::Limits<double> limits3( (-PI), PI, 0.1);
functor3.FuncPtr = &cosine;
pipes::Function<double, double, double> func3(limits3, functor3);
auto data3{ func3.data() };
for (auto& p : data3)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";
}
catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Function.h
#pragma once
#include <vector>
namespace pipes {
template<typename Ret, typename... Args>
struct Functor {
Ret(*FuncPtr)(Args...);
Ret operator()(Args... args) { return FuncPtr(args...); }
};
template<typename Ty>
class Limits {
private:
Ty Lower;
Ty Upper;
Ty Step;
public:
Limits() {}
Limits(Ty lower, Ty upper, Ty step) : Lower{ lower }, Upper{ upper }, Step{ step } {}
constexpr Ty lower_bound() { return Lower; }
constexpr Ty upper_bound() { return Upper; }
constexpr Ty step_size() { return Step; }
constexpr unsigned element_count() { return (unsigned)((Upper - Lower + 1)/Step); }
};
template<typename LimT, typename FuncT, typename... Args>
class Function {
Limits<LimT> limits_;
Functor<FuncT, Args...> functor_;
std::vector<std::pair<FuncT, FuncT>> data_points_;
public:
Function(Limits<LimT> limits, Functor<FuncT,Args...> func) {
limits_ = limits;
functor_ = func;
data_points_.resize( limits_.element_count() );
for (unsigned i = 0; i < limits_.element_count(); i++) {
auto x = limits_.lower_bound() + (i * limits_.step_size());
data_points_[i].first = (x);
data_points_[i].second = functor_(x);
}
}
FuncT operator()(Args... args) const {
return functor_.FuncPtr(args...);
}
constexpr auto lower() const { return limits_.lower_bound(); }
constexpr auto upper() const { return limits_.upper_bound(); }
constexpr auto count() const { return limits_.element_count(); }
constexpr auto step() const { return limits_.step_size(); }
constexpr auto data() const { return data_points_; }
};
} // namespace pipes
Output
(-10,100)
(-9,81)
(-8,64)
(-7,49)
(-6,36)
(-5,25)
(-4,16)
(-3,9)
(-2,4)
(-1,1)
(0,0)
(1,1)
(2,4)
(3,9)
(4,16)
(5,25)
(6,36)
(7,49)
(8,64)
(9,81)
(10,100)
f(25) = 625
(-10,-10)
(-9,-9)
(-8,-8)
(-7,-7)
(-6,-6)
(-5,-5)
(-4,-4)
(-3,-3)
(-2,-2)
(-1,-1)
(0,0)
(1,1)
(2,2)
(3,3)
(4,4)
(5,5)
(6,6)
(7,7)
(8,8)
(9,9)
(10,10)
f(25) = 25
(-6.28319,1)
(-6.18319,0.995004)
(-6.08319,0.980067)
(-5.98319,0.955336)
(-5.88319,0.921061)
(-5.78319,0.877583)
(-5.68319,0.825336)
(-5.58319,0.764842)
(-5.48319,0.696707)
(-5.38319,0.62161)
(-5.28319,0.540302)
(-5.18319,0.453596)
(-5.08319,0.362358)
(-4.98319,0.267499)
(-4.88319,0.169967)
(-4.78319,0.0707372)
(-4.68319,-0.0291995)
(-4.58319,-0.128844)
(-4.48319,-0.227202)
(-4.38319,-0.32329)
(-4.28319,-0.416147)
(-4.18319,-0.504846)
(-4.08319,-0.588501)
(-3.98319,-0.666276)
(-3.88319,-0.737394)
(-3.78319,-0.801144)
(-3.68319,-0.856889)
(-3.58319,-0.904072)
(-3.48319,-0.942222)
(-3.38319,-0.970958)
(-3.28319,-0.989992)
(-3.18319,-0.999135)
(-3.08319,-0.998295)
(-2.98319,-0.98748)
(-2.88319,-0.966798)
(-2.78319,-0.936457)
(-2.68319,-0.896758)
(-2.58319,-0.8481)
(-2.48319,-0.790968)
(-2.38319,-0.725932)
(-2.28319,-0.653644)
(-2.18319,-0.574824)
(-2.08319,-0.490261)
(-1.98319,-0.400799)
(-1.88319,-0.307333)
(-1.78319,-0.210796)
(-1.68319,-0.112153)
(-1.58319,-0.0123887)
(-1.48319,0.087499)
(-1.38319,0.186512)
(-1.28319,0.283662)
(-1.18319,0.377978)
(-1.08319,0.468517)
(-0.983185,0.554374)
(-0.883185,0.634693)
(-0.783185,0.70867)
(-0.683185,0.775566)
(-0.583185,0.834713)
(-0.483185,0.88552)
(-0.383185,0.927478)
(-0.283185,0.96017)
(-0.183185,0.983268)
(-0.0831853,0.996542)
(0.0168147,0.999859)
(0.116815,0.993185)
(0.216815,0.976588)
(0.316815,0.950233)
(0.416815,0.914383)
(0.516815,0.869397)
(0.616815,0.815725)
(0.716815,0.753902)
(0.816815,0.684547)
(0.916815,0.608351)
(1.01681,0.526078)
(1.11681,0.438547)
(1.21681,0.346635)
(1.31681,0.25126)
(1.41681,0.153374)
(1.51681,0.0539554)
(1.61681,-0.0460021)
(1.71681,-0.1455)
(1.81681,-0.243544)
(1.91681,-0.339155)
(2.01681,-0.431377)
(2.11681,-0.519289)
(2.21681,-0.602012)
(2.31681,-0.67872)
(2.41681,-0.748647)
(2.51681,-0.811093)
(2.61681,-0.865435)
(2.71681,-0.91113)
(2.81681,-0.947722)
(2.91681,-0.974844)
(3.01681,-0.992225)
(3.11681,-0.999693)
(3.21681,-0.997172)
(3.31681,-0.984688)
(3.41681,-0.962365)
(3.51681,-0.930426)
(3.61681,-0.889191)
(3.71681,-0.839072)
(3.81681,-0.780568)
(3.91681,-0.714266)
(4.01681,-0.640826)
(4.11681,-0.560984)
(4.21681,-0.475537)
(4.31681,-0.385338)
(4.41681,-0.291289)
(4.51681,-0.19433)
(4.61681,-0.0954289)
(4.71681,0.0044257)
(4.81681,0.104236)
(4.91681,0.203005)
(5.01681,0.299745)
(5.11681,0.393491)
(5.21681,0.483305)
(5.31681,0.56829)
(5.41681,0.647596)
(5.51681,0.720432)
(5.61681,0.78607)
(5.71681,0.843854)
(5.81681,0.893206)
(5.91681,0.933634)
(6.01681,0.964733)
(6.11681,0.986192)
(6.21681,0.997798)
(6.31681,0.999435)
(6.41681,0.991085)
(6.51681,0.972833)
(6.61681,0.94486)
(6.71681,0.907447)
(6.81681,0.860967)
(6.91681,0.805884)
(7.01681,0.742749)
(7.11681,0.672193)
f(25) = 0.991203
This is giving me the behavior that I want, however, I was trying to do the same thing using array... I'm guessing until C++ supports floating-point-constants as template arguments I'm going to have to settle with std::vector using heap allocations, instead of std::array and stack-cache friendly containers...

How to pass some constants in Boosts's brent_find_minima()?

How can I pass some constants in boost::math::tools::brent_find_minima() from main()?
struct func
{
template <class T>
T operator()(T const& x)
{ //
T Wnew = 20.0/9.0*720.0; // Goal is to pass it through main()
T W = 2500; // Goal is to pass it through main()
return abs(Wnew/2/x - atan(W/2/x));
}
};
int main(int argc, char **argv)
{
// How can I pass Wnew and W values while calling boost::math::tools::brent_find_minima() from main()
std::pair<double, double> r = boost::math::tools::brent_find_minima(func(), 1.0, 2000.0, std::numeric_limits<double>::digits);
std::cout.precision(std::numeric_limits<double>::digits10);
std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second << std::endl;
}
I suppose what you want is to create different instances of func with different values for W and Wnew. You are almost there, just give your func some state:
struct func
{
double Wnew;
double W;
func(double Wnew, double W) : Wnew(Wnew),W(W) {}
double operator()(double const& x)
{
return abs(Wnew/2/x - atan(W/2/x));
}
};
And then create an instance like this:
double Wnew = 1.0;
double W = 2.0;
auto r = boost::math::tools::brent_find_minima(func(Wnew,W), 1.0, 2000.0, std::numeric_limits<double>::digits);
// ^^
I was a bit puzzled by your operator() being a template and changed that. If you had good reasons for it, simply make it a template again.
PS: Since C++11, there are lambda expressions that allow a much terser syntax for functors.
I like the lambda approach the best:
#include <cmath>
#include <iostream>
#include <boost/math/tools/minima.hpp>
int main(int argc, char **argv)
{
double W = 2500;
double Wnew = 20.0/9.0*720.0;
if (argc == 3) {
double W = std::stod(argv[1]);
double Wnew = std::stod(argv[2]);
}
auto f = [&W, &Wnew](double x)->double {
return std::abs(Wnew/2/x - atan(W/2/x));
};
std::pair<double, double> r = boost::math::tools::brent_find_minima(f, 1.0, 2000.0, std::numeric_limits<double>::digits);
std::cout.precision(std::numeric_limits<double>::digits10);
std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second << std::endl;
}
The documentation for brent_find_minima was written pre-C++11, and uses what now should be regarded as overly verbose syntax. The post C++11 boost.math documentation examples (like the quadrature routines) all use lambdas.

ceres solver: how to do data type transformation and operation in operator

I am trying to use ceres solver to optimize the point cloud transformation process.
Through following the samples from ceres solver tutorial, I got a simple working version of the optimization process. However, when I try to further modify the function in operator (in MyCostFunctor class), the results are totally wrong (the solver converges, but gives wrong results). I found the problem is caused by the two lines of codes where I was trying to convert the parameters from template type T to Eigen matrix type.
Here are the codes:
template<typename T> inline
void DataTransfer(const T* input, Eigen::Matrix<T, Eigen::Dynamic, 1>& output) {
for (int i = 0; i < 12; ++i) {
output[i] = input[i];
}
}
template<typename T, typename PtT> inline
T* GetCorrespondingPoint(const T* rot, const PtT pt) {
//**!!!!!!!!!!! Error !!!!!!!!!!!**
//Eigen::Matrix<T, Eigen::Dynamic, 1> param_vecs = Eigen::Matrix<T, Eigen::Dynamic, 1>::Zero(12);
//DataTransfer<T>(rot, param_vecs);
// **!!!!!!!!!! Error !!!!!!!!!!!**
T result[3];
result[0] = rot[0] * T(pt(0)) + rot[1] * T(pt(1)) + rot[2] * T(pt(2)) + rot[9];
result[1] = rot[3] * T(pt(0)) + rot[4] * T(pt(1)) + rot[5] * T(pt(2)) + rot[10];
result[2] = rot[6] * T(pt(0)) + rot[7] * T(pt(1)) + rot[8] * T(pt(2)) + rot[11];
return result;
}
// A cost functor that implements the residual r = x - y.
// where x = R*x' + T or add more operations such as x = C*inverse((R*x')*A + T*B), A, B, C are related vectors or matrices
template<typename PtT>
class MyCostFunctor {
public:
MyCostFunctor(PtT& x, PtT& y, int pt_id)
:x_(x), y_(y), idx_(pt_id) {
}
template<typename T>
bool operator()(const T* const params, T* residual) const {
// Data transformation
T* rslt;
rslt = GetCorrespondingPoint<T, PtT>(params, x_);
residual[0] = T(rslt[0] - y_(0));
residual[1] = T(rslt[1] - y_(1));
residual[2] = T(rslt[2] - y_(2));
return true;
}
private:
PtT x_; // source point
PtT y_; // target point
int idx_; // source point idx
};
The two lines of codes are commented out in function "GetCorrespondingPoint".
The code of the main function are as follows:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <Eigen/Dense>
#include "ceres/ceres.h"
#include "glog/logging.h"
#include "ceres/dynamic_autodiff_cost_function.h"
using ceres::NumericDiffCostFunction;
using ceres::AutoDiffCostFunction;
using ceres::SizedCostFunction;
using ceres::CENTRAL;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solver;
using ceres::Solve;
int main(int argc, char** argv){
google::InitGoogleLogging(argv[0]);
// 1. Sample Data Set Up
std::vector<Eigen::Vector3d> model_pts;
model_pts.clear();
std::vector<Eigen::Vector3d> target_pts;
target_pts.clear();
model_pts.push_back(Eigen::Vector3d(10.0, 10.0, 10.0));
model_pts.push_back(Eigen::Vector3d(20.0, 10.0, 10.0));
model_pts.push_back(Eigen::Vector3d(10.0, 20.0, 10.0));
model_pts.push_back(Eigen::Vector3d(10.0, 10.0, 20.0));
target_pts.push_back(Eigen::Vector3d(40.0, 40.0, 40.0));
target_pts.push_back(Eigen::Vector3d(40.0, 30.0, 40.0));
target_pts.push_back(Eigen::Vector3d(30.0, 40.0, 40.0));
target_pts.push_back(Eigen::Vector3d(40.0, 40.0, 30.0));
/// Set up the index for pairing the model and target points
std::vector<int> pt_idx;
pt_idx.push_back(0);
pt_idx.push_back(1);
pt_idx.push_back(2);
pt_idx.push_back(3);
// print pts
std::cout << "Model pts\t\tTarget pts\n";
for (int i = 0; i < model_pts.size(); ++i) {
std::cout << model_pts[i](0) << " " << model_pts[i](1) << " " << model_pts[i](2) << "\t\t\t"
<< target_pts[i](0) << " " << target_pts[i](1) << " " << target_pts[i](2) << "\n";
}
// Parameter Set up
double params[12];
for (int i = 0; i < 12; ++i) {
params[i] = 1.0;
}
// Set up the problem
int num_pts = target_pts.size();
Problem problem;
for (int i = 0; i < num_pts; ++i) {
problem.AddResidualBlock(
new AutoDiffCostFunction<MyCostFunctor<Eigen::Vector3d>, 3, 12>(new MyCostFunctor<Eigen::Vector3d>(model_pts[i], target_pts[i], pt_idx[i])), NULL,&params[0]);
}
// Set the solver options
ceres::Solver::Options options;
options.minimizer_progress_to_stdout = true;
// Run the solver!
ceres::Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.FullReport() << "\n\n";
// print results
std::cout << "test results: \n";
for (int i = 0; i < model_pts.size(); ++i) {
Eigen::Vector3d pt;
pt(0) = params[0]*model_pts[i](0) + params[1]*model_pts[i](1) + params[2]*model_pts[i](2) + params[9];
pt(1) = params[3]*model_pts[i](0) + params[4]*model_pts[i](1) + params[5]*model_pts[i](2) + params[10];
pt(2) = params[6]*model_pts[i](0) + params[7]*model_pts[i](1) + params[8]*model_pts[i](2) + params[11];
std::cout << pt(0) << " " << pt(1) << " " << pt(2) << "\n";
}
return 0;
}
If I comment out the two lines, I will get right results:
results before data transfer
However, when I am trying to transfer the parameters into Eigen formate with those two lines of codes (NOT BEEN USED in the function, only copy and transfer), I will get the wrong results:
results after data transfer
Can anyone help me to figure out what's the problem and what should I do if I want to do some operation on the parameters to get the right corresponding points? Thanks!
Your code for the residual uses the matrix rot in row-major form, while Eigen defaults to column-major form:
https://eigen.tuxfamily.org/dox/group__TopicStorageOrders.html

What is the purpose of std::rank?

I just ran into std::rank and I don't really understand what it could be used for. I understand what it does, but can someone please give me a few use cases for it? I wasn't able to find anything useful on a search here.
Nice question.
I'm trying to learn C++11, so I could write something silly but ... suppose you want find the maximum value in a multidimensional array.
I tried to answer this question with std::rank (and SFINAE)
#include <iterator>
#include <iostream>
#include <type_traits>
template <typename X,
typename = typename std::enable_if<0U == std::rank<X>::value>::type>
X maxRank (X const & x)
{ return x; }
template <typename X,
typename = typename std::enable_if<0U != std::rank<X>::value>::type>
typename std::remove_all_extents<X>::type maxRank (X const & x)
{
auto it = std::begin(x);
auto ret = maxRank(*it);
for ( ; it != std::end(x) ; ++it )
{
auto val = maxRank(*it);
if ( val > ret )
ret = val;
}
return ret;
}
int main ()
{
int a0 = 12;
short a1[] = { 23, 7, 42, -19, 0, 95 };
unsigned a2[][2] = { {8U, 9U}, {0U, 77U}, {11U, 9U}, {5U, 3U} };
long a3[][3][2] = { { {123L, 3L}, {-45L, 77L}, {-12L, 678L} },
{ {1L, -54L}, {23L, 99L}, {56L, 1234L} },
{ {-4L, -12L}, {1L, 0L}, {122L, 19L} },
{ {2L, 23L}, {55L, 19L}, {2L, 99L} } };
std::cout << "maxRank a0 = " << maxRank(a0) << '\n';
std::cout << "maxRank a1 = " << maxRank(a1) << '\n';
std::cout << "maxRank a2 = " << maxRank(a2) << '\n';
std::cout << "maxRank a3 = " << maxRank(a3) << '\n';
return 0;
}