Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Suggests:
Encoding: UTF-8
NeedsCompilation: no
Roxygen: list(markdown = TRUE, r6 = FALSE)
RoxygenNote: 7.0.0
RoxygenNote: 7.0.2
Collate:
'Condition.R'
'Design.R'
Expand Down
19 changes: 16 additions & 3 deletions R/ParamSet.R
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@
#' Three \pkg{checkmate}-like check-functions. Takes a named list.
#' A point x is feasible, if it configures a subset of params,
#' all individual param constraints are satisfied and all dependencies are satisfied.
#' Please note that a dependency for param B, which depends on param A, can be satisfied in two ways:
#' Either A is correctly set in 'x' (for B to become active) or A's default value satisfies the dependency condition of B and A is unset in 'x'.
#' Params for which dependencies are not satisfied should not be part of `x`.
#' * `add_dep(id, on, cond)` \cr
#' (`character(1)`, `character(1)`, [Condition]) -> `self` \cr
Expand Down Expand Up @@ -244,7 +246,18 @@ ParamSet = R6Class("ParamSet",
}
}


# check dependencies
# this is a bit more complex. sometimes users set param B to a value, where B depends on param A. A is not set by the user,
# but its default value is already ok in the sense that B's condition if fulfilled.
# hence, to simulate this for the check, we do this.
# we insert all new user values into the default vector. then run thru all condiztion in the set. if a condition is places on a param
# whioch the user has passed, we check if its ok in the extended settings-vector
defs = self$default
vals_with_defs = insert_named(defs, xs)
ids_passed_params = names(xs)
ids_passed_and_defs = names(vals_with_defs)

if (self$has_deps) {
deps = self$deps
for (j in seq_row(self$deps)) {
Expand All @@ -254,10 +267,10 @@ ParamSet = R6Class("ParamSet",
# - if param is there, then parent must be there, then cond must be true
# - if param is not there
cond = deps$cond[[j]]
ok = (p1id %in% ns && p2id %in% ns && cond$test(xs[[p2id]])) ||
(p1id %nin% ns)
ok = (p1id %in% ids_passed_params && p2id %in% ids_passed_and_defs && cond$test(vals_with_defs[[p2id]])) ||
(p1id %nin% ids_passed_params)
if (isFALSE(ok)) {
val = xs[[p2id]]
val = vals_with_defs[[p2id]]
val = ifelse(is.null(val), "<not-there>", val)
return(sprintf("Condition for '%s' not ok: %s %s %s; instead: %s=%s",
p1id, p2id, cond$type, str_collapse(cond$rhs), p2id, val))
Expand Down
2 changes: 2 additions & 0 deletions man/ParamSet.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/Sampler1DRfun.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 41 additions & 5 deletions tests/testthat/test_deps.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ context("Dependencies")
test_that("basic example works", {
ps = th_paramset_full()
expect_false(ps$has_deps)
ps$add_dep("th_param_int", on = "th_param_fct", CondEqual$new("a"))
ps$add_dep("th_param_int", on = "th_param_fct", CondEqual$new("b"))
expect_true(ps$has_deps)
x = list(th_param_int = 1)
expect_string(ps$check(x), fixed = "Condition for 'th_param_int'")
x = list(th_param_int = 1, th_param_fct = "a")
expect_true(ps$check(x))
x = list(th_param_int = 1, th_param_fct = "b")
expect_true(ps$check(x))
x = list(th_param_int = 1, th_param_fct = "a")
expect_string(ps$check(x), fixed = "Condition for 'th_param_int'")
x = list(th_param_int = NA, th_param_fct = "b")
expect_string(ps$check(x), fixed = "May not be NA")
Expand All @@ -35,15 +35,15 @@ test_that("basic example works", {

test_that("nested deps work", {
ps = th_paramset_full()
ps$add_dep("th_param_int", on = "th_param_fct", CondAnyOf$new(c("a", "b")))
ps$add_dep("th_param_int", on = "th_param_fct", CondAnyOf$new(c("b", "c")))
ps$add_dep("th_param_dbl", on = "th_param_lgl", CondEqual$new(TRUE))
ps$add_dep("th_param_lgl", on = "th_param_fct", CondEqual$new("c"))

x1 = list(th_param_int = 1)
expect_string(ps$check(x1), fixed = "Condition for 'th_param_int'")
x2 = list(th_param_int = 1, th_param_fct = "b")
expect_true(ps$check(x2))
x3 = list(th_param_int = 1, th_param_fct = "c")
x3 = list(th_param_int = 1, th_param_fct = "a")
expect_string(ps$check(x3), fixed = "Condition for 'th_param_int'")
x4 = list(th_param_fct = "a")
expect_true(ps$check(x4))
Expand Down Expand Up @@ -118,3 +118,39 @@ test_that("deps make sense", {
expect_error(ps$add_dep("th_param_lgl", "th_param_fct", CondEqual$new("d")), "Condition has infeasible values for th_param_fct")
expect_error(ps$add_dep("th_param_lgl", "th_param_int", CondAnyOf$new(5:15)), "Condition has infeasible values for th_param_int")
})


test_that("deps / check works inplicitly on defaults", {
# see also this issue https://github.com/mlr-org/paradox/issues/259

# no defaults, simpler case, we just check 'whats really passed by the user'
ps = ParamSet$new(list(
ParamFct$new("x", levels = c("a", "b")),
ParamDbl$new("y")
))
ps$add_dep("y", on = "x", CondEqual$new("a"))
expect_true(ps$check(list(x = "a", y = 1)))
expect_string(ps$check(list(x = "b", y = 1)), pattern = "Condition")
expect_string(ps$check(list(y = 1)), pattern = "Condition")

# we now set a default on "x" (which implicitly allows 'y')
ps = ParamSet$new(list(
ParamFct$new("x", levels = c("a", "b"), default = "a"),
ParamDbl$new("y")
))
ps$add_dep("y", on = "x", CondEqual$new("a"))
expect_true(ps$check(list(x = "a", y = 1)))
expect_string(ps$check(list(x = "b", y = 1)), pattern = "Condition")
expect_true(ps$check(list(y = 1)))

# we now set a default on "x" (which not implicitly allows 'y')
ps = ParamSet$new(list(
ParamFct$new("x", levels = c("a", "b"), default = "b"),
ParamDbl$new("y")
))
ps$add_dep("y", on = "x", CondEqual$new("a"))
expect_true(ps$check(list(x = "a", y = 1)))
expect_string(ps$check(list(x = "b", y = 1)), pattern = "Condition")
expect_string(ps$check(list(y = 1)), pattern = "Condition")
})