0

Consider the following MWE. How do I get the m1 and m2 integers instead of expressions to be exposed to the func() arguments, instead of "object '1' not found"?

func <- function(x, m1, m2) {
  paste("M1=", m1, "M2=", m2, ": ", mean(unlist(x)))
}
p <- drake_plan(
  a = target(
    runif(10, m1, m2),
    transform = cross(m1 = 0, m2 = c(1,2), n = !!c(1,5))
  ),
  b = target(
    func(list(a), m1, m2),
    transform = combine(a, .by = m2)
  )
)
landau
  • 5,636
  • 1
  • 22
  • 50
adamski
  • 71
  • 6

1 Answers1

0

!!as.numeric(deparse(substitute())) does what I think you want.

library(drake)

f <- function(x, m1, m2) {
  paste("M1 = ", m1, "M2 = ", m2, ": ", mean(unlist(x)))
}

plan <- drake_plan(
  a = target(
    runif(10, m1, m2),
    transform = cross(m1 = 0, m2 = c(1, 2), n = c(1, 5))
  ),
  b = target(
    f(
      list(a),
      !!as.numeric(deparse(substitute(m1))),
      !!as.numeric(deparse(substitute(m2)))
    ),
    transform = combine(a, m1, m2, .by = m2)
  )
)

plan
#> # A tibble: 6 x 2
#>   target  command                        
#>   <chr>   <expr>                         
#> 1 a_0_1_1 runif(10, 0, 1)                
#> 2 a_0_2_1 runif(10, 0, 2)                
#> 3 a_0_1_5 runif(10, 0, 1)                
#> 4 a_0_2_5 runif(10, 0, 2)                
#> 5 b_1     f(list(a_0_1_1, a_0_1_5), 0, 1)
#> 6 b_2     f(list(a_0_2_1, a_0_2_5), 0, 2)

make(plan)
#> target a_0_2_5
#> target a_0_2_1
#> target a_0_1_1
#> target a_0_1_5
#> target b_2
#> target b_1

readd(b_1)
#> [1] "M1 =  0 M2 =  1 :  0.546001701243222"

readd(b_2)
#> [1] "M1 =  0 M2 =  2 :  1.12784601158928"

Created on 2019-11-07 by the reprex package (v0.3.0)

NB development drake now has dynamic branching, which completely avoids metaprogramming.

library(drake)

plan <- drake_plan(
  min = rep(c(1, 10), times = 2),
  max = rep(c(100, 1000), each = 2),
  range = target(
    range(runif(1000, min, max)),
    dynamic = map(min, max)
  ),
  out = target(
    list(range = range, min = min, max = max),
    dynamic = combine(range, min, max, .by = max)
  )
)

plan
#> # A tibble: 4 x 3
#>   target command                             dynamic                       
#>   <chr>  <expr>                              <expr>                        
#> 1 min    rep(c(1, 10), times = 2)          … NA                           …
#> 2 max    rep(c(100, 1000), each = 2)       … NA                           …
#> 3 range  range(runif(1000, min, max))      … map(min, max)                …
#> 4 out    list(range = range, min = min, max… combine(range, min, max, .by …

make(plan)
#> target max
#> target min
#> dynamic range
#> subtarget range_1d8ef6a7
#> subtarget range_b7af4aa4
#> subtarget range_4f5b896d
#> subtarget range_36590ee2
#> dynamic out
#> subtarget out_6d655424
#> subtarget out_79642dc2

str(readd(out))
#> List of 2
#>  $ :List of 3
#>   ..$ range:List of 2
#>   .. ..$ : num [1:2] 1.19 99.89
#>   .. ..$ : num [1:2] 10 99.9
#>   ..$ min  : num [1:2] 1 10
#>   ..$ max  : num [1:2] 100 100
#>  $ :List of 3
#>   ..$ range:List of 2
#>   .. ..$ : num [1:2] 2.95 999.07
#>   .. ..$ : num [1:2] 10.6 999.4
#>   ..$ min  : num [1:2] 1 10
#>   ..$ max  : num [1:2] 1000 1000

Created on 2019-11-07 by the reprex package (v0.3.0)

EDIT 2019-11-08: response to a comment

Here is a working example that shows what is going on with the plan you proposed in the comment.

library(drake)
func <- function(x, min, max) {
  obs_mins <- vapply(x[[1]], min, FUN.VALUE = numeric(1))
  obs_maxes <- vapply(x[[1]], max, FUN.VALUE = numeric(1))
  c(
    paste("true mins =", paste(min, collapse = " ")),
    paste("observed mins =", paste(obs_mins, collapse = " ")),
    paste("true maxes =", paste(max, collapse = " ")),
    paste("observed maxes =", paste(obs_maxes, collapse = " "))
  )
}

plan <- drake_plan(
  min = rep(c(1, 10), times = 2),
  max = rep(c(100, 1000), each = 2),
  range = target(
    runif(1000, min, max),
    dynamic = map(min, max)
  ),
  out = target(
    func(list(range), min, max),
    dynamic = combine(range, min, max, .by = max)
  )
)

make(plan)
#> target max
#> target min
#> dynamic range
#> subtarget range_1d8ef6a7
#> subtarget range_b7af4aa4
#> subtarget range_4f5b896d
#> subtarget range_36590ee2
#> dynamic out
#> subtarget out_f77512dc
#> subtarget out_6cdbf87f

readd(out)
#> [[1]]
#> [1] "true mins = 1 10"                                  
#> [2] "observed mins = 1.1893078815192 10.0397920585237"  
#> [3] "true maxes = 100 100"                              
#> [4] "observed maxes = 99.8936234710272 99.9091432918794"
#> 
#> [[2]]
#> [1] "true mins = 1 10"                                  
#> [2] "observed mins = 2.94825347024016 10.5835021450184" 
#> [3] "true maxes = 1000 1000"                            
#> [4] "observed maxes = 999.074836849002 999.377815874759"

Created on 2019-11-08 by the reprex package (v0.3.0)

landau
  • 5,636
  • 1
  • 22
  • 50
  • I forgot to mention that dynamic branching is currently only available in the development version: https;//github.com/ropensci/drake – landau Nov 08 '19 at 01:55
  • Thank you! That second alternative is beautiful :), looking forward to the release! – adamski Nov 08 '19 at 07:04
  • Ok not sure I get the dynamic, this doesn't work: ``` func <- function(x, m1, m2) { paste("M1=", m1, "M2=", m2, ": ", mean(unlist(x))) } plan <- drake_plan( min = rep(c(1, 10), times = 2), max = rep(c(100, 1000), each = 2), range = target( runif(1000, min, max), dynamic = map(min, max) ), out = target( func(list(range), min, max), # list(range = range, min = min, max = max), dynamic = combine(range, min, max, .by = max) ), trace = TRUE ) make(plan) ``` It takes mean over total range instead of by max – adamski Nov 08 '19 at 07:35
  • Please see the edit. When you call `func()` it is actually acting on 2 sub-targets at a time. Each element of `x[[1]]` is a vector of uniform random numbers. – landau Nov 08 '19 at 13:56
  • Would you post any follow-up questions to https://github.com/ropensci/drake/issues? Stack Overflow is not designed for extended discussions. – landau Nov 08 '19 at 13:57