class: center, middle, inverse, title-slide # std::vector and Rcpp Vectors ### Colin Rundel ### 2019-02-28 --- exclude: true ```r knitr::opts_chunk$set(cache=TRUE) ``` --- ## C Vectors ```cpp #include <Rcpp.h> // [[Rcpp::export]] void c_vec() { int v[8]; for(int i=0; i!=8; i++) { Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n"; } } ``` ```r c_vec() ``` ``` ## v[0] = -395604624 ## v[1] = 1048126214 ## v[2] = 126299560 ## v[3] = 1 ## v[4] = 0 ## v[5] = 0 ## v[6] = 0 ## v[7] = 0 ``` --- ```cpp #include <Rcpp.h> // [[Rcpp::export]] void c_vec_bad() { int v[8]; for(int i=0; i!=12; i++) { Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n"; } } ``` ```r c_vec_bad() ``` ``` ## v[0] = 0 ## v[1] = 0 ## v[2] = 0 ## v[3] = 32689 ## v[4] = -818741133 ## v[5] = 1048126214 ## v[6] = 126299560 ## v[7] = 1 ## v[8] = -818741133 ## v[9] = 1048126214 ## v[10] = 126299560 ## v[11] = 1 ``` --- ## C dynamic vectors ```cpp #include <Rcpp.h> // [[Rcpp::export]] void c_vec_dyn(int n) { int *v = (int *)calloc(n, sizeof(int)); for(int i=0; i!=n; i++) { Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n"; } Rcpp::Rcout << "\n"; free(v); } ``` ```r c_vec_dyn(2) ``` ``` ## v[0] = 0 ## v[1] = 0 ``` ```r c_vec_dyn(3) ``` ``` ## v[0] = 0 ## v[1] = 0 ## v[2] = 0 ``` --- ## C++ dynamic vectors ```cpp #include <Rcpp.h> // [[Rcpp::export]] void cpp_vec_dyn(int n) { int *v = new int[n](); for(int i=0; i!=n; i++) { Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n"; } Rcpp::Rcout << "\n"; delete[] v; } ``` ```r cpp_vec_dyn(2) ``` ``` ## v[0] = 0 ## v[1] = 0 ``` ```r cpp_vec_dyn(3) ``` ``` ## v[0] = 0 ## v[1] = 0 ## v[2] = 0 ``` --- ## C++ stl vectors ```cpp #include <Rcpp.h> // [[Rcpp::export]] void cpp_stl_vec(int n) { std::vector<int> v(n); for(int i=0; i!=n; i++) { Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n"; } Rcpp::Rcout << "\n"; } ``` ```r cpp_stl_vec(2) ``` ``` ## v[0] = 0 ## v[1] = 0 ``` ```r cpp_stl_vec(3) ``` ``` ## v[0] = 0 ## v[1] = 0 ## v[2] = 0 ``` --- ## C++ Templates (very briefly) ```cpp #include <Rcpp.h> #include <typeinfo> template<typename T> std::string what_am_i() { T obj; return typeid(obj).name(); } // [[Rcpp::export]] void template_ex() { Rcpp::Rcout << "bool : " << what_am_i<bool>() << "\n"; Rcpp::Rcout << "int : " << what_am_i<int>() << "\n"; Rcpp::Rcout << "long int : " << what_am_i<long int>() << "\n"; Rcpp::Rcout << "char : " << what_am_i<char>() << "\n"; Rcpp::Rcout << "float : " << what_am_i<float>() << "\n"; Rcpp::Rcout << "double : " << what_am_i<double>() << "\n"; Rcpp::Rcout << "std::string: " << what_am_i<std::string>() << "\n"; } ``` ```r template_ex() ``` ``` ## bool : b ## int : i ## long int : l ## char : c ## float : f ## double : d ## std::string: NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE ``` --- ## Initializing std::vector ```cpp #include <Rcpp.h> // [[Rcpp::plugins(cpp14)]] // [[Rcpp::export]] Rcpp::List init_int_vec() { std::vector<int> v1 = {1, 2, 3}; // Requires cpp14 std::vector<int> v2(2); std::vector<int> v3(2, 1); std::vector<int> v4(v1); std::vector<int> v5(v1.begin(), v1.end()); std::vector<int> v6(v1.begin(), v1.end()-1); std::vector<int> v7; v7.push_back(10); v7.push_back(9); v7.push_back(8); return Rcpp::List::create(v1,v2,v3,v4,v5,v6,v7); } ``` ```r str(init_int_vec()) ``` ``` ## List of 7 ## $ : int [1:3] 1 2 3 ## $ : int [1:2] 0 0 ## $ : int [1:2] 1 1 ## $ : int [1:3] 1 2 3 ## $ : int [1:3] 1 2 3 ## $ : int [1:2] 1 2 ## $ : int [1:3] 10 9 8 ``` --- ## Initializing std::vector ```cpp #include <Rcpp.h> // [[Rcpp::plugins(cpp14)]] // [[Rcpp::export]] Rcpp::List init_dbl_vec() { std::vector<double> v1 = {1, 2, 3}; // Requires cpp14 std::vector<double> v2(2); std::vector<double> v3(2, 1); std::vector<double> v4(v1); std::vector<double> v5(v1.begin(), v1.end()); std::vector<double> v6(v1.begin(), v1.end()-1); std::vector<double> v7; v7.push_back(10); v7.push_back(9); v7.push_back(8); return Rcpp::List::create(v1,v2,v3,v4,v5,v6,v7); } ``` ```r str(init_dbl_vec()) ``` ``` ## List of 7 ## $ : num [1:3] 1 2 3 ## $ : num [1:2] 0 0 ## $ : num [1:2] 1 1 ## $ : num [1:3] 1 2 3 ## $ : num [1:3] 1 2 3 ## $ : num [1:2] 1 2 ## $ : num [1:3] 10 9 8 ``` --- ## Translating std::vector ```cpp #include <Rcpp.h> // [[Rcpp::export]] Rcpp::IntegerVector from_std_vec(std::vector<int> v) { return Rcpp::IntegerVector(v.begin(), v.end()); } // [[Rcpp::export]] std::vector<int> to_std_vec(Rcpp::IntegerVector rv) { return std::vector<int>(rv.begin(), rv.end()); } ``` ```r from_std_vec(1:10) ``` ``` ## [1] 1 2 3 4 5 6 7 8 9 10 ``` ```r to_std_vec(1:10) ``` ``` ## [1] 1 2 3 4 5 6 7 8 9 10 ``` --- ## Translating std::vectors (SEXPs) ```cpp #include <Rcpp.h> // [[Rcpp::export]] SEXP sexp_std_vec(SEXP rv) { std::vector<int> v = Rcpp::as< std::vector<int> >(rv); return Rcpp::wrap(v); } // [[Rcpp::export]] SEXP sexp_rcpp_vec(SEXP rv) { Rcpp::IntegerVector v = Rcpp::as< Rcpp::IntegerVector >(rv); return Rcpp::wrap(v); } ``` ```r sexp_std_vec(1:10) ``` ``` ## [1] 1 2 3 4 5 6 7 8 9 10 ``` ```r sexp_rcpp_vec(1:10) ``` ``` ## [1] 1 2 3 4 5 6 7 8 9 10 ``` --- ## std::vector methods - access .small[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] void std_vec_access(std::vector<int> v) { Rcpp::Rcout << "v.front() = " << v.front() << "\n"; Rcpp::Rcout << "v[0] = " << v[0] << "\n"; Rcpp::Rcout << "v.at(0) = " << v.at(0) << "\n"; Rcpp::Rcout << "v.back() = " << v.back() << "\n"; Rcpp::Rcout << "v[5] = " << v[5] << "\n"; Rcpp::Rcout << "v.at(5) = " << v.at(5) << "\n"; Rcpp::Rcout << "\n"; } ``` ```r std_vec_access(1:6) ``` ``` ## v.front() = 1 ## v[0] = 1 ## v.at(0) = 1 ## v.back() = 6 ## v[5] = 6 ## v.at(5) = 6 ``` ```r std_vec_access(1:5) ``` ``` ## v.front() = 1 ## v[0] = 1 ## v.at(0) = 1 ## v.back() = 5 ## v[5] = 32689 ## v.at(5) = ``` ``` ## Error in std_vec_access(1:5): vector ``` ] --- ## Rcpp vector methods - access .small[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] void rcpp_vec_access(Rcpp::IntegerVector v) { Rcpp::Rcout << "v[0] = " << v[0] << "\n"; Rcpp::Rcout << "v(0) = " << v(0) << "\n"; Rcpp::Rcout << "v.at(0) = " << v.at(0) << "\n"; Rcpp::Rcout << "v[5] = " << v[5] << "\n"; Rcpp::Rcout << "v(5) = " << v(5) << "\n"; Rcpp::Rcout << "v.at(5) = " << v.at(5) << "\n"; Rcpp::Rcout << "\n"; } ``` ```r rcpp_vec_access(1:6) ``` ``` ## v[0] = 1 ## v(0) = 1 ## v.at(0) = 1 ## v[5] = 6 ## v(5) = 6 ## v.at(5) = 6 ``` ```r rcpp_vec_access(1:5) ``` ``` ## v[0] = 1 ## v(0) = 1 ## v.at(0) = 1 ## v[5] = 32689 ## v(5) = ``` ``` ## Error in rcpp_vec_access(1:5): Index out of bounds: [index=5; extent=5]. ``` ] --- ## Iterators .tiny[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] void iterators(int n) { std::vector<int> sv(n); Rcpp::IntegerVector rv(n); std::iota(sv.begin(), sv.end(), 1); std::iota(rv.begin(), rv.end(), 1); Rcpp::Rcout << " sv.begin() : " << &*sv.begin() << "\n"; Rcpp::Rcout << " sv.end() : " << &*sv.end() << "\n"; Rcpp::Rcout << " sv.end() - v.begin() : " << sv.end() - sv.begin() << "\n"; Rcpp::Rcout << "*sv.begin() : " << *sv.begin() << "\n"; Rcpp::Rcout << "*sv.end() : " << *sv.end() << "\n"; Rcpp::Rcout << "*(sv.end()-1) : " << *(sv.end()-1) << "\n"; Rcpp::Rcout << "\n"; Rcpp::Rcout << " rv.begin() : " << &*rv.begin() << "\n"; Rcpp::Rcout << " rv.end() : " << &*rv.end() << "\n"; Rcpp::Rcout << " rv.end() - v.begin() : " << rv.end() - rv.begin() << "\n"; Rcpp::Rcout << "*rv.begin() : " << *rv.begin() << "\n"; Rcpp::Rcout << "*rv.end() : " << *rv.end() << "\n"; Rcpp::Rcout << "*(rv.end()-1) : " << *(rv.end()-1) << "\n"; Rcpp::Rcout << "\n"; } ``` ] .smaller[ ```r iterators(100) ``` ``` ## sv.begin() : 0x7fb171432d30 ## sv.end() : 0x7fb171432ec0 ## sv.end() - v.begin() : 100 ## *sv.begin() : 1 ## *sv.end() : 0 ## *(sv.end()-1) : 100 ## ## rv.begin() : 0x7fb1714b2550 ## rv.end() : 0x7fb1714b26e0 ## rv.end() - v.begin() : 100 ## *rv.begin() : 1 ## *rv.end() : 0 ## *(rv.end()-1) : 100 ``` ] --- ## (More) Iterators .smaller[ ```cpp #include <Rcpp.h> // [[Rcpp::plugins(cpp11)]] // [[Rcpp::export]] void iterators2(int n) { std::vector<int> sv(n); std::iota(sv.begin(), sv.end(), 1); auto it = sv.begin(); Rcpp::Rcout << " *(sv.begin()) : " << *(sv.begin()) << "\n"; Rcpp::Rcout << " *(sv.begin()++) : " << *(sv.begin()++) << "\n"; Rcpp::Rcout << " *(++sv.begin()) : " << *(++sv.begin()) << "\n"; Rcpp::Rcout << " *(sv.begin()) : " << *(sv.begin()) << "\n"; Rcpp::Rcout << " *(it) : " << *(it) << "\n"; Rcpp::Rcout << " *(it++) : " << *(it++) << "\n"; Rcpp::Rcout << " *(++it) : " << *(++it) << "\n"; Rcpp::Rcout << " *(++it) : " << *(++it) << "\n"; Rcpp::Rcout << " *(it++) : " << *(it++) << "\n"; Rcpp::Rcout << "\n"; } ``` ```r iterators2(10) ``` ``` ## *(sv.begin()) : 1 ## *(sv.begin()++) : 1 ## *(++sv.begin()) : 2 ## *(sv.begin()) : 1 ## *(it) : 1 ## *(it++) : 1 ## *(++it) : 3 ## *(++it) : 4 ## *(it++) : 4 ``` ] --- ## std::vector methods - growing .small[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] void grow(int n, int m) { std::vector<int> v; for(int i = 0, k = 0; i < n; ++i) { for(int j = 0; j < m; ++j, ++k) { v.push_back(k); } Rcpp::Rcout << "iter: " << k << " size: " << v.size() << " capacity: " << v.capacity() << "\n"; } Rcpp::Rcout << "\n"; } ``` ```r grow(10, 2) ``` ``` ## iter: 2 size: 2 capacity: 2 ## iter: 4 size: 4 capacity: 4 ## iter: 6 size: 6 capacity: 8 ## iter: 8 size: 8 capacity: 8 ## iter: 10 size: 10 capacity: 16 ## iter: 12 size: 12 capacity: 16 ## iter: 14 size: 14 capacity: 16 ## iter: 16 size: 16 capacity: 16 ## iter: 18 size: 18 capacity: 32 ## iter: 20 size: 20 capacity: 32 ``` ] --- ## Growth performance .smaller[ .columns[ .col[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] int std_vec_grow(int n) { std::vector<int> v; for(int i = 0; i < n; ++i) { v.push_back(i); } return v.size(); } ``` ] .col[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] int rcpp_grow_back(int n) { Rcpp::IntegerVector v; for(int i = 0; i < n; ++i) { v.push_back(i); } return v.size(); } // [[Rcpp::export]] int rcpp_grow_front(int n) { Rcpp::IntegerVector v; for(int i = 0; i < n; ++i) { v.push_front(i); } return v.size(); } ``` ] ] ] --- .small[ ```r bench::mark( std_vec_grow(1e3), rcpp_grow_back(1e3), rcpp_grow_front(1e3) ) ``` ``` ## # A tibble: 3 x 10 ## expression min mean median max `itr/sec` mem_alloc n_gc n_itr total_time ## <chr> <bch:tm> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <bch:tm> ## 1 std_vec_grow(1000) 4.61µs 14.89µs 9.84µs 4.15ms 67171. 2.49KB 0 10000 149ms ## 2 rcpp_grow_back(1000) 406.67µs 1.15ms 864.51µs 5.05ms 874. 1.96MB 10 231 264ms ## 3 rcpp_grow_front(1000) 408.92µs 877.05µs 629.64µs 5.13ms 1140. 1.96MB 12 310 272ms ``` ] --- ## Allocation performance .smaller[ .columns[ .col[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] int std_vec_alloc(int n) { std::vector<int> v(n); for(int i = 0; i < n; ++i) { v[i] = i; } return v.size(); } // [[Rcpp::export]] int rcpp_alloc(int n) { Rcpp::IntegerVector v(n); for(int i = 0; i < n; ++i) { v[i] = i; } return v.size(); } ``` ] .col[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] int std_vec_alloc_at(int n) { std::vector<int> v(n); for(int i = 0; i < n; ++i) { v.at(i) = i; } return v.size(); } // [[Rcpp::export]] int rcpp_alloc_at(int n) { Rcpp::IntegerVector v(n); for(int i = 0; i < n; ++i) { v.at(i) = i; } return v.size(); } ``` ] ] ] .smaller[ ```r bench::mark( std_vec_alloc(1e6), rcpp_alloc(1e6), std_vec_alloc_at(1e6), rcpp_alloc_at(1e6) ) ``` ``` ## # A tibble: 4 x 10 ## expression min mean median max `itr/sec` mem_alloc n_gc n_itr total_time ## <chr> <bch:tm> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <bch:tm> ## 1 std_vec_alloc(1e+06) 286.49µs 943.41µs 486.09µs 10.17ms 1060. 2.49KB 0 531 501ms ## 2 rcpp_alloc(1e+06) 375.23µs 2.09ms 1.03ms 11.28ms 479. 3.82MB 13 157 327ms ## 3 std_vec_alloc_at(1e+06) 528.29µs 1.18ms 1.01ms 5.68ms 846. 2.49KB 0 423 500ms ## 4 rcpp_alloc_at(1e+06) 5.29ms 7.14ms 6.67ms 12.28ms 140. 3.82MB 5 60 429ms ``` ] --- ## Translation performance .smaller[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] std::vector<int> std_vec_trans(std::vector<int> v) { return v; } // [[Rcpp::export]] Rcpp::IntegerVector rcpp_vec_trans(Rcpp::IntegerVector v) { return v; } ``` ```cpp #include <Rcpp.h> // [[Rcpp::export]] std::vector<int> std_vec_trans_ref(std::vector<int> &v) { return v; } // [[Rcpp::export]] Rcpp::IntegerVector rcpp_vec_trans_ref(Rcpp::IntegerVector &v) { return v; } ``` ] --- .small[ ```r x = rpois(1e6, 1) bench::mark( std_vec_trans(x), rcpp_vec_trans(x), std_vec_trans_ref(x), rcpp_vec_trans_ref(x) ) ``` ``` ## # A tibble: 4 x 10 ## expression min mean median max `itr/sec` mem_alloc n_gc n_itr total_time ## <chr> <bch:tm> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <bch:tm> ## 1 std_vec_trans(x) 2.2ms 7.02ms 5.07ms 27.76ms 142. 3.82MB 9 48 337.1ms ## 2 rcpp_vec_trans(x) 1.68µs 8.08µs 3.54µs 5.72ms 123789. 2.49KB 0 10000 80.8ms ## 3 std_vec_trans_ref(x) 1.83ms 3.88ms 3.23ms 12.88ms 257. 3.82MB 13 81 314.6ms ## 4 rcpp_vec_trans_ref(x) 1.32µs 2.56µs 1.72µs 1.02ms 389917. 2.49KB 0 10000 25.6ms ``` ] --- ## Sorting performance .smaller[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] std::vector<double> std_vec_sort(std::vector<double> v) { std::sort(v.begin(), v.end()); return v; } // [[Rcpp::export]] Rcpp::NumericVector rcpp_vec_sort(Rcpp::NumericVector v) { v.sort(); return v; } ``` ```r x = rnorm(1e6) bench::mark( std_vec_sort(x), rcpp_vec_sort(x) ) ``` ``` ## # A tibble: 2 x 10 ## expression min mean median max `itr/sec` mem_alloc n_gc n_itr total_time ## <chr> <bch:tm> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <bch:tm> ## 1 std_vec_sort(x) 4.84ms 13.5ms 10.4ms 38.3ms 74.1 7.63MB 9 18 243ms ## 2 rcpp_vec_sort(x) 7.15ms 11.9ms 11ms 24.5ms 83.8 2.49KB 0 42 501ms ``` ] --- ## Insert performance .smaller[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] std::vector<int> std_vec_ins(std::vector<int> v, int n, int pos, int value) { for(int i=0; i<n; ++i) { v.insert(v.begin() + pos, value); } return v; } ``` ```cpp #include <Rcpp.h> // [[Rcpp::export]] Rcpp::IntegerVector rcpp_vec_ins_it(Rcpp::IntegerVector v, int n, int pos, int value) { for(int i=0; i<n; ++i) { v.insert(v.begin() + pos, value); } return v; } // [[Rcpp::export]] Rcpp::IntegerVector rcpp_vec_ins_pos(Rcpp::IntegerVector v, int n, int pos, int value) { for(int i=0; i<n; ++i) { v.insert(pos, value); } return v; } ``` ] --- .small[ ```r std_vec_ins(1:4, 5, 2, 0) ``` ``` ## [1] 1 2 0 0 0 0 0 3 4 ``` ] -- .smaller[ ```r bench::mark( std_vec_ins(1:4, 5, 2, 0), rcpp_vec_ins_it(1:4, 5, 2, 0), rcpp_vec_ins_pos(1:4, 5, 2, 0) ) ``` ``` ## # A tibble: 3 x 10 ## expression min mean median max `itr/sec` mem_alloc n_gc n_itr total_time ## <chr> <bch:tm> <bch:tm> <bch:tm> <bch:t> <dbl> <bch:byt> <dbl> <int> <bch:tm> ## 1 std_vec_ins(1:4, 5, 2, 0) 2.49µs 12.9µs 6.28µs 5.69ms 77719. 7.7KB 2 9998 129ms ## 2 rcpp_vec_ins_it(1:4, 5, 2, 0) 2.46µs 11µs 5.19µs 7.59ms 91089. 2.49KB 1 9999 110ms ## 3 rcpp_vec_ins_pos(1:4, 5, 2, 0) 2.44µs 10.6µs 5.85µs 9.22ms 94254. 2.49KB 1 9999 106ms ``` ] -- .smaller[ ```r x = 1:1e3 bench::mark( std_vec_ins(x, 500, 500, 0), rcpp_vec_ins_it(x, 500, 500, 0), rcpp_vec_ins_pos(x, 500, 500, 0) ) ``` ``` ## # A tibble: 3 x 10 ## expression min mean median max `itr/sec` mem_alloc n_gc n_itr total_time ## <chr> <bch:tm> <bch:tm> <bch:tm> <bch:t> <dbl> <bch:byt> <dbl> <int> <bch:tm> ## 1 std_vec_ins(x, 500, 500, 0) 27.7µs 80.09µs 47.22µs 11.45ms 12486. 12.35KB 2 5859 469ms ## 2 rcpp_vec_ins_it(x, 500, 500, … 434.2µs 1.34ms 907.05µs 7.61ms 746. 2.41MB 12 167 224ms ## 3 rcpp_vec_ins_pos(x, 500, 500,… 511.1µs 1.64ms 1.06ms 12.85ms 609. 2.41MB 10 154 253ms ``` ] --- ## Erase performance .smaller[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] std::vector<int> std_vec_erase(std::vector<int> v, int pos, int n) { for(int i=0; i<n; ++i) { v.erase(v.begin()+pos); } return v; } // [[Rcpp::export]] std::vector<int> std_vec_erase_range(std::vector<int> v, int pos, int n) { v.erase(v.begin()+pos, v.begin()+pos+n); return v; } ``` ```cpp #include <Rcpp.h> // [[Rcpp::export]] Rcpp::IntegerVector rcpp_vec_erase(Rcpp::IntegerVector v, int pos, int n) { for(int i=0; i<n; ++i) { v.erase(v.begin()+pos); } return v; } // [[Rcpp::export]] Rcpp::IntegerVector rcpp_vec_erase_range(Rcpp::IntegerVector v, int pos, int n) { v.erase(v.begin()+pos, v.begin()+pos+n); return v; } ``` ] --- .smaller[ ```r std_vec_erase(1:6, 2, 2) ``` ``` ## [1] 1 2 5 6 ``` ```r std_vec_erase_range(1:6, 2, 2) ``` ``` ## [1] 1 2 5 6 ``` ] -- .smaller[ ```r bench::mark( std_vec_erase(1:6, 2, 2), std_vec_erase_range(1:6, 2, 2), rcpp_vec_erase(1:6, 2, 2), rcpp_vec_erase_range(1:6, 2, 2) ) ``` ``` ## # A tibble: 4 x 10 ## expression min mean median max `itr/sec` mem_alloc n_gc n_itr total_time ## <chr> <bch:tm> <bch:tm> <bch:tm> <bch:t> <dbl> <bch:byt> <dbl> <int> <bch:tm> ## 1 std_vec_erase(1:6, 2, 2) 2.07µs 10.36µs 4.57µs 17.41ms 96509. 7.02KB 0 10000 103.6ms ## 2 std_vec_erase_range(1:6, 2, 2) 2.1µs 7.34µs 4.96µs 2.46ms 136204. 7.02KB 0 10000 73.4ms ## 3 rcpp_vec_erase(1:6, 2, 2) 2.38µs 11.21µs 5.35µs 7.54ms 89239. 2.49KB 1 9999 112ms ## 4 rcpp_vec_erase_range(1:6, 2, … 2.4µs 13.35µs 5.5µs 10.09ms 74895. 2.49KB 1 9999 133.5ms ``` ] -- .smaller[ ```r x = 1:1e3 bench::mark( std_vec_erase(x, 250, 500), std_vec_erase_range(x, 250, 500), rcpp_vec_erase(x, 250, 500), rcpp_vec_erase_range(x, 250, 500) ) ``` ``` ## # A tibble: 4 x 10 ## expression min mean median max `itr/sec` mem_alloc n_gc n_itr total_time ## <chr> <bch:tm> <bch:tm> <bch:tm> <bch:t> <dbl> <bch:byt> <dbl> <int> <bch:tm> ## 1 std_vec_erase(x, 250, 500) 15.14µs 43.25µs 23.11µs 27.82ms 23123. 8.45KB 1 9999 432.4ms ## 2 std_vec_erase_range(x, 250, 5… 2.33µs 11.03µs 5.22µs 12.38ms 90641. 4.49KB 1 9999 110.3ms ## 3 rcpp_vec_erase(x, 250, 500) 350.12µs 1.04ms 665.03µs 9.42ms 965. 1.46MB 11 262 271.6ms ## 4 rcpp_vec_erase_range(x, 250, … 2.02µs 6.46µs 4.47µs 3.29ms 154679. 4.49KB 1 9999 64.6ms ``` ] --- class: middle # Rcpp Sugar --- ## RMSE - Rcpp .smaller[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] double rcpp_rmse(Rcpp::NumericVector y, Rcpp::NumericVector y_hat) { Rcpp::NumericVector diff = y - y_hat; return sqrt( Rcpp::sum(diff*diff) / y.size() ); } ``` ```r rcpp_rmse(1:10, 1:10) ``` ``` ## [1] 0 ``` ```r rcpp_rmse(1:10, 10:1) ``` ``` ## [1] 5.744563 ``` ```r rcpp_rmse(1:10, 1:5) ``` ``` ## [1] 5.602671e+59 ``` ```r rcpp_rmse(1:5, 1:10) ``` ``` ## [1] 0 ``` ] --- ## RMSE - std::vector .smaller[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] double std_vec_rmse(std::vector<double> y, std::vector<double> y_hat) { double sum = 0.0; for(int i=0; i<y.size(); ++i) { double diff = y[i] - y_hat[i]; sum += diff * diff; } return sqrt( sum / y.size() ); } ``` ```r std_vec_rmse(1:10, 1:10) ``` ``` ## [1] 0 ``` ```r std_vec_rmse(1:10, 10:1) ``` ``` ## [1] 5.744563 ``` ```r std_vec_rmse(1:10, 1:5) ``` ``` ## [1] 5.744563 ``` ```r std_vec_rmse(1:5, 1:10) ``` ``` ## [1] 0 ``` ] --- ## Length coercion .small[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] Rcpp::NumericVector rcpp_len_issue(Rcpp::NumericVector y, Rcpp::NumericVector y_hat) { return y - y_hat; } ``` ```r rcpp_len_issue(1:10, 1:10) ``` ``` ## [1] 0 0 0 0 0 0 0 0 0 0 ``` ```r rcpp_len_issue(1:10, 10:1) ``` ``` ## [1] -9 -7 -5 -3 -1 1 3 5 7 9 ``` ```r rcpp_len_issue(1, 1:10) ``` ``` ## [1] 0 ``` ```r rcpp_len_issue(1:5, 1:10) ``` ``` ## [1] 0 0 0 0 0 ``` ] --- ## Logical Operators and Predicates .smaller[ ```cpp #include <Rcpp.h> // [[Rcpp::export]] void rcpp_logical() { Rcpp::IntegerVector x = Rcpp::IntegerVector::create(0, 1, NA_INTEGER, 3); Rcpp::LogicalVector l = x > 5; Rcpp::Rcout << "x : " << x << "\n"; Rcpp::Rcout << "x > 2 : " << Rcpp::LogicalVector(x > 2) << "\n"; Rcpp::Rcout << "is_na(x) : " << Rcpp::LogicalVector(Rcpp::is_na(x)) << "\n"; Rcpp::Rcout << "any(is_na(x)) : " << Rcpp::LogicalVector(Rcpp::any(Rcpp::is_na(x))) << "\n"; Rcpp::Rcout << "all(x < 5) : " << Rcpp::LogicalVector(Rcpp::all(x < 5)) << "\n"; Rcpp::Rcout << "ifelse(is_na(x), -1, x) : " << Rcpp::IntegerVector(Rcpp::ifelse(Rcpp::is_na(x), -1, x)) << "\n"; } ``` ```r rcpp_logical() ``` ``` ## x : 0 1 -2147483648 3 ## x > 2 : 0 0 -2147483648 1 ## is_na(x) : 0 0 1 0 ## any(is_na(x)) : 1 ## all(x < 5) : -2147483648 ## ifelse(is_na(x), -1, x) : 0 1 -1 3 ``` ]