-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
TerminatorCombo.R
121 lines (111 loc) · 3.59 KB
/
TerminatorCombo.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#' @title Combine Terminators
#'
#' @name mlr_terminators_combo
#' @include Terminator.R
#'
#' @description
#' This class takes multiple [Terminator]s and terminates as soon as one or all
#' of the included terminators are positive.
#'
#' @templateVar id combo
#' @template section_dictionary_terminator
#'
#' @section Parameters:
#' \describe{
#' \item{`any`}{`logical(1)`\cr
#' Terminate iff any included terminator is positive? (not all).
#' Default is `TRUE`.}
#' }
#'
#' @family Terminator
#'
#' @template param_archive
#'
#' @export
#' @examples
#' trm("combo",
#' list(trm("clock_time", stop_time = Sys.time() + 60),
#' trm("evals", n_evals = 10)), any = FALSE
#' )
TerminatorCombo = R6Class("TerminatorCombo",
inherit = Terminator,
public = list(
#' @field terminators (`list()`)\cr
#' List of objects of class [Terminator].
terminators = NULL,
#' @description
#' Creates a new instance of this [R6][R6::R6Class] class.
#'
#' @param terminators (`list()`)\cr
#' List of objects of class [Terminator].
initialize = function(terminators = list(TerminatorNone$new())) {
self$terminators = assert_list(terminators, types = "Terminator", min.len = 1L)
param_set = ps(
any = p_lgl(tags = "required")
)
param_set$values = list(any = TRUE)
properties = Reduce(intersect, map(terminators, "properties"))
properties = properties[properties != "progressr"]
super$initialize(
id = "combo",
param_set = param_set,
properties = properties,
unit = "percent",
label = "Combination",
man = "bbotk::mlr_terminators_combo")
},
#' @description
#' Is `TRUE` iff the termination criterion is positive, and `FALSE`
#' otherwise.
#'
#' @return `logical(1)`.
is_terminated = function(archive) {
assert_multi_class(archive, c("Archive", "ArchiveAsync"))
g = if (self$param_set$values$any) any else all
g(map_lgl(self$terminators, function(t) t$is_terminated(archive)))
},
#' @description
#' Printer.
#'
#' @param ... (ignored).
print = function(...) {
super$print(...)
catf(str_indent("* Terminators:", paste(map_chr(self$terminators, format),
collapse = ",")))
},
#' @description
#' Returns the remaining runtime in seconds. If `any = TRUE`, the remaining
#' runtime is determined by the time-based terminator with the shortest time
#' remaining. If non-time-based terminators are used and `any = FALSE`,
#' the the remaining runtime is always `Inf`.
#'
#' @return `integer(1)`.
remaining_time = function(archive) {
assert_r6(archive, "Archive")
min_max = if (self$param_set$values$any) min else max
min_max(map_dbl(self$terminators, function(t) t$remaining_time(archive)), na.rm = TRUE)
},
#' @description
#' Returns `max_steps` and `current_steps` for each terminator.
#'
#' @return [data.table::data.table].
status_long = function(archive) {
assert_r6(archive, "Archive")
map_dtr(self$terminators, function(t) {
cbind(as.data.table(as.list(t$status(archive))), unit = t$unit)
})
}
),
private = list(
.status = function(archive) {
max_steps = 100
min_max = if (self$param_set$values$any) max else min
current_steps = min_max(map_int(self$terminators, function(t) {
status = t$status(archive)
as.integer(status["current_steps"] / status["max_steps"] * 100)
}))
c("max_steps" = max_steps, "current_steps" = current_steps)
}
)
)
mlr_terminators$add("combo", TerminatorCombo)