[Rd] "interpolator constructor"; was "Scope problem?"
Martin Maechler
maechler at stat.math.ethz.ch
Mon May 25 17:08:11 CEST 2009
Hi Barry,
this is just a side-remark, probably not at all something you
were interested in, but to be put along this thread in the list
archives, in case some readers are side-tracked there ...
>>>>> "BaRow" == Barry Rowlingson <b.rowlingson at lancaster.ac.uk>
>>>>> on Fri, 22 May 2009 17:28:42 +0100 writes:
BaRow> I've just spent today trying to fix a Heisenbug...
BaRow> this function returns a linear interpolator function:
BaRow> interpOne <- function(xl,yl){
BaRow> f = function(data){
BaRow> t = (data-min(xl))/(max(xl)-min(xl))
BaRow> return(min(yl)+t*(max(yl)-min(yl)))
BaRow> }
BaRow> return(f)
BaRow> }
>> k=interpOne(c(0,1),c(4,5))
>> k(0.5)
BaRow> [1] 4.5
Note that "base R" has already two such functions,
namely
splinefun()
and approxfun(),
both returning a *function* as in your examples.
Best,
Martin Maechler, ETH Zurich
BaRow> and this function uses the above to return a function that returns a
BaRow> piece-wise linear interpolator function:
BaRow> mr <- function(){
BaRow> parts = list()
BaRow> ranges = rbind(c(0,1),c(1,2),c(2,3))
BaRow> domains = rbind(c(3,4),c(5,6),c(2,8))
BaRow> for(i in 1:length(ranges[,1])){
BaRow> parts[[i]] = interpOne(ranges[i,],domains[i,])
BaRow> }
BaRow> f = function(d){
BaRow> pos = sum(d>ranges[,1])
BaRow> cat("using pos = ",pos,"\n")
BaRow> return(parts[[pos]](d))
BaRow> }
BaRow> return(f)
BaRow> }
BaRow> m = mr()
BaRow> The 'ranges' and 'domains' vectors describe the pieces. But this doesn't work:
>> m(0.5)
BaRow> using pos = 1
BaRow> [1] -7
BaRow> - but it should be 3.5 (since 0.5 is in the first piece, and that
BaRow> then interpolates between 3 and 4). What about the other pieces:
>> m(1.5)
BaRow> using pos = 2
BaRow> [1] -1
>> m(2.5)
BaRow> using pos = 3
BaRow> [1] 5
BaRow> - which looks like it's using the last set of range/domain pairs each
BaRow> time. Curious, I thought.
BaRow> So I thought I'd evaluate the functions as they are created in the
BaRow> list to see what's going on. Change the loop to print out:
BaRow> for(i in 1:length(ranges[,1])){
BaRow> parts[[i]] = interpOne(ranges[i,],domains[i,])
BaRow> cat("part ",i," at zero = ",parts[[i]](0),"\n")
BaRow> }
BaRow> and try:
>> m=mr()
BaRow> part 1 at zero = 3
BaRow> part 2 at zero = 4
BaRow> part 3 at zero = -10
BaRow> looks good, those are the intercepts of my pieces... but now:
>> m(0.5)
BaRow> using pos = 1
BaRow> [1] 3.5
>> m(1.5)
BaRow> using pos = 2
BaRow> [1] 5.5
>> m(2.5)
BaRow> using pos = 3
BaRow> [1] 5
BaRow> Woah! It's now working! Trying to observe the thing changes it? A Heisenbug!
BaRow> I can only think it's my misunderstanding of some aspect of R's
BaRow> scoping and evaluation rules. Does evaluating the functions within
BaRow> that loop cause a copy of some environment to be made, or a 'lazy
BaRow> evaluation' to be evaluated? Or a 'promise' to be fulfilled? I don't
BaRow> really understand those terms, I'd just hoped functions ran in the
BaRow> environment they were created in. Seems sometimes they do, sometimes
BaRow> they dont... What's going on?
BaRow> R 2.9.0 on Ubuntu.
BaRow> Barry
BaRow> ______________________________________________
BaRow> R-devel at r-project.org mailing list
BaRow> https://stat.ethz.ch/mailman/listinfo/r-devel
More information about the R-devel
mailing list