Рассмотрим функцию fn()
которая хранит самый последний ввод x
и его возвращаемое значение ret <- x^2
в родительской среде.
makeFn <- function(){
xx <- ret <- NA
fn <- function(x){
if(!is.na(xx) && x==xx){
cat("x=", xx, ", ret=", ret, " (memory)", fill=TRUE, sep="")
return(ret)
}
xx <<- x; ret <<- sum(x^2)
cat("x=", xx, ", ret=", ret, " (calculate)", fill=TRUE, sep="")
ret
}
fn
}
fn <- makeFn()
fn()
выполняет вычисления только в том случае, если указано другое входное значение. В противном случае он читает ret
из родительской среды.
fn(2)
# x=2, ret=4 (calculate)
# [1] 4
fn(3)
# x=3, ret=9 (calculate)
# [1] 9
fn(3)
# x=3, ret=9 (memory)
# [1] 9
Когда плагин fn()
в optim()
находит его минимум, это приводит к неожиданному поведению:
optim(par=10, f=fn, method="L-BFGS-B")
# x=10, ret=100 (calculate)
# x=10.001, ret=100.02 (calculate)
# x=9.999, ret=100.02 (memory)
# $par
# [1] 10
#
# $value
# [1] 100
#
# (...)
Это ошибка? Как это может случиться?
Даже когда я использую C-API R, мне трудно представить, как можно добиться такого поведения. Есть идеи?
Замечания:
-
работает:
library("optimParallel") # (parallel) wrapper to optim(method="L-BFGS-B") cl <- makeCluster(2); setDefaultCluster(cl) optimParallel(par=10, f=fn)
-
работает:
optimize(f=fn, interval=c(-10, 10))
-
работает:
optim(par=10, fn=fn)
-
терпит неудачу:
optim(par=10, fn=fn, method="BFGS")
-
работает:
library("lbfgs"); library("numDeriv") lbfgs(call_eval=fn, call_grad=function(x) grad(func=fn, x=x), vars=10)
-
работает:
library("memoise") fn_mem <- memoise(function(x) x^2) optim(par=10, f=fn_mem, method="L-BFGS-B")
-
Протестировано с версией R 3.5.0.