Commit f34c162d authored by Laurent Belcour's avatar Laurent Belcour

Adding the NLopt solver, but it is not working right now

parent 9ab966c2
......@@ -120,18 +120,12 @@ bool nonlinear_fitter_ceres::fit_data(const data* d, function* fit, const argume
// Create the problem
ceres::Problem problem;
for(int i=0; i<d->size(); ++i)
{
vec xi = d->get(i);
problem.AddResidualBlock(new CeresFunctor(nf, xi), NULL, &p[0]);
}
std::cout << "<<INFO>> Nb parameters blocks = " << problem.NumParameterBlocks() << std::endl;
std::cout << "<<INFO>> Nb residuals blocks = " << problem.NumResidualBlocks() << std::endl;
std::cout << "<<INFO>> Nb residuals = " << problem.NumResiduals() << std::endl;
// Solver's options
ceres::Solver::Options options;
if(args.is_defined("ceres-max-num-iterations"))
......
......@@ -11,9 +11,41 @@
#include <core/args.h>
#include <core/vertical_segment.h>
/*! \brief A fitter for non-linear BRDF models that uses Eigen's
* Levenberg-Marquardt solver.
/*! \brief A non-linear fitter using the CERES solver
* \ingroup plugins
*
* \details
* <h3>Third party requirements</h3>
*
* You will need three external libraries to compile this plugin:
* <ul>
* <li><a href="https://ceres-solver.googlesource.com/ceres-solver">CERES</a>
* library, version 1.5.0</li>
* <li><a href="http://code.google.com/p/google-glog">Google glog</a> library
* version 0.3.1</li>
* <li><a href="http://eigen.tuxfamily.org/">Eigen library</a> version 3</li>
* </ul>
*
* The last two dependencies are required to compile CERES and this plugin
* must be linked against Google glog to run.
*
* You need to provide your own ceres.prf file for qmake to generate the correct
* Makefile or Visual Studio solution. In particular this configuration file
* should provide:
*
* <pre>
* INCLUDEPATH += [path-to-ceres-include]
* LIBS += -L[path-to-ceres-lib] -lceres -L[path-to-glog-lib] -lglog -lgomp
* </pre>
*
*
* <h3>Plugin parameters</h3>
*
* We provide the following command line arguments to manipulate this plugin:
* <ul>
* <li><b>--ceres-max-num-iterations</b> <em>[int]</em> to control the number
* of iterations the non linear solver will take before returning a solution</li>
* </ul>
*/
class nonlinear_fitter_ceres: public fitter
{
......
#include "fitter.h"
#include <nlopt.h>
#include <string>
#include <iostream>
#include <fstream>
#include <limits>
#include <algorithm>
#include <cmath>
#include <QTime>
#include <core/common.h>
ALTA_DLL_EXPORT fitter* provide_fitter()
{
return new nonlinear_fitter_nlopt();
}
void print_nlopt_error(nlopt_result res, char* string)
{
if(res == NLOPT_FAILURE)
{
std::cerr << "<<ERROR>> generic failure for \"" << string << "\"" << std::endl;
}
else if(res == NLOPT_INVALID_ARGS)
{
std::cerr << "<<ERROR>> invalid arguments for \"" << string << "\"" << std::endl;
}
else if(res == NLOPT_OUT_OF_MEMORY)
{
std::cerr << "<<ERROR>> not enough memory for \"" << string << "\"" << std::endl;
}
}
// The parameter of the function _f should be set prior to this function
// call. If not it will produce undesirable results.
void df(double* fjac, const nonlinear_function* f, const data* d)
{
// Each constraint is of the form data point * color channel
for(int s=0; s<d->size(); ++s)
{
vec xi = d->get(s);
// Get the jacobian of the function at position x_i for the current
// set of parameters (set prior to function call)
vec _jac = f->parametersJacobian(xi);
vec _di = vec(f->dimY());
for(int i=0; i<f->dimY(); ++i)
{
_di[i] = xi[f->dimX() + i];
}
// Should add the resulting vector completely
vec _y = (*f)(xi) - _di;
// For each output channel, update the subpart of the
// vector row
for(int i=0; i<f->dimY(); ++i)
{
// Fill the columns of the matrix
for(int j=0; j<f->nbParameters(); ++j)
{
fjac[j] -= 2 * _y[i] * _jac[i*f->nbParameters() + j];
}
}
}
}
double f(unsigned n, const double* x, double* dy, void* dat)
{
nonlinear_function* _f = (nonlinear_function*)(((void**)dat)[0]);
const data* _d = (const data*)(((void**)dat)[1]);
// Update the parameters vector
vec _p(_f->nbParameters());
for(int i=0; i<_f->nbParameters(); ++i) { _p[i] = x[i]; }
_f->setParameters(_p);
// Create the result vector
double y = 0.0;
// Each constraint is of the form data point * color channel
for(int s=0; s<_d->size(); ++s)
{
vec xi = _d->get(s);
vec _di = vec(_f->dimY());
for(int i=0; i<_f->dimY(); ++i)
{
_di[i] = xi[_f->dimX() + i];
}
// Should add the resulting vector completely
vec _y = (*_f)(xi) - _di;
for(int i=0; i<_f->dimY(); ++i)
{
y += pow(_y[i], 2);
}
}
if(dy != NULL)
{
df(dy, _f, _d);
}
return y;
}
nonlinear_fitter_nlopt::nonlinear_fitter_nlopt()
{
}
nonlinear_fitter_nlopt::~nonlinear_fitter_nlopt()
{
}
bool nonlinear_fitter_nlopt::fit_data(const data* d, function* fit, const arguments &args)
{
// I need to set the dimension of the resulting function to be equal
// to the dimension of my fitting problem
fit->setDimX(d->dimX()) ;
fit->setDimY(d->dimY()) ;
fit->setMin(d->min()) ;
fit->setMax(d->max()) ;
// Convert the function and bootstrap it with the data
if(dynamic_cast<nonlinear_function*>(fit) == NULL)
{
std::cerr << "<<ERROR>> the function is not a non-linear function" << std::endl;
return false;
}
nonlinear_function* nf = dynamic_cast<nonlinear_function*>(fit);
nf->bootstrap(d, args);
#ifndef DEBUG
std::cout << "<<DEBUG>> number of parameters: " << nf->nbParameters() << std::endl;
#endif
if(nf->nbParameters() == 0)
{
return true;
}
// the following starting values provide a rough fit is the bootstrap flag is
// enabled
vec p = nf->parameters();
// Create the optimizer
nlopt_opt opt = nlopt_create(NLOPT_GD_STOGO, nf->nbParameters());
if(opt == NULL)
{
std::cerr << "<<ERROR>> unable to create the optimizer" << std::endl;
return false;
}
// Create the problem
void* dat[2];
dat[0] = (void*)nf;
dat[1] = (void*)d;
nlopt_result res = nlopt_set_min_objective(opt, f, dat);
if(res < 0)
{
print_nlopt_error(res, "nlopt_set_min_objective");
return false;
}
// Set the stopping criterion to a maximum number of evaluation
res = nlopt_set_maxeval(opt, 50);
if(res < 0) { print_nlopt_error(res, "nlopt_set_maxeval"); }
// Launch minimization
double f_end;
res = nlopt_optimize(opt, &p[0], &f_end);
if(res > 0)
{
std::cout << "<<INFO>> found parameters: " << p << std::endl;
nf->setParameters(p);
}
else
{
print_nlopt_error(res, "nlopt_optimize");
}
nlopt_destroy(opt);
return res > 0;
}
void nonlinear_fitter_nlopt::set_parameters(const arguments& args)
{
}
#pragma once
// Include STL
#include <vector>
#include <string>
// Interface
#include <core/function.h>
#include <core/data.h>
#include <core/fitter.h>
#include <core/args.h>
#include <core/vertical_segment.h>
/*! \brief A non-linear fitter using the NLOpt solver
* \ingroup plugins
*
* \details
* <h3>Third party requirements</h3>
*
* You will need three external libraries to compile this plugin:
* <ul>
* <li><a href="http://ab-initio.mit.edu/wiki/index.php/NLopt">NLopt</a>
* library, version 2.3</li>
* </ul>
*
* You need to provide your own nlopt.prf file for qmake to generate the correct
* Makefile or Visual Studio solution. In particular this configuration file
* should provide:
*
* <pre>
* INCLUDEPATH += [path-to-nlopt-include]
* LIBS += -L[path-to-nlopt-lib] -lnlopt -lm
* </pre>
*
*
* <h3>Plugin parameters</h3>
*
*/
class nonlinear_fitter_nlopt: public fitter
{
public: // methods
nonlinear_fitter_nlopt() ;
virtual ~nonlinear_fitter_nlopt() ;
// Fitting a data object
//
virtual bool fit_data(const data* d, function* fit, const arguments& args) ;
// Provide user parameters to the fitter
//
virtual void set_parameters(const arguments& args) ;
protected: // function
protected: // data
} ;
TARGET = nonlinear_fitter_nlopt
TEMPLATE = lib
CONFIG *= qt \
plugin \
nlopt \
eigen
DESTDIR = ../../build
INCLUDEPATH += ../..
HEADERS = fitter.h
SOURCES = fitter.cpp
LIBS += -L../../build \
-lcore
......@@ -11,6 +11,7 @@ SUBDIRS = \
# rational_fitter_dca \
nonlinear_levenberg_eigen \
nonlinear_fitter_ceres \
nonlinear_fitter_nlopt \
nonlinear_fresnel_schlick \
nonlinear_function_diffuse \
nonlinear_function_phong \
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment