-2

I'm trying to write a cpp11 (the R package) code for an assignment and I have a problem that doesn't happen with Rcpp (another R package).

Both Rcpp and cpp11 allow to use C++ user defined functions in R. For example, with both of them I can write a function to obtain the correlation between two variable, and I would need to define variables such as "x is a vector of doubles", besides a non standard-header such as [[cpp11::register]].

I'm adapting from https://github.com/lrberge/fixest/blob/master/src/misc_funs.cpp#L62-L81 besides separate Stan codes, but this is a MWE. However, I couldn't find much examples of adaptation of existing Rcpp codes, besides https://cpp11.r-lib.org/articles/converting.html.

Rcpp

I created a file "rcpp_case.cpp" containing

#include <Rcpp.h>
#include <math.h>

using namespace Rcpp;
using namespace std;

// [[Rcpp::export]]
NumericVector RcppFun(int Q, IntegerVector nbCluster) {
  int q;
  int sum_cases=0;
  IntegerVector start(Q), end(Q);

  for(q=0 ; q<Q ; q++){
    // the total number of clusters (eg if man/woman and 10 countries: total of 12 cases)
    sum_cases += nbCluster(q);
    if(q == 0){
      start(q) = 0;
      end(q) = nbCluster(q);
    } else {
      start(q) = start(q-1) + nbCluster(q-1);
      end(q) = end(q-1) + nbCluster(q);
    }
  }

  return(q);
}

R

In R, I can use the function contained in the cpp file:

library(Rcpp)

sourceCpp("RcppFun.cpp")

RcppFun(Q = c(2L), nbCluster = c(1L,2L,3L))

> RcppFun(Q = c(2L), nbCluster = c(1L,2L,3L))
[1] 0 0

Rcpp -> cpp11

#include <cpp11.hpp>
#include <math.h>

using namespace cpp11;
using namespace std;

[[cpp11::register]]
doubles cpp11_fun(int Q, integers nbCluster) {
  int q;
  int sum_cases=0;
  writable::integers start(Q), end(Q);

  for(q=0 ; q<Q ; q++){
    // the total number of clusters (eg if man/woman and 10 countries: total of 12 cases)
    sum_cases += nbCluster(q);
    if(q == 0){
      start(q) = 0;
      end(q) = nbCluster(q);
    } else {
      start(q) = start(q-1) + nbCluster(q-1);
      end(q) = end(q-1) + nbCluster(q);
    }
  }

  return(q);
}
library(cpp11)

cpp_source("cpp11_fun.cpp")

> cpp_source("cpp11_fun.cpp")
/imputation-model/cpp11_fun.cpp: In function ‘cpp11::doubles cpp11_fun(int, cpp11::integers)’:
/imputation-model/cpp11_fun.cpp:17:29: error: no match for call to ‘(cpp11::integers {aka cpp11::r_vector<int>}) (int&)’
   17 |     sum_cases += nbCluster(q);
      |                             ^
/imputation-model/cpp11_fun.cpp:19:14: error: no match for call to ‘(cpp11::writable::integers {aka cpp11::writable::r_vector<int>}) (int&)’
   19 |       start(q) = 0;
      |              ^
/imputation-model/cpp11_fun.cpp:20:12: error: no match for call to ‘(cpp11::writable::integers {aka cpp11::writable::r_vector<int>}) (int&)’
   20 |       end(q) = nbCluster(q);
      |            ^
/imputation-model/cpp11_fun.cpp:20:27: error: no match for call to ‘(cpp11::integers {aka cpp11::r_vector<int>}) (int&)’
   20 |       end(q) = nbCluster(q);
      |                           ^
/imputation-model/cpp11_fun.cpp:22:14: error: no match for call to ‘(cpp11::writable::integers {aka cpp11::writable::r_vector<int>}) (int&)’
   22 |       start(q) = start(q-1) + nbCluster(q-1);
      |              ^
/imputation-model/cpp11_fun.cpp:22:27: error: no match for call to ‘(cpp11::writable::integers {aka cpp11::writable::r_vector<int>}) (int)’
   22 |       start(q) = start(q-1) + nbCluster(q-1);
      |                           ^
/imputation-model/cpp11_fun.cpp:22:44: error: no match for call to ‘(cpp11::integers {aka cpp11::r_vector<int>}) (int)’
   22 |       start(q) = start(q-1) + nbCluster(q-1);
      |                                            ^
/imputation-model/cpp11_fun.cpp:23:12: error: no match for call to ‘(cpp11::writable::integers {aka cpp11::writable::r_vector<int>}) (int&)’
   23 |       end(q) = end(q-1) + nbCluster(q);
      |            ^
/imputation-model/cpp11_fun.cpp:23:23: error: no match for call to ‘(cpp11::writable::integers {aka cpp11::writable::r_vector<int>}) (int)’
   23 |       end(q) = end(q-1) + nbCluster(q);
      |                       ^
/imputation-model/cpp11_fun.cpp:23:38: error: no match for call to ‘(cpp11::integers {aka cpp11::r_vector<int>}) (int&)’
   23 |       end(q) = end(q-1) + nbCluster(q);
      |                                      ^
