-
Notifications
You must be signed in to change notification settings - Fork 128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
R6 object keeps rebuilding #345
Comments
From the dependency graph, And as it turns out, when you define a new library(digest) # For fingerprinting objects.
digest(FoodEnvironment, algo = "xxhash64")
#> [1] "67082b8a867db411"
fenv2 <- FoodEnvironment$new(0.1, 40)
digest(FoodEnvironment, algo = "xxhash64")
#> [1] "b313eafc964c8ea9" The hashes above are different, so > dd$trigger <- c("missing", "any")
> dd
# A tibble: 2 x 3
target command trigger
<chr> <chr> <chr>
1 fenv2 ignore(FoodEnvironment$new)(0.1, 40) missing
2 fenv tmpf(0.1, 40) any You could even ignore() the call to > dd <- drake_plan(fenv2 = ignore(FoodEnvironment$new)(.1, 40))
> make(dd)
target fenv2
> make(dd)
Unloading targets from environment:
fenv2
All targets are already up to date. But both options undermine reproducibility. |
R does some record-keeping when functions are executed. I think it has something to do with the bytecode compiler. In general this means using For example: library(digest)
f <- function() {
1+1
}
f
digest(f)
f()
f
digest(f)
f()
f
digest(f)
f()
f
digest(f) Output:
You can use |
Thanks Winston, that helps a lot. Fortunately, when |
Looking at the hashes and indeed trying around one work around seems to be to call the functions 3 times before starting building with drake. Adding this seems to make drake work as expected FoodEnvironment$new(1,2)
FoodEnvironment$new(1,2)
FoodEnvironment$new(1,2)
drake::make(dd, cache=cache, verbose=4)
drake::make(dd, cache=cache, verbose=4) |
Another quick solution is to compile the function before hand # this re runs the function
f<-function() 1+1
b<-list('a'=f)
plan<-drake_plan(sim=b[[1]]())
make(plan)
make(plan)
# this works fine
f<-compiler::cmpfun(function() 1+1)
b<-list('a'=f)
plan<-drake_plan(sim=b[[1]]())
make(plan)
make(plan) |
As far as |
Reopening. Just realizing that sometimes there's just no way around this one if you absolutely have to use a certain toolkit. Looking for a way to represent an arbitrary R object that more stable under hashing. In the case of functions, f <- function(){}
.Internal(inspect(f))
f()
.Internal(inspect(f))
f()
.Internal(inspect(f))
f()
.Internal(inspect(f))
f()
.Internal(inspect(f))
f() I do not understand what it means yet. Like I said, |
A few thoughts: The source of the problem is that For example, see below. (Note that f <- function() { 1 + 1 }
g <- function() { 1 + 1 }
identical(f, g) # TRUE
identical(digest(f), digest(g)) # FALSE
f()
identical(f, g) # TRUE
identical(digest(f), digest(g)) # FALSE
f()
identical(f, g) # TRUE
identical(digest(f), digest(g)) # FALSE I believe the publicly-accessible bytecode compiler functions don't provide the same control as what happens in R. For example, if f <- function() { 1 + 1 }
g <- f
identical(f, g) # TRUE
identical(digest(f), digest(g)) # TRUE
f()
identical(f, g) # TRUE
identical(digest(f), digest(g)) # TRUE
f()
identical(f, g) # TRUE
identical(digest(f), digest(g)) # TRUE To really solve the problem, you may need to write your own serialization function, but that's definitely a non-trivial task. |
I see. With a less exact serialization method, we could just call |
Update: I just posted a Stack Overflow question here. Maybe someone has a clever workaround we have not considered. |
Convenient workaround: just wrap the library(drake)
library(R6)
clean()
new_circle <- function(radius){
circle_class <- R6Class(
"circle_class",
private = list(radius = NULL),
public = list(
initialize = function(radius){
private$radius <- radius
},
area = function(){
pi * private$radius ^ 2
}
)
)
circle_class$new(radius = radius)
}
plan <- drake_plan(
circle = new_circle(radius = 10),
area = circle$area()
)
make(plan)
#> target circle
#> target area
make(plan)
#> All targets are already up to date. I will reopen this issue if more robust serialization seems within reach. |
First of all thanks for all the good work and quick bug fixes! For some simulations I work with R6 classes, it is a convenient way to keep track of a lot of things in individual based simulations. I encountered issues where targets are rebuild while nothing changed. I tried to make a small reproducible example (here target fenv2 is also rebuild on the second call to make):
This gives the following results:
The text was updated successfully, but these errors were encountered: