rrcpparmadillonlopt

Passing data to nlopt in Rcpp?


This is a rather simple question, but I haven't been able to quite find the answer on the web yet.

Wishing my latest attempt, here is latest compiler output: note: candidate function not viable: no known conversion from 'double (unsigned int, const double *, void *, void )' to 'nlopt_func' (aka 'double ()(unsigned int, const double *, double *, void *)') for 2nd argument

From this error I surmise that I am now wrapping or 'type casting' the data argument correctly and also the parameter vector. The discrepency between the third input, the gradient, confuses me. As I am calling a gradient free optimization routine.

Here is a simple linear regression with a constant and a variable:

#include "RcppArmadillo.h"

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::depends(nloptr)]]
//#include <vector>
#include <nloptrAPI.h>
using namespace arma;
using namespace Rcpp;

typedef struct {
  arma::mat data_in;
} *my_func_data;

typedef struct {
  double a, b;
} my_theta;

double myfunc(unsigned n, const double *theta, void *grad, void *data){

  my_func_data &temp = (my_func_data &) data;
  arma::mat data_in = temp->data_in;

  my_theta *theta_temp = (my_theta *) theta;
  double a = theta_temp->a, b = theta_temp->b;

  int Len = arma::size(data_in)[0];
  arma::vec Y1 = data_in(span(0, Len-1), 1);
  arma::vec Y2 = data_in(span(0, Len-1), 2);
  arma::vec res = data_in(span(0, Len-1), 0) - a*Y1 - b*Y2 ;
  return sum(res);
}


// [[Rcpp::export]]
void test_nlopt_c() {

  arma::mat data_in(10,3);
  data_in(span(0,9),0) = arma::regspace(40, 49);
  data_in(span(0,9),1) = arma::ones(10);
  data_in(span(0,9),2) = arma::regspace(10, 19);

  my_func_data &temp = (my_func_data &) data_in;

  double lb[2] = { 0, 0,}; /* lower bounds */
  nlopt_opt opt;
  opt = nlopt_create(NLOPT_LN_NELDERMEAD, 2); /* algorithm and dimensionality */
  nlopt_set_lower_bounds(opt, lb);

  nlopt_set_min_objective(opt, myfunc, &data_in );

  nlopt_set_xtol_rel(opt, 1e-4);
  double minf; /* the minimum objective value, upon return */
  double x[2] = {0.5, 0.5};  /* some initial guess */
  nlopt_result result = nlopt_optimize(opt, x, &minf);
  Rcpp::Rcout << "result:" << result;
    return;
}

Solution

  • Got it figured out, stupid answer turns out to be correct, just change 'void' to 'double', no clue why. Anyway, the example code needs some improving but it works.

    #include "RcppArmadillo.h"
    
    // [[Rcpp::depends(RcppArmadillo)]]
    // [[Rcpp::depends(nloptr)]]
    //#include <vector>
    #include <nloptrAPI.h>
    using namespace arma;
    using namespace Rcpp;
    
    typedef struct {
      arma::mat data_in;
    } *my_func_data;
    
    typedef struct {
      double a, b;
    } my_theta;
    
    double myfunc(unsigned n, const double *theta, double *grad, void *data){
    
      my_func_data &temp = (my_func_data &) data;
      arma::mat data_in = temp->data_in;
    
      my_theta *theta_temp = (my_theta *) theta;
      double a = theta_temp->a, b = theta_temp->b;
    
      int Len = arma::size(data_in)[0];
      arma::vec Y1 = data_in(span(0, Len-1), 1);
      arma::vec Y2 = data_in(span(0, Len-1), 2);
      arma::vec res = data_in(span(0, Len-1), 0) - a*Y1 - b*Y2 ;
      return sum(res);
    }
    
    
    // [[Rcpp::export]]
    void test_nlopt_c() {
    
      arma::mat data_in(10,3);
      data_in(span(0,9),0) = arma::regspace(40, 49);
      data_in(span(0,9),1) = arma::ones(10);
      data_in(span(0,9),2) = arma::regspace(10, 19);
    
      my_func_data &temp = (my_func_data &) data_in;
    
      double lb[2] = { 0, 0,}; /* lower bounds */
      nlopt_opt opt;
      opt = nlopt_create(NLOPT_LN_NELDERMEAD, 2); /* algorithm and dimensionality */
      nlopt_set_lower_bounds(opt, lb);
    
      nlopt_set_min_objective(opt, myfunc, &data_in );
    
      nlopt_set_xtol_rel(opt, 1e-4);
      double minf; /* the minimum objective value, upon return */
      double x[2] = {0.5, 0.5};  /* some initial guess */
      nlopt_result result = nlopt_optimize(opt, x, &minf);
      Rcpp::Rcout << "result:" << result;
        return;
    }