[R] conditional assignments and calculations

Gabor Grothendieck ggrothendieck at myway.com
Sun Oct 3 08:05:16 CEST 2004


Michael Lachmann <lachmann <at> eva.mpg.de> writes:

: 
: Hello!
: 
: I am using the TeXmacs interface to R. (Though I encountered a similar 
: problem when using Sweave)
: In doing calculations I often ecounter this scenario: I'll have some 
: calculations in my file:
: --
: A=read.lots.of.data()
: 
: B=huge.calculation.on(A)
: 
: C=another.calculation.on(B)
: --
: Now, if A has already been read, I don't need to re-read it. If B has 
: already been calculated, I don't need to recalculate it. But I would 
: like to be able to just press 'enter' on each of them.
: 
: So, I would like R to somehow figure out dependencies (a bit like in 
: Makefiles)
: 
: I implemented something like this with the following functions:
: ----------------------
: touch=function(x) {attr(x,"last.updated")=Sys.time();x}
: 
: last.updated=function(a) {
:    if( length(attr(a,"last.updated")) == 0 ) {
:    	Sys.time()
:    } else {
:        attr(a,"last.updated")
:    }
: }
: 
: "depends<-"=function(a,value,...) {
:    args=list(...)
:    if( length(attr(a,"last.updated")) == 0 ) {
:      a <- value
:      a <-touch(a)
:    } else {
:      lu=(sapply(args,function(x) last.updated(x)-last.updated(a) > 0 ))
:      if( sum(lu)>0 ) {
:         a <- value
:         a <-touch(a)
:      }
:    }
:    a
: }
: ------------------------
: Then I can implement what I wanted above as follows:
: --
: if( !exists(A) ) { A=read.lots.of.data(); A=touch(A) }
: 
: depends(B,A)=huge.calculation.on(A)
: # this means the assignment 'B=huge.calculation.on(A)' is
: # done only if A has been updated more recently than B.
: 
: depends(C,B)=another.calculation.on(B)
: # dito for C more recent than B.
: --
: And now I can carelessly press 'enter' on these expression that might 
: otherwise take hours to compute. Each variable has a datestamp of the 
: last time it was updated, and I do each calculation conditional on 
: whether certain variables have been recently changed. I can also save 
: A,B,C to a file,later load them, and the calculations will not be redone.
: 
: But this solution is quite ugly, because of several problems:
: 
: 1. To call 'depends(A,B)=f(B)' the first time, A has to already exist, 
: otherwise I get an error (before I enter the "depends<-" function.)

The technique used to implement mulitple return values shown in 

   http://tolstoy.newcastle.edu.au/R/help/04/06/1406.html

could be adapted to this problem.  Using that technique the code would 
look like this:

   depends[A,B] <- f(B)

and A would not have to pre-exist.

You define a structure with a class of depends, say:

   depends <- structure(NA, class = "depends")

and then define the [<-.depends action on that structure
in an analogous way to what was done there.

: 2. I would also like to have a convenient way to do
: "if( !exists(A) ) { A=read.lots.of.data(); A=touch(A) }"
: maybe something like:
: depends(A)<-read.lots.of.data()
: But that doesn't work, because of 1.
: or
: A %set% read.lots.data()
: But that doesn't work, because I haven't figured out a way for a 
: function to change one of its variables.
: (Maybe I could do A=A %set read.lots.of.data(), but that is really ugly...)


Is this what you want?

R> f <- function(x,v) assign(as.character(substitute(x)), v, parent.frame())
R> x # x does not exist
Error: Object "x" not found
R> f(x,3)
R> x # now it does
[1] 3

<<- can be used if the   eval.parent is a third way (see #3 below).

: 3. It would be nice to be able to do touch(A) instead of A=touch(A)

touch <- function(x) 
    eval.parent(substitute(attr(x,"last.updated")<-Sys.time())) 
x <- 3
touch(x)

: 
: 4. If I modify A without calling 'A=touch(A)', then B will not be 
: updated next time I call 'depends(B,A)=huge.calculation.on(A)'. So it 
: would be nice to have the variable's 'last updated' time updated 
: automatically. (Though then it is a bit problematic to decide what the 
: 'last updated' time should be for variables loaded from a file...)

If its done in a function you could use on.exit to ensure that it gets
updated when leaving the function.

: 
: 5. The whole thing is rather cludgy. But I haven't found a good way to 
: implement it.
: 
: Suggestions?
: 
: Thanks,
: 
:     Michael
:




More information about the R-help mailing list