R: caching / memory for the environment

nI would like to use memoization to cache the results of some expensive operations so that they are not calculated over and over.

Both memoise and R.cache suit my needs. However, I find that caching is not reliable for calls.

Here is an example demonstrating the problem I am seeing:

library(memoise) # Memoisation works: b() is called only once a <- function(x) runif(1) replicate(5, a()) b <- memoise(a) replicate(5, b()) # Memoisation fails: mfn() is called every single time ProtoTester <- proto( calc = function(.) { fn <- function() print(runif(1)) mfn <- memoise(fn) invisible(mfn()) } ) replicate(5, ProtoTester$calc()) 

Updated based on answer

This question may have different answers based on whether persistent or non-persistent caching is used. Intermittent caching (e.g. memoise ) may require a separate assignment, and then the answer below is a great way. Persistent caching (e.g. R.cache ) works in all sessions and should be reliable across multiple destinations. The approach above works with R.cache . Despite multiple assignments, fn is only called once with R.cache . It will be called twice using memoise .

 > ProtoTester <- proto( + calc = function(.) { + fn <- function() print(runif(1)) + invisible(memoizedCall(fn)) + } + ) > replicate(5, ProtoTester$calc()) [1] 0.977563 [1] 0.1279641 [1] 0.01358866 [1] 0.9993092 [1] 0.3114813 [1] 0.97756303 0.12796408 0.01358866 0.99930922 0.31148128 > ProtoTester <- proto( + calc = function(.) { + fn <- function() print(runif(1)) + invisible(memoizedCall(fn)) + } + ) > replicate(5, ProtoTester$calc()) [1] 0.97756303 0.12796408 0.01358866 0.99930922 0.31148128 

The reason I thought I was having a problem with R.cache because I was passing the proto method as a memoizedCall function. proto methods are tied to environments in such a way that R.cache has a hard time. In this case, you need to cancel the function (get from the created method to a simple function), and then pass the object manually as the first argument. The following example shows how this works (both Report and Report$loader are proto objects:

 # This will not memoize the call memoizedCall(Report$loader$download_report) # This works as intended memoizedCall(with(Report$loader, download_report), Report$loader) 

I would really like to know why R.cache works with normal functions related to environments, but not using proto created methods.

+4
source share
2 answers

In your code, the function is re-saved again each time it is called. The following should work: it is only memoized once when it is defined.

 ProtoTester <- proto( calc = { fn <- function() print(runif(1)) mfn <- memoise(fn) function(.) mfn() } ) replicate(5, ProtoTester$calc()) 
+4
source

An alternative solution would be to use evals to evaluate from (my) the pander package , which has an internal one (temporary in the environment for the current R session or permanent with disk storage). A short example based on your code:

 library(pander) ProtoTester <- proto( calc = function(.) { fn <- function() runif(1) mfn <- evals('fn()')[[1]]$result invisible(mfn) } ) 

And starting evals with disabling and enabling the cache will result in:

 > evals.option('cache', FALSE) > replicate(5, ProtoTester$calc()) [1] 0.7152186 0.4529955 0.4160411 0.1166872 0.8776698 > evals.option('cache', TRUE) > evals.option('cache.time', 0) > replicate(5, ProtoTester$calc()) [1] 0.7716874 0.7716874 0.7716874 0.7716874 0.7716874 

Note that the evals.option si function will soon be renamed evalsOption to mitigate the R CMD check warnings about S3 methods.

+3
source

All Articles