[R] Environmental problems.

Duncan Murdoch murdoch.duncan at gmail.com
Tue Feb 25 13:13:55 CET 2014


On 14-02-25 3:08 AM, Rolf Turner wrote:
>
> I have a function that makes use of the ode() function from the
> "deSolve" package.  I am trying to find a way of getting it to put out a
> "progress report" every "t.int" time units (by "progress report" I just
> mean reporting what time it's got up to).
>
> I thought to put code something like the following in my "func" function
> that gets called by (is an argument to) ode():
>
>> cat("Before: time =",tt,"tdone =",tdone,"diff =",tt-tdone,"\n")
>> if(tt - tdone >= 0.1-sqrt(.Machine$double.eps)) {
>>      cat("Prog. Rep.: time =",tt,"tdone =",tdone,"diff =",tt-tdone,"\n")
>>      assign("tdone",tt,envir=parent.env(environment()))
>> }
>> cat("After: time =",tt,"tdone =",tdone,"diff =",tt-tdone,"\n")
>
> The object "tdone" gets initialized (to 0) outside of func(), so there
> is not a problem with "tdone" not being found the first time that func()
> gets called by ode().  (I'm hardwiring "t.int=0.1" in the forgoing just
> for test/illustration purposes.)  The "Before" and "After" cat()-s are
> there to demonstrate what goes wrong.
>
> What goes wrong is that I get no progress report and tdone remains equal
> to 0 until tt reaches 0.1. As desired. I then get a progress report and
> tdone gets set equal to the first value of tt which is greater than 0.1.
> As desired.
>
> Then I get no further progress reports and tdone gets set equal to tt at
> every call to func() --- even though tt - tdone = 0 which is less than
> 0.1 so the assignment of tdone cannot occur.  And yet it does, keeping
> the difference equal to 0.  (*Not* as desired!)
>
> So the function is recognizing that the difference is less than 0.1 in
> that it does not execute the cat() statement.  Yet it executes the
> assign() statement.  This is clearly impossible! :-)  But it happens.
>
> The output from the cat()-ing, around time = 0.1, looks like:
>
>> Before: time = 0.09364548 tdone = 0 diff = 0.09364548
>> After: time = 0.09364548 tdone = 0 diff = 0.09364548
>> Before: time = 0.0975779 tdone = 0 diff = 0.0975779
>> After: time = 0.0975779 tdone = 0 diff = 0.0975779
>> Before: time = 0.0975779 tdone = 0 diff = 0.0975779
>> After: time = 0.0975779 tdone = 0 diff = 0.0975779
>> Before: time = 0.09698997 tdone = 0 diff = 0.09698997
>> After: time = 0.09698997 tdone = 0 diff = 0.09698997
>> Before: time = 0.1009224 tdone = 0 diff = 0.1009224
>> Prog. Rep.: time = 0.1009224 tdone = 0 diff = 0.1009224
>> After: time = 0.1009224 tdone = 0.1009224 diff = 0
>> Before: time = 0.1009224 tdone = 0.1009224 diff = 0
>> After: time = 0.1009224 tdone = 0.1009224 diff = 0
>> Before: time = 0.1003344 tdone = 0.1003344 diff = 0  <--------------|
>> After: time = 0.1003344 tdone = 0.1003344 diff = 0
>> Before: time = 0.1042669 tdone = 0.1042669 diff = 0
>> After: time = 0.1042669 tdone = 0.1042669 diff = 0
>
> It's at that line indicated by "<----|", 4 lines from the bottom of the
> forgoing display, where things go to hell in a handcart.  Why (how on
> earth can) tdone change from 0.1009224 to 0.1003344, given that the
> difference is 0 whence no assignment of tdone should take place?
>
> What am I not seeing?  Can anyone help me out?  I'm going mad!
> ***MAD*** I tell you! :-)
>
> Suggestions as to a better way of accomplishing my desired goal of
> producing progress reports would also be welcome.
>
> I am not at all sure that assigning "tdone" in parent.env(environment())
> is the right thing to do.  I need to assign it in such a way and in such
> a location that its value will persist
> from call to call of "func".  Words of wisdom about this would be
> gratefully received.  (I don't really grok environments.  I just try
> things until *something* works!)

You don't show us everything (we want the full Monty!), so it's hard to 
say what's going wrong.  My guess would be that you have both a local 
copy as well as a parent copy of some variable, and your test is 
consulting the wrong one.

A better approach to what you are doing (better since yours modifies 
things in the global environment, and that can be dangerous; other code 
might modify it too) is the following.  Create your func in a local 
block, and it will have it's own mini-environment associated with it. 
Put tdone there.  For example,

func <- local({
   # local() creates an environment; that's where tdone will live
   tdone <- 0

   # this function's environment will be the one created by
   # local(), so it will see tdone, but other code won't see it.

   function(x) {
     # the timing stuff
     tt <- Sys.time()
     if (tt - tdone > 0.1) {
       cat("Prog rep...")
       tdone <<- tt
     }
     # now the real stuff
     ...
   })

Duncan Murdoch




More information about the R-help mailing list