[R] Environmental problems.

Rolf Turner r.turner at auckland.ac.nz
Tue Feb 25 22:43:29 CET 2014


Please see at end.

On 26/02/14 01:13, Duncan Murdoch wrote:
> 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
>      ...
>    })

(a) The only relevant variable is "tdone"; I have grepped on "tdone" in 
the code.  There are no other assignments than the one enclosed in the 
if statement and the initialization.  I swear they are out to get me.

(b) Your "local" idea looks like it should solve the problem.  I tried
it in a toy example and it worked like a charm.  In the real example I 
get "Error: object 'tdone' not found".

(c) In respect of giving you the full Monty: I have attached a tar-ball 
and a zip archive --- hope that they get through the listserv 
machinations --- both containing all the necessary code to demonstrate 
the phenomenon.  Unpack, source all the *.R files, then source 
"demoScript".  You'll get a browser() call inside the "func" (which is 
actually called "scrF"). Type "tdone" and you'll get the error message. 
  Press "return" again, and it all falls over (due to the same error).

Somehow, due to the fact that "scrF" gets called by ode() which gets 
called by xsolve.disc(), the local environment gets hidden.  I swear 
that they are still out to get me.

cheers,

Rolf


More information about the R-help mailing list