[Rcpp-devel] Delayed usage of auxiliary memory in RcppArmadillo
Simon Zehnder
szehnder at uni-bonn.de
Fri Jun 14 11:17:17 CEST 2013
Hi Rcpp::Devels and Rcpp::Users,
I would like to close my post with a solution I found after some days of experiencing:
If you want to create an Armadillo matrix conditional on a statement and that matrix should reuse R storage you can work with a pointer,
1. Create an R list object:
rlist <- list(par = array(1, dim = c(2,1)), cond = TRUE, par2 = array(1, dim = c(2,1)))
2. Define the function in C++ using RcppArmadillo plugin:
cfunction <- cxxfunction(signature(List_R = "list"), body='
Rcpp::List rList(List_R);
Rcpp::NumericMatrix parM((SEXP) rList["par"]);
bool cond = Rcpp::as<bool>(rList["cond"]);
arma::mat parAM(parM.begin(), 2, 1, false, true);
Rcpp::NumericMatrix par2M((SEXP) rList["par2"]);
arma::mat *par2Ptr;
if(cond) {
par2Ptr = new arma::mat(par2M.begin(), 2, 1, false, true);
} else {
par2Ptr = NULL;
}
parAM.fill(2);
if(cond) {
par2Ptr->fill(2);
}
delete par2Ptr;
return Rcpp::wrap(rList);',
plugin = "RcppArmadillo")
3. Run the function with the R list object:
cfunction(rlist)
$par
[,1]
[1,] 2
[2,] 2
$cond
[1] TRUE
$par2
[,1]
[1,] 2
[2,] 2
4. Create a new R list object and set the condition to FALSE, then run again the C++ function:
rlist <- list(par = array(1, dim = c(2,1)), cond = FALSE, par2 = array(1, dim = c(2,1)))
cfunction(rlist)
$par
[,1]
[1,] 2
[2,] 2
$cond
[1] FALSE
$par2
[,1]
[1,] 1
[2,] 1
We see, that working with an arma::mat pointer makes the conditional creation of the Armadillo matrix working. Even if it usually gives only a warning if you don't, set the pointer
always to NULL if it is not used. Also do not forget to delete the pointer at the end of the program. I do not know yet, how the deletion of arma::mat objects works, when
auxiliary memory is used (so maybe it does not matter if we delete the pointer or not), but it is always a good idea to delete a pointer, when it is not used anymore. There are
of course also safer pointers in C++, e.g. unique_ptr, but the main pattern to use a pointer is shown above.
Enjoy Rcpp/RcppArmadillo, possibilities are great!
Thanks to everyone for his comments.
Simon
On Jun 11, 2013, at 12:56 PM, Simon Zehnder <szehnder at uni-bonn.de> wrote:
>
> Hi Romain,
>
> thanks for refreshing my C++ basics
>
> As I am regrettably not privileged to spare the amount of time on C++
> skill improvement I would like to, but have the assignment to
> construct stochastic models and implement them, I focus here on a
> solution and maybe someone can help me, with his experience in C++
> (at this point I'd like to apologize for maybe confusing list members with my wrong statements below).
>
> Back to the origin of my problem I intend to solve:
>
> I have a variable STOREPOST, that indicates, if additional
> information should be stored during the processing of my algorithm. In
> the case
> STOREPOST is not true I would like to avoid the construction of an
> arma::mat object and in the case that STOREPOST is true an arma::mat
> object should be constructed with auxiliary memory from R.
>
> From your corrections below I understand, that the way I showed is
> not appropriate to solve my problem, as the temporary object in the
> if-clause is not known anymore to the compiler
> from the line on I close the bracket ('}') of the if-condition. I
> also assume, that using a pointer '*arma::mat maybeM' does not change
> this,
> as the object inside the if-clause is still a temporary rvalue
> (please correct me here if I am wrong).
>
> I would like to ask, if a list member has maybe an advice for me? Should I construct two
> different algorithms (that would be a very easy solution - maybe not
> the
> way a C++ programmer would use). Or would you construct a base class
> and one that inherits from the base class containing additional
> members? I think there are a lot
> of pitfalls I do not see yet.
>
>
> Best
>
> Simon
>
> On 06/11/2013 12:02 AM, romain at r-enthusiasts.com wrote:
>> Some C++ 101 insights below.
>>
>> Le 2013-06-10 23:07, Simon Zehnder a écrit :
>>> Dear Rcpp::Devels and Rcpp::Users,
>>>
>>> I am temporarily experiencing with a delayed assignment of auxiliary
>>> memory in RcppArmadillo:
>>>
>>> Declare a matrix from which you know you may need it
>>>
>>> arma::mat maybeM;
>>>
>>> (In C++ a declaration makes only known the type and name but allocates
>>> no storage yet).
>>
>> SO WRONG.
>> here the default constructor or arma::mat is called. What it does is entirely up to the implementation of the class.
>>
>>> Now you check a condition and if it is true, you will need the matrix,
>>> so you initialize it
>>>
>>> if(mycondition) {
>>> maybeM = arma::mat(aux_mem*, n_rows, n_cols, copy_aux_mem = false,
>>> strict = true)
>>> }
>>>
>>> (for simplicity I only printed here the default constructor for using
>>> auxiliary memory; please assume that all values are presented)
>>
>> wrong again.
>>
>> what happens here is in two steps.
>>
>> - first, an arma::mat is constructed, using the so called advanced constructor. this does use the auxiliary memory to create a temporary.
>> - second, the assignment operator is used to copy the temporary into "maybeM"
>>
>> So indeed maybeM does not use the auxiliary memory, I hope now you understand why.
>>
>>> The resulting matrix maybeM does not use the auxiliary memory. I tried
>>> to access in some way the 'mem' member in the Armadillo class, but
>>> this member is constant and can not be
>>> manipulated after first construction. A primer declaration and later
>>> initialization is a very common pattern in C++, but it seems not be
>>> possible in case of reusing memory.
>>
>> Everything is possible, it is a decision made by the implementation. e.g. for Rcpp classes copy construction means just cheap pointer copies, not data copies.
>> armadillo is implemented with more traditional copy semantics.
>>
>>> I conclude, that a delayed assignment of auxiliary memory is not
>>> possible.
>>
>> wrong conclusion. what you demonstrated here is that you need to study basic c++ (assignment operators, copy construction, ...) :)
>>
>> now, things would be different with move semantics in c++11. Not sure armadillo has implemented them already, but I'm pretty sure that is not what you were talking about.
>>
>> Romain
>>
>>> Best
>>>
>>> Simon
>> _______________________________________________
>> 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
>
> _______________________________________________
> 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
More information about the Rcpp-devel
mailing list