Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way in which to make an Infix function using sourceCpp()

Tags:

r

rcpp

I was wondering whether it is possible to make an infix function, e.g. A %o% B with Rcpp.

I know that this is possible using the inline package, but have yet been able to find a method for doing this when using sourceCpp().

I have made the following infix implementation of %o% / outer() when arguments are sure to be vectors using RcppEigen and inline:

`%op%` <- cxxfunction(signature(v1="NumericVector",
                                v2="NumericVector"),
                      plugin = "RcppEigen",
                      body = c("
                  NumericVector xx(v1);
                  NumericVector yy(v2);

                  const Eigen::Map<Eigen::VectorXd> x(as<Eigen::Map<Eigen::VectorXd> >(xx));
                  const Eigen::Map<Eigen::VectorXd> y(as<Eigen::Map<Eigen::VectorXd> >(yy));

                  Eigen::MatrixXd op = x * y.transpose();
                  return Rcpp::wrap(op);
                           "))

This can easily be implemented in to be imported using sourceCpp(), however not as an infix function.

My current attempt is as follows:

#include <Rcpp.h>
using namespace Rcpp;
#include <RcppEigen.h>

// [[Rcpp::depends(RcppEigen)]]



// [[Rcpp::export]]
NumericMatrix outerProd(NumericVector v1, NumericVector v2) {
  NumericVector xx(v1);
  NumericVector yy(v2);

  const Eigen::Map<Eigen::VectorXd> x(as<Eigen::Map<Eigen::VectorXd> >(xx));
  const Eigen::Map<Eigen::VectorXd> y(as<Eigen::Map<Eigen::VectorXd> >(yy));

  Eigen::MatrixXd op = x * y.transpose();
  return Rcpp::wrap(op);
}

So to summarize my question.. Is it possible to make an infix function available through sourceCpp?

like image 482
JPM Avatar asked Mar 27 '26 15:03

JPM


2 Answers

Is it possible to make an infix function available through sourceCpp?

Yes.

As always, one should read the Rcpp vignettes! In particular here, if you look in Section 1.6 of the Rcpp attributes vignette, you'd see you can modify the name of a function using the name parameter for Rcpp::export. For example, we could do:

#include <Rcpp.h>

// [[Rcpp::export(name = `%+%`)]]
Rcpp::NumericVector add(Rcpp::NumericVector x, Rcpp::NumericVector y) {
  return x + y;
}

/*** R
1:3 %+% 4:6
*/

Then we'd get:

Rcpp::sourceCpp("~/infix-test.cpp")

> 1:3 %+% 4:6
[1] 5 7 9

So, you still have to name C++ functions valid C++ names in the code, but you can export it to R through the name parameter of Rcpp::export without having to do anything further on the R side.

like image 102
duckmayr Avatar answered Mar 29 '26 05:03

duckmayr


John Chambers states three principles on page four of the (highly recommended) "Extending R" book:

  • Everything that exists in R is an object.
  • Everything that happens in R is a function call.
  • Interfaces to other software are part of R.

So per point two, you can of course use sourceCpp() to create your a compiled function and hang that at any odd infix operator you like.

Code Example

library(Rcpp)
cppFunction("std::string cc(std::string a, std::string b) { return a+b; }")
`%+%` <- function(a,b) cc(a,b)

cc("Hello", "World")

"hello" %+% "world"

Output

R> library(Rcpp)
R> cppFunction("std::string cc(std::string a, std::string b) { return a+b; }")
R> `%+%` <- function(a,b) cc(a,b)
R> 
R> cc("Hello", "World")
[1] "HelloWorld"
R> 
R> "hello" %+% "world"
[1] "helloworld"
R> 

Summary

Rcpp is really just one cog in the machinery.

Edit

It also works with your initial function, with some minor simplification. For

`%op%` <- cppFunction("Eigen::MatrixXd op(Eigen::VectorXd x, Eigen::VectorXd y) { Eigen::MatrixXd op = x * y.transpose(); return op; }", depends="RcppEigen")

as.numeric(1:3) %op% as.numeric(3:1)

we get

R> `%op%` <- cppFunction("Eigen::MatrixXd op(Eigen::VectorXd x, Eigen::VectorXd y) { Eigen::MatrixXd op = x * y.transpose(); return op; }", depends="RcppEigen")
R> as.numeric(1:3) %op% as.numeric(3:1)
     [,1] [,2] [,3]
[1,]    3    2    1
[2,]    6    4    2
[3,]    9    6    3
R> 

(modulo some line noise from the compiler).

like image 33
Dirk Eddelbuettel Avatar answered Mar 29 '26 06:03

Dirk Eddelbuettel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!