[Rd] [R] Use of 'defineVar' and 'install' in .Call
Daniel Berg
daniel at danielberg.no
Thu Mar 29 08:32:10 CEST 2007
Thanks for your suggestions Douglas,
I just discovered the asInteger, asReal etc. but did not know of
ScalarInteger etc. Will examine these immediately. I am very new to
.Call and SEXP, just started experimenting with these. Previously I
have been using .C for all my functions, transforming a matrix to a
vector for the passing from R to C and back. Did not know of R_init
and the corresponding global opportunities either, thanks. Perhaps I
should go through "Writing R extensions" all over again now that I can
understand more of it :)
Concerning "x", the value to be assigned to "x" will be different for
each observation of my data set and each time the function is called.
This also applies to all the other variables I am installing. It
sounds like a good idea to rather do the assignment of u1,u2,... in R
and make my "zero"/"feval" functions even more general. I could
basically just pass the dimension, i.e. the number of u's that needs
to be assigned. Will examine this. But in my code I have
defineVar(install("u1"),mkans(x),rho) to assign the value of x to u1
in R. Then I run eval(f) to evaluate the expression f that includes
u1. How can I assign values to all u's, do I need a separate function
in R that I also need to pass to C? This function being a function to
assign values to expressions? Or can I send an entire vector to
defineVar(install())?
//Daniel
On 3/29/07, Douglas Bates <bates at stat.wisc.edu> wrote:
> I did read your second message about the problem symptoms disappearing
> but I thought that I might make a couple of suggestions about your
> code anyway.
>
> There are a number of helper functions declared in Rinternals.h such
> as ScalarReal, which is equivalent to your mkans. (Also
> ScalarInteger, ScalarLogical, ...) The functions to convert scalars in
> the other direction, i.e. taking an SEXP and returning an int or a
> double or a ... , are called asInteger, asReal, ...
>
> If you are writing a package you can define an initialization function
> called R_init_<pkgname> to perform initialization for the package. If
> you are going to use a symbol like x many times then you can save the
> result of install("x") as a global, say, myPkg_xSymbol during
> initialization and use the global variable instead of calling install
> many times. The overhead for calling install is small but if you can
> avoid it I don't see a reason not to.
>
> Finally, why do you want to use identifiers like u1, u2, ... when you
> could pass a vector named "u" and use that. In other words, wouldn't
> it be easier to do the extraction of the components in the R code for
> the function rather than generating a whole bunch of different names?
>
> I suggest that this thread be moved to the r-devel list, which I have cc:d.
>
> On 3/27/07, Daniel Berg <daniel at danielberg.no> wrote:
> > Dear all,
> >
> > [system and version information below]
> >
> > I am trying to modify a C function for finding the root of an
> > expression. The function is to be called from R as .Call with input
> > parameters:
> >
> > f: expression for which we will find the root
> > guesses: interval for the solution
> > stol: tolerance
> > rho: environment
> >
> > The original functions I use are:
> >
> > SEXP mkans(double x) {
> > SEXP ans;
> > PROTECT(ans = allocVector(REALSXP, 1));
> > REAL(ans)[0] = x;
> > UNPROTECT(1);
> > return ans;
> > }
> > double feval(double x, SEXP f, SEXP rho) {
> > defineVar(install("x"), mkans(x), rho);
> > return(REAL(eval(f, rho))[0]);
> > }
> > SEXP zero(SEXP f, SEXP guesses, SEXP stol, SEXP rho) {
> > double x0 = REAL(guesses)[0], x1 = REAL(guesses)[1], tol = REAL(stol)[0];
> > double f0, f1, fc, xc;
> > if(tol <= 0.0) error("non-positive tol value");
> > f0 = feval(x0, f, rho); f1 = feval(x1, f, rho);
> > if(f0 == 0.0) return mkans(x0);
> > if(f1 == 0.0) return mkans(x1);
> > if(f0*f1 > 0.0) error("x[0] and x[1] have the same sign");
> > for(;;) {
> > xc = 0.5*(x0+x1);
> > if(fabs(x0-x1) < tol) return mkans(xc);
> > fc = feval(xc, f, rho);
> > if(fc == 0) return mkans(xc);
> > if(f0*fc > 0.0) {
> > x0 = xc; f0 = fc;
> > }
> > else {
> > x1 = xc; f1 = fc;
> > }
> > }
> > }
> >
> >
> > This works great. However, I wish to make it more general, by
> > modifying 'feval'. Given that my problem involves a data set 'u', with
> > dimension (i x j), I need to assign values to 'u1', 'u2', ..., 'ui'
> > via defineVar(install(...)). I tried the following:
> >
> > double feval(double x, double *u, int d, double v, SEXP f, SEXP rho) {
> > int i;
> > char *str1="u", str2[1001], *str3;
> > defineVar(install("x"), mkans(x), rho);
> > defineVar(install("y"), mkans(v), rho);
> > for(i=0;i<d;i++) {
> > sprintf(str2,"%d",i+1);
> > str3 = (char *)malloc((strlen(str1)+strlen(str2)+1)*sizeof(char));
> > strcpy(str3,str1);
> > strcat(str3,str2);
> > defineVar(install(str3), mkans(u[i]), rho);
> > }
> > free(str3);
> > return(REAL(eval(f,rho))[0]);
> > }
> >
> > My R-package still compiles without errors but R crashes due to the
> > defineVar command.
> >
> > Any suggestions to how I can do the defineVar bit?
> >
> > Thanks in advance.
> >
> > Reagards,
> > Daniel Berg
> >
> > --------------------------------------------
> > > R.Version()
> > $platform
> > [1] "i486-pc-linux-gnu"
> > $arch
> > [1] "i486"
> > $os
> > [1] "linux-gnu"
> > $system
> > [1] "i486, linux-gnu"
> > $status
> > [1] ""
> > $major
> > [1] "2"
> > $minor
> > [1] "3.1"
> > $year
> > [1] "2006"
> > $month
> > [1] "06"
> > $day
> > [1] "01"
> > $`svn rev`
> > [1] "38247"
> > $language
> > [1] "R"
> > $version.string
> > [1] "Version 2.3.1 (2006-06-01)"
> >
> > ______________________________________________
> > R-help at stat.math.ethz.ch mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-help
> > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> > and provide commented, minimal, self-contained, reproducible code.
> >
>
>
--
danielberg.no
More information about the R-devel
mailing list