Skip to content
Prev 5330 / 10988 Next

[Rcpp-devel] Rcpp: Distinguishing between input types to function call

Thanks a lot! 

I thought that Rf_inherits was the Rcpp version of inherits (which gives what I expect).
[1] TRUE
[1] FALSE
[1] FALSE
[1] FALSE
[1] FALSE
[1] TRUE
[1] FALSE
[1] TRUE
[1] FALSE

Best regards
S?ren

-----Original Message-----
From: Romain Francois [mailto:romain at r-enthusiasts.com] 
Sent: 20. februar 2013 09:53
To: S?ren H?jsgaard
Cc: rcpp-devel at lists.r-forge.r-project.org
Subject: Re: [Rcpp-devel] Rcpp: Distinguishing between input types to function call

Hello,

Here is a shorter version of your code. The key idea was to use TYPEOF instead of Rf_inherits which uses the class attribute (simple vectors don't have them).

#include <Rcpp.h>
using namespace Rcpp;

template <int RTYPE>
SEXP allpairsXtemplate_( SEXP XX_ ){
   Vector<RTYPE> X(XX_);
   Matrix<RTYPE> ans(2, X.size()*(X.size()-1)/2);
   int col=0;
   for (int ii=0; ii<X.size(); ii++){
     for (int jj=ii+1; jj<X.size(); jj++){
       ans(0,col) = X(ii);
       ans(1,col++) = X(jj);
     }
   }
   return ans ;
};

// [[Rcpp::export]]
SEXP allpairsX_ ( SEXP XX_ ){
     int type = TYPEOF(XX_) ;
     switch( type ){
         case INTSXP : return allpairsXtemplate_<INTSXP> ( XX_ ) ;
         case REALSXP: return allpairsXtemplate_<REALSXP>( XX_ ) ;
         case STRSXP : return allpairsXtemplate_<STRSXP> ( XX_ ) ;
     }
     return R_NilValue ;
}


/*** R

XX1 <- letters[1:4] # character
XX2 <- 1:4          # integer
XX3 <- (1:4)+.5     # numeric

allpairsX_( XX1 )
allpairsX_( XX2 )
allpairsX_( XX3 )

***/

Also, I'm templating allpairsXtemplate_ on the R type rather than the actual classes, because NumericVector = Vector<REALSXP>, etc ...


About your code, with e.g. TT = NumericVector, you don't need as in :

TT X = as<TT>(XX_);

because NumericVector already has a SEXP constructor, that is why I do: 
Vector<RTYPE> X(XX_);



Same for return(wrap(ans));  you don't need to call wrap here because 
ans can convert itself to SEXP.



Another way to write this using Rcpp's builtin dispatch mechanism is to 
use RCPP_RETURN_VECTOR. For example :

#include <Rcpp.h>
using namespace Rcpp;

template <typename T>
SEXP allpairsXtemplate_( const T& X){
   const int RTYPE = T::r_type::value ;
   Matrix<RTYPE> ans(2, X.size()*(X.size()-1)/2);
   int col=0;
   for (int ii=0; ii<X.size(); ii++){
     for (int jj=ii+1; jj<X.size(); jj++){
       ans(0,col) = X(ii);
       ans(1,col++) = X(jj);
     }
   }
   return ans ;
};

// [[Rcpp::export]]
SEXP allpairsX_ ( SEXP XX_ ){
     RCPP_RETURN_VECTOR( allpairsXtemplate_, XX_ ) ;
     return R_NilValue ; // never used
}


So we call one of the generated overloads of allpairsXtemplate_ which 
takes a Vector as input. From this vector, we can deduce the RTYPE (at 
compile time):

const int RTYPE = T::r_type::value ;

use it to get the correct Matrix type : Matrix<RTYPE>.



Yet another way, probably the one I would use:

template <int RTYPE>
Matrix<RTYPE> allpairsXtemplate_( const Vector<RTYPE>& X){
   Matrix<RTYPE> ans(2, X.size()*(X.size()-1)/2);
   int col=0;
   for (int ii=0; ii<X.size(); ii++){
     for (int jj=ii+1; jj<X.size(); jj++){
       ans(0,col) = X(ii);
       ans(1,col++) = X(jj);
     }
   }
   return ans ;
};

This works because RCPP_RETURN_VECTOR will cast to the appropriate 
Vector type.

And knowing the RTYPE at first lets us use it on the output signture.


RCPP_RETURN_VECTOR is defined in dispatch.h (macro haters beware):

#define ___RCPP_HANDLE_CASE___( ___RTYPE___ , ___FUN___ , ___OBJECT___ , 
___RCPPTYPE___ )	\
	case ___RTYPE___ :																	\
		return ___FUN___( ::Rcpp::___RCPPTYPE___< ___RTYPE___ >( 
___OBJECT___ ) ) ;	
		
#define ___RCPP_RETURN___( __FUN__, __SEXP__ , __RCPPTYPE__ )						\
	SEXP __TMP__ = __SEXP__ ;															\
	switch( TYPEOF( __TMP__ ) ){										 				\
		___RCPP_HANDLE_CASE___( INTSXP  , __FUN__ , __TMP__ , __RCPPTYPE__ )			\
		___RCPP_HANDLE_CASE___( REALSXP , __FUN__ , __TMP__ , __RCPPTYPE__ )			\
		___RCPP_HANDLE_CASE___( RAWSXP  , __FUN__ , __TMP__ , __RCPPTYPE__ )			\
		___RCPP_HANDLE_CASE___( LGLSXP  , __FUN__ , __TMP__ , __RCPPTYPE__ )			\
		___RCPP_HANDLE_CASE___( CPLXSXP , __FUN__ , __TMP__ , __RCPPTYPE__ )			\
		___RCPP_HANDLE_CASE___( STRSXP  , __FUN__ , __TMP__ , __RCPPTYPE__ )			\
		___RCPP_HANDLE_CASE___( VECSXP  , __FUN__ , __TMP__ , __RCPPTYPE__ )			\
		___RCPP_HANDLE_CASE___( EXPRSXP , __FUN__ , __TMP__ , __RCPPTYPE__ )			\
	default:																			\
		throw std::range_error( "not a vector" ) ;									\
	}

#define RCPP_RETURN_VECTOR( _FUN_, _SEXP_ )  ___RCPP_RETURN___( _FUN_, 
_SEXP_ , Vector )
#define RCPP_RETURN_MATRIX( _FUN_, _SEXP_ )  ___RCPP_RETURN___( _FUN_, 
_SEXP_ , Matrix )



Romain

Le 20/02/13 00:15, S?ren H?jsgaard a ?crit :
his scope
 template.cpp:84:10: warning: unused variable 'XX_' [-Wunused-variable] template.cpp: In function 'SEXPREC* sourceCpp_55702_allpairsX_num(SEXP)': template.cpp:94:5: error: expected unqualified-id before string constant template.cpp:95:23: error: '__result' was not declared in this scope template.cpp:93:10: warning: unused variable 'XX_' [-Wunused-variable] template.cpp: In function 'SEXPREC* sourceCpp_55702_allpairsX_(SEXP)': template.cpp:103:5: error: expected unqualified-id before string constant template.cpp:104:23: error: '__result' was not declared in this scope template.cpp:102:10: warning: unused variable 'XX_' [-Wunused-variable] make: *** [template.o] Error 1