[Rcpp-devel] How to modifying the elements of a list in the global environment?

Dirk Eddelbuettel edd at debian.org
Fri Oct 19 04:55:12 CEST 2012


On 19 October 2012 at 02:28, Giovanni Petris wrote:
| Thanks Dirk!
| 
| By the way, I just figured out a working solution for what I wanted to achieve - 'code_f' below.

Cool. 

In return, a "repaired" version without globals that receives the list, and
returns the modified list.  That is much more "functional" and in the spirit
of R, and if you have a moment to run rbenchmark or microbenchmark over it
will presumably be about as fast (or so I conjecture :)

R> code_f <- '
+     Rcpp::NumericMatrix cpp_x(x);
+     Rcpp::NumericMatrix cpp_mu(mu);
+     Rcpp::List cpp_work(ls);             // pass list in
+     int K = cpp_mu.ncol();
+     int M = cpp_mu.nrow();
+     NumericMatrix tmpMatrix;
+ 
+     for (int k=0; k < K; k++) {
+         tmpMatrix = Rcpp::as<Rcpp::NumericMatrix>(cpp_work[k]);
+         for (int i=0; i < M; i++)
+             tmpMatrix(_, i) = cpp_x(_, i) - cpp_mu(i, k);
+         cpp_work[k] = tmpMatrix;
+     }
+     return cpp_work;
+ '
R> f <- rcpp(signature(x = "numeric", mu = "numeric", ls = "list"), code_f)
R> ws2 <- lapply(1:K, function(k) matrix(0.0, N, M))
R> ws2 <- f(x, mu, ws2)
R> all.equal(workspace, ws2)
[1] TRUE
R> 

Dirk

PS  You forgot a set.seed(someVal) to make it really reproducible.

 
| Best,
| Giovanni
| =====
| 
| ### Small reproducible example
| K <- 2; N <- 5; M <- 3
| x <- matrix(rnorm(N * M), N, M)
| mu <- matrix(rnorm(M * K, mean = 1 : K), M, K, TRUE)
| 
| ### What I would do in R
| f_R <- function() {
|     ## center observations in 'x' using columns of 'mu'
|     w <- lapply(1L:K, function(i) x - rep(mu[, i], each = N))
|     ## eventually more stuff here...
|     w
| }
| 
| ### For the Rcpp part, set aside working space in the global environment
| workspace <- lapply(1:K, function(k) matrix(0.0, N, M))
| 
| code_f <- '
|     Rcpp::NumericMatrix cpp_x(x);
|     Rcpp::NumericMatrix cpp_mu(mu); 
|     int K = cpp_mu.ncol();
|     int M = cpp_mu.nrow();
|     int N = cpp_x.nrow();
|     Environment glob = Environment::global_env(); 
|     List cpp_work(glob.get("workspace"));
|     NumericMatrix tmpMatrix;
| 
|     for (int k=0; k < K; k++) {
|         tmpMatrix = as<SEXP>(cpp_work[k]);
|         for (int i=0; i < M; i++) 
|             tmpMatrix(_, i) = cpp_x(_, i) - cpp_mu(i, k);
|     }
| 
|     return R_NilValue;
| '
| ## library(Rcpp); library(inline)
| f_cpp <- cxxfunction(signature(x = "numeric", mu = "numeric"), code_f, plugin = "Rcpp")
| 
| ## try it
| f_cpp(x, mu)
| all.equal(workspace, f_R())
| 
| 
| ________________________________________
| From: Dirk Eddelbuettel [edd at debian.org]
| Sent: Thursday, October 18, 2012 9:15 PM
| To: Giovanni Petris
| Cc: Dirk Eddelbuettel; rcpp-devel at lists.r-forge.r-project.org
| Subject: RE: [Rcpp-devel] How to modifying the elements of a list in the        global  environment?
| 
| On 19 October 2012 at 01:32, Giovanni Petris wrote:
| | Hi Dirk,
| |
| | Thank you for the quick reply. I will look for more examples on the net.
| |
| | About your suggestion of allocating scrap space inside the C++ routine, am I wrong to think that when the matrices are large and the function is called repeatedly within a Gibbs sampler loop, this is not a very efficient approach?
| 
| Yes, if you want to use it several times you can pass it around for reuse.
| As I mentioned, a reference is just a pointer and hence unrelated to the size
| of the object.
| 
| Dirk
| 
| | Thanks again!
| |
| | Best,
| | Giovanni
| |
| | ________________________________________
| | From: Dirk Eddelbuettel [edd at debian.org]
| | Sent: Thursday, October 18, 2012 8:06 PM
| | To: Dirk Eddelbuettel
| | Cc: Giovanni Petris; rcpp-devel at lists.r-forge.r-project.org
| | Subject: Re: [Rcpp-devel] How to modifying the elements of a list in the        global  environment?
| |
| | Giovanni,
| |
| | On 18 October 2012 at 17:46, Dirk Eddelbuettel wrote:
| | | | > code_f <- '
| | | | +     Rcpp::NumericMatrix cpp_x(x);
| | | | +     Rcpp::NumericMatrix cpp_mu(mu);
| | | | +     int K = cpp_mu.ncol();
| | | | +     int M = cpp_mu.nrow();
| | | | +     int N = cpp_x.nrow();
| | | | +     Environment glob = Environment::global_env();
| | | | +     List cpp_work(glob.get("workspace"));
| | | | +
| | | | +     for (int k=0; k < K; k++) {
| | | | +         cpp_work[k] = clone(cpp_x);
| | | | +         for (int i=0; i < M; i++)
| | | | +             cpp_work(_, i) = cpp_work(_, i) - cpp_mu(i, k);
| |
| | That can't work.  You have the types confused.
| |
| | You could just pass the list object down, and then pick from it.  Working
| | examples for that are in the list archives, in the RcppExamples package, and
| | in other places on the net.
| |
| | Or, as I suggested, just allocate the scrap space inside the C++ routine.
| |
| | Hth,  Dirk
| |
| | --
| | Dirk Eddelbuettel | edd at debian.org | http://dirk.eddelbuettel.com
| 
| --
| Dirk Eddelbuettel | edd at debian.org | http://dirk.eddelbuettel.com

-- 
Dirk Eddelbuettel | edd at debian.org | http://dirk.eddelbuettel.com  


More information about the Rcpp-devel mailing list