Skip to content

[Rcpp-devel] Rcpp equivalent of sample()?

7 messages · Dirk Eddelbuettel, Chris DuBois

#
Hi all,

I'm just getting my feet wet with some Rcpp.  I'm comfortable with R but new
to C++.  In the Rcpp vignettes, I found some of the R-like functions for
sampling from distributions (runif, rnorm, etc), but I didn't see a function
mimicking sample(). I checked the list of unit tests and didn't see it there
either.  Have I missed it?  Is there a C++ function I should be using to
sample (with replacement in my particular situation) from a vector (with
provided weights).

Thanks for any pointers,
Chris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20110514/09b7779b/attachment.htm>
#
On 14 May 2011 at 14:11, Chris DuBois wrote:
| I'm just getting my feet wet with some Rcpp. ?I'm comfortable with R but new
| to C++. ?In the Rcpp vignettes, I found some of the R-like functions for
| sampling from distributions (runif, rnorm, etc), but I didn't see a function
| mimicking sample(). I checked the list of unit tests and didn't see it there
| either. ?Have I missed it? ?Is there a C++ function I should be using to
| sample (with replacement in my particular situation) from a vector (with
| provided weights).

No, sorry, I think you'd have to write a local version.  

Dirk
#
Thanks Dirk.  Quick newbie followup question: Can we put functions within
the inline C++ code?  The following doesn't compile, for example:
src <- '
int addition (int a, int b)
{
  int r;
  r=a+b;
  return (r);
}
NumericVector xx(x);
return(xx);
'
testfun = cxxfunction(signature(x="numeric"),body=src,plugin="Rcpp")

On a related note, would you mind showing a quick working example using
std::accumulate?  The one below from the quick reference doesn't compile for
me.

Thanks in advance.
Chris

std::accumulate( xx.begin(), xx.end(),std::plus<double>(), 0.0 );
On Sat, May 14, 2011 at 2:54 PM, Dirk Eddelbuettel <edd at debian.org> wrote:

            
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20110514/ce466c71/attachment.htm>
#
On 14 May 2011 at 17:13, Chris DuBois wrote:
| Thanks Dirk. ?Quick newbie followup question: Can we put functions within the
| inline C++ code? ?The following doesn't compile, for example:
| src <- '
| int addition (int a, int b)
| {
| ??int r;
| ??r=a+b;
| ??return (r);
| }
| NumericVector xx(x);
| return(xx);
| '
| testfun = cxxfunction(signature(x="numeric"),body=src,plugin="Rcpp")

Use the 'verbose=TRUE' to cxxfunction() and it will become clear
why -- a function is written around the 'body=...' argument,
hence no chance that that part may contain another C++ function.

The remedy is simple: use the "include=..." argument as in 

   inc <- '
   int addition (int a, int b) {
     int r = a + b;
     return (r);
   }
   '
   
   src = '
   NumericVector xx(x);
   return(xx);
   '

   testfun = cxxfunction(signature(x="numeric"), body=src, include=inc, plugin="Rcpp") 


That trick is used a couple of time in the documentation and examples.


| On a related note, would you mind showing a quick working example using
| std::accumulate? ?The one below from the quick reference doesn't compile for
| me.


Try Google for something like that, eg a query that is restricted to my site as in

    site:dirk.eddelbuettel.com  "std::accumulate"

show five immediate hits.  You can similarly constrict the search
to the rcpp-devel list.

Can you send a small example for inline that shows how/where it quickref
example fails for you?

Dirk
#
Thanks Dirk.  Passing the addition function in the includes argument worked
great.

Also, one of the links from your suggested Google search led me to this
(working) example for std::accumulate:

src <- 'NumericVector xx(x);
return wrap( std::accumulate( xx.begin(), xx.end(), 0.0));'
fx <- cxxfunction(signature( x = "numeric" ),body=src,plugin = "Rcpp")
fx(1:10)  # 55

I had been copying the quickref and using:  std::accumulate( xx.begin(),
xx.end(),std::plus<double>(),0.0)

I think this might be a typo where the last two arguments are transposed
(which I shouldn't have noticed after browsing the function's c++
reference<http://www.cppreference.com/wiki/algorithm/accumulate>),
as the following works just fine:  std::accumulate( xx.begin(),
xx.end(),0.0,std::plus<double>())

Chris
On Sat, May 14, 2011 at 5:29 PM, Dirk Eddelbuettel <edd at debian.org> wrote:

            
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20110514/ed55ffb0/attachment.htm>
#
On 14 May 2011 at 18:01, Chris DuBois wrote:
| Thanks Dirk. ?Passing the addition function in the includes argument worked
| great. ?
| 
| Also, one of the links from your suggested Google search led me to this
| (working) example for std::accumulate:
| 
| src <-?'NumericVector xx(x);
| return wrap( std::accumulate( xx.begin(), xx.end(), 0.0));'
| fx <- cxxfunction(signature( x = "numeric" ),body=src,plugin = "Rcpp")
| fx(1:10) ?# 55
| 
| I had been copying the quickref and using: ?std::accumulate( xx.begin(),
| xx.end(),std::plus<double>(),0.0)
| 
| I think this might be a typo where the last two arguments are transposed (which
| I shouldn't have noticed after browsing the function's c++ reference), as the
| following works just fine:??std::accumulate( xx.begin(), xx.end
| (),0.0,std::plus<double>())

Good catch.  The arguments are

     start, end, intial value, (optional) operator function

and std::plus<double>() is the default for summation. So that was an error,
and hence a Thank You! for catching it.  I just committed this new section:


\paragraph{STL interface}~
  \newline
<<lang=cpp>>=
// sum a vector from beginning to end
double s = std::accumulate(x.begin(),
   x.end(), 0.0);
// prod of elements from beginning to end
int p = std::accumulate(vec.begin(),
    vec.end(), 1, std::multiplies<int>());
// inner_product to compute sum of squares
double s2 = std::inner_product(res.begin(),
    res.end(), res.begin(), 0.0);
@


which shows std::multiplies<int>() as an alternative operator for accumulate
as well as inner_product for a sum-of-squares computation (as once suggested
by Doug).

Dirk
#
For now I am using the following, which seems to work.  I didn't really need
all the functionality from sample(); I just needed to get a random index
(but with non-uniform probabilities).  It might be cleaner to use
std::accumulate in rcategorical, but I got this working first.  Also,
rcategorical requires a double[K]; how do I cast my probabilities argument P
as a doubles array?  I naively thought P would already be an array of
doubles, but rcategorical(P,K) doesn't compile.

Any thoughts/suggestions on how to improve on this first attempt?
Thanks in advance,
Chris

###

inc <-
'int rcategorical(double probs[],int K) {
  double total = 0;
  double cumpr = 0;
  int k = 0;
  for (k = 0; k < K; k++) {
    total += probs[k];
  }
  double u = unif_rand();
  for (k = 0; k < K; k++) {
    cumpr += probs[k] / total;
    if (u < cumpr) break;
  }
  return(k);
}'

src <- '
Rcpp:NumericVector probs(P);
int K = probs.size();
double pr[K];
for (int k = 0; k < K; k++) {  // copy elements over one-by-one?  Noob
status, but works. :-)
  pr[k] = probs[k];
}
int R = rcategorical(pr,K);
return wrap(R);
'
fun <-  cxxfunction(signature(P="numeric"),includes=inc,body = src,
plugin="Rcpp")
p <- c(.2,.3,.4,.1)
fun(p)
On Sat, May 14, 2011 at 6:19 PM, Dirk Eddelbuettel <edd at debian.org> wrote:

            
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20110514/e7cd3a4f/attachment-0001.htm>