c++optimizationnlopt

Passing void function as argument into double function in c++


I'm trying to use NLopt library for an optimization problem in c++. The docs indicate the input function to be optimized should look like this:

double myfunc(const std::vector<double> &x, std::vector<double> &grad, void *my_func_data);

I don't understand how to use the void *my_func_data argument, which accepts additional data necessary for the function to be optimized.

The docs show the example to create your function to be optimized here:

int count = 0;
double myfunc(int n, const double *x, double *grad, void *my_func_data)
{
    ++count;
    if (grad) {
        grad[0] = 0.0;
        grad[1] = 0.5 / sqrt(x[1]);
    }
    return sqrt(x[1]);
}

However, they do not use the void *my_func_data argument.

I want to use this argument, because I have additional data I'll need to pass in. My function looks like this:

double myfunc(const std::vector<double> &x, std::vector<double> &grad, void *my_func_data)
{
    if (!grad.empty()) {
        grad[0] = 0.0;
        grad[1] = 0.5 / sqrt(x[1]);
    }
    my_func_data;
    double xM = 1.;
    double yM = 1.;
    double xF = 1.;
    double yF = 1.;
    double theta = 2.;
    double tx = 1.4;
    double ty = 0.4;

    return sqrt(
                pow(abs(xF - (cos(theta)*xM) - (sin(theta)*yM) + tx), 2) + \
                pow(abs(yF - (sin(theta)*xM) + (cos(theta)*yM) + ty), 2)
            );
}

However, I want these variables:

    double xM = 1.;
    double yM = 1.;
    double xF = 1.;
    double yF = 1.;

to be passed into the function using the my_func_data argument, but I don't understand how to format a void input argument. Please advise.

Docs: https://nlopt.readthedocs.io/en/latest/NLopt_Tutorial/#example-in-c

xM, yM are x,y coordinates stored in a vector of Point2f. xF, yF are also x,y coordinates stored in a vector of Point2f.

EDIT

Now my code is this:

struct ExtraData
{
    double xM = 1.;
    double yM = 1.;
    double xF = 1.;
    double yF = 1.;
};
double myfunc(const std::vector<double> &x, std::vector<double> &grad, void *my_func_data);

double myfunc(const std::vector<double> &x, std::vector<double> &grad, void *my_func_data)
{
    if (!grad.empty()) {
        grad[0] = 0.0;
        grad[1] = 0.5 / sqrt(x[1]);
    }
    ExtraData* extraData = static_cast<ExtraData*>(my_func_data);
    double xM = extraData -> xM;
    double yM = extraData -> yM;
    double xF = extraData -> xF;
    double yF = extraData -> yF;


    // double xM = 1.;
    // double yM = 1.;
    // double xF = 1.;
    // double yF = 1.;
    double theta = 2.;
    double tx = 1.4;
    double ty = 0.4;

    return sqrt(
                pow(abs(xF - (cos(theta)*xM) - (sin(theta)*yM) + tx), 2) + \
                pow(abs(yF - (sin(theta)*xM) + (cos(theta)*yM) + ty), 2)
            );
}

int main()
{
    nlopt::opt opt(nlopt::LD_SLSQP, 2);
    std::vector<double> lb(2);
    lb[0] = -HUGE_VAL;   //HUGE_VAL is a C++ constant
    lb[1] = 0;
    opt.set_lower_bounds(lb);

    opt.set_min_objective(myfunc, NULL);

    double data[4] = {2,0,-1,1};   //use one dimensional array
    std::vector<double> tol_constraint(2);
    tol_constraint[0] = 1e-8;
    tol_constraint[1] = 1e-8;
    opt.add_inequality_mconstraint(multi_constraint, data, tol_constraint);
    opt.set_xtol_rel(1e-4);

    std::vector<double> x(2);
    x[0] = 1.234;
    x[1] = 5.678;
    double minf;
    nlopt::result result = opt.optimize(x, minf);
    std::cout << "The result is" << std::endl;
    std::cout << result << std::endl;
    std::cout << "Minimal function value " << minf << std::endl;
}

Which compiles, but when I run it, I get:

Segmentation fault: 11


Solution

  • You have to define struct containing required data:

    struct ExtraData
    {
        double xM = 1.;
        double yM = 1.;
        double xF = 1.;
        double yF = 1.;
    };
    
    

    I do not know this library - but probably it has function accepting void* and pointer to your function - let's refer to it as Xxxx:

    Xxxx(..., double(*)(const std::vector<double>&, std::vector<double> &, void *), void* extraData);

    When you pass pointer ExtraData* type - it will auto-cast to void*.

    ExtraData extraData{.xM = 1., ... };
    Xxxx(..., &myfunc, &extraData);
    
    

    In your function - cast explicitly from void* to ExtraData*:

    double myfunc(const std::vector<double> &x, std::vector<double> &grad, void *my_func_data)
    {
        if (!grad.empty()) {
            grad[0] = 0.0;
            grad[1] = 0.5 / sqrt(x[1]);
        }
        ExtraData* extraData = reinterpret_cast<ExtraData*>(my_func_data);
        double xM = = extraData->xM;
        ...
    

    In doc you have example of such usage - look at the first line:

    double myvconstraint(const std::vector<double> &x, std::vector<double> &grad, void *data)
    {
        my_constraint_data *d = reinterpret_cast<my_constraint_data*>(data);
        double a = d->a, b = d->b;
        if (!grad.empty()) {
            grad[0] = 3 * a * (a*x[0] + b) * (a*x[0] + b);
            grad[1] = -1.0;
        }
        return ((a*x[0] + b) * (a*x[0] + b) * (a*x[0] + b) - x[1]);
    }
    
    

    So pair of function pointer and void* data - is very ancient (derived from "C") way of passing "functors" or "callbacks" to other functions. Modern C++ ways are lambdas and std::function.