<div dir="ltr"><div dir="ltr"><div dir="ltr"><br></div><div>Just to close this thread out, I did a more comprehensive benchmark using 8 different approaches</div><div> and it looks like <br></div><div><br></div><div>A) Jan's solution using memcopy and NumericVector. <br></div><div><br></div><div>B) A push_front solution using NumericVector<br></div><div><br></div><div>C) Serguei's const trick solution using NumericVector <br></div><div><br></div><div>are the top 3 solutions in terms of speed with B) push_front technically the winner !!!!! <br></div><div>Thanks to everyone for their help. I learned much.</div><div><br></div><div>#======================================================================</div><div><br></div><div dir="ltr">#include <Rcpp.h><br>using namespace Rcpp;<br><br>// [[Rcpp::export]]<br>std::vector<double> mybar(const std::vector<double>& x, double firstelem) {<br> std::vector<double> tmp(x.size() + 1);<br> tmp[0] = firstelem;<br> for (int i = 1; i < (x.size()+1); i++)<br> tmp[i] = x[i-1];<br> return tmp;<br>}<br>// [[Rcpp::export]]<br>std::vector<double> mybar2(const std::vector<double>& x, double firstelem) {<br> std::vector<double> tmp(x.size() + 1);<br> tmp[0] = firstelem;<br> std::copy(x.begin(), x.end(), tmp.begin()+1);<br> return tmp;<br>}<br><br>// [[Rcpp::export]]<br>NumericVector mybar3(NumericVector x, double firstelem) {<br> NumericVector tmp(x.size() + 1);<br> tmp[0] = firstelem;<br> std::copy(x.begin(), x.end(), tmp.begin()+1);<br> return tmp;<br>}<br><br>// [[Rcpp::export]]<br>NumericVector mybar4(NumericVector x, double firstelem) {<br> NumericVector result(x.size() + 1);<br> result[0] = firstelem;<br> std::memcpy(result.begin()+1, x.begin(), x.size()*sizeof(double));<br> return result;<br>}<br><br>// [[Rcpp::export]]<br>NumericVector mybar5(NumericVector x, NumericVector y) {<br> NumericVector result(x.size() + y.size());<br> std::memcpy(result.begin(), x.begin(), x.size()*sizeof(double));<br> std::memcpy(result.begin()+x.size(), y.begin(), y.size()*sizeof(double));<br> return result;<br>}<br><br>// [[Rcpp::export]]<br>NumericVector mybar6(NumericVector x, double firstelem) {<br> x.insert(0, firstelem);<br> return x;<br>}<br><br>// [[Rcpp::export]]<br>NumericVector mybar7(NumericVector x, double firstelem) {<br> x.push_front(firstelem);<br> return x;<br>}<br><br>// [[Rcpp::export]]<br>NumericVector mybar8(const NumericVector &x, const NumericVector &y) {<br> NumericVector result(x.size() + y.size());<br> std::memcpy(result.begin(), x.begin(), x.size()*sizeof(double));<br> std::memcpy(result.begin()+x.size(), y.begin(),<br> y.size()*sizeof(double));<br> return result;<br>}<br><br><br>/*** R<br><br>library(microbenchmark)<br><br> n=1E7<br> testvec = c(1,seq_len(n))<br> testelem <- 7<br> microbenchmark(c(testelem, testvec), mybar(testvec,testelem),<br> mybar2(testvec,testelem),<br> mybar3(testvec,testelem),<br> mybar4(testvec,testelem),<br> mybar5(testvec,testelem),<br> mybar6(testvec,testelem),<br> mybar7(testvec,testelem),<br> mybar8(testvec,testelem)<br> )<br><br><br> */<br></div><div dir="ltr"><br></div><div dir="ltr">microbenchmark(c(testelem, testvec), mybar(testvec,testelem),<br>+ mybar2(testvec,testelem),<br>+ mybar3(testvec,testelem),<br>+ mybar4(testvec,testelem) .... [TRUNCATED] <br>Unit: milliseconds<br> expr min lq mean median uq max neval<br> c(testelem, testvec) 33.82390 37.41429 42.70048 42.48487 47.72840 81.53239 100<br> mybar(testvec, testelem) 93.35373 100.67106 105.30134 105.67559 109.62234 125.15337 100<br> mybar2(testvec, testelem) 88.00770 94.62231 98.84161 98.51031 102.49516 114.58349 100<br> mybar3(testvec, testelem) 27.93793 31.94207 36.76242 37.17255 41.52102 47.31534 100<br> mybar4(testvec, testelem) 31.37486 34.73718 39.72786 40.83917 44.21151 49.48883 100<br> mybar5(testvec, testelem) 30.90608 35.25496 40.24085 40.59592 44.88581 50.33709 100<br> mybar6(testvec, testelem) 33.24435 38.32075 43.11721 43.46578 47.93726 52.72538 100<br> mybar7(testvec, testelem) 30.80926 33.41609 38.45877 37.71916 43.70371 48.88513 100<br> mybar8(testvec, testelem) 30.88067 35.01826 40.38411 40.02501 44.49641 73.84147 100<br>> <br></div><div dir="ltr"><br></div><div dir="ltr"><br></div><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Dec 10, 2018 at 8:42 AM Serguei Sokol <<a href="mailto:serguei.sokol@gmail.com">serguei.sokol@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Le 10/12/2018 à 13:04, Jan van der Laan a écrit :<br>
> Small addendum: A large part of the performance gain in my example comes <br>
> from using NumericVector instead of std::vector<double>. Which avoids a <br>
> conversion. An example using std::copy with Numeric vector runs in the <br>
> same time as the version using memcpy.<br>
<br>
Yep.<br>
Few more percents of mean cpu time can be saved by using "const &" trick :<br>
<br>
// [[Rcpp::export]]<br>
NumericVector mybar5(const NumericVector &x, const NumericVector &y) {<br>
NumericVector result(x.size() + y.size());<br>
std::memcpy(result.begin(), x.begin(), x.size()*sizeof(double));<br>
std::memcpy(result.begin()+x.size(), y.begin(), <br>
y.size()*sizeof(double));<br>
return result;<br>
}<br>
<br>
# output<br>
Unit: microseconds<br>
expr min lq mean median uq <br>
max<br>
c(testelem, testvec) 258.343 338.3110 418.0047 343.4450 378.7850 <br>
3077.347<br>
mybar(testvec, testelem) 352.699 366.8770 498.3948 374.6635 450.4420 <br>
3046.408<br>
mybar2(testvec, testelem) 334.820 348.3685 425.0098 354.7240 366.5270 <br>
3024.128<br>
mybar3(testvec, testelem) 233.689 244.8640 315.7256 247.5180 255.0955 <br>
2945.068<br>
mybar4(testvec, testelem) 232.083 241.9655 340.0751 245.0035 252.8260 <br>
2934.312<br>
mybar5(testvec, testelem) 150.787 242.7685 285.4264 245.9465 254.1880 <br>
2049.493<br>
<br>
Serguei.<br>
<br>
> <br>
> Jan<br>
> <br>
> <br>
> <br>
> On 10-12-18 12:28, Jan van der Laan wrote:<br>
>><br>
>> For performance memcpy is probably fastest. This gives the same <br>
>> performance a c().<br>
>><br>
>> // [[Rcpp::export]]<br>
>> NumericVector mybar3(NumericVector x, double firstelem) {<br>
>> NumericVector result(x.size() + 1);<br>
>> result[0] = firstelem;<br>
>> std::memcpy(result.begin()+1, x.begin(), x.size()*sizeof(double));<br>
>> return result;<br>
>> }<br>
>><br>
>><br>
>> Or a more general version concatenating vector of arbitrary lengths:<br>
>><br>
>><br>
>> // [[Rcpp::export]]<br>
>> NumericVector mybar4(NumericVector x, NumericVector y) {<br>
>> NumericVector result(x.size() + y.size());<br>
>> std::memcpy(result.begin(), x.begin(), x.size()*sizeof(double));<br>
>> std::memcpy(result.begin()+x.size(), y.begin(), <br>
>> y.size()*sizeof(double));<br>
>> return result;<br>
>> }<br>
>><br>
>><br>
>><br>
>> > n=1E7<br>
>> > testvec = c(1,seq_len(n))<br>
>> > testelem <- 7<br>
>> > microbenchmark(c(testelem, testvec), mybar(testvec,testelem),<br>
>> + mybar2(testvec,testelem),<br>
>> + mybar3(testvec,testelem),<br>
>> + mybar4(testvec,testelem)<br>
>> + )<br>
>> Unit: milliseconds<br>
>> expr min lq mean median <br>
>> uq max neval<br>
>> c(testelem, testvec) 36.48577 36.93754 41.10550 43.76742 <br>
>> 44.20709 46.09741 100<br>
>> mybar(testvec, testelem) 102.54042 103.21756 106.88749 104.32033 <br>
>> 110.31527 119.55512 100<br>
>> mybar2(testvec, testelem) 95.64696 96.19447 100.24691 102.61380 <br>
>> 103.58189 109.28290 100<br>
>> mybar3(testvec, testelem) 36.45794 36.87915 40.43486 37.18063 <br>
>> 43.49643 95.49049 100<br>
>> mybar4(testvec, testelem) 36.51334 37.05409 41.39680 43.20627 <br>
>> 43.57958 94.95482 100<br>
>><br>
>><br>
>> Best,<br>
>> Jan<br>
>><br>
>><br>
>><br>
>> On 10-12-18 12:10, Serguei Sokol wrote:<br>
>>> Le 09/12/2018 à 09:35, Mark Leeds a écrit :<br>
>>>> Hi All: I wrote below and it works but I have a strong feeling <br>
>>>> there's a better way to do it.<br>
>>> If performance is an issue, you can save few percents of cpu time by <br>
>>> using std::copy() instead of explicit for loop. Yet, for this <br>
>>> operation R's c() remains the best bet. It is more then twice faster <br>
>>> than both Rcpp versions below:<br>
>>><br>
>>> #include <Rcpp.h><br>
>>> using namespace Rcpp;<br>
>>><br>
>>> // [[Rcpp::export]]<br>
>>> std::vector<double> mybar(const std::vector<double>& x, double <br>
>>> firstelem) {<br>
>>> std::vector<double> tmp(x.size() + 1);<br>
>>> tmp[0] = firstelem;<br>
>>> for (int i = 1; i < (x.size()+1); i++)<br>
>>> tmp[i] = x[i-1];<br>
>>> return tmp;<br>
>>> }<br>
>>> // [[Rcpp::export]]<br>
>>> std::vector<double> mybar2(const std::vector<double>& x, double <br>
>>> firstelem) {<br>
>>> std::vector<double> tmp(x.size() + 1);<br>
>>> tmp[0] = firstelem;<br>
>>> std::copy(x.begin(), x.end(), tmp.begin()+1);<br>
>>> return tmp;<br>
>>> }<br>
>>><br>
>>> /*** R<br>
>>> library(microbenchmark)<br>
>>> n=100000<br>
>>> testvec = c(1,seq_len(n))<br>
>>> testelem <- 7<br>
>>> microbenchmark(c(testelem, testvec), mybar(testvec,testelem), <br>
>>> mybar2(testvec,testelem))<br>
>>> */<br>
>>><br>
>>> # Ouput<br>
>>> Unit: microseconds<br>
>>> expr min lq mean <br>
>>> median uq<br>
>>> c(testelem, testvec) 247.098 248.5655 444.8657 257.3300 <br>
>>> 630.7725<br>
>>> mybar(testvec, testelem) 594.978 622.3560 1226.5683 637.0230 <br>
>>> 1386.8385<br>
>>> mybar2(testvec, testelem) 576.191 604.7565 1029.2124 616.1055 <br>
>>> 1351.6740<br>
>>> max neval<br>
>>> 7587.977 100<br>
>>> 22149.605 100<br>
>>> 11651.831 100<br>
>>><br>
>>><br>
>>> Best,<br>
>>> Serguei.<br>
>>><br>
>>>> I looked on the net and found some material from back in ~2014 about <br>
>>>> concatenating<br>
>>>> vectors but I didn't see anything final about it. Thanks for any <br>
>>>> insights.<br>
>>>><br>
>>>> Also, the documentation for Rcpp is beyond incredible (thanks to <br>
>>>> dirk, romain, kevin and all the other people I'm leaving out ) but <br>
>>>> is there a general methodology for finding equivalents of R <br>
>>>> functions. For example, if I want a cumsum function in Rcpp, how do <br>
>>>> I know whether to use the stl with accumulate or if there's already <br>
>>>> one built in so<br>
>>>> that I just call cumsum.<br>
>>>><br>
>>>> Thanks.<br>
>>>><br>
>>>> #=======================================================<br>
>>>><br>
>>>> #include <Rcpp.h><br>
>>>> using namespace Rcpp;<br>
>>>><br>
>>>> // [[Rcpp::export]]<br>
>>>> std::vector<double> mybar(const std::vector<double>& x, double <br>
>>>> firstelem) {<br>
>>>> std::vector<double> tmp(x.size() + 1);<br>
>>>> tmp[0] = firstelem;<br>
>>>> for (int i = 1; i < (x.size()+1); i++)<br>
>>>> tmp[i] = x[i-1];<br>
>>>> return tmp;<br>
>>>> }<br>
>>>><br>
>>>> /*** R<br>
>>>><br>
>>>> testvec = c(1,2,3)<br>
>>>> testelem <- 7<br>
>>>> mybar(testvec,testelem)<br>
>>>><br>
>>>> */<br>
>>>><br>
>>>> #===============================<br>
>>>> # OUTPUT FROM RUNNING ABOVE<br>
>>>> #=================================<br>
>>>> > testvec <- c(1,2,3)<br>
>>>> > testelem <- 7<br>
>>>> > mybar(testvec,testelem)<br>
>>>> [1] 7 1 2 3<br>
>>>> ><br>
>>>><br>
>>>><br>
>>>><br>
>>>><br>
>>>><br>
>>>><br>
>>>><br>
>>>> _______________________________________________<br>
>>>> Rcpp-devel mailing list<br>
>>>> <a href="mailto:Rcpp-devel@lists.r-forge.r-project.org" target="_blank">Rcpp-devel@lists.r-forge.r-project.org</a><br>
>>>> <a href="https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel" rel="noreferrer" target="_blank">https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel</a><br>
>>>><br>
>>><br>
>>> _______________________________________________<br>
>>> Rcpp-devel mailing list<br>
>>> <a href="mailto:Rcpp-devel@lists.r-forge.r-project.org" target="_blank">Rcpp-devel@lists.r-forge.r-project.org</a><br>
>>> <a href="https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel" rel="noreferrer" target="_blank">https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel</a><br>
>> _______________________________________________<br>
>> Rcpp-devel mailing list<br>
>> <a href="mailto:Rcpp-devel@lists.r-forge.r-project.org" target="_blank">Rcpp-devel@lists.r-forge.r-project.org</a><br>
>> <a href="https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel" rel="noreferrer" target="_blank">https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel</a><br>
> <br>
<br>
_______________________________________________<br>
Rcpp-devel mailing list<br>
<a href="mailto:Rcpp-devel@lists.r-forge.r-project.org" target="_blank">Rcpp-devel@lists.r-forge.r-project.org</a><br>
<a href="https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel" rel="noreferrer" target="_blank">https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel</a></blockquote></div></div></div>