Skip to content

Call and memory

3 messages · Bob Wheeler, Thomas Lumley, Brian Ripley

#
I use a large real matrix, X, in C code that is passed from R and 
transposed in place in the C code. I would like to conserve memory and, 
if possible, allocate space for only one copy of X -- hence I would like 
to pass a pointer to the data in the X object to the C code.

The Writing R Extensions manual says that neither .Call nor .External 
copy their arguments. They also say that these arguments should be 
treated as read only.

Fine, but in testing I seem to be able to transpose very large X's in 
place, in C code without an error. This leads me to assume that the 
manual was just giving good advice about treating arguments as read 
only. However, I find that I have done nothing to the X in R. It seems 
that a copy has been made after all. I may as well call the code with .C 
  and avoid the use of macros.

Could someone please point out the error in my thinking or suggest a way 
to accomplish my goal?

My code follows:

"mListTest" <-
function(X,N,k) {

	.Call("mList",as.double(X),as.integer(N),as.integer(k));
}


SEXP mList(
	SEXP Xi,
	SEXP Ni,
	SEXP ki
)
{
	double *pX=NUMERIC_POINTER(Xi);
	int	N=INTEGER_POINTER(Ni)[0];
	int k=INTEGER_POINTER(ki)[0];
	SEXP alist;
	SEXP avector;
	SEXP nvector;
	SEXP rvector;
	SEXP kvector;
	int n;
	int i;

	transposeMatrix(pX,N,k);

	n=4;
	PROTECT(alist=NEW_LIST(n));
	PROTECT(avector=NEW_NUMERIC(200));

	for (i=0;i<200;i++) {
		NUMERIC_POINTER(avector)[i]=pX[i];
	}
	SET_ELEMENT(alist,0,avector);
	UNPROTECT(1);
	PROTECT(nvector=NEW_INTEGER(1));
	INTEGER_POINTER(nvector)[0]=N;
	SET_ELEMENT(alist,1,nvector);
	UNPROTECT(1);
	PROTECT(rvector=NEW_NUMERIC(1));
	NUMERIC_POINTER(rvector)[0]=0.5;
	SET_ELEMENT(alist,2,rvector);
	UNPROTECT(1);
	PROTECT(kvector=NEW_INTEGER(1));
	INTEGER_POINTER(kvector)[0]=k;
	SET_ELEMENT(alist,3,kvector);
	UNPROTECT(1);

	UNPROTECT(1);
	return alist;

}
#
On Fri, 9 Jan 2004, Bob Wheeler wrote:

            
as.double(X) returns a copy of X, so you are only passing a copy to C.


	-thomas
#
On Fri, 9 Jan 2004, Thomas Lumley wrote:

            
storage.mode(X) <- "double" is the standard paradigm to avoid an copy here 
if not needed (even with .C, which would make two copies of X on entry and 
one on exit).

Both arima() and the Kalman fitering code used by StructTS() makes use of
the ability of .Call to alter its arguments, so the advice given is
definitely right.

It is hard to predict when R will make a copy, not least because from time 
to time we spot an unnecessary copy or add a necessary one.  So if you do 
want .Call to alter its arguments you need to test your assumptions (and 
retest when R is updated).