Re: [R] Sending "..." to a C external
On Mon, Aug 25, 2008 at 12:28 PM, John Tillinghast <[EMAIL PROTECTED]> wrote: > > > On Sat, Aug 23, 2008 at 11:46 AM, Douglas Bates <[EMAIL PROTECTED]> wrote: > > I don't think it is necessary to go through the agonies of dealing > with the argument list in a .External call., which is what I assume > you are doing. (You haven't given us very much information on how you > are trying to pass the ... argument and such information would be very > helpful. The readers of this list are quite intelligent but none, as > far as I know, have claimed to be telepathic.) > --- > This is the first project for which I've tried to write C code for R. > I am so innocent that I don't even know what I have to explain to get help. > This is to speed up a friend's R package (BB), which is for general-purpose > continuous optimization. So it has to do many of the same things as nlm or > optim: take a function provided by the user, which might have any number of > arguments, and optimize over one (vector) argument. > As with optim, this C code will pass all the arguments for the user-provided > R function back into R, over and over. > I am open to any suggestions about how to do this simply and efficiently. In this sort of programming, "simply" is rarely achievable. Looking at the code in the BB package on CRAN it seems that the current version is written entirely in R and the calls to the objective function are created by code like fargs <- list(...) Fnew <- do.call("fn", append(list(xnew), fargs)) One way to accomplish this in C code is to create an environment in which to evaluate the function and then to create a function call to be evaluated in that environment. Creating a function call is not always that easy, however. It is sometimes easier to pass an expression or a formula as the "fn" argument because you can then strip out the function call without needing to construct it. Consider > str(expression(foo(x, y = 30))[[1]]) language foo(x, y = 30) > str((~ foo(x, y = 30))[[2]]) language foo(x, y = 30) Once you have the function call (which is what a language object is), you decide which argument has not been specified or, more simply, you require that the first argument be some name like 'x' and that this is the argument that will be varied by the optimizer. One way to do this with formulas is formeval <- function(par, form) { stopifnot(inherits(form, "formula"), length(form) == 2) fc <- form[[2]] # the function call env <- new.env(parent = environment(form)) # its environment stopifnot(is.name(fc[[2]]), as.character(fc[[2]]) == "x") assign("x", par, env = env) eval(fc, env) } Then > foo <- function(x, y = 40) x + y > formeval(1:3, ~ foo(x)) [1] 41 42 43 > formeval(1:3, ~ foo(x, y = 3)) [1] 4 5 6 > y <- 6 > formeval(1:3, ~ foo(x, y)) [1] 7 8 9 Once you have checked that the function call and the environment are as you want you can pass them through the .Call interface to a C function. In the C function you use FindVarInFrame to determine the SEXP named "x" in the environment then check that it is numeric and keep rewriting the value of the REAL pointer and forcing an evaluation of the function call in that environment. As I said, "simply" is not usually achievable. Further discussion should probably move to the R-devel list. >> On Fri, Aug 22, 2008 at 2:16 PM, John Tillinghast <[EMAIL PROTECTED]> >> wrote: >> > I'm trying to figure this out with "Writing R Extensions" but there's >> > not a >> > lot of detail on this issue. >> > I want to write a (very simple really) C external that will be able to >> > take >> > "..." as an argument. >> > (It's for optimizing a function that may have several parameters besides >> > the >> > ones being optimized.) >> >> > I got the "showArgs" code (from R-exts) to compile and install, but it >> > only >> > gives me error messages when I run it. I think I'm supposed to pass it >> > different arguments from what I'm doing, but I have no idea which ones. >> >> > What exactly are CAR, CDR, and CADR anyway? Why did the R development >> > team >> > choose this very un-C-like set of commands? They are not explained much >> > in >> > R-exts. >> >> Emmanuel has answered that - very engagingly too. On the train from >> Dortmund to Dusseldorf last week I was describing exactly that >> etymology of the names CAR, CDR, CDDR, ... to my companions but I got >> it wrong. I had remembered CDR as "contents of the data register" but >> Emmanuel is correct that it was "contents of the decrement register". >> >> >> >> The way that I would go about this is using .Call in something like >> >> .Call("myCfunction", arg1, arg2, dots = list(...), PACKAGE = "myPackage") >> >> Then in your C code you check the length and the names of the dots >> argument and take appropriate action. >> >> An alternative, if you want to use the ... arguments in an R >> expression to be evaluated by your optimizer, is to create an >> environment, assign
Re: [R] Sending "..." to a C external
On Sat, Aug 23, 2008 at 11:46 AM, Douglas Bates <[EMAIL PROTECTED]> wrote: I don't think it is necessary to go through the agonies of dealing with the argument list in a .External call., which is what I assume you are doing. (You haven't given us very much information on how you are trying to pass the ... argument and such information would be very helpful. The readers of this list are quite intelligent but none, as far as I know, have claimed to be telepathic.) --- This is the first project for which I've tried to write C code for R. I am so innocent that I don't even know what I have to explain to get help. This is to speed up a friend's R package (BB), which is for general-purpose continuous optimization. So it has to do many of the same things as nlm or optim: take a function provided by the user, which might have any number of arguments, and optimize over one (vector) argument. As with optim, this C code will pass all the arguments for the user-provided R function back into R, over and over. I am open to any suggestions about how to do this simply and efficiently. On Fri, Aug 22, 2008 at 2:16 PM, John Tillinghast <[EMAIL PROTECTED]> wrote: > > I'm trying to figure this out with "Writing R Extensions" but there's not > a > > lot of detail on this issue. > > I want to write a (very simple really) C external that will be able to > take > > "..." as an argument. > > (It's for optimizing a function that may have several parameters besides > the > > ones being optimized.) > > > I got the "showArgs" code (from R-exts) to compile and install, but it > only > > gives me error messages when I run it. I think I'm supposed to pass it > > different arguments from what I'm doing, but I have no idea which ones. > > > What exactly are CAR, CDR, and CADR anyway? Why did the R development > team > > choose this very un-C-like set of commands? They are not explained much > in > > R-exts. > > Emmanuel has answered that - very engagingly too. On the train from > Dortmund to Dusseldorf last week I was describing exactly that > etymology of the names CAR, CDR, CDDR, ... to my companions but I got > it wrong. I had remembered CDR as "contents of the data register" but > Emmanuel is correct that it was "contents of the decrement register". > > > > The way that I would go about this is using .Call in something like > > .Call("myCfunction", arg1, arg2, dots = list(...), PACKAGE = "myPackage") > > Then in your C code you check the length and the names of the dots > argument and take appropriate action. > > An alternative, if you want to use the ... arguments in an R > expression to be evaluated by your optimizer, is to create an > environment, assign the elements of list(...) to the appropriate names > in that environment and pass the environment through .Call to be used > as the evaluation environment for your R expression. There is a > somewhat complicated example of this in the nlmer function in the lme4 > package which you can find at http://lme4.r-forge.r-project.org/. > However, I don't feel embarrassed about the example being complicated. > This is complex stuff and it is not surprising that it isn't > completely straightforward to accomplish. If you feel that this is > opaque in R i can hardly wait to see what you think about writing the > SPSS version. > [[alternative HTML version deleted]] __ R-help@r-project.org 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.
Re: [R] Sending "..." to a C external
On Fri, Aug 22, 2008 at 2:16 PM, John Tillinghast <[EMAIL PROTECTED]> wrote: > I'm trying to figure this out with "Writing R Extensions" but there's not a > lot of detail on this issue. > I want to write a (very simple really) C external that will be able to take > "..." as an argument. > (It's for optimizing a function that may have several parameters besides the > ones being optimized.) > I got the "showArgs" code (from R-exts) to compile and install, but it only > gives me error messages when I run it. I think I'm supposed to pass it > different arguments from what I'm doing, but I have no idea which ones. > What exactly are CAR, CDR, and CADR anyway? Why did the R development team > choose this very un-C-like set of commands? They are not explained much in > R-exts. Emmanuel has answered that - very engagingly too. On the train from Dortmund to Dusseldorf last week I was describing exactly that etymology of the names CAR, CDR, CDDR, ... to my companions but I got it wrong. I had remembered CDR as "contents of the data register" but Emmanuel is correct that it was "contents of the decrement register". I don't think it is necessary to go through the agonies of dealing with the argument list in a .External call., which is what I assume you are doing. (You haven't given us very much information on how you are trying to pass the ... argument and such information would be very helpful. The readers of this list are quite intelligent but none, as far as I know, have claimed to be telepathic.) The way that I would go about this is using .Call in something like .Call("myCfunction", arg1, arg2, dots = list(...), PACKAGE = "myPackage") Then in your C code you check the length and the names of the dots argument and take appropriate action. An alternative, if you want to use the ... arguments in an R expression to be evaluated by your optimizer, is to create an environment, assign the elements of list(...) to the appropriate names in that environment and pass the environment through .Call to be used as the evaluation environment for your R expression. There is a somewhat complicated example of this in the nlmer function in the lme4 package which you can find at http://lme4.r-forge.r-project.org/. However, I don't feel embarrassed about the example being complicated. This is complex stuff and it is not surprising that it isn't completely straightforward to accomplish. If you feel that this is opaque in R i can hardly wait to see what you think about writing the SPSS version. __ R-help@r-project.org 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.
Re: [R] Sending "..." to a C external
2008/8/22 Emmanuel Charpentier <[EMAIL PROTECTED]>: > Le vendredi 22 août 2008 à 15:16 -0400, John Tillinghast a écrit : >> I'm trying to figure this out with "Writing R Extensions" but there's not a >> lot of detail on this issue. >> I want to write a (very simple really) C external that will be able to take >> "..." as an argument. >> (It's for optimizing a function that may have several parameters besides the >> ones being optimized.) > > !!! That's a hard one. I have never undertaken this kind of job, but I expect > that your "..." argument, if you can reach it from C (which I don't know) will > be bound to a Lisp-like structure, notoriously hard to decode in C. Basically, > you'll have to create very low level code (an duplicate a good chunk of the R > parser-interpreter...). > > I'd rather treat the "..." argument in a wrapper that could call the relevant > C function with all arguments interpreted and bound... This wrapper would > probably be an order of magnitude slower than C code, but two orders of > magnitude > easier to write (and maintain !). Since "..." argument parsing would be done > *once* > before the "grunt work" is accomplished by C code, the slowdown would > (probably) > be negligible... I think you're overstating the problem somewhat! Everything you need to process "..." in C is pretty much in the showArgs function in the R-ext help. The problem is that John's not told us what his error was! It works for me: > showArgs(x=2,y=3,z=4) [1] 'x' 2.00 [2] 'y' 3.00 [3] 'z' 4.00 NULL > showArgs(x=2,y=3,z="s") [1] 'x' 2.00 [2] 'y' 3.00 [3] 'z' s NULL But I can get an error if I don't name an argument: > showArgs(x=2,y=3,"s") [1] 'x' 2.00 [2] 'y' 3.00 Error in showArgs(x = 2, y = 3, "s") : CHAR() can only be applied to a 'CHARSXP', not a 'NULL' But that's just because the C doesn't check for this. Is that what you're getting? What errors are you getting? Barry [this was on an R 2.7.0 I had kicking around, so maybe changed for later versions...] __ R-help@r-project.org 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.
Re: [R] Sending "..." to a C external
Le vendredi 22 août 2008 à 15:16 -0400, John Tillinghast a écrit : > I'm trying to figure this out with "Writing R Extensions" but there's not a > lot of detail on this issue. > I want to write a (very simple really) C external that will be able to take > "..." as an argument. > (It's for optimizing a function that may have several parameters besides the > ones being optimized.) !!! That's a hard one. I have never undertaken this kind of job, but I expect that your "..." argument, if you can reach it from C (which I don't know) will be bound to a Lisp-like structure, notoriously hard to decode in C. Basically, you'll have to create very low level code (an duplicate a good chunk of the R parser-interpreter...). I'd rather treat the "..." argument in a wrapper that could call the relevant C function with all arguments interpreted and bound... This wrapper would probably be an order of magnitude slower than C code, but two orders of magnitude easier to write (and maintain !). Since "..." argument parsing would be done *once* before the "grunt work" is accomplished by C code, the slowdown would (probably) be negligible... > I got the "showArgs" code (from R-exts) to compile and install, but it only > gives me error messages when I run it. I think I'm supposed to pass it > different arguments from what I'm doing, but I have no idea which ones. > > What exactly are CAR, CDR, and CADR anyway? Why did the R development team > choose this very un-C-like set of commands? 'Cause they are fundamental to the Lisp-like language that is S/R. Read on... > They are not explained much in > R-exts. At the risk of incurring the R-help deities wrath : "In the beginning, John Mc Carthy created Lisp 1.5, who begat MACLISP who begat ..., who begat Scheme ... ". Nonwhistanding a long inheritance story, full of sound, fury, holy wars and bastardry (sometimes evoking European royalty lines...), all Lisp-like language bear one mark (dominant allele) of their common ancestor, which is the list structure. This structure is implemented as a pair of pointers, the first one pointing to the first element of the list, the second pointing to ... the list of the rest of the members (or nothing, aka NIL). In McCarthy's implementation, which was machine code on an IBM 704 (we were in 1957, mind you...) such word was spanned among different parts of a CPU word, known in the technical documentation of this dinosaur as "address register" and "decrement register respectively. Thus the mnemonic names of "Content of the Address Register" and "Content of Decrement Register" (aka "CAR" and "CDR") for these two pointers, names which were used for the (lisp) functions allowing to access them. Those names have stuck mainly for historical (sentimental ? hysterical ? ) reasons. Even when "reasonable" synonyms were introduced (e. g. "first" and "rest" in Common Lisp), all the old hands (and young dummies who wanted to emulate them) kept "car" and "cdr" close to their hearts. So, fifty one years after McCarthy stroke of genius, this piece of CS snobbery is still with us (and probably will 'til 64-bit Linux time counters roll over...). Despite its C-like syntax, its huge collection of array and array-like structures, its loops, S and R are fundamentally Lisp-like languages. Most notably, the representation of executable code is accessible by the code itself : one can create a function which computes another function. Lisp was the first language explicitly created for this purpose, and it is no happenstance that it (or one of his almost uncountable dialects) that many (most ?) of such language use Lisp fundamentals. Many of R/S "common way of doing things" have a Lisp smell : for example, it is no chance that {s|t|l}apply(), outer() and suchlike are *way* more efficient than for(), and they are strongly reminescent of Lisp's mapcar... BTW, this ability to "compute the language" is probably the most fundamental point distinguishing S/R from all the rest of "statistical packages" (SPSS, Stata, SAS and the rest of the crowd... Now I have to say that I'm not old enough to have first-hand knowledge of this history. I was born, but not weaned, when McCarthy unleashed Lisp on an unsuspecting world ... I learned that ca. 1978-9, while discovering VLisp. While I can't really help you (I still think that processing "..." at C level is either hubris of the worst sort, pure folly or a desperate case), I hope to have entertained you. Sincerely, Emmanuel Charpentier __ R-help@r-project.org 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.
[R] Sending "..." to a C external
I'm trying to figure this out with "Writing R Extensions" but there's not a lot of detail on this issue. I want to write a (very simple really) C external that will be able to take "..." as an argument. (It's for optimizing a function that may have several parameters besides the ones being optimized.) I got the "showArgs" code (from R-exts) to compile and install, but it only gives me error messages when I run it. I think I'm supposed to pass it different arguments from what I'm doing, but I have no idea which ones. What exactly are CAR, CDR, and CADR anyway? Why did the R development team choose this very un-C-like set of commands? They are not explained much in R-exts. Thanks in advance for any info. John [[alternative HTML version deleted]] __ R-help@r-project.org 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.