[Rcpp-devel] Issue with Matrices and Iterators

Romain Francois romain at r-enthusiasts.com
Mon Oct 14 21:41:32 CEST 2013


Le 14/10/13 21:21, Alessandro Mammana a écrit :
> Hi all,
> I have very little experience with Rcpp and also with c++, so I am
> sorry if my question might be too stupid.
> I am trying to use iterators in my code, because I understand them
> better than vectors, because they should be efficient, and because I
> should be able to combine different implementations of vector and
> matrix classes. However the following code does not compile:
>
> #include <Rcpp.h>
> using namespace Rcpp;
>
> typedef NumericVector::iterator DoubleIter;
>
> double sum(DoubleIter b, DoubleIter e){
>      double sum = 0;
>      while (b!=e){
>          sum += *(b++);
>      }
>      return sum;
> }
>
> // [[Rcpp::export]]
> double sumFirstRow(NumericMatrix mat){
>      return sum(mat(0,_).begin(), mat(0,_).end());
> }
>
> The error message is not very useful (or at least I cannot interpret it):
>
> In function 'double sumFirstRow(Rcpp::NumericMatrix)':
> error: no matching function for call to
> 'sum(Rcpp::MatrixRow<14>::iterator, Rcpp::MatrixRow<14>::iterator)'
> note: candidates are:
> note: double sum(DoubleIter, DoubleIter)
> note: no known conversion for argument 1 from
> 'Rcpp::MatrixRow<14>::iterator' to 'DoubleIter {aka double*}'
>
> Am I missing something very basic?
> Thanks a lot!
> Ale

mat(0,_).begin() gives you an object that acts 	as an iterator over the 
first row. This is not the same thing as an iterator over a vector.

 > demangle( "NumericVector::iterator" )
[1] "double*"
 > demangle( "NumericMatrix::Row::iterator" )
[1] "Rcpp::MatrixRow<14>::iterator"


The first part of what you are missing is templates: you should define 
you sum function like this:

template <typename Iterator>
double sum(Iterator b, Iterator e){
     double sum = 0;
     while (b!=e){
         sum += *(b++);
     }
     return sum;
}

although, this is not generic enough, in situations where you iterate 
over the first row of an integer matrix, you should not use double, but 
int. So you can do something like this:

template <typename Iterator>
typename traits::remove_reference< typename 
std::iterator_traits<Iterator>::value_type>::type sum(Iterator b, 
Iterator e){
     typedef typename traits::remove_reference<typename 
std::iterator_traits<Iterator>::value_type>::type STORAGE ;
     STORAGE sum = 0;
     while (b!=e) sum += *(b++);
     return sum;
}

A bit more involved, but more generic.

Lastly, you can also recognize that this is in fact an algorithm from 
the STL: accumulate, so you can do something like this;


// [[Rcpp::export]]
double sumFirstRowSTL(NumericMatrix mat){
     return std::accumulate(mat(0,_).begin(), mat(0,_).end(), 0.0);
}

Romain

-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30



More information about the Rcpp-devel mailing list