I am trying to use dlib to minimize a function where I can calculate the function and it's gradient at a given parameter value, using find_min.
As the function changes depending on input, I have defined a class with the inputs as members of the class, and two public functions which calculate the function and its gradient at the current guess of the solution:
#include <dlib/matrix.h>
typedef dlib::matrix<double,0,1> column_vector;
class Link
{
public:
// Initialisation
Link(const column_vector& predictors, const column_vector& responses)
: _predictors(predictors), _responses(responses)
{
}
// Likelihood and first derivative
double likelihood(const column_vector& b) const;
column_vector gradient(const column_vector& b) const;
protected:
column_vector _predictors;
column_vector _responses;
};
(omitting the code to calculate these functions for simplicity).
I then run through a loop of predictors and responses, minimising each case:
column_vector starting_point(2);
Link linear(x, y);
dlib::find_min(dlib::bfgs_search_strategy(),
dlib::objective_delta_stop_strategy(1e-7),
linear.likelihood,
linear.gradient,
starting_point);
However, I get a compiler error from trying to provide the non-static member functions linear.likelihood
and linear.gradient
from Link
: 'reference to non-static member function must be called'.
I'd previously gotten this to work by overloading operator()
when using only the likelihood, but can't do this with two functions (likelihood and gradient). Turning these into function pointers gives the same error.
Searching other answers I've found similar problems with trying to pass non-static member functions as arguments, but couldn't get them to work here. Is there a standard solution using template arguments I should be using to fix this?
Or am I going about this problem the wrong way entirely, and I shouldn't be using a class like this?
The arguments to dlib::find_min()
have to be objects that can be called with the function-call operator()
. linear.likelihood()
calls the likelihood function and returns a result, but linear.likelihood
by itself is not well-formed C++.
An easy solution is to use lambda expressions and to capture the object linear
by reference. The lambda expression is a temporary object that is callable.
dlib::find_min(dlib::bfgs_search_strategy(),
dlib::objective_delta_stop_strategy(1e-7),
[&linear](const column_vector& a) {
return linear.likelihood(a);
},
[&linear](const column_vector& b) {
return linear.gradient(b);
},
starting_point);