From bill at insightful.com  Wed Jun  6 23:30:28 2007
From: bill at insightful.com (Bill Dunlap)
Date: Wed, 6 Jun 2007 14:30:28 -0700 (PDT)
Subject: [Rd] C function with unknown output length
In-Reply-To: <3BAA52D0-FF46-4130-B337-FD95BCA21316@act.ulaval.ca>
References: <3BAA52D0-FF46-4130-B337-FD95BCA21316@act.ulaval.ca>
Message-ID: <Pine.GSO.4.56.0706061423360.16082@durian.statsci.com>

On Wed, 6 Jun 2007, Vincent Goulet wrote:

> Could anyone point me to one or more examples in the R sources of a C
> function that is called without knowing in advance what will be the
> length (say) of the output vector?
>
> To make myself clearer, we have a C function that computes
> probabilities until their sum gets "close enough" to 1. Hence, the
> number of probabilities is not known in advance.
>
> I would like to have an idea what is the best way to handle this
> situation in R.

I think you will want to use the .Call(), not .C(),
interface.  Then you can expand the output vector
as you see fit.  E.g., the following sets the output
vector length to 0 and adds 1 to it each time it
needs to.   This works in both R and Splus 8.0.

In Splus SET_LENGTH(vec, len) reserves some extra
space (above the 'len' requested items) so that
future calls to expand it a bit don't always copy
it.  In R, each call to SET_LENGTH appears to copy
the input vector, so you probably want to add extra
logic to reserve some extra space and finally trim
it down to the precise size you want.

#include <R.h>
#include <Rdefines.h>

/* .Call("unknownReturnLength", 0.02) : return
 * sequence of random uniforms, quitting when
 * you see the first one below 0.02.
 */
SEXP unknownReturnLength(SEXP prob_p)
{
   int retval_length ; /* long preferred in S-PLUS */
   double prob, r ;
   SEXP retval ;
   retval_length = 0 ;
   /* how does PROTECT interact with SET_LENGTH? */
   PROTECT(retval = NEW_NUMERIC(retval_length)) ;
   prob = asReal(prob_p);
   GetRNGstate();
   while((r=unif_rand()) >= prob) {
      double *oldptr = NUMERIC_POINTER(retval) ;
      retval_length++ ;
      SET_LENGTH(retval, retval_length) ;
      if (oldptr != NUMERIC_POINTER(retval))
        Rprintf("expanding retval from %d to %d moved it\n", retval_length-1, retval_length) ;
      NUMERIC_POINTER(retval)[retval_length-1] = r ;
   }
   PutRNGstate();
   return retval ;
}

----------------------------------------------------------------------------
Bill Dunlap
Insightful Corporation
bill at insightful dot com
360-428-8146

 "All statements in this message represent the opinions of the author and do
 not necessarily reflect Insightful Corporation policy or position."



[Rd] C function with unknown output length
Bill Dunlap