[R-pkg-devel] Trying to work around missing functionality
J C Nash
profjcn@@h @ending from gm@il@com
Tue Aug 28 21:15:44 CEST 2018
Thanks for this. Also Duncan's description of how code in the R directory is executed.
I've more or less figured out a workaround. Unfortunately Georgi's solution doesn't quite
do the trick. Here is my current understanding and solution.
Issue: I want to get root of a function of 1 parameter x, but there may be exogenous data Xdata.
I also want to count the evaluations.
Some rootfinders don't have counter and some don't allow "..."
Initial solution: Create global envroot with counters and such. Put name of function and
gradient in there, then use a dummy FnTrace (and possibly grTrace). This gave various
check complaints about globals etc. However, does appear to work.
Present approach: Slightly less flexible, but no complaints.
Within rootwrap() which calls different rootfinders according to method="name", define
FnTrace and grTrace, set up a list glist for the items I want to share, then
envroot <- list2env(glist)
The FnTrace and grTrace are defined before the calls to rootfinders, so envroot can be found.
No globals. R CMD check is happy. However, I must call rootfinders via the wrapper, which is
actually simpler from point of view of syntax.
I've still some testing and tweaking, but I think main issues resolved by this.
Thanks to all who responded.
JN
On 2018-08-28 12:27 PM, Georgi Boshnakov wrote:
> If you don't insist on putting the variable in the global environment,
> variations of the following give a cleaner solution:
>
> TraceSetup_1 <- local({
> ifn = 0
> igr = 0
> ftrace = FALSE
> fn = NA
> gr = NA
>
> function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){
> ifn <<- ifn
> igr <<- igr
> ftrace <<- ftrace
> fn <<- fn
> gr <<- gr
> parent.env(environment())
> }
> })
>
> For example,
>
> TraceSetup_1 <- local({
> + ifn = 0
> + igr = 0
> + ftrace = FALSE
> + fn = NA
> + gr = NA
> + function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){
> + ifn <<- ifn
> + igr <<- igr
> + ftrace <<- ftrace
> + fn <<- fn
> + gr <<- gr
> + parent.env(environment())
> + }
> + })
>>
>> e <- TraceSetup_1(fn = function(x) x^2)
>> ls(e)
> [1] "fn" "ftrace" "gr" "ifn" "igr"
>> e$fn
> function(x) x^2
>
> ## let's change 'fn':
>> e$fn <- function(x) x^4
>> e$fn
> function(x) x^4
>
>
> Note that the environment is always the same, so can be accessed from anywhere in your code:
>
>> e2 <- environment(TraceSetup_1)
>> e2
> <environment: 0x000000000d1af620>
>> identical(e2, e)
> [1] TRUE
>>
>
> If you need a new environment every time, a basic setup might be:
>
> TraceSetup_2 <- local({
> staticVar1 <- NULL
> ## other variables here
>
> function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){
> ## force evaluation of the arguments
> ifn
> igr
> ftrace
> fn
> gr
> environment()
> }
> })
>
> There is no need for local() here but usually one needs also some static variables.
> Now every call gives a different environment (but all have the same parent):
>
> ea <- TraceSetup_2(fn = function(x) x^2 - 2*x + 1)
>> ls(ea)
> [1] "fn" "ftrace" "gr" "ifn" "igr"
>> ea$fn
> function(x) x^2 - 2*x + 1
>>
>> eb <- TraceSetup_2(fn = function(x) x^2 + 1)
>> eb$fn
> function(x) x^2 + 1
>>
>> ## ea$fn is still the same:
>> ea$fn
> function(x) x^2 - 2*x + 1
>>
>
> Obviously, in this case some further arrangements are needed for the environments to be made available to the external world.
>
> Hope this helps,
> Georgi Boshnakov
>
>
> -----Original Message-----
> From: R-package-devel [mailto:r-package-devel-bounces using r-project.org] On Behalf Of J C Nash
> Sent: 28 August 2018 14:18
> To: Fox, John; Richard M. Heiberger
> Cc: List r-package-devel
> Subject: Re: [R-pkg-devel] Trying to work around missing functionality
>
> Indeed, it appears that globalVariables must be outside the function. However, I had quite a bit of
> fiddle to get things to work without errors or warnings or notes. While I now have a package that
> does not complain with R CMD check, I am far from satisfied that I can give a prescription. I had
> to remove lines in the rootfinder like
> envroot$fn <- fn
> that were used to set the function to be used inside my instrumented function, and instead
> call TraceSetup(fn=fn, ...) where a similar statement was given. Why that worked while the direct
> assignment (note, not a <<- one) did not, I do not understand. However, I will work with this for
> a while and try to get a better handle on it.
>
> Thanks for the pointer. As an old-time programmer from days when you even set the add table, I'm
> still uncomfortable just putting code in a directory and assuming it will be executed, i.e., the
> globals.R file. However, I now have this set to establish the global structure as follows
>
>> ## Put in R directory.
>> if(getRversion() >= "2.15.1") { utils::globalVariables(c('envroot')) } # Try declaring here
>> groot<-list(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA, label="none")
>> envroot <- list2env(groot) # Note globals in FnTrace
>
> Then TraceSetup() is
>
>> TraceSetup <- function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){
>> envroot$ifn <- ifn
>> envroot$igr <- igr
>> envroot$ftrace <- ftrace
>> envroot$fn <- fn
>> envroot$gr <- gr
>> return()
>> }
>
> and it is called at the start of the rootfinder routine.
>
> Thus I am establishing a global, then (re-)setting values in TraceSetup(), then
> incrementing counters etc. in the instrumented FnTrace() that is the function for which I find
> the root, which calls fn() given by the "user". Messy, but I can now track progress and measure
> effort.
>
> I'm sure there are cleaner solutions. I suggest offline discussion would be better until such
> options are clearer.
>
> Thanks again.
>
> JN
>
>
>
> On 2018-08-28 12:01 AM, Fox, John wrote:
>> Hi John,
>>
>> It's possible that I didn’t follow what you did, but it appears as if you call globalVariables() *inside* the function. Instead try to do as Richard Heiberger suggested and place the call outside of the function, e.g., in a source file in the package R directory named globals.R. (Of course, the name of the source file containing the command isn’t important.)
>>
>> I hope this helps,
>> John
>>
>> -----------------------------------------------------------------
>> John Fox
>> Professor Emeritus
>> McMaster University
>> Hamilton, Ontario, Canada
>> Web: https://socialsciences.mcmaster.ca/jfox/
>>
>>
>>
>>> -----Original Message-----
>>> From: R-package-devel [mailto:r-package-devel-bounces using r-project.org] On
>>> Behalf Of J C Nash
>>> Sent: Monday, August 27, 2018 8:44 PM
>>> To: Richard M. Heiberger <rmh using temple.edu>
>>> Cc: List r-package-devel <r-package-devel using r-project.org>
>>> Subject: Re: [R-pkg-devel] Trying to work around missing functionality
>>>
>>> Unfortunately, makes things much worse. I'd tried something like this already.
>>>
>>>> * checking examples ... ERROR
>>>> Running examples in ‘rootoned-Ex.R’ failed The error most likely
>>>> occurred in:
>>>>
>>>>> ### Name: rootwrap
>>>>> ### Title: zeroin: Find a single root of a function of one variable within
>>>>> ### a specified interval.
>>>>> ### Aliases: rootwrap
>>>>> ### Keywords: root-finding
>>>>>
>>>>> ### ** Examples
>>>>>
>>>>> # Dekker example
>>>>> # require(rootoned)
>>>>> dek <- function(x){ 1/(x-3) - 6 }
>>>>> r1 <- rootwrap(dek, ri=c(3.0000001, 6), ftrace=TRUE,
>>>>> method="uniroot")
>>>> Error in registerNames(names, package, ".__global__", add) :
>>>> The namespace for package "rootoned" is locked; no changes in the global
>>> variables list may be made.
>>>> Calls: rootwrap -> TraceSetup -> <Anonymous> -> registerNames
>>>> Execution halted
>>>
>>> Also had to use utils::globalVariables( ...
>>>
>>> JN
>>>
>>>
>>> On 2018-08-27 08:40 PM, Richard M. Heiberger wrote:
>>>> Does this solve the problem?
>>>>
>>>> if (getRversion() >= '2.15.1')
>>>> globalVariables(c('envroot'))
>>>>
>>>> I keep this in file R/globals.R
>>>>
>>>> I learned of this from John Fox's use in Rcmdr.
>>>>
>>>> On Mon, Aug 27, 2018 at 8:28 PM, J C Nash <profjcnash using gmail.com>
>>> wrote:
>>>>> In order to track progress of a variety of rootfinding or
>>>>> optimization routines that don't report some information I want, I'm
>>>>> using the following setup (this one for rootfinding).
>>>>>
>>>>> TraceSetup <- function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){ #
>>>>> JN: Define globals here
>>>>> groot<-list(ifn=ifn, igr=igr, ftrace=ftrace, fn=fn, gr=gr, label="none")
>>>>> envroot <<- list2env(groot) # Note globals in FnTrace
>>>>> ## This generates a NOTE that
>>>>> ## TraceSetup: no visible binding for '<<-' assignment to ‘envroot’
>>>>> ## envroot<-list2env(groot, parent=.GlobalEnv) # Note globals in FnTrace -
>>> - this does NOT work
>>>>> ## utils::globalVariables("envroot") # Try declaring here --
>>>>> causes errors # end globals
>>>>> envroot
>>>>> }
>>>>>
>>>>> FnTrace <- function(x,...) {
>>>>> # Substitute function to call when rootfinding
>>>>> # Evaluate fn(x, ...)
>>>>> val <- envroot$fn(x, ...)
>>>>> envroot$ifn <- envroot$ifn + 1 # probably more efficient ways
>>>>> if (envroot$ftrace) {
>>>>> cat("f(",x,")=",val," after ",envroot$ifn," ",envroot$label,"\n")
>>>>> }
>>>>> val
>>>>> }
>>>>>
>>>>>
>>>>> Perhaps there are better ways to do this, but this does seem to work quite
>>> well.
>>>>> It lets me call a rootfinder with FnTrace and get information on evaluations
>>> of fn().
>>>>> (There's another gr() routine, suppressed here.)
>>>>>
>>>>> However, R CMD check gives a NOTE for
>>>>>
>>>>> TraceSetup: no visible binding for global variable ‘envroot’
>>>>> Undefined global functions or variables:
>>>>> envroot
>>>>>
>>>>> The commented lines in TraceSetup suggest some of the things I've
>>>>> tried. Clearly I don't fully comprehend how R is grinding up the
>>>>> code, but searches on the net seem to indicate I am far from alone. Does
>>> anyone have any suggestion of a clean way to avoid the NOTE?
>>>>>
>>>>> JN
>>>>>
>>>>> ______________________________________________
>>>>> R-package-devel using r-project.org mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/r-package-devel
>>>
>>> ______________________________________________
>>> R-package-devel using r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-package-devel
>
> ______________________________________________
> R-package-devel using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-package-devel
>
More information about the R-package-devel
mailing list