I want to fit dlib's LDA on my training set and apply the transformation to both the training and testing set. I wrote following minimal example to reproduce the problem. If you delete the sections that uses LDA, it should output a meaningful prediction.
#include <iostream>
#include <vector>
#include <dlib/svm.h>
int main() {
typedef dlib::matrix<float, 2, 1> sample_type;
typedef dlib::radial_basis_kernel<sample_type> kernel_type;
dlib::svm_c_trainer<kernel_type> trainer;
trainer.set_kernel(kernel_type(0.5f));
trainer.set_c(1.0f);
std::vector<sample_type> samples_train;
std::vector<float> labels_train;
std::vector<sample_type> samples_test;
std::vector<float> labels_test;
sample_type sample;
float label;
label = -1;
sample(0) = -1;
sample(1) = -1;
samples_train.push_back(sample);
labels_train.push_back(label);
label = 1;
sample(0) = 1;
sample(1) = 1;
samples_train.push_back(sample);
labels_train.push_back(label);
label = 1;
sample(0) = 0.5;
sample(1) = 0.5;
samples_test.push_back(sample);
labels_test.push_back(label);
// Fit LDA on training data
dlib::matrix<sample_type> X;
dlib::matrix<sample_type,0,1> mean;
dlib::compute_lda_transform(X, mean, labels_train);
// Apply LDA on train data
for (auto &sample_train : samples_train){
sample_train = X * sample_train;
}
// Apply LDA on test data
for (auto &sample_test : samples_test){
sample_test = X * sample_test;
}
auto predictor = trainer.train(samples_train, labels_train);
std::cout << "Train Sample 1: " << predictor(samples_train[0]) << ", label: " << labels_train[0] << std::endl;
std::cout << "Train Sample 2: " << predictor(samples_train[1]) << ", label: " << labels_train[1] << std::endl;
std::cout << "Test Sample: " << predictor(samples_test[0]) << ", label: " << labels_test[0] << std::endl;
}
Error:
cannot convert 'labels_train' (type 'std::__debug::vector<float>') to type 'const std::__debug::vector<long unsigned int>&'
But if the labels are not of the same type as the samples, the SVM throws an error. I could not find any example on dlib's github repository.
You should use two set of labels, one being of type long unsigned for the lda and another of type float for your SVM
Related
I need to pass structure to the function Constraint::AddFixedOrientationAxis, however when I check the passed data their values are completely wrong. I have tried to use different datatypes but without any luck.
typedef struct{
size_t idx;
size_t axis_idx;
double axis_vector_1;
double axis_vector_2;
double axis_vector_3;
}AddFixedOrientationAxisData;
double Constraint::AddFixedOrientationAxis(const std::vector<double> &x, std::vector<double> &grad, void *data)
{
Eigen::VectorXd fixed_rot(3);
AddFixedOrientationAxisData *d = reinterpret_cast<AddFixedOrientationAxisData*>(data);
auto idx = d->idx;
auto axis_idx = d->axis_idx; // 0->x, 1->y, 2->z
fixed_rot << d->axis_vector_1, d->axis_vector_2, d->axis_vector_3;
std::cout << "idx: " << idx << std::endl;
std::cout << "axis: " << axis_idx << std::endl;
std::cout << "fixed_rot: " << fixed_rot << std::endl;
}
In the main, I call use it the same way as the tutorial is:
AddFixedOrientationAxisData fixed_orient_constraint_data;
fixed_orient_constraint_data.idx = 0;
fixed_orient_constraint_data.axis_idx = 0;
fixed_orient_constraint_data.axis_vector_1 = FK_q(0,0);
fixed_orient_constraint_data.axis_vector_2 = FK_q(1,0);
fixed_orient_constraint_data.axis_vector_3 = FK_q(2,0);
opt.add_equality_constraint(Constraint::AddFixedOrientationAxis, &fixed_orient_constraint_data);
The terminal output is:
idx: 93901286131024
axis: 93901286131080
fixed_rot:
4.63934e-310
-0.54938 //interestingly, this is the correct value
0.00838157 //interestingly, this is the correct value
As #{Some programmer dude} told me in the comments, the problem was that the variable was not alive when the function was called.
I am a beginner to ITK and c++. I have the following code where I can get the height and width of an image. Instead of giving the input image in the console, I want to do it in the code itself. How do I directly give the input image to this code?
#include "itkImage.h"
#include "itkImageFileReader.h"
int main()
{
mat m("filename");
imshow("windowname", m);
}
// verify command line arguments
if( argc < 2 )
{
std::cout << "usage: " << std::endl;
std::cerr << argv[0] << " inputimagefile" << std::endl;
return exit_failure;
}
typedef itk::image<float, 2> imagetype;
typedef itk::imagefilereader<imagetype> readertype;
readertype::pointer reader = readertype::new();
reader->setfilename( argv[1] );
reader->update();
std::cout << reader->getoutput()->getlargestpossibleregion().getsize()[0] << " "
<< reader->getoutput()->getlargestpossibleregion().getsize()[1] << std::endl;
// an example image had w = 200 and h = 100 (it is wider than it is tall). the above output
// 200 100
// so w = getsize()[0]
// and h = getsize()[1]
// a pixel inside the region
itk::index<2> indexinside;
indexinside[0] = 150;
indexinside[1] = 50;
std::cout << reader->getoutput()-
>getlargestpossibleregion().isinside(indexinside) << std::endl;
// a pixel outside the region
itk::index<2> indexoutside;
indexoutside[0] = 50;
indexoutside[1] = 150;
std::cout << reader->getoutput()- >getlargestpossibleregion().isinside(indexoutside) << std::endl;
// this means that the [0] component of the index is referencing the left to right (column) index
// and the [1] component of index is referencing the top to bottom (row) index
return exit_success;
}
Change the line reader->setfilename( argv[1] ); by reader->setfilename( "C:/path/to/file.png" );
I assume that
mat m("filename");
imshow("windowname", m);
sneaked in from some unrelated code? Otherwise the example would not compile.
I have an artificial matrix which I pass to the EM Gaussian Mixture Model algorithm in OpenCV - version 3.0.0 of the form :
[1.1, 3.2;
1.15, 3.1500001;
3.0999999, 4.1999998;
3.2, 4.3000002;
5, 5]
I call the GMM prediction via:
cv::Ptr<cv::ml::EM> source_model = cv::ml::EM::create();
source_model->setClustersNumber(3);
cv::Mat logs;
cv::Mat labels;
cv::Mat probs;
source_model->trainEM( openCVPointCloud,logs,labels,probs)
The documentation states about the matrix labels which I am interested in:
labels – The optional output 'class label' for each sample:
labels_i = {arg max}k(p{i,k}), i=1..N (indices of the most probable mixture component for each sample). It has nsamples x 1 size and 'CV_32SC1' type.
My non working access to 'labels' prints (0,0,0,0,0) instead of expected (0,0,1,1,2) which is plotted via
std::cout << labels <<std::endl;
. I need though working with the integer indices to work with my original PCL point cloud which I want to cluster via poitn cloud features:
std::cout << labels.data[0] << std::endl;
std::cout << labels.data[1] << std::endl;
std::cout << labels.data[2] << std::endl;
std::cout << labels.data[3] << std::endl;
std::cout << labels.data[4] << std::endl;
The code fragments wrapped together in an untested minimal example (I have problems with qmake without using my frame work):
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/ml.hpp>
int main()
{
cv::Mat openCVPointCloud(5, 2, CV_32FC(1));
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(0,0);
values1.val[0] = 1.1;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(0,1);
values2.val[0] = 3.2;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(1,0);
values1.val[0] = 1.15;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(1,1);
values2.val[0] = 3.15;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(2,0);
values1.val[0] = 3.1;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(2,1);
values2.val[0] = 4.2;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(3,0);
values1.val[0] = 3.2;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(3,1);
values2.val[0] = 4.3;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(4,0);
values1.val[0] = 5;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(4,1);
values2.val[0] = 5;
}
std::cout << openCVPointCloud << std::endl;
cv::Ptr<cv::ml::EM> source_model = cv::ml::EM::create();
source_model->setClustersNumber(3);
cv::Mat logs;
cv::Mat labels;
cv::Mat probs;
if(source_model->trainEM( openCVPointCloud,logs,labels,probs))
{
std::cout << "true train em";
std::cout << labels.data[0] << std::endl;
std::cout << labels.data[1] << std::endl;
std::cout << labels.data[2] << std::endl;
std::cout << labels.data[3] << std::endl;
std::cout << labels.data[4] << std::endl;
} else {
std::cout <<"false train em" << std::endl;
}
}
What can I do to get access to the integer numbers stored in labels?
This stackexchange topic states, that if I know the matrix element type I can use the templated at() function. The api states that the label Matrix is of type $CV_32SC1$. Accessing now via:
std::cout << labels.at<CV_32SC1>(2,0) << std::endl;
Results in the following error:
invalid template argument for '_Tp', type expected
At the time of creation of this question I was also 100% sure I tested
std::cout << labels.at<int>(2,0) << std::endl;
also which plotted 0 (and should have been 1). Code in front of me after accepted answer adaptian though prooves me wrong. Might be a duplicate because of a typo I did not see for some hours and the "typo" might have been QT's qdebug() usage instead of std::cout. If still considered valuable someone might improve the constructor in the minimal example I provided and remove this sentence and the following. I still hope for a one line solution which I yet failed to perform.
Proper way to print Mat value is to use operator<<. You already have it.
Your cv::Mat labels has type CV_32SC1. It contain 32 bit signed integer elements. So you can access items by labels.at<int> method.
Better way to access items is to use iterator cv::MatIterator_< _Tp >:
for(cv::MatIterator_<int> it(labels.begin<int>()); it != labels.end<int>(); it++)
{
std::cout << (*it) << std::endl; // int i = *it
}
I am working on a PCL (Point Cloud Library) project. One part of it requires me to clip point clouds, for which I need to know the minimum and maximum coordinates of given point cloud.
PCL provides a predefined function called getminmax3d(). I tried and It works well, The only problem is, It takes a lot of time when I input a large point cloud file. I made my own definition of getminmax3d() and it takes lesser time. I am not understanding why these two behave like this.
I tried with 5 point cloud data files. In all cases, program that uses predefined function takes long time as compare to the program for which I defined the definition.
Here is the code:
First implementation - It uses predefined function getminmax3d()
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/common.h>
int main (int, char**)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr (new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile<pcl::PointXYZ> ("your_pcd_file.pcd", *cloud);
pcl::PointXYZ minPt, maxPt;
pcl::getMinMax3D (*cloud, minPt, maxPt);
std::cout << "Max x: " << maxPt.x << std::endl;
std::cout << "Max y: " << maxPt.y << std::endl;
std::cout << "Max z: " << maxPt.z << std::endl;
std::cout << "Min x: " << minPt.x << std::endl;
std::cout << "Min y: " << minPt.y << std::endl;
std::cout << "Min z: " << minPt.z << std::endl;
return (0);
}
Second implementation - This source code uses a user-defined function definition to replace functionality of getminmax3d()
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/time.h>
int main (int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ> ("rhino.pcd", *cloud) == -1) //* load the file
{
PCL_ERROR ("Couldn't read file rhino.pcd \n");
return (-1);
}
float min_x = cloud->points[0].x, min_y = cloud->points[0].y, min_z = cloud->points[0].z, max_x = cloud->points[0].x, max_y = cloud->points[0].y, max_z = cloud->points[0].z;
pcl::StopWatch watch;
for (size_t i = 1; i < cloud->points.size (); ++i){
if(cloud->points[i].x <= min_x )
min_x = cloud->points[i].x;
else if(cloud->points[i].y <= min_y )
min_y = cloud->points[i].y;
else if(cloud->points[i].z <= min_z )
min_z = cloud->points[i].z;
else if(cloud->points[i].x >= max_x )
max_x = cloud->points[i].x;
else if(cloud->points[i].y >= max_y )
max_y = cloud->points[i].y;
else if(cloud->points[i].z >= max_z )
max_z = cloud->points[i].z;
}
pcl::console::print_highlight ("Time taken: %f\n", watch.getTimeSeconds());
std::cout << "Min x: " << min_x <<"\t";
std::cout << "Max x: " << max_x << std::endl;
std::cout << "Min y: " << min_y <<"\t";
std::cout << "Max y: " << max_y << std::endl;
std::cout << "Min z: " << min_z <<"\t";
std::cout << "Max z: " << max_z << std::endl;
return (0);
}
I tried both programs on following 5 point cloud files.
Result obtained:
ttf : Time taken factor
ttf = 15 means user definition is about 15 times faster than predefined functions. ttf value is measured by taking average of 10 trials for both implementations.
PCD file Filetype File size ttf
Rhino.pcd XYZ 2.57 MB 15.260
Bun_zipper XYZCI 1.75 MB 17.422
Armadillo XYZ 5.26 MB 15.847
Dragon_vrip XYZ 14.7 MB 17.013
Happy_vrip XYZ 18.0 MB 14.981
I am wondering why predefined function is taking more time? I want to reduce my program source code lines. I've always believed that using standard header files and their function gives you best performance, But in this case it seems to fail.
This is where you can find standard definition.
Would anyone please help me to find out why second implementation takes less times(approx 15 times), even the standard definition of getminmax3d() is similar to mine.
pcl::getMinMax3D has a very inefficient implementation. To search for the minimum and max point it does the following:
Eigen::Array4f min_p, max_p;
min_p.setConstant (FLT_MAX);
max_p.setConstant (-FLT_MAX);
for (size_t i = 0; i < cloud.points.size (); ++i)
{
// ... (check the validity of the point if it is not a dense cloud)
pcl::Array4fMapConst pt = cloud.points[i].getArray4fMap ();
min_p = min_p.min (pt);
max_p = max_p.max (pt);
}
And if you check for the getArray4fMap() function:
typedef Eigen::Map<Eigen::Array4f, Eigen::Aligned> Array4fMap;
inline pcl::Array4fMap getArray4fMap() const {
return (pcl::Array4fMap(data));
}
For each point in the cloud it is constructing an Eigen::Map and then comparing it against the current minimum and maximum points. This is VERY inefficient.
The predefined function pcl::getMinMax3D is able to be faster with optimization flags set and in Release. Since if SSE intrinsics are used by Eigen, then the operations happen on 4 aligned bytes.
More information at
https://gitter.im/PointCloudLibrary/pcl?at=5e3899d06f9d3d34981c0687
I'm trying to minimize a following sample function:
F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1])
A normal way to minimize such a funct could be the Levenberg-Marquardt algorithm.
I would like to perform this minimization in c++ and have done some initial tests
with Eigen that resulted in the expected solution.
My question is the following:
I'm used to optimization in python using i.e. scipy.optimize.fmin_powell. Here
the input function parameters are (func, x0, args=(), xtol=0.0001, ftol=0.0001, maxiter=None, maxfun=None, full_output=0, disp=1, retall=0, callback=None, direc=None).
So I can define a func(x0), give the x0 vector and start optimizing. If needed I can change
the optimization parameters.
Now the Eigen Lev-Marq algorithm works in a different way. I need to define a function
vector (why?) Furthermore I can't manage to set the optimization parameters.
According to:
http://eigen.tuxfamily.org/dox/unsupported/classEigen_1_1LevenbergMarquardt.html
I should be able to use the setEpsilon() and other set functions.
But when I have the following code:
my_functor functor;
Eigen::NumericalDiff<my_functor> numDiff(functor);
Eigen::LevenbergMarquardt<Eigen::NumericalDiff<my_functor>,double> lm(numDiff);
lm.setEpsilon(); //doesn't exist!
So I have 2 questions:
Why is a function vector needed and why wouldn't a function scalar be enough?
References where I've searched for an answer:
http://www.ultimatepp.org/reference$Eigen_demo$en-us.html
http://www.alglib.net/optimization/levenbergmarquardt.php
How do I set the optimization parameters using the set functions?
So I believe I've found the answers.
1) The function is able to work as a function vector and as a function scalar.
If there are m solveable parameters, a Jacobian matrix of m x m needs to be created or numerically calculated. In order to do a Matrix-Vector multiplication J(x[m]).transpose*f(x[m]) the function vector f(x) should have m items. This can be the m different functions, but we can also give f1 the complete function and make the other items 0.
2) The parameters can be set and read using lm.parameters.maxfev = 2000;
Both answers have been tested in the following example code:
#include <iostream>
#include <Eigen/Dense>
#include <unsupported/Eigen/NonLinearOptimization>
#include <unsupported/Eigen/NumericalDiff>
// Generic functor
template<typename _Scalar, int NX = Eigen::Dynamic, int NY = Eigen::Dynamic>
struct Functor
{
typedef _Scalar Scalar;
enum {
InputsAtCompileTime = NX,
ValuesAtCompileTime = NY
};
typedef Eigen::Matrix<Scalar,InputsAtCompileTime,1> InputType;
typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
int m_inputs, m_values;
Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
int inputs() const { return m_inputs; }
int values() const { return m_values; }
};
struct my_functor : Functor<double>
{
my_functor(void): Functor<double>(2,2) {}
int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
{
// Implement y = 10*(x0+3)^2 + (x1-5)^2
fvec(0) = 10.0*pow(x(0)+3.0,2) + pow(x(1)-5.0,2);
fvec(1) = 0;
return 0;
}
};
int main(int argc, char *argv[])
{
Eigen::VectorXd x(2);
x(0) = 2.0;
x(1) = 3.0;
std::cout << "x: " << x << std::endl;
my_functor functor;
Eigen::NumericalDiff<my_functor> numDiff(functor);
Eigen::LevenbergMarquardt<Eigen::NumericalDiff<my_functor>,double> lm(numDiff);
lm.parameters.maxfev = 2000;
lm.parameters.xtol = 1.0e-10;
std::cout << lm.parameters.maxfev << std::endl;
int ret = lm.minimize(x);
std::cout << lm.iter << std::endl;
std::cout << ret << std::endl;
std::cout << "x that minimizes the function: " << x << std::endl;
std::cout << "press [ENTER] to continue " << std::endl;
std::cin.get();
return 0;
}
This answer is an extension of two existing answers:
1) I adapted the source code provided by #Deepfreeze to include additional comments and two different test functions.
2) I use the suggestion from #user3361661 to rewrite the objective function in the correct form. As he suggested, it reduced the iteration count on my first test problem from 67 to 4.
#include <iostream>
#include <Eigen/Dense>
#include <unsupported/Eigen/NonLinearOptimization>
#include <unsupported/Eigen/NumericalDiff>
/***********************************************************************************************/
// Generic functor
// See http://eigen.tuxfamily.org/index.php?title=Functors
// C++ version of a function pointer that stores meta-data about the function
template<typename _Scalar, int NX = Eigen::Dynamic, int NY = Eigen::Dynamic>
struct Functor
{
// Information that tells the caller the numeric type (eg. double) and size (input / output dim)
typedef _Scalar Scalar;
enum { // Required by numerical differentiation module
InputsAtCompileTime = NX,
ValuesAtCompileTime = NY
};
// Tell the caller the matrix sizes associated with the input, output, and jacobian
typedef Eigen::Matrix<Scalar,InputsAtCompileTime,1> InputType;
typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
// Local copy of the number of inputs
int m_inputs, m_values;
// Two constructors:
Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
// Get methods for users to determine function input and output dimensions
int inputs() const { return m_inputs; }
int values() const { return m_values; }
};
/***********************************************************************************************/
// https://en.wikipedia.org/wiki/Test_functions_for_optimization
// Booth Function
// Implement f(x,y) = (x + 2*y -7)^2 + (2*x + y - 5)^2
struct BoothFunctor : Functor<double>
{
// Simple constructor
BoothFunctor(): Functor<double>(2,2) {}
// Implementation of the objective function
int operator()(const Eigen::VectorXd &z, Eigen::VectorXd &fvec) const {
double x = z(0); double y = z(1);
/*
* Evaluate the Booth function.
* Important: LevenbergMarquardt is designed to work with objective functions that are a sum
* of squared terms. The algorithm takes this into account: do not do it yourself.
* In other words: objFun = sum(fvec(i)^2)
*/
fvec(0) = x + 2*y - 7;
fvec(1) = 2*x + y - 5;
return 0;
}
};
/***********************************************************************************************/
// https://en.wikipedia.org/wiki/Test_functions_for_optimization
// Himmelblau's Function
// Implement f(x,y) = (x^2 + y - 11)^2 + (x + y^2 - 7)^2
struct HimmelblauFunctor : Functor<double>
{
// Simple constructor
HimmelblauFunctor(): Functor<double>(2,2) {}
// Implementation of the objective function
int operator()(const Eigen::VectorXd &z, Eigen::VectorXd &fvec) const {
double x = z(0); double y = z(1);
/*
* Evaluate Himmelblau's function.
* Important: LevenbergMarquardt is designed to work with objective functions that are a sum
* of squared terms. The algorithm takes this into account: do not do it yourself.
* In other words: objFun = sum(fvec(i)^2)
*/
fvec(0) = x * x + y - 11;
fvec(1) = x + y * y - 7;
return 0;
}
};
/***********************************************************************************************/
void testBoothFun() {
std::cout << "Testing the Booth function..." << std::endl;
Eigen::VectorXd zInit(2); zInit << 1.87, 2.032;
std::cout << "zInit: " << zInit.transpose() << std::endl;
Eigen::VectorXd zSoln(2); zSoln << 1.0, 3.0;
std::cout << "zSoln: " << zSoln.transpose() << std::endl;
BoothFunctor functor;
Eigen::NumericalDiff<BoothFunctor> numDiff(functor);
Eigen::LevenbergMarquardt<Eigen::NumericalDiff<BoothFunctor>,double> lm(numDiff);
lm.parameters.maxfev = 1000;
lm.parameters.xtol = 1.0e-10;
std::cout << "max fun eval: " << lm.parameters.maxfev << std::endl;
std::cout << "x tol: " << lm.parameters.xtol << std::endl;
Eigen::VectorXd z = zInit;
int ret = lm.minimize(z);
std::cout << "iter count: " << lm.iter << std::endl;
std::cout << "return status: " << ret << std::endl;
std::cout << "zSolver: " << z.transpose() << std::endl;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
}
/***********************************************************************************************/
void testHimmelblauFun() {
std::cout << "Testing the Himmelblau function..." << std::endl;
// Eigen::VectorXd zInit(2); zInit << 0.0, 0.0; // soln 1
// Eigen::VectorXd zInit(2); zInit << -1, 1; // soln 2
// Eigen::VectorXd zInit(2); zInit << -1, -1; // soln 3
Eigen::VectorXd zInit(2); zInit << 1, -1; // soln 4
std::cout << "zInit: " << zInit.transpose() << std::endl;
std::cout << "soln 1: [3.0, 2.0]" << std::endl;
std::cout << "soln 2: [-2.805118, 3.131312]" << std::endl;
std::cout << "soln 3: [-3.77931, -3.28316]" << std::endl;
std::cout << "soln 4: [3.584428, -1.848126]" << std::endl;
HimmelblauFunctor functor;
Eigen::NumericalDiff<HimmelblauFunctor> numDiff(functor);
Eigen::LevenbergMarquardt<Eigen::NumericalDiff<HimmelblauFunctor>,double> lm(numDiff);
lm.parameters.maxfev = 1000;
lm.parameters.xtol = 1.0e-10;
std::cout << "max fun eval: " << lm.parameters.maxfev << std::endl;
std::cout << "x tol: " << lm.parameters.xtol << std::endl;
Eigen::VectorXd z = zInit;
int ret = lm.minimize(z);
std::cout << "iter count: " << lm.iter << std::endl;
std::cout << "return status: " << ret << std::endl;
std::cout << "zSolver: " << z.transpose() << std::endl;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
}
/***********************************************************************************************/
int main(int argc, char *argv[])
{
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
testBoothFun();
testHimmelblauFun();
return 0;
}
The output at the command line from running this test script is:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Testing the Booth function...
zInit: 1.87 2.032
zSoln: 1 3
max fun eval: 1000
x tol: 1e-10
iter count: 4
return status: 2
zSolver: 1 3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Testing the Himmelblau function...
zInit: 1 -1
soln 1: [3.0, 2.0]
soln 2: [-2.805118, 3.131312]
soln 3: [-3.77931, -3.28316]
soln 4: [3.584428, -1.848126]
max fun eval: 1000
x tol: 1e-10
iter count: 8
return status: 2
zSolver: 3.58443 -1.84813
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As an alternative you may simply create a new functor like this,
struct my_functor_w_df : Eigen::NumericalDiff<my_functor> {};
and then initialize the LevenbergMarquardt instance using like this,
my_functor_w_df functor;
Eigen::LevenbergMarquardt<my_functor_w_df> lm(functor);
Personally, I find this approach a bit cleaner.
It seems that the function is more general:
Let's say you have an m parameter model.
You have n observations to which you want to fit the m-parameter model in a least-squares sense.
The Jacobian, if provided, will be n times m.
You will need to supply n error values in the fvec.
Also, there is no need to square the f-values because it is implicitly assumed that the overall error function is made up of the sum of squares of the fvec components.
So, if you follow these guidelines and change the code to:
fvec(0) = sqrt(10.0)*(x(0)+3.0);
fvec(1) = x(1)-5.0;
It will converge in a ridiculously small number of iterations - like less than 5. I also tried it on a more complex example - the Hahn1 benchmark at http://www.itl.nist.gov/div898/strd/nls/data/hahn1.shtml with m=7 parameters and n=236 observations and it converges to the known right solution in only 11 iterations with the numerically computed Jacobian.