passing a function reference outside a class

Hi,

I'm trying to link a molecular dynamics code (LAMMPS) with an optimization library (NLopt, http://ab-initio.mit.edu/wiki/index.php/NLopt_C-plus-plus_Reference) to extend the available algorithms for optimization. To do this I think it suffices to create two files: min_nlopt.cpp and min_nlopt.h. Here is the basic structure I think I need.

min_nlopt.h looks like this

1
2
3
4
5
6
7
8
class MinNLOPT : public MinLineSearch {
 public:
  MinNLOPT(class LAMMPS *);
  int iterate(int);
  double objective_function(const std::vector<double>&, std::vector<double>&, void*);
  double minf;
  std::vector<double> x;
};


It defines the (obligatory) iterator (which is what will be called eventually), and creates an objective_function which is necessary for NLopt.


And min_nlopt.cpp fills in these two functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
double MinNLOPT::objective_function(const std::vector<double> &x, std::vector<double> &grad, void *data) {
  /* objective function :
     this will be evaluated by nlopt to see how good we are doing
    @param x,           || array with x_1,x_2,x_3,..,x_n as parameters that 
                           have to be optimized under the objective function o(x)
    @param grad,        || array to store gradient
    @param my_func_data || possible parameters required to evaluate the o(x)

    @return f,          || the function value (energy)
  */
  eprevious = ecurrent;
  // ... update x and compute grad and f ... //
  printf("@@ obj. func.  e=%f\nm",ecurrent);
  return ecurrent;
}


int MinNLOPT::iterate(int maxiter) {
  nlopt::opt opt(nlopt::LD_LBFGS, nvec);
  opt.set_min_objective(objective_function, NULL);
  opt.set_maxeval(maxiter);
  opt.optimize(x, minf);
  printf("# found minimum at f = %0.10g\n", minf);
  return 0;
}



My problem is that NLopt requires a function reference as input and I am not sure how to handle this since its inside a class. If I compile this I get an error like

1
2
3
4
5
min_nlopt.cpp: In member function ‘virtual int LAMMPS_NS::MinNLOPT::iterate(int)’:
min_nlopt.cpp:68: error: no matching function for call to ‘nlopt::opt::set_min_objective(<unresolved overloaded function type>, NULL)’
/usr/local/include/nlopt.hpp:334: note: candidates are: void nlopt::opt::set_min_objective(double (*)(unsigned int, const double*, double*, void*), void*)
/usr/local/include/nlopt.hpp:341: note:                 void nlopt::opt::set_min_objective(double (*)(const std::vector<double, std::allocator<double> >&, std::vector<double, std::allocator<double> >&, void*), void*)
/usr/local/include/nlopt.hpp:367: note:                 void nlopt::opt::set_min_objective(double (*)(unsigned int, const double*, double*, void*), void*, void* (*)(void*), void* (*)(void*))


I have no what to do with this. I think I cannot leave the objective_function outside of the class because it needs some of the inherited properties.


I have a C code which works in much the same way, but without the classes (the C syntax is bit different mainly because of the arrays vs. vectors).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
double objective(unsigned n, const double *x, double *grad, void *data) {
  // ... compute some stuff
  return 1.234
}
int main(int argc, char *argv[]) {
  int nsteps = 500; 
  int method = 11;
  double x[2] = {-0.2, 5. };
  double minf;

  nlopt_opt opt = nlopt_create(method, 2);
  nlopt_set_min_objective(opt, objective, NULL);
  nlopt_set_maxeval(opt, nsteps);
  int return_value = nlopt_optimize(opt, x, &minf);
}



Could somebody please help me on this? Any solution will do, ugly or beautiful!
Maybe I can make the entire namespace or class static or global?? Or maybe I should just add something with (*this), but I can't figure it out..

Thanks.
1
2
3
int foo::bar(double d); //method bar of class foo
//equivalent to
int bar(foo *this, double d); //global function 
So make objetive_function() a global function or static method
1
2
double objective_function(const std::vector<double> &x, std::vector<double> &grad, void *data) {
  MinNLOPT *obj = static_cast<MinNLOPT *>(data);


and call opt.set_min_objective(objective_function, this);
You can't provide a function that is member of a class when a global function is required.

if objective_function doesn't access member variable of MinNLOPT you might make objective_function static. Otherwise you can call objective_function only indirect
The problem is that I indeed need to access members of MinNLOPT (actually inherited members).
So I cannot just leave out 'MinNLOPT::' and try to make only the function global.

I'm not sure how to make an indirect call, I tried following this example

1
2
3
4
5
6
7
8
9
10
11
12
13
int Add(int nX, int nY)
{
    return nX + nY;
}
 
int main()
{
    // Create a function pointer and make it point to the Add function
    int (*pFcn)(int, int) = Add;
    cout << pFcn(5, 3) << endl; // add 5 + 3
 
    return 0;
}


to create a function like this

double (*indirect)(const std::vector<double>&, std::vector<double>&, void*) = objective_function;

but my compiler complains

min_nlopt.cpp:70: error: argument of type 
‘double (LAMMPS_NS::MinNLOPT::)(const std::vector<double, std::allocator<double> >&, std::vector<double, std::allocator<double> >&, void*)’ does not match 
‘double (*)                    (const std::vector<double, std::allocator<double> >&, std::vector<double, std::allocator<double> >&, void*)’

You could
A_ Make the global function a friend
1_ Make it a wrapper
1
2
3
4
double objective_function(const std::vector<double> &x, std::vector<double> &grad, void *data) {
  MinNLOPT *obj = static_cast<MinNLOPT *>(data);
  return obj->objective_function(x,grad);
}


Again, you can't make that assignment as the prototypes are different. A method receives the this pointer as an implicit argument
Last edited on
Sorry I may be in over my head with this..
friend, wrapper, static and indirect functions.. I'm not exactly comfortable with these, I need to read up a bit I think.

The function objective_function is already public so I'm not sure if I can make it more 'friendly'.
From what I understand a 'wrapper' sounds like what I need.

I modified the code like this, "min_nlopt.h" still contains the same definition

double objective_function(const std::vector<double>&, std::vector<double>&, void*);

and "min_nlopt.cpp" contains

1
2
3
4
5
6
7
8
9
10
11
12
13
double MinNLOPT::objective_function(const std::vector<double> &x, std::vector<double> &grad, void *data) {
  return 1.234;
}

double obj_wrapper(const std::vector<double> &x, std::vector<double> &grad, void *data) {
  MinNLOPT *obj = static_cast<MinNLOPT *>(data);   
  return obj->objective_function(x, grad, data);
}

int MinNLOPT::iterate(int maxiter) {
  nlopt::opt opt(nlopt::LD_LBFGS, nvec); 
  opt.set_min_objective(obj_wrapper, NULL);
}


This actually compiles! Thanks!


However I don't really understand this line
MinNLOPT *obj = static_cast<MinNLOPT *>(data);
In my case data will most likely be a NULL pointer.
Shouldn't it be this or did you mean that I should use the data object to pass the instance and initialize it like you wrote before?
opt.set_min_objective(obj_wrapper, this)
Last edited on
did you mean that I should use the data object to pass the instance and initialize it like you wrote before?
opt.set_min_objective(obj_wrapper, this);
Yep.
You said that you needed the state of the object, so you need to pass it somehow.
That's the purpose of the data pointer.

Also note that if you don't need data in your method then there is no reason for it to be an argument (because now you can freely chose the prototype of the method)
Ok, thanks a lot!
It works fine like this, I am now 30 algorithms richer :)
Topic archived. No new replies allowed.