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)"
Now it works, I made no changes to the functions in question, must have been some other mistake in my code and I obviously misinterpreted the crash report. defineVar(install(str),mkans(x),rho) works fine. The content of the variable 'str' is assigned in the given environment in R as it should. I apologize that I posted this before testing it properly. Regards, Daniel 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)" > -------------------------------------------- >-- danielberg.no
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. >
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