[R] Error generated by nlme::gnls

Rolf Turner r@turner @end|ng |rom @uck|@nd@@c@nz
Mon Jul 25 01:40:41 CEST 2022


On Sun, 24 Jul 2022 15:57:25 +0300
Ivan Krylov <krylov.r00t using gmail.com> wrote:

> Sorry for being too terse in my previous e-mail!
> 
> On Sun, 24 Jul 2022 23:03:02 +1200
> Rolf Turner <r.turner using auckland.ac.nz> wrote:
> 
> > The maintainer of the nlme package (who is, according to
> > maintainer(), "R-core") could change the code so that it uses
> > invokes deparse1() rather than deparse, but the user cannot do so,
> > not without in effect re-creating the package.
> 
> You're right. I think there's a buglet in nlme::gnls that nobody
> noticed until R 4.2.0 was released *and* Aaron Crowley used the
> function with a sufficiently long formula.

Makes sense. :-)

> > Also, the question remains:  why did Aaron Crowley's code work in
> > the past, whereas now it throws an error?  What changed?
> 
> gnls() may have been performing the `if (deparse(...) != '1')` test
> for a long time, but never crashed before because it wasn't a fatal
> error until R 4.2.0. Previously, if() would issue a warning and use
> the first element of the boolean vector.

N'ya-ha!  Makes sense too.
> 
> R 4.2.0 was released this April, which was less than 6 months ago. I
> think it all fits.

Indeed,  
> 
> A temporary solution would be to make use of the fact that R is a very
> dynamic language and perform surgery on a live function inside a
> loaded package:
> 
> library(codetools)
> 
> nlme <- loadNamespace('nlme')
> unlockBinding('gnls', nlme)
> nlme$gnls <- `body<-`(fun = nlme$gnls, value = walkCode(
> 	body(nlme$gnls), makeCodeWalker(
> 		call = function(e, w)
> 			as.call(lapply(as.list(e), function(ee)
> 				if (!missing(ee)) walkCode(ee, w)
> 			)),
> 		leaf = function(e, w)
> 			if (is.symbol(e) && e == 'deparse') {
> 				as.name('deparse1')
> 			} else e
> 	)
> ))
> lockBinding('gnls', nlme)
> rm(nlme)
> 
> grep('deparse', deparse(nlme::gnls), value = TRUE)
> # [1] "                deparse1(pp[[3]]), sep = \"~\"), collapse =
> \",\"), " # [2] "        if (deparse1(params[[nm]][[3]]) != \"1\") {"
> # [3] "        list(row.names(dataModShrunk), deparse1(form[[2]]))), "
> 
> Aaron's example seems to work after this, modulo needing 12 starting
> values instead of 13.

Such surgery is beyond the capability of us ordinary mortals, but given
your explicit and clear recipe it should be do-able. 

Thanks for all of this.

cheers,

Rolf

P. S.  Ben:  you were correct in your original conjecture, to which I
erroneously said "No".  Lack of insight on my part.

R.

-- 
Honorary Research Fellow
Department of Statistics
University of Auckland
Phone: +64-9-373-7599 ext. 88276



More information about the R-help mailing list