[R] Call by reference or suggest workaround

Romain Francois romain.francois at dbmail.com
Sat Jun 19 17:25:57 CEST 2010


Le 19/06/10 16:32, Chidambaram Annamalai a écrit :
>
> I have written code to compute multi-indices in R [1] and due to the
> recursive nature of the computation I need to pass around the *same*
> matrix object (where each row corresponds to one multi-index). As pass
> by reference wasn't the default behavior I declared a global matrix
> (mat) and used the<<- operator to write to the global matrix. So the
> usage would be to call genMultiIndices(3,2) for side effects to
> generate all multi-indices of length 3 and sum 2. And then access the
> global matrix.
>
> However, after coding this I can't seem to export the global matrix
> object (in the NAMESPACE file) and still retain mutability since its
> binding is "locked" (R throws an error). Can I somehow unlock this?
>
> Ideally I would want to pass around the same matrix to the recursive
> function. Is that possible? If not, could someone please suggest a
> workaround to use the code in an R package?
>
> [1]: http://dpaste.com/209186/

Hi,

You can use lexical scoping and you might like ?Recall as well.

genMultiIndices <- function(N, V) {
     mat <- matrix(nrow=choose(N + V - 1, V), ncol=N)
	fillMultiIndices <- function(i, j, n, v) {
		if (n == 1) {
	        mat[i, j] <<- v
	    }
	    else if (v == 0) {
	        mat[i, j:(j + n - 1)] <<- 0L
	    }
	    else {
	        rowOffset <- 0
	        # the first element of each multi-index can be any of 0, 1, ..., v
	        for (k in v:0) {
	            times <- choose((n - 1) + (v - k) - 1, (v - k))
	            mat[(i + rowOffset):(i + rowOffset + times - 1), j] <<- k
	            Recall(i + rowOffset, j + 1, n - 1, v - k)
	            rowOffset <- rowOffset + times
	        }
	    }
	}
     fillMultiIndices(1, 1, N, V)
     mat
}



Also, you can consider writing your code in a language that supports 
references, e.g. C++. Here is a start with inline/Rcpp :

require( inline )
require( Rcpp )

genMultiIndices_internal <-  local({
inc <- '
void fillMultiIndices( Rcpp::IntegerMatrix& mat, int i, int j, int n, 
int v ){
	if( n == 1 ){
		mat( (i-1), (j-1) ) = v ;
	} else if( v == 0 ){
		for( int k=j; k < j+n; k++){
			mat( (i-1), (k-1) ) = 0 ;
		}
	} else {
		
		// using the R function
		// I leave it to you to use a C implementation
		Function choose( "choose" ) ;
		
		int rowOffset = 0 ;
		int times ;
		for( int k=v; k>=0; k--){
			times = as<int>( choose( (n-1) + (v-k) - 1, (v-k) ) );
			int start = i + rowOffset ;
			int end   = i + rowOffset + times ;
			for( int z = start; z < end; z++ ){
				mat( z-1 , j-1 ) = k ;
			}
			fillMultiIndices( mat, i + rowOffset, j+1, n-1, v-k ) ;
			rowOffset += times ;
		}
	}
}
'
code <- '
	int N  = as<int>( N_) ;
	int V  = as<int>( V_) ;
	int NR = as<int>( NR_) ;
	Rcpp::IntegerMatrix mat( NR, N ) ;
	fillMultiIndices( mat, 1, 1, N, V ) ;
	return mat ;
'
	.genMultiIndices <- cxxfunction(
		signature( N_ = "integer", V_ = "integer", NR_ = "integer" ),
		code, include = inc, plugin = "Rcpp" )
	function( N, V){
		.genMultiIndices( N, V, choose(N + V - 1, V) )
	}
} )


I've been lazy here and I am using the choose function from R, so there 
is room for some improvement.

 > ( x <- genMultiIndices( 3L , 2L )          )
      [,1] [,2] [,3]
[1,]    2    0    0
[2,]    1    1    0
[3,]    1    0    1
[4,]    0    2    0
[5,]    0    1    1
[6,]    0    0    2
 > ( y <- genMultiIndices_internal( 3L, 2L )  )
      [,1] [,2] [,3]
[1,]    2    0    0
[2,]    1    1    0
[3,]    1    0    1
[4,]    0    2    0
[5,]    0    1    1
[6,]    0    0    2
 > identical( x, y )
[1] TRUE

Romain


-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://bit.ly/98Uf7u : Rcpp 0.8.1
|- http://bit.ly/c6YnCi : graph gallery collage
`- http://bit.ly/bZ7ltC : inline 0.3.5



More information about the R-help mailing list