Le 13/09/13 14:00, JJ Allaire a écrit :
    Is it a big deal that we would cheat on chat reference passing means ?


If you want to implement these sort of semantics I think at a _minimum_
the type should be const & (otherwise it looks like you are going to
actually modify the matrix in place which would appear to bypass the
implicit memory barrier of SEXP). Realize that you won't actually bypass
the memory barrier but it sure looks like you intend to for a reader of
the code.

             Rcpp::RNGScope __rngScope;
             arma::mat& m = Rcpp::as<arma::mat& >(mSEXP);
             test_ref(m);


It looks like this behavior changed as of rev 4400 when the full_name()
method was introduced. I may not understand the mechanism you
established 100% but to me this generated code looks potentially
problematic if you are taking a reference to a stack variable establish
within the as<> method. My guess is that you have something more
sophisticated going on here and there is no memory problem, however I'd
love to understand things a bit better to be 100% sure there isn't
something to drill into further.

Here is where I am now. To wrap up this function:

// [[Rcpp::export]]
void test_const_ref( const arma::mat& m ){}

This code gets created by the attributes parser:

RcppExport SEXP sourceCpp_71975_test_const_ref(SEXP mSEXP) {
BEGIN_RCPP
    {
        Rcpp::RNGScope __rngScope;
        Rcpp::InputParameter< const arma::mat&> m(mSEXP );
        test_const_ref(m);
    }
    return R_NilValue;
END_RCPP
}

The difference is this line:

Rcpp::InputParameter< const arma::mat&> m(mSEXP );

instead of this line:

const arma::mat& m = Rcpp::as< const arma::mat& >( mSEXP ) ;



The InputParameter template class need to be able to take a SEXP asinput and have a conversion operator to the requested type. So the default implementation obvisouly used Rcpp::as, this is how the default class is implemented:

    template <typename T>
    class InputParameter {
    public:
        InputParameter(SEXP x_) : x(x_){}

        inline operator T() { return as<T>(x) ; }

    private:
        SEXP x ;
    } ;

So we get exactly the same as before. What we gain however is that we can redefine InputParameter for other types and we can take advantage of its destructor to do something when the InputParameter object goes out of scope. Here is how I implemented a custom version for const reference to arma::Mat :

template <typename T>
    class InputParameter< const arma::Mat<T>& > {
                public:
                        typedef const typename arma::Mat<T>& const_reference ;
                        
InputParameter( SEXP x_ ) : m(x_), mat( m.begin(), m.nrow(), m.ncol(), false ){}
                        
                        inline operator const_reference(){
                                return mat ;    
                        }
                        
                private:
                        Rcpp::Matrix< Rcpp::traits::r_sexptype_traits<T>::rtype 
> m ;
                        arma::Mat<T> mat ;
    } ;

The arma::mat is a member of InputParameter, constructed via the advanced constructor, so using the same memory as the R object, and we retrieve a reference to this object with the operator const_reference


This is simple and elegant. And now we can pass down references and const references of armadillo matrices from R without performance penalty.

This makes using RcppArmadillo even more compelling.

It leaves the issue of what happens when we return an armadillo matrix. At the moment, this still makes a copy of the data. I don't see a way around that just yet. If we want to avoid making a copy, we need to construct the arma::mat out of R memory and return that R object.

I also have to deal with references and const references of other arma types (arma::rowvec, etc ...).

I'm happy to discuss the changes I've made in Rcpp and RcppArmadillo for this. For now I've included the version for non const references too, but maybe I should not, although it does work perfectly. This is much better ythan what we used to have where we would allow passing references but still make lots of data copies which sort of goes against using references. When I see a function that passes an object by reference, I tend to think that calling the function is cheap. Now it is.


I'd specifically would like to hear from Gabor and Baptiste about the simplification of being able to just use (const) references as inputs and have RcppArmadillo simply borrow memory from the R object :

// [[Rcpp::export]]
arma::mat plus( const arma::mat& m1, const arma::mat& m2){
    return m1 + m2 ;
}

Romain

--
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30

_______________________________________________
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

Reply via email to