[Rcpp-commits] r2208 - in pkg/Rcpp/inst: . examples/performance include include/Rcpp/traits include/Rcpp/vector

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Mon Sep 27 15:10:33 CEST 2010


Author: romain
Date: 2010-09-27 15:10:33 +0200 (Mon, 27 Sep 2010)
New Revision: 2208

Added:
   pkg/Rcpp/inst/include/Rcpp/traits/is_sugar_expression.h
Modified:
   pkg/Rcpp/inst/ChangeLog
   pkg/Rcpp/inst/examples/performance/extractors.R
   pkg/Rcpp/inst/include/Rcpp/traits/matrix_interface.h
   pkg/Rcpp/inst/include/Rcpp/vector/Vector.h
   pkg/Rcpp/inst/include/Rcpp/vector/VectorBase.h
   pkg/Rcpp/inst/include/RcppCommon.h
Log:
speedup in Vector::operator=( sugar expression )

Modified: pkg/Rcpp/inst/ChangeLog
===================================================================
--- pkg/Rcpp/inst/ChangeLog	2010-09-27 10:22:26 UTC (rev 2207)
+++ pkg/Rcpp/inst/ChangeLog	2010-09-27 13:10:33 UTC (rev 2208)
@@ -1,3 +1,11 @@
+2010-09-27  Romain Francois <romain at r-enthusiasts.com>
+
+        * inst/include/Rcpp/traits/is_sugar_expression.h: new trait class
+        to recognize sugar expressions
+        
+        * inst/include/Rcpp/vector/Vector.h: operator=( sugar expression) 
+        no longer allocate unnecessary memory. 
+
 2010-09-26  Romain Francois <romain at r-enthusiasts.com>
 
         * inst/include/Rpp/Fast.h: new helper class Rcpp::Fast that allows

Modified: pkg/Rcpp/inst/examples/performance/extractors.R
===================================================================
--- pkg/Rcpp/inst/examples/performance/extractors.R	2010-09-27 10:22:26 UTC (rev 2207)
+++ pkg/Rcpp/inst/examples/performance/extractors.R	2010-09-27 13:10:33 UTC (rev 2208)
@@ -33,7 +33,12 @@
     list( 
         direct = signature( x_ = "numeric", y_ = "numeric" ), 
         extractor = signature( x_ = "numeric", y_ = "numeric" ), 
-        sugar_nona = signature( x_ = "numeric", y_ = "numeric" )
+        sugar_nona = signature( x_ = "numeric", y_ = "numeric" ), 
+        
+        assign_direct = signature( x_ = "numeric", y_ = "numeric" ), 
+        assign_extractor = signature( x_ = "numeric", y_ = "numeric" ), 
+        assign_sugar_nona = signature( x_ = "numeric", y_ = "numeric" ) 
+        
     ) , 
     list( 
         direct = '
@@ -53,23 +58,61 @@
         for( int j=0; j<1000; j++) 
             res = sugar_nona__( x_, y_ ) ;
         return res ;
+        ', 
+        
+        assign_direct = '
+        NumericVector x( x_ ), y( y_ ), z( x.size() ) ;
+        int n = x.size() ;
+        for( int j=0; j<1000; j++)
+            for( int i=0; i<n; i++) 
+                z[i] = x[i] * y[i] ;
+        return z ; 
+        ', 
+        
+        assign_extractor = '
+        NumericVector x( x_ ), y( y_ ), z( x.size() ) ;
+        Fast<NumericVector> fx(x), fy(y), fz(z)  ;
+        int n = x.size() ;
+        for( int j=0; j<1000; j++)
+            for( int i=0; i<n; i++) 
+                fz[i] = fx[i] * fy[i] ;
+        return z ; 
+        ', 
+        
+        assign_sugar_nona = '
+        NumericVector x( x_ ), y( y_ ), z( x.size() ) ;
+        sugar::Nona< REALSXP, true, NumericVector > nx(x), ny(y) ;
+        for( int j=0; j<1000; j++)
+            z = nx * ny ;
+        return z ;
         '
     ) , plugin = "Rcpp", includes = inc )
 
-x <- rnorm( 1000000 )
-y <- rnorm( 1000000 )
+x <- rnorm( 100000 )
+y <- rnorm( 100000 )
 
 # resolving
-invisible( { fx$direct( 1.0, 1.0 ); fx$extractor( 1.0, 1.0 ); fx$sugar_nona(1.0, 1.0 )} )
-    
+invisible( getDynLib( fx ) )
+
 require( rbenchmark )
+
 benchmark( 
     fx$direct( x, y ), 
     fx$extractor( x, y ), 
     fx$sugar_nona( x, y ), 
+    
     replications = 1, 
     columns=c("test", "elapsed", "relative", "user.self", "sys.self"),
     order="relative"
 )
     
+benchmark( 
+    fx$assign_direct( x, y ), 
+    fx$assign_extractor( x, y ), 
+    fx$assign_sugar_nona( x, y ), 
+    
+    replications = 1, 
+    columns=c("test", "elapsed", "relative", "user.self", "sys.self"),
+    order="relative"
+)     
 

