[Rcpp-devel] Integer matrices in Rcpp and Armadillo
Kevin Ushey
kevinushey at gmail.com
Sat Jun 8 21:48:35 CEST 2013
I'm pretty the sure the Rcpp / RcppArmadillo way is to reuse memory
whenever the types match between the as'ed containers, and copy if type
coercion makes sense. Ie, an R integer vector --> an Rcpp IntegerVector
would reuse the same memory, while an R integer vector --> an Rcpp
NumericVector would require a copy and a coercion from integer to numeric.
Similar things will apply between R and RcppArmadillo. Just remember that
with R, numeric <-> double, integer <-> signed int.
A simple example to illustrate (also shows how you can discover these
things yourself):
---
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::NumericVector test_numeric(Rcpp::NumericVector x) {
x = x + 1;
return x;
}
// [[Rcpp::export]]
Rcpp::IntegerVector test_integer(Rcpp::IntegerVector x) {
x = x + 1;
return x;
}
/*** R
x <- c(1, 2, 3)
test_numeric(x) ## returns c(2, 3, 4)
print(x) ## x is now c(2, 3, 4)
test_integer(x) ## returns c(3, 4, 5)
print(x) ## x is still c(2, 3, 4)
*/
---
Since this thread has become rather long, I suggest generating your own
minimal examples whenever you need to discover / be certain whether you're
reusing memory or forcing a copy.
-Kevin
On Sat, Jun 8, 2013 at 12:22 PM, Simon Zehnder <szehnder at uni-bonn.de> wrote:
> Hi Romain,
>
> I considered the implicit use of Rcpp::as<>() inside of the arma::mat()
> constructor. My target was to reuse memory and try to use a very simple
> setting, i.e. (at least in my opinion) not too much lines of code.
>
> You answered to my question
>
> "On the other side I then assume, that the Rcpp:as<class M>() function
> makes a cast and therefore creates a copy with new allocated memory of the
> type included in M? Therefore a reuse of memory with this function is not
> possible":
>
> Depends what is M, but most of the time yes, as<> copies data.
>
> What I then tried, was this:
>
> setClass("myclass", representation(par = "list"))
> l <- list(lambda = array(0, dim = c(10,2)))
> mclass <- new("myclass", par = l)
> cfunction <- cxxfunction(signature(myClass_R = "array"), body = 'Rcpp::S4
> myclass(myClass_R); Rcpp::List parL((SEXP) myclass.slot("par")); arma::mat
> armaPar(Rcpp::as<Rcpp::NumericMatrix>(parL["lambda"]).begin(), 10, 2,
> false, true); armaPar(0,0) = 1.2 ;return Rcpp::wrap(myclass);', plugin =
> "RcppArmadillo")
> cfunction(mclass)
> An object of class "myclass"
> Slot "par":
> $lambda
> [,1] [,2]
> [1,] 1.2 0
> [2,] 0.0 0
> [3,] 0.0 0
> [4,] 0.0 0
> [5,] 0.0 0
> [6,] 0.0 0
> [7,] 0.0 0
> [8,] 0.0 0
> [9,] 0.0 0
> [10,] 0.0 0
>
> So, it seems, that calling Rcpp::as<>() implicitly inside the arma::mat()
> constructor, enables the reuse of memory with only a few lines of code,
> which is pretty nice. So in case of M being Rcpp::NumericMatrix,
> Rcpp::as<>() seems not to copy data. But it also could be, that I
> misunderstood your answer above, or that we were talking about two
> different things there. In this case please apologize my confusion.
>
>
> Best
>
> Simon
>
>
> On Jun 8, 2013, at 8:08 AM, Romain Francois <romain at r-enthusiasts.com>
> wrote:
>
> > Le 07/06/13 16:07, Simon Zehnder a écrit :
> >> Hi Romain,
> >>
> >> thanks for this precise answer. So the suggested methods below will
> work without making a copy of the object.
> >
> > yes
> >
> >> What is about the implicit call of Rcpp::as<>() inside arma::mat()? It
> is a very convenient way to create an arma object reusing memory and it
> seems to work just fine.
> >
> > I don't know what you are talking about.
> >
> >> Best
> >>
> >> Simon
> >> On Jun 7, 2013, at 3:47 PM, Romain Francois <romain at r-enthusiasts.com>
> wrote:
> >>
> >>> Le 07/06/13 15:14, Simon Zehnder a écrit :
> >>>> Hi Romain, hi Dirk,
> >>>>
> >>>> sorry for posting here again, but I found something in some way
> connected to this discussion - and pretty interesting concerning the
> Rcpp::as<>() function:
> >>>>
> >>>> 1. I create a class containing a list:
> >>>>
> >>>> setClass("myclass", representation(par = "list"))
> >>>>
> >>>> l <- list(lambda = array(0, dim = c(10,2)))
> >>>>
> >>>> mclass <- new("myclass", par = l)
> >>>>
> >>>> 2. I compile a C++ function, that should reuse the memory of 'lambda'
> inside the list:
> >>>>
> >>>> library(inline)
> >>>> cfunction <- cxxfunction(signature(myClass_R = "array"), body =
> 'Rcpp::S4 myclass(myClass_R); Rcpp::List parL((SEXP) myclass.slot("par"));
> arma::mat armaPar(parL["lambda"].begin(), 10, 2, false, true); armaPar(0,0)
> = 1.2 ;return Rcpp::wrap(myclass);', plugin = "RcppArmadillo")
> >>>>
> >>>> I get an error:
> >>>>
> >>>> Error in compileCode(f, code, language = language, verbose = verbose)
> :
> >>>> Compilation ERROR, function(s)/method(s) not created!
> file6fc2ab39965.cpp: In function ‘SEXPREC* file6fc2ab39965(SEXP)’:
> >>>> file6fc2ab39965.cpp:30:109: error: ‘Rcpp::Vector<19>::NameProxy’ has
> no member named ‘begin’
> >>>> Rcpp::S4 myclass(myClass_R); Rcpp::List parL((SEXP)
> myclass.slot("par")); arma::umat armaPar(parL["lambda"].begin(), 100, 10,
> false, true); armaPar(0,0) = 1.2 ;return Rcpp::wrap(myclass);
> >>>
> >>> What you get from doing parL["lambda"] is an object of class
> NameProxy, it will be converted to the appropioate class later. NameProxy
> have no .begin method.
> >>>
> >>> Do this:
> >>>
> >>> NumericVector tmp = parL["lambda"] ;
> >>> arma::mat armaPar(tmp.begin(), 10, 2, false, true);
> >>>
> >>> This will not make copies of the data.
> >>>
> >>> If thius feels like too much to type, just stuff this into a function:
> >>>
> >>> inline arma::mat convert( SEXP x ){
> >>> NumericVector tmp = parL["lambda"] ;
> >>> return arma::mat(tmp.begin(), 10, 2, false, true);
> >>> }
> >>>
> >>> and call :
> >>>
> >>> arma::mat armaPar = convert( parL["lambda"] ) ;
> >>>
> >>> There is a chance convert won't make a copy thanks to RVO.
> >>> ^
> >>>> make: *** [file6fc2ab39965.o] Error 1
> >>>> In addition: Warning message:
> >>>> running command '/Library/Frameworks/R.framework/Resources/bin/R CMD
> SHLIB file6fc2ab39965.cpp 2> file6fc2ab39965.cpp.err.txt' had status 1
> >>>>
> >>>> -----------------------------------------------------------
> >>>>
> >>>> It seems, that the SEXP inside the List is not yet an
> Rcpp::NumericMatrix, so I make it explicit to the arma::mat() constructor:
> >>>>
> >>>> cfunction <- cxxfunction(signature(myClass_R = "array"), body =
> 'Rcpp::S4 myclass(myClass_R); Rcpp::List parL((SEXP) myclass.slot("par"));
> arma::mat armaPar(Rcpp::as<Rcpp::NumericMatrix>(parL["lambda"]).begin(),
> 100, 10, false, true); armaPar(0,0) = 1.2 ;return Rcpp::wrap(myclass);',
> plugin = "RcppArmadillo")
> >>>>
> >>>> That compiles.
> >>>>
> >>>> If we let it run it gives us:
> >>>>
> >>>> cfunction(mclass)
> >>>> An object of class "myclass"
> >>>> Slot "par":
> >>>> $lambda
> >>>> [,1] [,2]
> >>>> [1,] 1.2 0
> >>>> [2,] 0.0 0
> >>>> [3,] 0.0 0
> >>>> [4,] 0.0 0
> >>>> [5,] 0.0 0
> >>>> [6,] 0.0 0
> >>>> [7,] 0.0 0
> >>>> [8,] 0.0 0
> >>>> [9,] 0.0 0
> >>>> [10,] 0.0 0
> >>>>
> >>>> So, we can see, that implicitly calling Rcpp::as<>() inside the
> constructor arma::mat() avoids a copy by Rcpp::as<>() - which is just
> beautiful!
> >>>>
> >>>>
> >>>> Best
> >>>>
> >>>> Simon
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>> On Jun 7, 2013, at 1:19 PM, Simon Zehnder <szehnder at uni-bonn.de>
> wrote:
> >>>>
> >>>>> Thank you Romain!
> >>>>>
> >>>>> All clear now!
> >>>>>
> >>>>>
> >>>>> Best
> >>>>>
> >>>>> Simon
> >>>>>
> >>>>> On Jun 7, 2013, at 1:13 PM, Romain Francois <
> romain at r-enthusiasts.com> wrote:
> >>>>>
> >>>>>> Le 07/06/13 13:09, Simon Zehnder a écrit :
> >>>>>>> HI Dirk, hi Romain,
> >>>>>>>
> >>>>>>> allright, this is now clear to me, if I want to reuse memory, the
> allocated memory from R (so implicitly in C) must of course have the same
> type - otherwise the memory has a different size.
> >>>>>>
> >>>>>> so far, this is obvious.
> >>>>>>
> >>>>>>> On the other side I then assume, that the Rcpp:as<class M>()
> function makes a cast and therefore creates a copy with new allocated
> memory of the type included in M? Therefore a reuse of memory with this
> function is not possible.
> >>>>>>
> >>>>>> Depends what is M, but most of the time yes, as<> copies data.
> >>>>>>
> >>>>>>> Best
> >>>>>>>
> >>>>>>> Simon
> >>>>>>>
> >>>>>>>
> >>>>>>> On Jun 6, 2013, at 8:31 PM, Dirk Eddelbuettel <edd at debian.org>
> wrote:
> >>>>>>>
> >>>>>>>>
> >>>>>>>> On 6 June 2013 at 13:17, Dirk Eddelbuettel wrote:
> >>>>>>>> |
> >>>>>>>> | On 6 June 2013 at 19:05, Simon Zehnder wrote:
> >>>>>>>> | | sorry I had overseen this message from you. Okay, so the
> explicit cast to SEXP together with the assignment operator makes the deal.
> But it still includes the reuse of memory right, i.e. the '=' does not call
> the copy constructor?
> >>>>>>>> |
> >>>>>>>> | But how could an _unsigned int_ from Armadillo possibly have
> the same value
> >>>>>>>> | as a _signed int_ in R?
> >>>>>>>> |
> >>>>>>>> | Either you are efficient (no copy), or you are correct (with a
> copy). I do
> >>>>>>>> | not see how you could have both.
> >>>>>>>>
> >>>>>>>> Sorry -- please ignore this message.
> >>>>>>>>
> >>>>>>>> I had mistakenly assumed that you were still thinking about
> arma::umat to
> >>>>>>>> integer. For direct int-to-int this is indeed efficient just
> like the
> >>>>>>>> double-to-double is for arma::mat to NumericMatrix (and dito for
> vectors). I
> >>>>>>>> though that was a given -- maybe need to make this (even) more
> explicit in
> >>>>>>>> the documentation.
> >>>>>>>>
> >>>>>>>> So in sum: you get correct and efficient behaviour if and only if
> you stick
> >>>>>>>> with the types natively supported in Armadillo and R.
> >>>>>>>>
> >>>>>>>> Dirk
> >>>>>>>>
> >
> >
> > --
> > Romain Francois
> > Professional R Enthusiast
> > +33(0) 6 28 91 30 30
> >
> > R Graph Gallery: http://gallery.r-enthusiasts.com
> >
> > blog: http://blog.r-enthusiasts.com
> > |- http://bit.ly/Zs97qg : highlight 0.4.1
> > `- http://bit.ly/10X94UM : Mobile version of the graph gallery
> >
>
> _______________________________________________
> Rcpp-devel mailing list
> Rcpp-devel at lists.r-forge.r-project.org
> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
>
--
-Kevin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130608/2b01cc6f/attachment-0001.html>
More information about the Rcpp-devel
mailing list