[Rcpp-devel] When does using iterators for subscripting help?
Douglas Bates
bates at stat.wisc.edu
Fri Jan 6 20:23:09 CET 2012
2012/1/6 Hadley Wickham <hadley at rice.edu>:
>> I'm coming late to the party but ... I was able to squeeze a couple
>> of milliseconds from the computation by expressing the counts as
>> integers and ensuring that I did not copy x by using an Eigen::Map.
>> It may well be that an Rcpp::NumericVector will not be a copy in this
>> case but I have found it difficult to determine exactly when an Rcpp
>> vector is going to be copied. With Eigen I can ensure that the
>> original storage in R will be used for the vector.
>>
>> count_eigen <- cxxfunction(signature(x="numeric", binwidth="numeric",
>> origin="numeric", nbins="integer"), '
>> double binwidth_ = ::Rf_asReal(binwidth), origin_ = ::Rf_asReal(origin);
>>
>> Eigen::VectorXi counts(::Rf_asInteger(nbins));
>> Eigen::Map<Eigen::VectorXd> x_(as<Eigen::Map<Eigen::VectorXd> >(x));
>>
>> int n = x_.size();
>>
>> counts.setZero();
>> for (int i = 0; i < n; i++) counts[((x_[i] - origin_) / binwidth_)]++;
>>
>> return wrap(counts);
>> ', plugin="RcppEigen")
>>
>>
>> As you see, I use ::Rf_asReal() and ::Rf_asInteger() for conversion to
>> scalar doubles or scalar integers. Those functions are part of the R
>> API and are fast and general.
>
> Thanks. Would you mind explaining a couple of the C++ idioms that you used?
>
> * What's going on with Eigen::Map<Eigen::VectorXd>
> x_(as<Eigen::Map<Eigen::VectorXd> >(x)) - you're creating a new Map
> (templated to contain VectorXds) called x_ and initialising with a
> converted x?
Dirk and I wrote an introductory vignette for the RcppEigen package
which, if you have not already done so, would be worth looking at.
An Eigen::VectorXd is a double precision vector with storage allocated
from the C++ heap. An Eigen::Map<Eigen::Vector> behaves similarly but
maps the storage from some other source, in this case the storage from
R. Had I followed the recommendations in the vignette mentioned above
I would have declared it as
const Eigen::Map<Eigen::VectorXd> x_(as<Eigen::Map<Eigen::VectorXd> >(x));
to emphasize that it is a read-only vector.
> * I find it hard to visually parse <Eigen::Map<Eigen::VectorXd> >(x).
> Is there a reason you don't write it as
> x_(as<Eigen::Map<Eigen::VectorXd>>(x)? Maybe because that would then
> form the >> operator?
Yes, exactly. In production code I usually write something like
typedef Eigen::Map<Eigen::VectorXd> MVec;
const MVec x_(as<MVec>(x));
As I said earlier, this construction guarantees that the storage is
not copied. An Rcpp::NumericVector also uses the storage from R but
it can be difficult to determine exactly when a copy constructor,
which actually allocates new storage for an SEXPREC, is invoked.
> * What does ::Rf_asReal mean? How is it different to Rf_asReal?
>
> Thanks!
>
> Hadley
>
> --
> Assistant Professor / Dobelman Family Junior Chair
> Department of Statistics / Rice University
> http://had.co.nz/
More information about the Rcpp-devel
mailing list