Added: pkg/Rcpp/inst/include/Rcpp/traits/is_sugar_expression.h
===================================================================
--- pkg/Rcpp/inst/include/Rcpp/traits/is_sugar_expression.h	                        (rev 0)
+++ pkg/Rcpp/inst/include/Rcpp/traits/is_sugar_expression.h	2010-09-27 13:10:33 UTC (rev 2208)
@@ -0,0 +1,49 @@
+// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 4 -*-
+//
+// is_sugar_expression.h: Rcpp R/C++ interface class library -- 
+//
+// Copyright (C) 2010	Dirk Eddelbuettel and Romain Francois
+//
+// This file is part of Rcpp.
+//
+// Rcpp is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 2 of the License, or
+// (at your option) any later version.
+//
+// Rcpp is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Rcpp.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef Rcpp__traits__is_sugar_expression_h
+#define Rcpp__traits__is_sugar_expression_h
+
+namespace Rcpp{
+namespace traits{
+
+	template<typename T>
+	class _is_sugar_expression_helper : __sfinae_types {
+      template<typename U> struct _Wrap_type { };
+
+      template<typename U>
+        static __one __test(_Wrap_type<typename U::rcpp_sugar_expression>*);
+
+      template<typename U>
+        static __two __test(...);
+
+    public:
+      static const bool value = sizeof(__test<T>(0)) == 1;
+    };
+  
+  template<typename T> struct is_sugar_expression : 
+  	integral_constant<bool, _is_sugar_expression_helper<T>::value >{ };
+    
+    
+} 
+}
+
+#endif

