On 14-02-25 4:43 PM, Rolf Turner wrote:
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.
One problem in your scrF: you have
tdone <- tt
rather than
tdone <<- tt
That creates a new local copy, it doesn't update the one in the parent
environment. That doesn't explain a "not found" error, but it would
cause problems...
The thing that causes the "not found" error is in xsolve.disc.R, where
you replace the environment of scrF with new.env(). That wipes out the
tiny one that local() created, and replaces it with an empty one whose
parent is the evaluation frame of xsolve.disc.
Generally speaking it's a bad idea to replace the environment of
functions, it's hard to get it right. It's better to create the right
one in the first place.
Duncan Murdoch
______________________________________________
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.