/imputation-model/cpp11_fun.cpp:27:11: error: invalid conversion from ‘int’ to ‘SEXP’ {aka ‘SEXPREC*’} [-fpermissive]
   27 |   return(q);
      |           ^
      |           |
      |           int
In file included from /usr/lib/R/site-library/cpp11/include/cpp11/list.hpp:10,
                 from /usr/lib/R/site-library/cpp11/include/cpp11/data_frame.hpp:12,
                 from /usr/lib/R/site-library/cpp11/include/cpp11.hpp:7,
                 from /imputation-model/cpp11_fun.cpp:1:
/usr/lib/R/site-library/cpp11/include/cpp11/r_vector.hpp:368:41: note:   initializing argument 1 of ‘cpp11::r_vector<T>::r_vector(SEXP) [with T = double; SEXP = SEXPREC*]’
  368 | inline r_vector<T>::r_vector(const SEXP data)
      |                              ~~~~~~~~~~~^~~~
make: *** [/usr/lib/R/etc/Makeconf:177: /imputation-model/cpp11_fun.o] Error 1
Error: Compilation failed.
coatless
  • 20,011
  • 13
  • 69
  • 84
pachadotdev
  • 3,345
  • 6
  • 33
  • 60
  • You are using `nbCluster` as an `int` but in the source you linked, it is an `IntegerVector`. I guess `IntegerVector` overrides the `()-operator` which `int` doesn't. Did you include all the headers necessary for the code example to work? – cediwelli Apr 03 '22 at 06:08
  • yes, all the headers. with rcpp it works – pachadotdev Apr 03 '22 at 06:14
  • Ok, try to change the `int nbCluster` to `IntegerVector nbCluster` – cediwelli Apr 03 '22 at 06:15
  • I did, but with cpp11 it's "integers", which is the translation from rcpp – pachadotdev Apr 03 '22 at 06:17
  • The second code block you posted seems definitly more close to what you acutally want. In the first block, as you already found out, the `writable::integers q` does not implement `++` operator with `int` and you changed that. In the second block, you made `start` and `end` to `writable::integers` because as you stated, the `IntegerVector` translates the `writeable::integers`. Shouldn't you then also change the `int nbCluster` to `writeable::integers nbCluster` in the parameter-list of your function? For what I think, that would fix the `expression cannot be used as a function` – cediwelli Apr 03 '22 at 06:34
  • 2
    @coatless why the new [tag:cpp11] tag? Did you mean [tag:c++11]? – jps Apr 05 '22 at 15:34
  • 2
    No. @jps The tag is for the R package cpp11. Note the question above. – coatless Apr 05 '22 at 15:36
  • 2
    @coatless ok, sorry, don't know about R packages. Could this tag have a different name then? With the current naming you'll certainly get many mistagged questions, which indeed refer to c++11 and are not related to the R package. – jps Apr 05 '22 at 15:39
  • 1
    Splitting the difference as another package known as `Rcpp11` exists. New tag is: `r-lib-cpp11` – coatless Apr 08 '22 at 02:01

1 Answers1

1

You had a couple of small errors which in the accumulation made for several error messages:

  • your signature returns a double, the return statement has an int
  • your had an unused variable (just a warning)
  • you index the vectors with round parens, cpp11 seems to prefer squared brackets

The following works here:

#include <cpp11.hpp>
#include <math.h>

using namespace cpp11;
using namespace std;

[[cpp11::register]]
int cpp11_fun(int Q, integers nbCluster) {
    int q;
    int sum_cases=0;
    writable::integers start(Q), end(Q);

    for(q=0 ; q<Q ; q++){
        // total nb of clusters (eg if man/woman and 10 countries)
        sum_cases += nbCluster[q];
        if (q == 0){
            start[q] = 0;
            end[q] = nbCluster[q];
        } else {
            start[q] = start[q-1] + nbCluster[q-1];
            end[q] = end[q-1] + nbCluster[q];
        }
    }
    return(q);
}
Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • Thanks a lot. Bad but necessary comment: The ( ) notation in Rcpp is a sugar, after going to a "pure" C++ book I got the difference w.r. to the [ ] notation to extract coordinates. – pachadotdev Apr 07 '22 at 22:47
  • 1
    My pleasure. I am not sure I understand what you are trying to say -- what I was referring to is that _some_ C++ libraries for vectors use both `()` and `[]` to support one with 'bounds check' and one without (and so does `Rcpp`, but most people use `[]`). In general you can not go by "generic C++ books" as all the class extensions are necessarily "local" so you have to check the header files (or documentation). The compiler was reasonably clear here (though still not as clear as one would hope). One gets used to these error messages over time. – Dirk Eddelbuettel Apr 07 '22 at 23:11
  • 1
    Also, if I may, it seems you have never accepted an answer at StackOverflow. It is fairly common (and some may say even expected) to 'reward' an answer addressing your question by 'accepting' it (besides possibly upvoting it). To 'accept' you click the 'tick' sign only you as the person who asked sees; to upvote you click on the 'up' triangle. You get some karma points for accepting too, and it is generally the right thing to do. – Dirk Eddelbuettel Apr 08 '22 at 00:06