Modified: pkg/Rcpp/inst/include/Rcpp/traits/matrix_interface.h
===================================================================
--- pkg/Rcpp/inst/include/Rcpp/traits/matrix_interface.h	2010-09-27 10:22:26 UTC (rev 2207)
+++ pkg/Rcpp/inst/include/Rcpp/traits/matrix_interface.h	2010-09-27 13:10:33 UTC (rev 2208)
@@ -29,14 +29,6 @@
 namespace Rcpp{
 namespace traits{
 
-	template <int RTYPE>
-	struct matrix_interface__impl{} ;
-	
-	template <>
-	struct matrix_interface__impl<LGLSXP> {
-		struct r_matrix_interface{}; 
-	} ;
-
 	template<typename T>
 	class _has_matrix_interface_helper : __sfinae_types {
       template<typename U> struct _Wrap_type { };

Modified: pkg/Rcpp/inst/include/Rcpp/vector/Vector.h
===================================================================
--- pkg/Rcpp/inst/include/Rcpp/vector/Vector.h	2010-09-27 10:22:26 UTC (rev 2207)
+++ pkg/Rcpp/inst/include/Rcpp/vector/Vector.h	2010-09-27 13:10:33 UTC (rev 2208)
@@ -22,6 +22,8 @@
 #ifndef Rcpp__vector__Vector_h
 #define Rcpp__vector__Vector_h
 
+// template <int RTYPE, typename VEC, typename T> class Assigner ; 
+
 template <int RTYPE>
 class Vector :
 	public RObject,       
@@ -51,7 +53,7 @@
 	}
 	
 	Vector& operator=( const Vector& other ){
-		RObject::setSEXP( other.asSexp() ) ;
+		set_sexp( other.asSexp() ) ;
 		return *this ;
 	}
 	
@@ -62,15 +64,58 @@
 	Vector( const RObject::AttributeProxy& proxy ) throw(not_compatible) {
 		RObject::setSEXP( r_cast<RTYPE>( proxy ) ) ;
 	}
-	
+		
 	template <typename T>
 	Vector& operator=( const T& x){
-	    // TODO: wrap will reallocate the memory. we can definitely avoid that
-	    //       if this is of the same size as the target
-		RObject::setSEXP( r_cast<RTYPE>( wrap(x) ) ) ;
-		return *this ;
+	    assign_object( x, typename traits::is_sugar_expression<T>::type() ) ;
+	    return *this ;
 	}
 	
+private:
+    
+    // sugar
+    template <typename T>
+	inline void assign_object( const T& x, traits::true_type ){
+	    int n = size() ;
+	    if( n == x.size() ){
+           
+            // just copy the data 
+            iterator start = begin() ;
+            
+            int __trip_count = n >> 2 ;
+            int i = 0 ;
+            for ( ; __trip_count > 0 ; --__trip_count) { 
+            	start[i] = x[i] ; i++ ;            
+            	start[i] = x[i] ; i++ ;            
+            	start[i] = x[i] ; i++ ;            
+            	start[i] = x[i] ; i++ ;            
+            }                                            
+            switch (n - i){                          
+              case 3:                                    
+                  start[i] = x[i] ; i++ ;             
+              case 2:                                    
+                  start[i] = x[i] ; i++ ;             
+              case 1:                                    
+                  start[i] = x[i] ; i++ ;             
+              case 0:                                    
+              default:                                   
+                  {}                         
+            }
+        } else{
+            // different size, so we change the memory
+            set_sexp( r_cast<RTYPE>( wrap(x) ) ); 
+        }
+    }
+    
+	// anything else
+	template <typename T>
+	inline void assign_object( const T& x, traits::false_type ){
+	    // TODO: maybe we already have the memory to host the results
+	    set_sexp( r_cast<RTYPE>( wrap(x) ) ) ;
+	}
+    
+public:
+	
 	internal::ListInitialization<iterator,init_type> operator=( init_type x){
 		iterator start = begin() ; *start = x; 
 		return internal::ListInitialization<iterator,init_type>( start + 1 ) ; ;
@@ -470,10 +515,12 @@
 	}
 	
 	
+public:
 	void set_sexp(SEXP x){
 		RObject::setSEXP( x) ;
 		update_vector() ;
 	}
+private:
 	
 	void push_back__impl(const stored_type& object){
 		int n = size() ;
@@ -744,4 +791,69 @@
 	
 } ; /* Vector */
 
+// template <int RTYPE, typename VEC, typename T>
+// class Assigner{
+// public:
+//     
+//     Assigner( VEC& target_, const T& source_ ) : target(target_), source(source_){
+//         Rprintf( "Assigner wrap ( %s )\n", DEMANGLE(Assigner) ) ;
+//     }
+// 
+//     inline void assign(){ 
+//         target.set_sexp( r_cast<RTYPE>( wrap(source) ) ); 
+//     }
+//     
+// private:
+//     VEC& target ;
+//     const T& source ;
+// } ;
+// 
+// template <int RTYPE,  typename VEC, bool SOURCE_NA, typename SOURCE_T>
+// class Assigner<RTYPE,VEC, VectorBase<RTYPE,SOURCE_NA,SOURCE_T> >{
+// public:
+//     
+//     typedef VectorBase<RTYPE,SOURCE_NA,SOURCE_T> T ;
+//     
+//     Assigner( VEC& target_, const T& source_ ) : target(target_), source(source_){
+//         Rprintf( "Assigner sugar ( %s )\n", DEMANGLE(Assigner) ) ;
+//     }
+// 
+//     inline void assign(){ 
+//         int n = target.size() ;
+//         if( n == source.size() ){
+//            
+//             const SOURCE_T& ref = source.get_ref() ;
+//             // just copy the data 
+//             typename VEC::iterator start = target.begin() ;
+//             
+//             int __trip_count = n >> 2 ;
+//             int i = 0 ;
+//             for ( ; __trip_count > 0 ; --__trip_count) { 
+//             	start[i] = ref[i] ; i++ ;            
+//             	start[i] = ref[i] ; i++ ;            
+//             	start[i] = ref[i] ; i++ ;            
+//             	start[i] = ref[i] ; i++ ;            
+//             }                                            
+//             switch (n - i){                          
+//               case 3:                                    
+//                   start[i] = ref[i] ; i++ ;             
+//               case 2:                                    
+//                   start[i] = ref[i] ; i++ ;             
+//               case 1:                                    
+//                   start[i] = ref[i] ; i++ ;             
+//               case 0:                                    
+//               default:                                   
+//                   {}                         
+//             }
+//         } else{
+//             target.set_sexp( r_cast<RTYPE>( wrap(source) ) ); 
+//         }
+//     }
+//     
+// private:
+//     VEC& target ;
+//     const T& source ;
+//     
+// } ;
+
 #endif

Modified: pkg/Rcpp/inst/include/Rcpp/vector/VectorBase.h
===================================================================
--- pkg/Rcpp/inst/include/Rcpp/vector/VectorBase.h	2010-09-27 10:22:26 UTC (rev 2207)
+++ pkg/Rcpp/inst/include/Rcpp/vector/VectorBase.h	2010-09-27 13:10:33 UTC (rev 2208)
@@ -28,7 +28,8 @@
 template <int RTYPE, bool na, typename VECTOR>
 class VectorBase : public traits::expands_to_logical__impl<RTYPE> {
 public:
-	struct r_type : traits::integral_constant<int,RTYPE>{} ;
+	struct rcpp_sugar_expression{} ;
+    struct r_type : traits::integral_constant<int,RTYPE>{} ;
 	struct can_have_na : traits::integral_constant<bool,na>{} ;
 	typedef typename traits::storage_type<RTYPE>::type stored_type ;
 	typedef typename traits::storage_type<RTYPE>::type elem_type ;

Modified: pkg/Rcpp/inst/include/RcppCommon.h
===================================================================
--- pkg/Rcpp/inst/include/RcppCommon.h	2010-09-27 10:22:26 UTC (rev 2207)
+++ pkg/Rcpp/inst/include/RcppCommon.h	2010-09-27 13:10:33 UTC (rev 2208)
@@ -224,6 +224,7 @@
 #include <Rcpp/traits/has_iterator.h>
 #include <Rcpp/traits/expands_to_logical.h>
 #include <Rcpp/traits/matrix_interface.h>
+#include <Rcpp/traits/is_sugar_expression.h>
 #include <Rcpp/traits/has_na.h>
 #include <Rcpp/traits/storage_type.h>
 #include <Rcpp/traits/r_sexptype_traits.h>



More information about the Rcpp-commits mailing list