Re: [Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread Dirk Eddelbuettel

On 7 January 2012 at 11:40, baptiste auguie wrote:
| Hi,
| 
| (Rcpp)Armadillo has a 1D convolution function <
| http://arma.sourceforge.net/docs.html#conv >. It might be a very
| inefficient way, to use it sequentially for 2D; I haven't tried.

Good point. Off-list, I already suggested to Hadley to look at what the image
processing folks have done.  And as Conrad is now proud author of several
published papers in the area (kudos!), he may have a pointers.  Conrad?

Dirk
 
| HTH,
| 
| baptiste
| 
| 
| 
| On 7 January 2012 07:43, Hadley Wickham  wrote:
| > Hi all,
| >
| > The rcpp-devel list has been very helpful to me so far, so I hope you
| > don't mind another question!  I'm trying to speed up my 2d convolution
| > function:
| >
| >
| >
| > library(inline)
| > # 2d convolution 
-
| >
| > convolve_2d <- cxxfunction(signature(sampleS = "numeric", kernelS =
| > "numeric"), plugin = "Rcpp", '
| >    Rcpp::NumericMatrix sample(sampleS), kernel(kernelS);
| >    int x_s = sample.nrow(), x_k = kernel.nrow();
| >    int y_s = sample.ncol(), y_k = kernel.ncol();
| >
| >    Rcpp::NumericMatrix output(x_s + x_k - 1, y_s + y_k - 1);
| >    for (int row = 0; row < x_s; row++) {
| >      for (int col = 0; col < y_s; col++) {
| >        for (int i = 0; i < x_k; i++) {
| >          for (int j = 0; j < y_k; j++) {
| >            output(row + i, col + j) += sample(row, col) * kernel(i, j);
| >          }
| >        }
| >      }
| >    }
| >    return output;
| > ')
| >
| >
| > x <- diag(1000)
| > k <- matrix(runif(20* 20), ncol = 20)
| > system.time(convolve_2d(x, k))
| > #    user  system elapsed
| > # 14.759   0.028  15.524
| >
| > I have a vague idea that to get better performance I need to get
| > closer to bare pointers, and I need to be careful about the order of
| > my loops to ensure that I'm working over contiguous chunks of memory
| > as often as possible, but otherwise I've basically exhausted my
| > C++/Rcpp knowledge.  Where should I start looking to improve the
| > performance of this function?
| >
| > The example data basically matches the real problem - x is not usually
| > going to be much bigger than 1000 x 1000 and k typically will be much
| > smaller.  (And hence, based on what I've read, this technique should
| > be faster than doing it via a discrete fft)
| >
| > Hadley
| >
| > --
| > Assistant Professor / Dobelman Family Junior Chair
| > Department of Statistics / Rice University
| > http://had.co.nz/
| > ___
| > Rcpp-devel mailing list
| > Rcpp-devel@lists.r-forge.r-project.org
| > https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
| ___
| Rcpp-devel mailing list
| Rcpp-devel@lists.r-forge.r-project.org
| https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel

-- 
"Outside of a dog, a book is a man's best friend. Inside of a dog, it is too
dark to read." -- Groucho Marx
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread baptiste auguie
On 7 January 2012 11:40, baptiste auguie  wrote:
> Hi,
>
> (Rcpp)Armadillo has a 1D convolution function <
> http://arma.sourceforge.net/docs.html#conv >. It might be a very
> inefficient way, to use it sequentially for 2D; I haven't tried.

Also, it only works for separable kernels.

baptiste

>
> HTH,
>
> baptiste
>
>
>
> On 7 January 2012 07:43, Hadley Wickham  wrote:
>> Hi all,
>>
>> The rcpp-devel list has been very helpful to me so far, so I hope you
>> don't mind another question!  I'm trying to speed up my 2d convolution
>> function:
>>
>>
>>
>> library(inline)
>> # 2d convolution 
>> -
>>
>> convolve_2d <- cxxfunction(signature(sampleS = "numeric", kernelS =
>> "numeric"), plugin = "Rcpp", '
>>    Rcpp::NumericMatrix sample(sampleS), kernel(kernelS);
>>    int x_s = sample.nrow(), x_k = kernel.nrow();
>>    int y_s = sample.ncol(), y_k = kernel.ncol();
>>
>>    Rcpp::NumericMatrix output(x_s + x_k - 1, y_s + y_k - 1);
>>    for (int row = 0; row < x_s; row++) {
>>      for (int col = 0; col < y_s; col++) {
>>        for (int i = 0; i < x_k; i++) {
>>          for (int j = 0; j < y_k; j++) {
>>            output(row + i, col + j) += sample(row, col) * kernel(i, j);
>>          }
>>        }
>>      }
>>    }
>>    return output;
>> ')
>>
>>
>> x <- diag(1000)
>> k <- matrix(runif(20* 20), ncol = 20)
>> system.time(convolve_2d(x, k))
>> #    user  system elapsed
>> # 14.759   0.028  15.524
>>
>> I have a vague idea that to get better performance I need to get
>> closer to bare pointers, and I need to be careful about the order of
>> my loops to ensure that I'm working over contiguous chunks of memory
>> as often as possible, but otherwise I've basically exhausted my
>> C++/Rcpp knowledge.  Where should I start looking to improve the
>> performance of this function?
>>
>> The example data basically matches the real problem - x is not usually
>> going to be much bigger than 1000 x 1000 and k typically will be much
>> smaller.  (And hence, based on what I've read, this technique should
>> be faster than doing it via a discrete fft)
>>
>> Hadley
>>
>> --
>> Assistant Professor / Dobelman Family Junior Chair
>> Department of Statistics / Rice University
>> http://had.co.nz/
>> ___
>> Rcpp-devel mailing list
>> Rcpp-devel@lists.r-forge.r-project.org
>> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread baptiste auguie
Hi,

(Rcpp)Armadillo has a 1D convolution function <
http://arma.sourceforge.net/docs.html#conv >. It might be a very
inefficient way, to use it sequentially for 2D; I haven't tried.

HTH,

baptiste



On 7 January 2012 07:43, Hadley Wickham  wrote:
> Hi all,
>
> The rcpp-devel list has been very helpful to me so far, so I hope you
> don't mind another question!  I'm trying to speed up my 2d convolution
> function:
>
>
>
> library(inline)
> # 2d convolution -
>
> convolve_2d <- cxxfunction(signature(sampleS = "numeric", kernelS =
> "numeric"), plugin = "Rcpp", '
>    Rcpp::NumericMatrix sample(sampleS), kernel(kernelS);
>    int x_s = sample.nrow(), x_k = kernel.nrow();
>    int y_s = sample.ncol(), y_k = kernel.ncol();
>
>    Rcpp::NumericMatrix output(x_s + x_k - 1, y_s + y_k - 1);
>    for (int row = 0; row < x_s; row++) {
>      for (int col = 0; col < y_s; col++) {
>        for (int i = 0; i < x_k; i++) {
>          for (int j = 0; j < y_k; j++) {
>            output(row + i, col + j) += sample(row, col) * kernel(i, j);
>          }
>        }
>      }
>    }
>    return output;
> ')
>
>
> x <- diag(1000)
> k <- matrix(runif(20* 20), ncol = 20)
> system.time(convolve_2d(x, k))
> #    user  system elapsed
> # 14.759   0.028  15.524
>
> I have a vague idea that to get better performance I need to get
> closer to bare pointers, and I need to be careful about the order of
> my loops to ensure that I'm working over contiguous chunks of memory
> as often as possible, but otherwise I've basically exhausted my
> C++/Rcpp knowledge.  Where should I start looking to improve the
> performance of this function?
>
> The example data basically matches the real problem - x is not usually
> going to be much bigger than 1000 x 1000 and k typically will be much
> smaller.  (And hence, based on what I've read, this technique should
> be faster than doing it via a discrete fft)
>
> Hadley
>
> --
> Assistant Professor / Dobelman Family Junior Chair
> Department of Statistics / Rice University
> http://had.co.nz/
> ___
> Rcpp-devel mailing list
> Rcpp-devel@lists.r-forge.r-project.org
> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread Douglas Bates
On Fri, Jan 6, 2012 at 2:58 PM, Douglas Bates  wrote:
> On Fri, Jan 6, 2012 at 2:02 PM, Hadley Wickham  wrote:
>>> What are you doing the timing on?  On a modest desktop (2.6 GHz Athlon
>>> X4) I get less than a second for this
>> ...
 k <- matrix(runif(20* 20), ncol = 20)
 system.time(convolve_2d(x, k))
>>>   user  system elapsed
>>>  0.864   0.000   0.862
>>
>> Ooops, I must have been using a old k - I now get
>>
>>> system.time(convolve_2d(x, k))
>>   user  system elapsed
>>  2.265   0.006   2.298
>>
>> I'm on a 2nd gen macbook air, so the processor isn't the fastest (2.13
>> GHz). Maybe my intuition is wrong but it seems like you should be able
>> to do it faster than that.
>>
>> But let me think - I'm doing 1000 * 1000 * 20 * 20 = 4e08 multiplies +
>> adds in ~2s.  So that's 5e-9 s = 5 ns per operation.  Looking at it
>> that way it does seem pretty fast already.
>
> You can make this about 40% faster by using block operations in Eigen
> through RcppEigen.  In this code fragment I did remember to use a
> typedef and a const modifier.  I allocated the result as an
> Rcpp::NumericMatrix then mapped it to avoid an extra allocation and
> copy but that is a minor speedup for matrices of this size.

I just saw a superfluous statement after I changed to allocating an
Rcpp::NumericMatrix.  The .setZero() is no longer needed because Rcpp
zeros the storage.

R version 2.14.1 (2011-12-22)
Copyright (C) 2011 The R Foundation for Statistical Computing
ISBN 3-900051-07-0
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> library(inline)
> # 2d convolution -
> 
> convolve_2d <- cxxfunction(signature(sampleS = "numeric", kernelS =
+ "numeric"), plugin = "Rcpp", '
+Rcpp::NumericMatrix sample(sampleS), kernel(kernelS);
+int x_s = sample.nrow(), x_k = kernel.nrow();
+int y_s = sample.ncol(), y_k = kernel.ncol();
+ 
+Rcpp::NumericMatrix output(x_s + x_k - 1, y_s + y_k - 1);
+for (int row = 0; row < x_s; row++) {
+  for (int col = 0; col < y_s; col++) {
+for (int i = 0; i < x_k; i++) {
+  for (int j = 0; j < y_k; j++) {
+output(row + i, col + j) += sample(row, col) * kernel(i, j);
+  }
+}
+  }
+}
+return output;
+ ')
> 
> convolve_2d_Eigen <- cxxfunction(signature(sampleS = "numeric", kernelS =
+ "numeric"), plugin = "RcppEigen", '
+typedef Eigen::Map  MMat;
+ 
+const MMat sample(as(sampleS)), kernel(as(kernelS));
+int x_s = sample.rows(), x_k = kernel.rows();
+int y_s = sample.cols(), y_k = kernel.cols();
+int x_o = x_s + x_k - 1, y_o = y_s + y_k - 1;
+ 
+Rcpp::NumericMatrix out(x_o, y_o);
+MMat  output(out.begin(), x_o, y_o);
+ 
+for (int row = 0; row < x_s; row++) {
+  for (int col = 0; col < y_s; col++) {
+output.block(row, col, x_k, y_k) += sample(row, col) * kernel;
+  }
+}
+return out;
+ ')
Loading required package: lattice

Attaching package: ‘Matrix’

The following object(s) are masked from ‘package:base’:

det

> 
> x <- diag(1000)
> set.seed(1)
> k <- matrix(runif(20* 20), ncol = 20)
> system.time(loop <- convolve_2d(x, k))
   user  system elapsed 
  0.840   0.004   0.847 
> system.time(block <- convolve_2d_Eigen(x, k))
   user  system elapsed 
  0.580   0.004   0.584 
> all.equal(loop, block)
[1] TRUE
> 
> library(microbenchmark)
> microbenchmark(loop  = convolve_2d(x, k),
+block = convolve_2d_Eigen(x, k), times=30)
Unit: milliseconds
   expr  min   lq   median   uq  max
1 block 473.0885 476.9951 478.4295 481.5343 492.4735
2  loop 830.6481 833.8049 835.1170 841.9029 854.5755
> 
> proc.time()
   user  system elapsed 
 51.726   1.180  52.486 
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel

Re: [Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread Douglas Bates
On Fri, Jan 6, 2012 at 2:02 PM, Hadley Wickham  wrote:
>> What are you doing the timing on?  On a modest desktop (2.6 GHz Athlon
>> X4) I get less than a second for this
> ...
>>> k <- matrix(runif(20* 20), ncol = 20)
>>> system.time(convolve_2d(x, k))
>>   user  system elapsed
>>  0.864   0.000   0.862
>
> Ooops, I must have been using a old k - I now get
>
>> system.time(convolve_2d(x, k))
>   user  system elapsed
>  2.265   0.006   2.298
>
> I'm on a 2nd gen macbook air, so the processor isn't the fastest (2.13
> GHz). Maybe my intuition is wrong but it seems like you should be able
> to do it faster than that.
>
> But let me think - I'm doing 1000 * 1000 * 20 * 20 = 4e08 multiplies +
> adds in ~2s.  So that's 5e-9 s = 5 ns per operation.  Looking at it
> that way it does seem pretty fast already.

You can make this about 40% faster by using block operations in Eigen
through RcppEigen.  In this code fragment I did remember to use a
typedef and a const modifier.  I allocated the result as an
Rcpp::NumericMatrix then mapped it to avoid an extra allocation and
copy but that is a minor speedup for matrices of this size.

R version 2.14.1 (2011-12-22)
Copyright (C) 2011 The R Foundation for Statistical Computing
ISBN 3-900051-07-0
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> library(inline)
> # 2d convolution -
> 
> convolve_2d <- cxxfunction(signature(sampleS = "numeric", kernelS =
+ "numeric"), plugin = "Rcpp", '
+Rcpp::NumericMatrix sample(sampleS), kernel(kernelS);
+int x_s = sample.nrow(), x_k = kernel.nrow();
+int y_s = sample.ncol(), y_k = kernel.ncol();
+ 
+Rcpp::NumericMatrix output(x_s + x_k - 1, y_s + y_k - 1);
+for (int row = 0; row < x_s; row++) {
+  for (int col = 0; col < y_s; col++) {
+for (int i = 0; i < x_k; i++) {
+  for (int j = 0; j < y_k; j++) {
+output(row + i, col + j) += sample(row, col) * kernel(i, j);
+  }
+}
+  }
+}
+return output;
+ ')
> 
> convolve_2d_Eigen <- cxxfunction(signature(sampleS = "numeric", kernelS =
+ "numeric"), plugin = "RcppEigen", '
+typedef Eigen::Map  MMat;
+ 
+const MMat sample(as(sampleS)), kernel(as(kernelS));
+int x_s = sample.rows(), x_k = kernel.rows();
+int y_s = sample.cols(), y_k = kernel.cols();
+int x_o = x_s + x_k - 1, y_o = y_s + y_k - 1;
+ 
+Rcpp::NumericMatrix out(x_o, y_o);
+MMat  output(out.begin(), x_o, y_o);
+output.setZero();   // Must explicitly zero out Eigen matrices
+for (int row = 0; row < x_s; row++) {
+  for (int col = 0; col < y_s; col++) {
+output.block(row, col, x_k, y_k) += sample(row, col) * kernel;
+  }
+}
+return out;
+ ')
Loading required package: lattice

Attaching package: ‘Matrix’

The following object(s) are masked from ‘package:base’:

det

> 
> x <- diag(1000)
> set.seed(1)
> k <- matrix(runif(20* 20), ncol = 20)
> system.time(loop <- convolve_2d(x, k))
   user  system elapsed 
   0.840.000.84 
> system.time(block <- convolve_2d_Eigen(x, k))
   user  system elapsed 
  0.588   0.000   0.587 
> all.equal(loop, block)
[1] TRUE
> 
> library(microbenchmark)
> microbenchmark(loop  = convolve_2d(x, k),
+block = convolve_2d_Eigen(x, k), times=30)
Unit: milliseconds
   expr  min   lq   median   uq  max
1 block 479.5808 481.5312 482.7564 492.0526 495.4081
2  loop 839.4510 844.4272 846.7940 854.1737 859.0746
> 
> proc.time()
   user  system elapsed 
 52.242   1.180  53.027 
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel

Re: [Rcpp-devel] Idiom for accessing scalars

2012-01-06 Thread Dirk Eddelbuettel

On 6 January 2012 at 13:46, Douglas Bates wrote:
| I didn't make myself clear.  What I meant was that it is not possible
| to use asInteger in Rcpp and count on the name being remapped to
| Rf_asInteger.

Right. I had to enforce that a long time ago because the non-prefixed
variants too often clash with things commonly used in other places. One
example was length(), and I think I even had issues with error().  

Hence the use of the remap toggle and the need for ugliness via Rf_*.

Dirk

-- 
"Outside of a dog, a book is a man's best friend. Inside of a dog, it is too
dark to read." -- Groucho Marx
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread Hadley Wickham
> What are you doing the timing on?  On a modest desktop (2.6 GHz Athlon
> X4) I get less than a second for this
...
>> k <- matrix(runif(20* 20), ncol = 20)
>> system.time(convolve_2d(x, k))
>   user  system elapsed
>  0.864   0.000   0.862

Ooops, I must have been using a old k - I now get

> system.time(convolve_2d(x, k))
   user  system elapsed
  2.265   0.006   2.298

I'm on a 2nd gen macbook air, so the processor isn't the fastest (2.13
GHz). Maybe my intuition is wrong but it seems like you should be able
to do it faster than that.

But let me think - I'm doing 1000 * 1000 * 20 * 20 = 4e08 multiplies +
adds in ~2s.  So that's 5e-9 s = 5 ns per operation.  Looking at it
that way it does seem pretty fast already.

Hadley

-- 
Assistant Professor / Dobelman Family Junior Chair
Department of Statistics / Rice University
http://had.co.nz/
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread Hadley Wickham
> Fancy indexing tricks aside, another avenue you might want to look
> into is doing the convolution in fourier space ...

I have looked into that, and I'm pretty sure for my case (k much
smaller than x), that it's less efficient (and less numerically
stable).  In my experience, it also make the code much harder to
understand - convolutions in fourier space are circular, which means
you have to add a whole lot of extra padding and it's non-obvious how
to debug.  I spent several months going down the fft route, and I've
already made more progress in a week of using loops.

Hadley

-- 
Assistant Professor / Dobelman Family Junior Chair
Department of Statistics / Rice University
http://had.co.nz/
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] When does using iterators for subscripting help?

2012-01-06 Thread Hadley Wickham
> As I said earlier, this construction guarantees that the storage is
> not copied.  An Rcpp::NumericVector also uses the storage from R but
> it can be difficult to determine exactly when a copy constructor,
> which actually allocates new storage for an SEXPREC, is invoked.

But that's half the fun of programming in R! ;)

Thanks for the other explanations.

Hadley


-- 
Assistant Professor / Dobelman Family Junior Chair
Department of Statistics / Rice University
http://had.co.nz/
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Idiom for accessing scalars

2012-01-06 Thread Douglas Bates
On Fri, Jan 6, 2012 at 1:12 PM, Dirk Eddelbuettel  wrote:
>
> On 6 January 2012 at 12:59, Douglas Bates wrote:
> | On Fri, Jan 6, 2012 at 12:39 PM, John Chambers  
> wrote:
> | > The "Rf_" part of the API in particular is ugly and somewhat of an add-on
> | > forced in a few examples by the use of some common names in the macro 
> files.
> |
> | But, as it stands, that is a requirement when using Rcpp.
>
> Where?  I can think of one propagated use, which is at the bottom of the
> try/catch structure where we use ::Rf_error.  But the commonly used macros
> hide it, and we could/should obviously wrap this.
>
> Otherwise, and especially since the 'Rcpp sugar' initiative took off, I don't
> really touch any ::Rf_* myself anymore.  Inside the Rcpp code base, sure. But
> not really in user-facing stuff and Rcpp applications.

I didn't make myself clear.  What I meant was that it is not possible
to use asInteger in Rcpp and count on the name being remapped to
Rf_asInteger.

> | I think of the Rf_ part as more due to the fact that C doesn't have a
> | concept of namespaces so anything in the R API is at the top level
> | namespace leading to some conflicts.
>
> Agreed.  But speaking stylistically, for the same reason that we prefer C++
> versions of C header files (eg cstdint over stdint.h, cstdio over stdio.h,
> ...) I am with John on the preference for C++ idioms when given a choice.

I suppose I could have just checked whether Rcpp::as calls
Rf_asInteger.  If so, everything is cool.  Unfortunately, I haven't
been able to find that specialization.
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] When does using iterators for subscripting help?

2012-01-06 Thread Douglas Bates
2012/1/6 Hadley Wickham :
>> I'm coming late to the party but ...  I was able to squeeze a couple
>> of milliseconds from the computation by expressing the counts as
>> integers and ensuring that I did not copy x by using an Eigen::Map.
>> It may well be that an Rcpp::NumericVector will not be a copy in this
>> case but I have found it difficult to determine exactly when an Rcpp
>> vector is going to be copied.  With Eigen I can ensure that the
>> original storage in R will be used for the vector.
>>
>> count_eigen <- cxxfunction(signature(x="numeric", binwidth="numeric",
>>                                     origin="numeric", nbins="integer"), '
>> double binwidth_ = ::Rf_asReal(binwidth), origin_ = ::Rf_asReal(origin);
>>
>> Eigen::VectorXi counts(::Rf_asInteger(nbins));
>> Eigen::Map x_(as >(x));
>>
>> int n = x_.size();
>>
>> counts.setZero();
>> for (int i = 0; i < n; i++) counts[((x_[i] - origin_) / binwidth_)]++;
>>
>> return wrap(counts);
>> ', plugin="RcppEigen")
>>
>>
>> As you see, I use ::Rf_asReal() and ::Rf_asInteger() for conversion to
>> scalar doubles or scalar integers.  Those functions are part of the R
>> API and are fast and general.
>
> Thanks.  Would you mind explaining a couple of the C++ idioms that you used?
>
> * What's going on with Eigen::Map
> x_(as >(x)) - you're creating a new Map
> (templated to contain VectorXds) called x_ and initialising with a
> converted x?

Dirk and I wrote an introductory vignette for the RcppEigen package
which, if you have not already done so, would be worth looking at.

An Eigen::VectorXd is a double precision vector with storage allocated
from the C++ heap.  An Eigen::Map behaves similarly but
maps the storage from some other source, in this case the storage from
R.  Had I followed the recommendations in the vignette mentioned above
I would have declared it as

const Eigen::Map  x_(as >(x));

to emphasize that it is a read-only vector.

> * I find it hard to visually parse   >(x).
>  Is there a reason you don't write it as
> x_(as>(x)?  Maybe because that would then
> form the >> operator?

Yes, exactly.  In production code I usually write something like

typedef Eigen::Map  MVec;

const MVec x_(as(x));

As I said earlier, this construction guarantees that the storage is
not copied.  An Rcpp::NumericVector also uses the storage from R but
it can be difficult to determine exactly when a copy constructor,
which actually allocates new storage for an SEXPREC, is invoked.
> * What does ::Rf_asReal mean?  How is it different to Rf_asReal?
>
> Thanks!
>
> Hadley
>
> --
> Assistant Professor / Dobelman Family Junior Chair
> Department of Statistics / Rice University
> http://had.co.nz/
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Idiom for accessing scalars

2012-01-06 Thread Dirk Eddelbuettel

On 6 January 2012 at 12:59, Douglas Bates wrote:
| On Fri, Jan 6, 2012 at 12:39 PM, John Chambers  wrote:
| > The "Rf_" part of the API in particular is ugly and somewhat of an add-on
| > forced in a few examples by the use of some common names in the macro files.
| 
| But, as it stands, that is a requirement when using Rcpp.

Where?  I can think of one propagated use, which is at the bottom of the
try/catch structure where we use ::Rf_error.  But the commonly used macros
hide it, and we could/should obviously wrap this.

Otherwise, and especially since the 'Rcpp sugar' initiative took off, I don't
really touch any ::Rf_* myself anymore.  Inside the Rcpp code base, sure. But
not really in user-facing stuff and Rcpp applications.
 
| I think of the Rf_ part as more due to the fact that C doesn't have a
| concept of namespaces so anything in the R API is at the top level
| namespace leading to some conflicts.

Agreed.  But speaking stylistically, for the same reason that we prefer C++
versions of C header files (eg cstdint over stdint.h, cstdio over stdio.h,
...) I am with John on the preference for C++ idioms when given a choice.

Dirk

-- 
"Outside of a dog, a book is a man's best friend. Inside of a dog, it is too
dark to read." -- Groucho Marx
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread Steve Lianoglou
Hi,

Fancy indexing tricks aside, another avenue you might want to look
into is doing the convolution in fourier space ...

I'll stop there so I minimize the damage I'm doing as far as spreading
misinformation in a public forum goes. I'm also interested in
investigating that avenue further, as I wrote a 1d convolution for
something else in Rcpp and want to drive the "fourier trick" via C
code ... I just haven't had the time to do the follow up reading.

Anyway, I "know" it works in the 1d case (that's how the base R
convolve works), I guess there are particulars to sort out in the 2d
case ...

And if you *really* want it to go fast, I guess you can go the CUDA route :-)

http://developer.download.nvidia.com/compute/cuda/2_2/sdk/website/projects/convolutionFFT2D/doc/convolutionFFT2D.pdf

HTH (but I'm sure it didn't :-)

-steve

On Fri, Jan 6, 2012 at 1:43 PM, Hadley Wickham  wrote:
> Hi all,
>
> The rcpp-devel list has been very helpful to me so far, so I hope you
> don't mind another question!  I'm trying to speed up my 2d convolution
> function:
>
>
>
> library(inline)
> # 2d convolution -
>
> convolve_2d <- cxxfunction(signature(sampleS = "numeric", kernelS =
> "numeric"), plugin = "Rcpp", '
>    Rcpp::NumericMatrix sample(sampleS), kernel(kernelS);
>    int x_s = sample.nrow(), x_k = kernel.nrow();
>    int y_s = sample.ncol(), y_k = kernel.ncol();
>
>    Rcpp::NumericMatrix output(x_s + x_k - 1, y_s + y_k - 1);
>    for (int row = 0; row < x_s; row++) {
>      for (int col = 0; col < y_s; col++) {
>        for (int i = 0; i < x_k; i++) {
>          for (int j = 0; j < y_k; j++) {
>            output(row + i, col + j) += sample(row, col) * kernel(i, j);
>          }
>        }
>      }
>    }
>    return output;
> ')
>
>
> x <- diag(1000)
> k <- matrix(runif(20* 20), ncol = 20)
> system.time(convolve_2d(x, k))
> #    user  system elapsed
> # 14.759   0.028  15.524
>
> I have a vague idea that to get better performance I need to get
> closer to bare pointers, and I need to be careful about the order of
> my loops to ensure that I'm working over contiguous chunks of memory
> as often as possible, but otherwise I've basically exhausted my
> C++/Rcpp knowledge.  Where should I start looking to improve the
> performance of this function?
>
> The example data basically matches the real problem - x is not usually
> going to be much bigger than 1000 x 1000 and k typically will be much
> smaller.  (And hence, based on what I've read, this technique should
> be faster than doing it via a discrete fft)
>
> Hadley
>
> --
> Assistant Professor / Dobelman Family Junior Chair
> Department of Statistics / Rice University
> http://had.co.nz/
> ___
> Rcpp-devel mailing list
> Rcpp-devel@lists.r-forge.r-project.org
> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel



-- 
Steve Lianoglou
Graduate Student: Computational Systems Biology
 | Memorial Sloan-Kettering Cancer Center
 | Weill Medical College of Cornell University
Contact Info: http://cbio.mskcc.org/~lianos/contact
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread Douglas Bates
On Fri, Jan 6, 2012 at 12:43 PM, Hadley Wickham  wrote:
> Hi all,
>
> The rcpp-devel list has been very helpful to me so far, so I hope you
> don't mind another question!  I'm trying to speed up my 2d convolution
> function:
>
>
>
> library(inline)
> # 2d convolution -
>
> convolve_2d <- cxxfunction(signature(sampleS = "numeric", kernelS =
> "numeric"), plugin = "Rcpp", '
>    Rcpp::NumericMatrix sample(sampleS), kernel(kernelS);
>    int x_s = sample.nrow(), x_k = kernel.nrow();
>    int y_s = sample.ncol(), y_k = kernel.ncol();
>
>    Rcpp::NumericMatrix output(x_s + x_k - 1, y_s + y_k - 1);
>    for (int row = 0; row < x_s; row++) {
>      for (int col = 0; col < y_s; col++) {
>        for (int i = 0; i < x_k; i++) {
>          for (int j = 0; j < y_k; j++) {
>            output(row + i, col + j) += sample(row, col) * kernel(i, j);
>          }
>        }
>      }
>    }
>    return output;
> ')
>
>
> x <- diag(1000)
> k <- matrix(runif(20* 20), ncol = 20)
> system.time(convolve_2d(x, k))
> #    user  system elapsed
> # 14.759   0.028  15.524
>
> I have a vague idea that to get better performance I need to get
> closer to bare pointers, and I need to be careful about the order of
> my loops to ensure that I'm working over contiguous chunks of memory
> as often as possible, but otherwise I've basically exhausted my
> C++/Rcpp knowledge.  Where should I start looking to improve the
> performance of this function?
>
> The example data basically matches the real problem - x is not usually
> going to be much bigger than 1000 x 1000 and k typically will be much
> smaller.  (And hence, based on what I've read, this technique should
> be faster than doing it via a discrete fft)

What are you doing the timing on?  On a modest desktop (2.6 GHz Athlon
X4) I get less than a second for this


> library(inline)
> convolve_2d <- cxxfunction(signature(sampleS = "numeric", kernelS =
+ "numeric"), plugin = "Rcpp", '
+Rcpp::NumericMatrix sample(sampleS), kernel(kernelS);
+int x_s = sample.nrow(), x_k = kernel.nrow();
+int y_s = sample.ncol(), y_k = kernel.ncol();
+Rcpp::NumericMatrix output(x_s + x_k - 1, y_s + y_k - 1);
+for (int row = 0; row < x_s; row++) {
+  for (int col = 0; col < y_s; col++) {
+for (int i = 0; i < x_k; i++) {
+  for (int j = 0; j < y_k; j++) {
+output(row + i, col + j) += sample(row, col) * kernel(i, j);
+  }
+}
+  }
+}
+return output;
+ ')
> x <- diag(1000)
> k <- matrix(runif(20* 20), ncol = 20)
> system.time(convolve_2d(x, k))
   user  system elapsed
  0.864   0.000   0.862
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Idiom for accessing scalars

2012-01-06 Thread Douglas Bates
On Fri, Jan 6, 2012 at 12:39 PM, John Chambers  wrote:
> At the risk of derailing this thread into the quicksand of programming style
> 
>
> Except when required by the specific application, my preference would be to
> stay with the Rcpp idiom.  Mixing in the older C API seems to risk more
> programming error.  Of course, each application is different and we have to
> make decisions about efficiency (machine) vs possible inefficiency (human).

I would argue that special-purpose functions and macros for handling
the funky C structures are the best way of handling the funky C
structures.   Relative to working with C++ classes and methods they
are clunky but, short of converting to something like CXXR, we are
stuck with the C structures.

> The "Rf_" part of the API in particular is ugly and somewhat of an add-on
> forced in a few examples by the use of some common names in the macro files.

But, as it stands, that is a requirement when using Rcpp.

I think of the Rf_ part as more due to the fact that C doesn't have a
concept of namespaces so anything in the R API is at the top level
namespace leading to some conflicts.

> This year in our Stanford grad course, I'm planning to push Rcpp, so in a
> few months I may have a different view.  :-)
>
> Cheers,
>  John
>
>
> On 1/6/12 10:15 AM, Dirk Eddelbuettel wrote:
>>
>> On 6 January 2012 at 13:00, Steve Lianoglou wrote:
>> | Hi,
>> |
>> | 2012/1/6 Douglas Bates:
>> | [snip]
>> |>  As I mentioned in another thread, I prefer the idiom
>> |>
>> |>  int n2 = ::Rf_asInteger(n);
>> |>
>> |>  because asInteger is part of the R API (in Rcpp it must be called as
>> |>  Rf_asInteger - the :: is a hint to the compiler that it will be found
>> |>  in the global namespace).  Functions like asInteger and asReal are
>> |>  used in thousands of places in the base R code and have been optimized
>> |>  to death as well as being as general as they can possibly be.
>> |
>> | Cool ... I actually missed that tip, thanks for pointing it out again.
>>
>> And if one overcomes the "ick" factor of mixing APIs, it saves a
>> little:
>>
>> R>  library(inline)
>> R>  library(microbenchmark)
>> R>
>> R>  fr<- cxxfunction(signature(xs="integer"), plugin="Rcpp", body='
>> +    int x = ::Rf_asInteger(xs);
>> +    return Rcpp::wrap(x);
>> + ')
>> R>
>> R>  frcpp<- cxxfunction(signature(xs="integer"), plugin="Rcpp", body='
>> +    int x = Rcpp::as(xs);
>> +    return Rcpp::wrap(x);
>> + ')
>> R>
>> R>  microbenchmark(fr(123), frcpp(123))
>> Unit: nanoseconds
>>         expr min    lq median   uq   max
>> 1    fr(123) 841 878.5  908.5  976 15684
>> 2 frcpp(123) 976 999.5 1017.0 1085  6589
>> R>
>>
>> A good chunk here is "fixed" cost of calling a function, returning a
>> value, ... so that the "variable" gain of ::Rf_asInteger() looks pretty
>> good.
>>
>> Dirk, somewhat wondering why we're debating 100ns gains in the context of
>> R
>>
> ___
> Rcpp-devel mailing list
> Rcpp-devel@lists.r-forge.r-project.org
> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Idiom for accessing scalars

2012-01-06 Thread Dirk Eddelbuettel

On 6 January 2012 at 10:39, John Chambers wrote:
| At the risk of derailing this thread into the quicksand of programming 
| style 

Au contraire: thanks for joining in.
 
| Except when required by the specific application, my preference would be 
| to stay with the Rcpp idiom.  Mixing in the older C API seems to risk 
| more programming error.  Of course, each application is different and we 
| have to make decisions about efficiency (machine) vs possible 
| inefficiency (human).

Couldn't agree more.
 
| The "Rf_" part of the API in particular is ugly and somewhat of an 
| add-on forced in a few examples by the use of some common names in the 
| macro files.
| 
| This year in our Stanford grad course, I'm planning to push Rcpp, so in 
| a few months I may have a different view.  :-)

Let the bug reports roll in :)

Dirk
 
| Cheers,
|John
| 
| On 1/6/12 10:15 AM, Dirk Eddelbuettel wrote:
| > On 6 January 2012 at 13:00, Steve Lianoglou wrote:
| > | Hi,
| > |
| > | 2012/1/6 Douglas Bates:
| > | [snip]
| > |>  As I mentioned in another thread, I prefer the idiom
| > |>
| > |>  int n2 = ::Rf_asInteger(n);
| > |>
| > |>  because asInteger is part of the R API (in Rcpp it must be called as
| > |>  Rf_asInteger - the :: is a hint to the compiler that it will be found
| > |>  in the global namespace).  Functions like asInteger and asReal are
| > |>  used in thousands of places in the base R code and have been optimized
| > |>  to death as well as being as general as they can possibly be.
| > |
| > | Cool ... I actually missed that tip, thanks for pointing it out again.
| >
| > And if one overcomes the "ick" factor of mixing APIs, it saves a
| > little:
| >
| > R>  library(inline)
| > R>  library(microbenchmark)
| > R>
| > R>  fr<- cxxfunction(signature(xs="integer"), plugin="Rcpp", body='
| > +int x = ::Rf_asInteger(xs);
| > +return Rcpp::wrap(x);
| > + ')
| > R>
| > R>  frcpp<- cxxfunction(signature(xs="integer"), plugin="Rcpp", body='
| > +int x = Rcpp::as(xs);
| > +return Rcpp::wrap(x);
| > + ')
| > R>
| > R>  microbenchmark(fr(123), frcpp(123))
| > Unit: nanoseconds
| >  expr minlq median   uq   max
| > 1fr(123) 841 878.5  908.5  976 15684
| > 2 frcpp(123) 976 999.5 1017.0 1085  6589
| > R>
| >
| > A good chunk here is "fixed" cost of calling a function, returning a
| > value, ... so that the "variable" gain of ::Rf_asInteger() looks pretty 
good.
| >
| > Dirk, somewhat wondering why we're debating 100ns gains in the context of R
| >

-- 
"Outside of a dog, a book is a man's best friend. Inside of a dog, it is too
dark to read." -- Groucho Marx
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


[Rcpp-devel] Optimising 2d convolution

2012-01-06 Thread Hadley Wickham
Hi all,

The rcpp-devel list has been very helpful to me so far, so I hope you
don't mind another question!  I'm trying to speed up my 2d convolution
function:



library(inline)
# 2d convolution -

convolve_2d <- cxxfunction(signature(sampleS = "numeric", kernelS =
"numeric"), plugin = "Rcpp", '
Rcpp::NumericMatrix sample(sampleS), kernel(kernelS);
int x_s = sample.nrow(), x_k = kernel.nrow();
int y_s = sample.ncol(), y_k = kernel.ncol();

Rcpp::NumericMatrix output(x_s + x_k - 1, y_s + y_k - 1);
for (int row = 0; row < x_s; row++) {
  for (int col = 0; col < y_s; col++) {
for (int i = 0; i < x_k; i++) {
  for (int j = 0; j < y_k; j++) {
output(row + i, col + j) += sample(row, col) * kernel(i, j);
  }
}
  }
}
return output;
')


x <- diag(1000)
k <- matrix(runif(20* 20), ncol = 20)
system.time(convolve_2d(x, k))
#user  system elapsed
# 14.759   0.028  15.524

I have a vague idea that to get better performance I need to get
closer to bare pointers, and I need to be careful about the order of
my loops to ensure that I'm working over contiguous chunks of memory
as often as possible, but otherwise I've basically exhausted my
C++/Rcpp knowledge.  Where should I start looking to improve the
performance of this function?

The example data basically matches the real problem - x is not usually
going to be much bigger than 1000 x 1000 and k typically will be much
smaller.  (And hence, based on what I've read, this technique should
be faster than doing it via a discrete fft)

Hadley

-- 
Assistant Professor / Dobelman Family Junior Chair
Department of Statistics / Rice University
http://had.co.nz/
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Idiom for accessing scalars

2012-01-06 Thread John Chambers
At the risk of derailing this thread into the quicksand of programming 
style 


Except when required by the specific application, my preference would be 
to stay with the Rcpp idiom.  Mixing in the older C API seems to risk 
more programming error.  Of course, each application is different and we 
have to make decisions about efficiency (machine) vs possible 
inefficiency (human).


The "Rf_" part of the API in particular is ugly and somewhat of an 
add-on forced in a few examples by the use of some common names in the 
macro files.


This year in our Stanford grad course, I'm planning to push Rcpp, so in 
a few months I may have a different view.  :-)


Cheers,
  John

On 1/6/12 10:15 AM, Dirk Eddelbuettel wrote:

On 6 January 2012 at 13:00, Steve Lianoglou wrote:
| Hi,
|
| 2012/1/6 Douglas Bates:
| [snip]
|>  As I mentioned in another thread, I prefer the idiom
|>
|>  int n2 = ::Rf_asInteger(n);
|>
|>  because asInteger is part of the R API (in Rcpp it must be called as
|>  Rf_asInteger - the :: is a hint to the compiler that it will be found
|>  in the global namespace).  Functions like asInteger and asReal are
|>  used in thousands of places in the base R code and have been optimized
|>  to death as well as being as general as they can possibly be.
|
| Cool ... I actually missed that tip, thanks for pointing it out again.

And if one overcomes the "ick" factor of mixing APIs, it saves a
little:

R>  library(inline)
R>  library(microbenchmark)
R>
R>  fr<- cxxfunction(signature(xs="integer"), plugin="Rcpp", body='
+int x = ::Rf_asInteger(xs);
+return Rcpp::wrap(x);
+ ')
R>
R>  frcpp<- cxxfunction(signature(xs="integer"), plugin="Rcpp", body='
+int x = Rcpp::as(xs);
+return Rcpp::wrap(x);
+ ')
R>
R>  microbenchmark(fr(123), frcpp(123))
Unit: nanoseconds
 expr minlq median   uq   max
1fr(123) 841 878.5  908.5  976 15684
2 frcpp(123) 976 999.5 1017.0 1085  6589
R>

A good chunk here is "fixed" cost of calling a function, returning a
value, ... so that the "variable" gain of ::Rf_asInteger() looks pretty good.

Dirk, somewhat wondering why we're debating 100ns gains in the context of R


___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] When does using iterators for subscripting help?

2012-01-06 Thread Hadley Wickham
> I'm coming late to the party but ...  I was able to squeeze a couple
> of milliseconds from the computation by expressing the counts as
> integers and ensuring that I did not copy x by using an Eigen::Map.
> It may well be that an Rcpp::NumericVector will not be a copy in this
> case but I have found it difficult to determine exactly when an Rcpp
> vector is going to be copied.  With Eigen I can ensure that the
> original storage in R will be used for the vector.
>
> count_eigen <- cxxfunction(signature(x="numeric", binwidth="numeric",
>                                     origin="numeric", nbins="integer"), '
> double binwidth_ = ::Rf_asReal(binwidth), origin_ = ::Rf_asReal(origin);
>
> Eigen::VectorXi counts(::Rf_asInteger(nbins));
> Eigen::Map x_(as >(x));
>
> int n = x_.size();
>
> counts.setZero();
> for (int i = 0; i < n; i++) counts[((x_[i] - origin_) / binwidth_)]++;
>
> return wrap(counts);
> ', plugin="RcppEigen")
>
>
> As you see, I use ::Rf_asReal() and ::Rf_asInteger() for conversion to
> scalar doubles or scalar integers.  Those functions are part of the R
> API and are fast and general.

Thanks.  Would you mind explaining a couple of the C++ idioms that you used?

* What's going on with Eigen::Map
x_(as >(x)) - you're creating a new Map
(templated to contain VectorXds) called x_ and initialising with a
converted x?

* I find it hard to visually parse   >(x).
 Is there a reason you don't write it as
x_(as>(x)?  Maybe because that would then
form the >> operator?

* What does ::Rf_asReal mean?  How is it different to Rf_asReal?

Thanks!

Hadley

-- 
Assistant Professor / Dobelman Family Junior Chair
Department of Statistics / Rice University
http://had.co.nz/
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Idiom for accessing scalars

2012-01-06 Thread Dirk Eddelbuettel

On 6 January 2012 at 13:00, Steve Lianoglou wrote:
| Hi,
| 
| 2012/1/6 Douglas Bates :
| [snip]
| > As I mentioned in another thread, I prefer the idiom
| >
| > int n2 = ::Rf_asInteger(n);
| >
| > because asInteger is part of the R API (in Rcpp it must be called as
| > Rf_asInteger - the :: is a hint to the compiler that it will be found
| > in the global namespace).  Functions like asInteger and asReal are
| > used in thousands of places in the base R code and have been optimized
| > to death as well as being as general as they can possibly be.
| 
| Cool ... I actually missed that tip, thanks for pointing it out again.

And if one overcomes the "ick" factor of mixing APIs , it saves a
little:

R> library(inline)
R> library(microbenchmark)
R> 
R> fr <- cxxfunction(signature(xs="integer"), plugin="Rcpp", body='
+int x = ::Rf_asInteger(xs);
+return Rcpp::wrap(x);
+ ')
R> 
R> frcpp <- cxxfunction(signature(xs="integer"), plugin="Rcpp", body='
+int x = Rcpp::as(xs);
+return Rcpp::wrap(x);
+ ')
R> 
R> microbenchmark(fr(123), frcpp(123))
Unit: nanoseconds
expr minlq median   uq   max
1fr(123) 841 878.5  908.5  976 15684
2 frcpp(123) 976 999.5 1017.0 1085  6589
R>  

A good chunk here is "fixed" cost of calling a function, returning a
value, ... so that the "variable" gain of ::Rf_asInteger() looks pretty good.

Dirk, somewhat wondering why we're debating 100ns gains in the context of R

-- 
"Outside of a dog, a book is a man's best friend. Inside of a dog, it is too
dark to read." -- Groucho Marx
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Idiom for accessing scalars

2012-01-06 Thread Steve Lianoglou
Hi,

2012/1/6 Douglas Bates :
[snip]
> As I mentioned in another thread, I prefer the idiom
>
> int n2 = ::Rf_asInteger(n);
>
> because asInteger is part of the R API (in Rcpp it must be called as
> Rf_asInteger - the :: is a hint to the compiler that it will be found
> in the global namespace).  Functions like asInteger and asReal are
> used in thousands of places in the base R code and have been optimized
> to death as well as being as general as they can possibly be.

Cool ... I actually missed that tip, thanks for pointing it out again.

Cheers,
-steve

-- 
Steve Lianoglou
Graduate Student: Computational Systems Biology
 | Memorial Sloan-Kettering Cancer Center
 | Weill Medical College of Cornell University
Contact Info: http://cbio.mskcc.org/~lianos/contact
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] Idiom for accessing scalars

2012-01-06 Thread Douglas Bates
2012/1/4 Romain François :
> Le 04/01/12 14:29, Hadley Wickham a écrit :
>
>> Hi all,
>>
>> I'm still just getting my feet wet in Rcpp, so please excuse the
>> naivety of my question, but is this the appropriate idiom for treating
>> an input as a C++ scalar?
>>
>> f<- cxxfunction(signature(x = "integer"), plugin = "Rcpp", '
>>   Rcpp::IntegerVector x1(x);
>>   int x2 = x1[0];
>>
>>   return(Rcpp::NumericVector(x2));
>> ')
>>
>> i.e. is there any way I can turn x in x2 more succinctly?  (This
>> function is just for illustrative purposes - I'm trying to do
>> something at least a little more complicated)
>>
>> Thanks!
>>
>> Hadley
>
> Yep,
>
> We have "as" for this, and wrap for the other way around:
>
>
> f<- cxxfunction(signature(x = "integer"), plugin = "Rcpp", '
>  int x2 = as(x) ;
>
>  return wrap(x2) ;
> ')

As I mentioned in another thread, I prefer the idiom

int n2 = ::Rf_asInteger(n);

because asInteger is part of the R API (in Rcpp it must be called as
Rf_asInteger - the :: is a hint to the compiler that it will be found
in the global namespace).  Functions like asInteger and asReal are
used in thousands of places in the base R code and have been optimized
to death as well as being as general as they can possibly be.
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


Re: [Rcpp-devel] When does using iterators for subscripting help?

2012-01-06 Thread Douglas Bates
2012/1/4 Hadley Wickham :
>> NumericVector:::iterator is actually alias to double*. Here is a trick
>> (probably does not work on not gcc compilers):
>
> Ah, interesting - thanks!

I'm coming late to the party but ...  I was able to squeeze a couple
of milliseconds from the computation by expressing the counts as
integers and ensuring that I did not copy x by using an Eigen::Map.
It may well be that an Rcpp::NumericVector will not be a copy in this
case but I have found it difficult to determine exactly when an Rcpp
vector is going to be copied.  With Eigen I can ensure that the
original storage in R will be used for the vector.

count_eigen <- cxxfunction(signature(x="numeric", binwidth="numeric",
 origin="numeric", nbins="integer"), '
double binwidth_ = ::Rf_asReal(binwidth), origin_ = ::Rf_asReal(origin);

Eigen::VectorXi counts(::Rf_asInteger(nbins));
Eigen::Map x_(as >(x));

int n = x_.size();

counts.setZero();
for (int i = 0; i < n; i++) counts[((x_[i] - origin_) / binwidth_)]++;

return wrap(counts);
', plugin="RcppEigen")


As you see, I use ::Rf_asReal() and ::Rf_asInteger() for conversion to
scalar doubles or scalar integers.  Those functions are part of the R
API and are fast and general.

With this version I get a minor speedup

> microbenchmark(operator = count_bin(x, binwidth, origin, nbins = n),
+iterator = count_bini(x, binwidth, origin, nbins = n),
+eigen= count_eigen(x, binwidth, origin, nbins = n)
+ )
Unit: milliseconds
  expr  min   lq   median   uq  max
1eigen 145.6456 145.7102 145.7536 145.8210 151.0456
2 iterator 153.3059 153.3603 153.4182 153.6056 155.3246
3 operator 156.2418 156.7063 156.7637 156.8982 159.8635
___
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel