From c829fe072b3f42e61e9e67adf53e87a699cc770b Mon Sep 17 00:00:00 2001 From: Jakob Richter Date: Fri, 15 Sep 2017 17:07:45 +0200 Subject: [PATCH 1/8] concept drift layout --- R/OptState_getter.R | 13 ++++++++++ R/evalTargetFun.R | 1 + R/setMBOControlConceptDrift.R | 29 ++++++++++++++++++++++ todo-files/project_conceptdrift.R | 41 +++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 R/setMBOControlConceptDrift.R create mode 100644 todo-files/project_conceptdrift.R diff --git a/R/OptState_getter.R b/R/OptState_getter.R index 98b2df398..9bd16ff0c 100644 --- a/R/OptState_getter.R +++ b/R/OptState_getter.R @@ -133,3 +133,16 @@ getOptStateValidStates = function() { getOptStateValidTerminationStates = function() { c("term.iter", "term.time", "term.exectime", "term.yval", "term.feval", "term.custom") } + +getOpstStateConceptDriftParam = function(opt.state) { + dob = getOptStateLoop(opt.state) + opt.problem = getOptStateOptProblem(opt.state) + control = getOptProblemControl(opt.problem) + if (!is.null(control$conceptdrift.drift.param)) { + res = list(control$conceptdrift.drift.function(dob)) + res = setNames(res, control$conceptdrift.drift.param) + } else { + res = list() + } + res +} diff --git a/R/evalTargetFun.R b/R/evalTargetFun.R index 3f79fb118..a2b5b78a9 100644 --- a/R/evalTargetFun.R +++ b/R/evalTargetFun.R @@ -36,6 +36,7 @@ evalTargetFun.OptState = function(opt.state, xs, extras) { # function to measure of fun call wrapFun = function(x) { st = proc.time() + x = insert(x, getOptStateConceptDriftParam(opt.state)) y = do.call(getOptProblemFun(opt.problem), insert(list(x = x), getOptProblemMoreArgs(opt.problem))) user.extras = list() # here we extract additional stuff which the user wants to log in the opt path diff --git a/R/setMBOControlConceptDrift.R b/R/setMBOControlConceptDrift.R new file mode 100644 index 000000000..571f50b12 --- /dev/null +++ b/R/setMBOControlConceptDrift.R @@ -0,0 +1,29 @@ +#' @title Set concept drift options. +#' @description +#' Extends an MBO control object with options for concept drift in the objective function. +#' @template arg_control +#' @param drift.param [\code{character(1)}]\cr +#' Which parameter determines the drift position we are in? +#' @param drift.function [\code{function}]\cr +#' Function that returns the position in the drift we are in, depending on the dob. +#' @param window.width [\code{integer(1)}]\cr +#' Width (in dobs) of the window that will be used to train the surrogate. +#' @return [\code{\link{MBOControl}}]. +#' @family MBOControl +#' @export +setMBOControlConceptDrift = function(control, + drift.param = NULL, + drift.function = NULL, + window.width = NULL) { + + assertClass(control, "MBOControl") + assertCharacter(drift.param) + assertFunction(drift.function, args = "dob") + assertIntegerish(window.width) + + control$conceptdrift.drift.param = coalesce(drift.param, control$conceptdrift.drift.param) + control$conceptdrift.drift.function = coalesce(drift.function, control$conceptdrift.drift.function) + control$conceptdrift.window.width = coalesce(window.width, control$conceptdrift.window.width) + + return(control) +} diff --git a/todo-files/project_conceptdrift.R b/todo-files/project_conceptdrift.R new file mode 100644 index 000000000..f74fdd9f1 --- /dev/null +++ b/todo-files/project_conceptdrift.R @@ -0,0 +1,41 @@ +library(mlrMBO) +library(ggplot2) +fn = makeBraninFunction() +autoplot(fn, render.levels = TRUE) + +# we will take x1 as a time factor and optimize over x2 + +# questions +# For the intial design, the concept does not change? + +wrapSmoofConceptDrift = function(fn, drift.param, sub.par.set = NULL) { + par.set = getParamSet(fn) + if (drift.param %in% getParamIds(par.set) && is.null(sub.par.set)) { + sub.par.set = dropNamed(par.set, drift.param) + } + fn = setAttribute(fn, "original.par.set", value = par.set) + fn = setAttribute(fn, "original.global.opt.params", attr(fn, "global.opt.params")) + fn = setAttribute(fn, "original.global.opt.value", attr(fn, "global.opt.value")) + fn = setAttribute(fn, "par.set", value = sub.par.set) + fn = setAttribute(fn, "global.opt.params", value = NULL) + fn = setAttribute(fn, "original.global.opt.value", value = NULL) + fn = setAttribute(fn, "drift.param", value = drift.param) + return(fn) +} + +w.fn = wrapSmoofConceptDrift(fn = fn, drift.param = "x1", sub.par.set = makeNumericParamSet(id = "x2", len = 1, lower = 0, upper = 15)) + +slow.drift = function(dob) { + -5 + 0.5 * dob +} + +ctrl = makeMBOControl() +ctrl = setMBOControllConceptDrift( + control = ctrl, + drift.param = "x1", + drift.function = slow.drift, + window.width = 10) + +ps = getParamSet(fn) +dropNamed(ps, "x1") + From 2881c24580850bc8bbfc7356baba637a75bfa8fd Mon Sep 17 00:00:00 2001 From: Jakob Richter Date: Mon, 18 Sep 2017 16:24:22 +0200 Subject: [PATCH 2/8] use OptPathNg --- DESCRIPTION | 3 +- NAMESPACE | 3 + R/OptPathNg.R | 203 +++++++++++++++++++++++++++++++ R/OptState.R | 4 +- R/OptState_getter.R | 5 +- R/subsetOptPath.R | 5 + man/makeMBOControl.Rd | 3 +- man/setMBOControlConceptDrift.Rd | 35 ++++++ man/setMBOControlInfill.Rd | 1 + man/setMBOControlMultiObj.Rd | 1 + man/setMBOControlMultiPoint.Rd | 1 + man/setMBOControlTermination.Rd | 1 + 12 files changed, 259 insertions(+), 6 deletions(-) create mode 100644 R/OptPathNg.R create mode 100644 R/subsetOptPath.R create mode 100644 man/setMBOControlConceptDrift.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 5e4af79e8..9cb8b8b92 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -32,7 +32,8 @@ Imports: checkmate (>= 1.8.2), data.table, lhs, - parallelMap (>= 1.3) + parallelMap (>= 1.3), + R6 Suggests: akima, cmaesr (>= 1.0.3), diff --git a/NAMESPACE b/NAMESPACE index 4461e59bd..886cd5248 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -49,6 +49,7 @@ export(mboContinue) export(mboFinalize) export(plotExampleRun) export(renderExampleRunPlot) +export(setMBOControlConceptDrift) export(setMBOControlInfill) export(setMBOControlMultiObj) export(setMBOControlMultiPoint) @@ -58,12 +59,14 @@ export(trafoSqrt) import(BBmisc) import(ParamHelpers) import(checkmate) +import(data.table) import(grDevices) import(mlr) import(parallelMap) import(smoof) import(stats) import(utils) +importFrom(R6,R6Class) importFrom(lhs,randomLHS) useDynLib(mlrMBO,c_eps_indicator) useDynLib(mlrMBO,c_sms_indicator) diff --git a/R/OptPathNg.R b/R/OptPathNg.R new file mode 100644 index 000000000..7f1c24940 --- /dev/null +++ b/R/OptPathNg.R @@ -0,0 +1,203 @@ +## mlr-org/mlrng/attic/OptPath.R - 18.09.2017 + +#' @importFrom R6 R6Class +#' @import data.table +OptPathNg = R6Class(c("OptPathNg", "OptPath"), + public = list( + initialize = function(par.set, y.names = "y", minimize = TRUE) { + x.names = getParamIds(par.set, repeated = TRUE, with.nr = TRUE) + private$tab = data.table( + dob = integer(0L), + eol = integer(0L), + msg = character(0L), + exec.time = double(0L), + extra = list()) + Map(function(id, type) { + set(private$tab, j = id, value = get(type, mode = "function")()) + }, + id = x.names, + type = getParamTypes(par.set, df.cols = TRUE) + ) + for (y.name in y.names) { + set(private$tab, j = y.name, value = numeric(0L)) + } + names(minimize) = y.names + self$x.names = x.names + self$y.names = y.names + self$par.set = par.set + self$minimize = minimize + }, + + add = function(x, y, dob = NULL, eol = NA_integer_, msg = NA_character_, exec.time = NA_real_, extra = NULL) { + if (private$cache.pos == length(private$cache)) + self$flush() + + cache.pos = private$cache.pos = private$cache.pos + 1L + private$cache[[cache.pos]] = c(x, list(y = y, dob = dob %??% (nrow(private$tab) + cache.pos), + eol = eol, msg = msg, exec.time = exec.time, extra = list(extra))) + }, + + flush = function() { + if (private$cache.pos > 0L) { + cached = rbindlist(head(private$cache, private$cache.pos), fill = TRUE) + private$tab = rbindlist(list(private$tab, cached), fill = TRUE) + setorderv(private$tab, "dob") + private$cache.pos = 0L + } + }, + x.names = NULL, + y.names = NULL, + par.set = NULL, + minimize = NULL + ), + + active = list( + data = function() { + self$flush() + private$tab + }, + env = function() { + self$data + } + ), + + private = list( + cache.pos = 0L, + cache = vector("list", 512L), + tab = NULL + ) +) + +## overwrite creation + +makeOptPathDF = function(par.set, y.names, minimize, add.transformed.x = FALSE, include.error.message = FALSE, include.exec.time = FALSE, include.extra = FALSE) { + if (add.transformed.x == TRUE) { + stop("add.transformed.x == TRUE not supported by OptPathNg") + } + if (include.error.message == FALSE) { + stop("include.error.message == FALSE not supported by OptPathNg") + } + if (include.exec.time == FALSE) { + stop("include.exec.time == FALSE not supported by OptPathNg") + } + if (include.extra == FALSE) { + stop("include.extra == FALSE not supported by OptPathNg") + } + op = OptPathNg$new(par.set, y.names = y.names, minimize = minimize) + return(op) +} + +addOptPathEl.OptPathNg = function(op, x, y, dob = getOptPathLength(op)+1L, eol = NA_integer_, error.message = NA_character_, exec.time = NA_real_, extra = NULL, check.feasible = FALSE) { + if (isTRUE(check.feasible)) { + warning("check.feasible is ignored for OptPathNg") + } + if (any(extractSubList(op$par.set$pars, "len") > 1)) { + x = lapply(x, as.list) + x = unlist(x, recursive = FALSE, use.names = FALSE) + x = setNames(x, getParamIds(op$par.set, repeated = TRUE, with.nr = TRUE)) + } + op$add(x = x, y = y, dob = dob, exec.time = exec.time, eol = eol, msg = error.message, extra = extra) + invisible(op) +} +## overwrite getters of ParamHelpers:: + +getOptPathLength.OptPathNg = function(op) { + nrow(op$data) +} + + +getOptPathExecTimes.OptPathNg = function(op, dob, eol) { + if (!missing(dob) || !missing(eol)) { + error("dob and eol not supported for OptPathNg") + } + op$data$exec.time +} + + +getOptPathX.OptPathNg = function(op, dob, eol) { + if (!missing(dob) || !missing(eol)) { + error("dob and eol not supported for OptPathNg") + } + op$data[,op$x.names, with = FALSE] +} + +getOptPathY.OptPathNg = function(op, names, dob, eol, drop) { + if (!missing(dob) || !missing(eol) || !missing(drop)) { + error("dob, eol and drop not supported for OptPathNg") + } + names = names %??% op$y.names + res = op$data[, names, with = FALSE] + if (ncol(res) == 1) { + res[[1]] + } else { + as.matrix(res) + } +} + +getOptPathDob.OptPathNg = function(op, dob, eol) { + if (!missing(dob) || !missing(eol)) { + error("dob and eol not supported for OptPathNg") + } + op$data$dob +} + + +getOptPathErrorMessages.OptPathNg = function(op, dob, eol) { + if (!missing(dob) || !missing(eol)) { + error("dob and eol not supported for OptPathNg") + } + op$data$msg +} + + +getOptPathEl.OptPathNg = function(op, index) { + x = dfRowToList(df = getOptPathX(op), par.set = op$par.set, i = index) + y = getOptPathY(op) + if (is.matrix(y)) { + y = y[index,] + } else { + y = y[index] + } + res = list(x = x, y = y, dob = op$data$dob[index], eol = op$data$eol[index], error.message = op$data$msg[index], exec.time = op$data$exec.time[index], extra = op$data$extra[index]) +} + +#not supported warnings + +getOptPathCol.OptPathNg = function(op, name, dob = op$env$dob, eol = op$env$eol) { + error("Not supported for OptPathNg!") +} + +getOptPathCols.OptPathNg = function(op, names, dob = op$env$dob, eol = op$env$eol, row.names = NULL) { + error("Not supported for OptPathNg!") +} + +getOptPathEOL.OptPathNg = function(op, dob = op$env$dob, eol = op$env$eol) { + error("Not supported for OptPathNg!") +} + +# data.frame conversion +as.data.frame.OptPathNg = function(x, row.names = NULL, optional, include.x = TRUE, include.y = TRUE, include.rest = TRUE, dob, eol, ...) { + + if (!missing(optional) || !missing(dob) || !missing(eol)) { + stop("optional, dob or eol not supported for OptPathNg") + } + + dt = data.table::copy(x$data) + + if (include.rest == FALSE) { + dt[, c("dob", "eol", "msg", "exec.time", "extra"):=NULL] + } else { + extra = rbindlist(dt$extra) + dt[, "extra" := NULL] + dt = cbind(dt, extra) + } + if (include.x == FALSE) { + dt[, x$x.names := NULL] + } + if (include.y == FALSE) { + dt[, x$y.names := NULL] + } + + as.data.frame(dt, ...) +} + diff --git a/R/OptState.R b/R/OptState.R index bbf52ddb8..2de09f198 100644 --- a/R/OptState.R +++ b/R/OptState.R @@ -59,9 +59,9 @@ makeOptState = function(opt.problem, loop = 0L, tasks = NULL, models = NULL, opt.state$models.loop = -1L #the loop the models where generated opt.state$tasks.loop = -1L #the loop the tasks where generated opt.state$time.model = time.model - opt.state$opt.result = coalesce(opt.result, makeOptResult()) + opt.state$opt.result = opt.result %??% makeOptResult() opt.state$state = state #possible states: init, iter, iter.exceeded, time.exceeded, exec.time.exceeded - opt.state$opt.path = coalesce(opt.path, makeMBOOptPath(opt.problem)) + opt.state$opt.path = opt.path %??% makeMBOOptPath(opt.problem) opt.state$time.last.saved = time.last.saved opt.state$loop.starttime = loop.starttime opt.state$time.used = time.used diff --git a/R/OptState_getter.R b/R/OptState_getter.R index 9bd16ff0c..c82573ec1 100644 --- a/R/OptState_getter.R +++ b/R/OptState_getter.R @@ -62,7 +62,8 @@ getOptStateTimeUsed = function(opt.state) { opt.state$time.used } -getOptStateOptPath = function(opt.state) { +getOptStateOptPath = function(opt.state, ...) { + #subsetOptPath(opt.path = opt.state$opt.path, opt.state = opt.state, ...) opt.state$opt.path } @@ -134,7 +135,7 @@ getOptStateValidTerminationStates = function() { c("term.iter", "term.time", "term.exectime", "term.yval", "term.feval", "term.custom") } -getOpstStateConceptDriftParam = function(opt.state) { +getOptStateConceptDriftParam = function(opt.state) { dob = getOptStateLoop(opt.state) opt.problem = getOptStateOptProblem(opt.state) control = getOptProblemControl(opt.problem) diff --git a/R/subsetOptPath.R b/R/subsetOptPath.R new file mode 100644 index 000000000..78c642f1a --- /dev/null +++ b/R/subsetOptPath.R @@ -0,0 +1,5 @@ +subsetOptPath = function(opt.path, opt.state) { + opt.problem = getOptStateOptProblem(opt.state) + control = getOptProblemControl(opt.problem) + +} diff --git a/man/makeMBOControl.Rd b/man/makeMBOControl.Rd index e3b533944..94e3e3cf8 100644 --- a/man/makeMBOControl.Rd +++ b/man/makeMBOControl.Rd @@ -108,7 +108,8 @@ Format string for the precision of the numeric output of mbo.} Creates a control object for MBO optimization. } \seealso{ -Other MBOControl: \code{\link{setMBOControlInfill}}, +Other MBOControl: \code{\link{setMBOControlConceptDrift}}, + \code{\link{setMBOControlInfill}}, \code{\link{setMBOControlMultiObj}}, \code{\link{setMBOControlMultiPoint}}, \code{\link{setMBOControlTermination}} diff --git a/man/setMBOControlConceptDrift.Rd b/man/setMBOControlConceptDrift.Rd new file mode 100644 index 000000000..ad6cda3a4 --- /dev/null +++ b/man/setMBOControlConceptDrift.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/setMBOControlConceptDrift.R +\name{setMBOControlConceptDrift} +\alias{setMBOControlConceptDrift} +\title{Set concept drift options.} +\usage{ +setMBOControlConceptDrift(control, drift.param = NULL, + drift.function = NULL, window.width = NULL) +} +\arguments{ +\item{control}{[\code{\link{MBOControl}}]\cr +Control object for mbo.} + +\item{drift.param}{[\code{character(1)}]\cr +Which parameter determines the drift position we are in?} + +\item{drift.function}{[\code{function}]\cr +Function that returns the position in the drift we are in, depending on the dob.} + +\item{window.width}{[\code{integer(1)}]\cr +Width (in dobs) of the window that will be used to train the surrogate.} +} +\value{ +[\code{\link{MBOControl}}]. +} +\description{ +Extends an MBO control object with options for concept drift in the objective function. +} +\seealso{ +Other MBOControl: \code{\link{makeMBOControl}}, + \code{\link{setMBOControlInfill}}, + \code{\link{setMBOControlMultiObj}}, + \code{\link{setMBOControlMultiPoint}}, + \code{\link{setMBOControlTermination}} +} diff --git a/man/setMBOControlInfill.Rd b/man/setMBOControlInfill.Rd index b6ccc585a..9f890d05f 100644 --- a/man/setMBOControlInfill.Rd +++ b/man/setMBOControlInfill.Rd @@ -154,6 +154,7 @@ minimizes that. } \seealso{ Other MBOControl: \code{\link{makeMBOControl}}, + \code{\link{setMBOControlConceptDrift}}, \code{\link{setMBOControlMultiObj}}, \code{\link{setMBOControlMultiPoint}}, \code{\link{setMBOControlTermination}} diff --git a/man/setMBOControlMultiObj.Rd b/man/setMBOControlMultiObj.Rd index 4dfba869b..40d147435 100644 --- a/man/setMBOControlMultiObj.Rd +++ b/man/setMBOControlMultiObj.Rd @@ -117,6 +117,7 @@ et.al. (eds.), IEEE, 2005, ISBN 0-7803-9363-5, pp. 2138-2145 } \seealso{ Other MBOControl: \code{\link{makeMBOControl}}, + \code{\link{setMBOControlConceptDrift}}, \code{\link{setMBOControlInfill}}, \code{\link{setMBOControlMultiPoint}}, \code{\link{setMBOControlTermination}} diff --git a/man/setMBOControlMultiPoint.Rd b/man/setMBOControlMultiPoint.Rd index d939eb10f..085a3d903 100644 --- a/man/setMBOControlMultiPoint.Rd +++ b/man/setMBOControlMultiPoint.Rd @@ -86,6 +86,7 @@ Extends an MBO control object with options for multipoint proposal. } \seealso{ Other MBOControl: \code{\link{makeMBOControl}}, + \code{\link{setMBOControlConceptDrift}}, \code{\link{setMBOControlInfill}}, \code{\link{setMBOControlMultiObj}}, \code{\link{setMBOControlTermination}} diff --git a/man/setMBOControlTermination.Rd b/man/setMBOControlTermination.Rd index 0446ec466..60ead7511 100644 --- a/man/setMBOControlTermination.Rd +++ b/man/setMBOControlTermination.Rd @@ -75,6 +75,7 @@ print(res) } \seealso{ Other MBOControl: \code{\link{makeMBOControl}}, + \code{\link{setMBOControlConceptDrift}}, \code{\link{setMBOControlInfill}}, \code{\link{setMBOControlMultiObj}}, \code{\link{setMBOControlMultiPoint}} From c18c35a364168ff807961d64992b29164b1a398e Mon Sep 17 00:00:00 2001 From: Jakob Richter Date: Mon, 18 Sep 2017 17:13:54 +0200 Subject: [PATCH 3/8] remove caching --- R/OptPathNg.R | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/R/OptPathNg.R b/R/OptPathNg.R index 7f1c24940..31ac34bc8 100644 --- a/R/OptPathNg.R +++ b/R/OptPathNg.R @@ -6,20 +6,20 @@ OptPathNg = R6Class(c("OptPathNg", "OptPath"), public = list( initialize = function(par.set, y.names = "y", minimize = TRUE) { x.names = getParamIds(par.set, repeated = TRUE, with.nr = TRUE) - private$tab = data.table( + self$data = data.table( dob = integer(0L), eol = integer(0L), msg = character(0L), exec.time = double(0L), extra = list()) Map(function(id, type) { - set(private$tab, j = id, value = get(type, mode = "function")()) + set(self$data, j = id, value = get(type, mode = "function")()) }, id = x.names, type = getParamTypes(par.set, df.cols = TRUE) ) for (y.name in y.names) { - set(private$tab, j = y.name, value = numeric(0L)) + set(self$data, j = y.name, value = numeric(0L)) } names(minimize) = y.names self$x.names = x.names @@ -29,42 +29,26 @@ OptPathNg = R6Class(c("OptPathNg", "OptPath"), }, add = function(x, y, dob = NULL, eol = NA_integer_, msg = NA_character_, exec.time = NA_real_, extra = NULL) { - if (private$cache.pos == length(private$cache)) - self$flush() - - cache.pos = private$cache.pos = private$cache.pos + 1L - private$cache[[cache.pos]] = c(x, list(y = y, dob = dob %??% (nrow(private$tab) + cache.pos), - eol = eol, msg = msg, exec.time = exec.time, extra = list(extra))) - }, - - flush = function() { - if (private$cache.pos > 0L) { - cached = rbindlist(head(private$cache, private$cache.pos), fill = TRUE) - private$tab = rbindlist(list(private$tab, cached), fill = TRUE) - setorderv(private$tab, "dob") - private$cache.pos = 0L + if (!is.list(y)) { + y = setNames(as.list(y), self$y.names) } + assert_list(x, names = "strict") + assert_list(y, names = "strict") + self$data = rbindlist( + list(self$data, c(list(dob = dob %??% (nrow(self$data) + 1), eol = eol, msg = msg, exec.time = exec.time, extra = list(extra)), x, y)) + ) }, x.names = NULL, y.names = NULL, par.set = NULL, - minimize = NULL + minimize = NULL, + data = NULL ), active = list( - data = function() { - self$flush() - private$tab - }, env = function() { self$data } - ), - - private = list( - cache.pos = 0L, - cache = vector("list", 512L), - tab = NULL ) ) From 3f82faaa8f73812f7403b45b16dd95d2e7129479 Mon Sep 17 00:00:00 2001 From: Jakob Richter Date: Tue, 19 Sep 2017 11:06:05 +0200 Subject: [PATCH 4/8] finish optPathNg replacement --- R/OptPathNg.R | 57 ++++++++++++++++++++++++++-------------- R/evalFinalPoint.R | 2 +- R/filterProposedPoints.R | 2 +- R/proposePointsHelpers.R | 9 +++++++ 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/R/OptPathNg.R b/R/OptPathNg.R index 31ac34bc8..472e01912 100644 --- a/R/OptPathNg.R +++ b/R/OptPathNg.R @@ -92,7 +92,7 @@ getOptPathLength.OptPathNg = function(op) { getOptPathExecTimes.OptPathNg = function(op, dob, eol) { if (!missing(dob) || !missing(eol)) { - error("dob and eol not supported for OptPathNg") + stop("dob and eol not supported for OptPathNg") } op$data$exec.time } @@ -100,35 +100,33 @@ getOptPathExecTimes.OptPathNg = function(op, dob, eol) { getOptPathX.OptPathNg = function(op, dob, eol) { if (!missing(dob) || !missing(eol)) { - error("dob and eol not supported for OptPathNg") + stop("dob and eol not supported for OptPathNg") } op$data[,op$x.names, with = FALSE] } -getOptPathY.OptPathNg = function(op, names, dob, eol, drop) { - if (!missing(dob) || !missing(eol) || !missing(drop)) { - error("dob, eol and drop not supported for OptPathNg") +getOptPathY.OptPathNg = function(op, names, dob, eol, drop = TRUE) { + if (!missing(dob) || !missing(eol)) { + stop("dob, eol and drop not supported for OptPathNg") } names = names %??% op$y.names res = op$data[, names, with = FALSE] - if (ncol(res) == 1) { + if (drop && ncol(res) == 1) { res[[1]] } else { as.matrix(res) } } -getOptPathDob.OptPathNg = function(op, dob, eol) { - if (!missing(dob) || !missing(eol)) { - error("dob and eol not supported for OptPathNg") - } - op$data$dob +getOptPathDOB.OptPathNg = function(op, dob = NULL, eol = NULL) { + dobeol.sub = getOptPathDobAndEolIndex(op, dob, eol) + op$data$dob[dobeol.sub] } getOptPathErrorMessages.OptPathNg = function(op, dob, eol) { if (!missing(dob) || !missing(eol)) { - error("dob and eol not supported for OptPathNg") + stop("dob and eol not supported for OptPathNg") } op$data$msg } @@ -142,36 +140,39 @@ getOptPathEl.OptPathNg = function(op, index) { } else { y = y[index] } - res = list(x = x, y = y, dob = op$data$dob[index], eol = op$data$eol[index], error.message = op$data$msg[index], exec.time = op$data$exec.time[index], extra = op$data$extra[index]) + res = list(x = x, y = y, dob = op$data$dob[index], eol = op$data$eol[index], error.message = op$data$msg[index], exec.time = op$data$exec.time[index], extra = op$data$extra[[index]]) } #not supported warnings getOptPathCol.OptPathNg = function(op, name, dob = op$env$dob, eol = op$env$eol) { - error("Not supported for OptPathNg!") + stop("Not supported for OptPathNg!") } getOptPathCols.OptPathNg = function(op, names, dob = op$env$dob, eol = op$env$eol, row.names = NULL) { - error("Not supported for OptPathNg!") + stop("Not supported for OptPathNg!") } getOptPathEOL.OptPathNg = function(op, dob = op$env$dob, eol = op$env$eol) { - error("Not supported for OptPathNg!") + stop("Not supported for OptPathNg!") } # data.frame conversion -as.data.frame.OptPathNg = function(x, row.names = NULL, optional, include.x = TRUE, include.y = TRUE, include.rest = TRUE, dob, eol, ...) { +as.data.frame.OptPathNg = function(x, row.names = NULL, optional, include.x = TRUE, include.y = TRUE, include.rest = TRUE, dob = NULL, eol = NULL, ...) { - if (!missing(optional) || !missing(dob) || !missing(eol)) { - stop("optional, dob or eol not supported for OptPathNg") + if (!missing(optional)) { + stop("optional is not supported for OptPathNg") } dt = data.table::copy(x$data) + dobeol.sub = getOptPathDobAndEolIndex(x, dob, eol) + dt = dt[dobeol.sub, ] + if (include.rest == FALSE) { dt[, c("dob", "eol", "msg", "exec.time", "extra"):=NULL] } else { - extra = rbindlist(dt$extra) + extra = rbindlist(dt$extra, fill = TRUE) dt[, "extra" := NULL] dt = cbind(dt, extra) } @@ -182,6 +183,22 @@ as.data.frame.OptPathNg = function(x, row.names = NULL, optional, include.x = TR dt[, x$y.names := NULL] } + as.data.frame(dt, ...) } +# helpers +getOptPathDobAndEolIndex = function(op, dob = NULL, eol = NULL) { + if (!is.null(dob)) { + dob.sub = op$data$dob %in% dob + } else { + dob.sub = rep(TRUE, times = nrow(op$data)) + } + + if (!is.null(eol)) { + eol.sub = op$data$eol %in% eol + } else { + eol.sub = rep(TRUE, times = nrow(op$data)) + } + dob.sub & eol.sub +} diff --git a/R/evalFinalPoint.R b/R/evalFinalPoint.R index 0cccd6488..5e17cecfe 100644 --- a/R/evalFinalPoint.R +++ b/R/evalFinalPoint.R @@ -8,7 +8,7 @@ evalFinalPoint = function(opt.state, x.df) { # do some final evaluations and compute mean of target fun values # FIXME: Do we really want the resampling of the last point be part of the opt.path and thus be part of a new model fit if we restart the problem? showInfo(getOptProblemShowInfo(opt.problem), "Performing %i final evals", n) - x.df[seq_len(n), ] = x.df + x.df = x.df[rep(1, times = n), ] prop = makeProposal( control = control, prop.points = x.df, diff --git a/R/filterProposedPoints.R b/R/filterProposedPoints.R index e2456ebb4..4791ce304 100644 --- a/R/filterProposedPoints.R +++ b/R/filterProposedPoints.R @@ -28,7 +28,7 @@ filterProposedPoints = function(prop, opt.state) { # look at min distance from i-point to current set (design + accepted) for (i in seq_len(n)) { - pp = prop$prop.points[i, ] + pp = prop$prop.points[i, , drop = FALSE] min.dist = min(apply(design, 1L, calcMaxMetric, y = pp)) # if too close, mark i-point, otherwise add it to set if (min.dist < control$filter.proposed.points.tol) diff --git a/R/proposePointsHelpers.R b/R/proposePointsHelpers.R index 87ef5462b..6d00568b3 100644 --- a/R/proposePointsHelpers.R +++ b/R/proposePointsHelpers.R @@ -53,6 +53,15 @@ createSinglePointControls = function(control, crit, crit.pars = NULL) { # so we can store (temporary) stuff in it, without changing the real opt.path # needed in CL and DIB multipoint deepCopyOptPath = function(op) { + UseMethod("deepCopyOptPath") +} + +deepCopyOptPath.OptPathNg = function(op) { + op$clone() +} + + +deepCopyOptPath.OptPath = function(op) { op2 = op op2$env = new.env() op2$env$path = op$env$path From b44a33ec04f7795b00b82ca03aa55724077d3de2 Mon Sep 17 00:00:00 2001 From: Jakob Richter Date: Tue, 19 Sep 2017 11:20:30 +0200 Subject: [PATCH 5/8] undo concept drift related stuff --- R/OptState_getter.R | 14 ----------- R/evalTargetFun.R | 1 - R/setMBOControlConceptDrift.R | 29 ---------------------- R/subsetOptPath.R | 5 ---- todo-files/project_conceptdrift.R | 41 ------------------------------- 5 files changed, 90 deletions(-) delete mode 100644 R/setMBOControlConceptDrift.R delete mode 100644 R/subsetOptPath.R delete mode 100644 todo-files/project_conceptdrift.R diff --git a/R/OptState_getter.R b/R/OptState_getter.R index c82573ec1..57540c9b5 100644 --- a/R/OptState_getter.R +++ b/R/OptState_getter.R @@ -63,7 +63,6 @@ getOptStateTimeUsed = function(opt.state) { } getOptStateOptPath = function(opt.state, ...) { - #subsetOptPath(opt.path = opt.state$opt.path, opt.state = opt.state, ...) opt.state$opt.path } @@ -134,16 +133,3 @@ getOptStateValidStates = function() { getOptStateValidTerminationStates = function() { c("term.iter", "term.time", "term.exectime", "term.yval", "term.feval", "term.custom") } - -getOptStateConceptDriftParam = function(opt.state) { - dob = getOptStateLoop(opt.state) - opt.problem = getOptStateOptProblem(opt.state) - control = getOptProblemControl(opt.problem) - if (!is.null(control$conceptdrift.drift.param)) { - res = list(control$conceptdrift.drift.function(dob)) - res = setNames(res, control$conceptdrift.drift.param) - } else { - res = list() - } - res -} diff --git a/R/evalTargetFun.R b/R/evalTargetFun.R index a2b5b78a9..3f79fb118 100644 --- a/R/evalTargetFun.R +++ b/R/evalTargetFun.R @@ -36,7 +36,6 @@ evalTargetFun.OptState = function(opt.state, xs, extras) { # function to measure of fun call wrapFun = function(x) { st = proc.time() - x = insert(x, getOptStateConceptDriftParam(opt.state)) y = do.call(getOptProblemFun(opt.problem), insert(list(x = x), getOptProblemMoreArgs(opt.problem))) user.extras = list() # here we extract additional stuff which the user wants to log in the opt path diff --git a/R/setMBOControlConceptDrift.R b/R/setMBOControlConceptDrift.R deleted file mode 100644 index 571f50b12..000000000 --- a/R/setMBOControlConceptDrift.R +++ /dev/null @@ -1,29 +0,0 @@ -#' @title Set concept drift options. -#' @description -#' Extends an MBO control object with options for concept drift in the objective function. -#' @template arg_control -#' @param drift.param [\code{character(1)}]\cr -#' Which parameter determines the drift position we are in? -#' @param drift.function [\code{function}]\cr -#' Function that returns the position in the drift we are in, depending on the dob. -#' @param window.width [\code{integer(1)}]\cr -#' Width (in dobs) of the window that will be used to train the surrogate. -#' @return [\code{\link{MBOControl}}]. -#' @family MBOControl -#' @export -setMBOControlConceptDrift = function(control, - drift.param = NULL, - drift.function = NULL, - window.width = NULL) { - - assertClass(control, "MBOControl") - assertCharacter(drift.param) - assertFunction(drift.function, args = "dob") - assertIntegerish(window.width) - - control$conceptdrift.drift.param = coalesce(drift.param, control$conceptdrift.drift.param) - control$conceptdrift.drift.function = coalesce(drift.function, control$conceptdrift.drift.function) - control$conceptdrift.window.width = coalesce(window.width, control$conceptdrift.window.width) - - return(control) -} diff --git a/R/subsetOptPath.R b/R/subsetOptPath.R deleted file mode 100644 index 78c642f1a..000000000 --- a/R/subsetOptPath.R +++ /dev/null @@ -1,5 +0,0 @@ -subsetOptPath = function(opt.path, opt.state) { - opt.problem = getOptStateOptProblem(opt.state) - control = getOptProblemControl(opt.problem) - -} diff --git a/todo-files/project_conceptdrift.R b/todo-files/project_conceptdrift.R deleted file mode 100644 index f74fdd9f1..000000000 --- a/todo-files/project_conceptdrift.R +++ /dev/null @@ -1,41 +0,0 @@ -library(mlrMBO) -library(ggplot2) -fn = makeBraninFunction() -autoplot(fn, render.levels = TRUE) - -# we will take x1 as a time factor and optimize over x2 - -# questions -# For the intial design, the concept does not change? - -wrapSmoofConceptDrift = function(fn, drift.param, sub.par.set = NULL) { - par.set = getParamSet(fn) - if (drift.param %in% getParamIds(par.set) && is.null(sub.par.set)) { - sub.par.set = dropNamed(par.set, drift.param) - } - fn = setAttribute(fn, "original.par.set", value = par.set) - fn = setAttribute(fn, "original.global.opt.params", attr(fn, "global.opt.params")) - fn = setAttribute(fn, "original.global.opt.value", attr(fn, "global.opt.value")) - fn = setAttribute(fn, "par.set", value = sub.par.set) - fn = setAttribute(fn, "global.opt.params", value = NULL) - fn = setAttribute(fn, "original.global.opt.value", value = NULL) - fn = setAttribute(fn, "drift.param", value = drift.param) - return(fn) -} - -w.fn = wrapSmoofConceptDrift(fn = fn, drift.param = "x1", sub.par.set = makeNumericParamSet(id = "x2", len = 1, lower = 0, upper = 15)) - -slow.drift = function(dob) { - -5 + 0.5 * dob -} - -ctrl = makeMBOControl() -ctrl = setMBOControllConceptDrift( - control = ctrl, - drift.param = "x1", - drift.function = slow.drift, - window.width = 10) - -ps = getParamSet(fn) -dropNamed(ps, "x1") - From a727cb27be9351abf5e30f537501097dd21d1252 Mon Sep 17 00:00:00 2001 From: Jakob Richter Date: Tue, 19 Sep 2017 11:23:58 +0200 Subject: [PATCH 6/8] tidy up --- NAMESPACE | 1 - R/OptState_getter.R | 2 +- man/makeMBOControl.Rd | 3 +-- man/setMBOControlConceptDrift.Rd | 35 -------------------------------- man/setMBOControlInfill.Rd | 1 - man/setMBOControlMultiObj.Rd | 1 - man/setMBOControlMultiPoint.Rd | 1 - man/setMBOControlTermination.Rd | 1 - 8 files changed, 2 insertions(+), 43 deletions(-) delete mode 100644 man/setMBOControlConceptDrift.Rd diff --git a/NAMESPACE b/NAMESPACE index 886cd5248..cf308a2a2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -49,7 +49,6 @@ export(mboContinue) export(mboFinalize) export(plotExampleRun) export(renderExampleRunPlot) -export(setMBOControlConceptDrift) export(setMBOControlInfill) export(setMBOControlMultiObj) export(setMBOControlMultiPoint) diff --git a/R/OptState_getter.R b/R/OptState_getter.R index 57540c9b5..98b2df398 100644 --- a/R/OptState_getter.R +++ b/R/OptState_getter.R @@ -62,7 +62,7 @@ getOptStateTimeUsed = function(opt.state) { opt.state$time.used } -getOptStateOptPath = function(opt.state, ...) { +getOptStateOptPath = function(opt.state) { opt.state$opt.path } diff --git a/man/makeMBOControl.Rd b/man/makeMBOControl.Rd index 94e3e3cf8..e3b533944 100644 --- a/man/makeMBOControl.Rd +++ b/man/makeMBOControl.Rd @@ -108,8 +108,7 @@ Format string for the precision of the numeric output of mbo.} Creates a control object for MBO optimization. } \seealso{ -Other MBOControl: \code{\link{setMBOControlConceptDrift}}, - \code{\link{setMBOControlInfill}}, +Other MBOControl: \code{\link{setMBOControlInfill}}, \code{\link{setMBOControlMultiObj}}, \code{\link{setMBOControlMultiPoint}}, \code{\link{setMBOControlTermination}} diff --git a/man/setMBOControlConceptDrift.Rd b/man/setMBOControlConceptDrift.Rd deleted file mode 100644 index ad6cda3a4..000000000 --- a/man/setMBOControlConceptDrift.Rd +++ /dev/null @@ -1,35 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/setMBOControlConceptDrift.R -\name{setMBOControlConceptDrift} -\alias{setMBOControlConceptDrift} -\title{Set concept drift options.} -\usage{ -setMBOControlConceptDrift(control, drift.param = NULL, - drift.function = NULL, window.width = NULL) -} -\arguments{ -\item{control}{[\code{\link{MBOControl}}]\cr -Control object for mbo.} - -\item{drift.param}{[\code{character(1)}]\cr -Which parameter determines the drift position we are in?} - -\item{drift.function}{[\code{function}]\cr -Function that returns the position in the drift we are in, depending on the dob.} - -\item{window.width}{[\code{integer(1)}]\cr -Width (in dobs) of the window that will be used to train the surrogate.} -} -\value{ -[\code{\link{MBOControl}}]. -} -\description{ -Extends an MBO control object with options for concept drift in the objective function. -} -\seealso{ -Other MBOControl: \code{\link{makeMBOControl}}, - \code{\link{setMBOControlInfill}}, - \code{\link{setMBOControlMultiObj}}, - \code{\link{setMBOControlMultiPoint}}, - \code{\link{setMBOControlTermination}} -} diff --git a/man/setMBOControlInfill.Rd b/man/setMBOControlInfill.Rd index 9f890d05f..b6ccc585a 100644 --- a/man/setMBOControlInfill.Rd +++ b/man/setMBOControlInfill.Rd @@ -154,7 +154,6 @@ minimizes that. } \seealso{ Other MBOControl: \code{\link{makeMBOControl}}, - \code{\link{setMBOControlConceptDrift}}, \code{\link{setMBOControlMultiObj}}, \code{\link{setMBOControlMultiPoint}}, \code{\link{setMBOControlTermination}} diff --git a/man/setMBOControlMultiObj.Rd b/man/setMBOControlMultiObj.Rd index 40d147435..4dfba869b 100644 --- a/man/setMBOControlMultiObj.Rd +++ b/man/setMBOControlMultiObj.Rd @@ -117,7 +117,6 @@ et.al. (eds.), IEEE, 2005, ISBN 0-7803-9363-5, pp. 2138-2145 } \seealso{ Other MBOControl: \code{\link{makeMBOControl}}, - \code{\link{setMBOControlConceptDrift}}, \code{\link{setMBOControlInfill}}, \code{\link{setMBOControlMultiPoint}}, \code{\link{setMBOControlTermination}} diff --git a/man/setMBOControlMultiPoint.Rd b/man/setMBOControlMultiPoint.Rd index 085a3d903..d939eb10f 100644 --- a/man/setMBOControlMultiPoint.Rd +++ b/man/setMBOControlMultiPoint.Rd @@ -86,7 +86,6 @@ Extends an MBO control object with options for multipoint proposal. } \seealso{ Other MBOControl: \code{\link{makeMBOControl}}, - \code{\link{setMBOControlConceptDrift}}, \code{\link{setMBOControlInfill}}, \code{\link{setMBOControlMultiObj}}, \code{\link{setMBOControlTermination}} diff --git a/man/setMBOControlTermination.Rd b/man/setMBOControlTermination.Rd index 60ead7511..0446ec466 100644 --- a/man/setMBOControlTermination.Rd +++ b/man/setMBOControlTermination.Rd @@ -75,7 +75,6 @@ print(res) } \seealso{ Other MBOControl: \code{\link{makeMBOControl}}, - \code{\link{setMBOControlConceptDrift}}, \code{\link{setMBOControlInfill}}, \code{\link{setMBOControlMultiObj}}, \code{\link{setMBOControlMultiPoint}} From 1445b3bd5125d08960a8905940446cd6d83ab228 Mon Sep 17 00:00:00 2001 From: Jakob Richter Date: Tue, 19 Sep 2017 11:36:17 +0200 Subject: [PATCH 7/8] exports --- NAMESPACE | 12 ++++++++++++ R/OptPathNg.R | 17 +++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index cf308a2a2..621f26d12 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,17 @@ # Generated by roxygen2: do not edit by hand +S3method(addOptPathEl,OptPathNg) +S3method(as.data.frame,OptPathNg) +S3method(getOptPathCol,OptPathNg) +S3method(getOptPathCols,OptPathNg) +S3method(getOptPathDOB,OptPathNg) +S3method(getOptPathEOL,OptPathNg) +S3method(getOptPathEl,OptPathNg) +S3method(getOptPathErrorMessages,OptPathNg) +S3method(getOptPathExecTimes,OptPathNg) +S3method(getOptPathLength,OptPathNg) +S3method(getOptPathX,OptPathNg) +S3method(getOptPathY,OptPathNg) S3method(initCrit,InfillCritCB) S3method(initCrit,default) S3method(plot,MBOMultiObjResult) diff --git a/R/OptPathNg.R b/R/OptPathNg.R index 472e01912..26f98be45 100644 --- a/R/OptPathNg.R +++ b/R/OptPathNg.R @@ -71,6 +71,7 @@ makeOptPathDF = function(par.set, y.names, minimize, add.transformed.x = FALSE, return(op) } +#' @export addOptPathEl.OptPathNg = function(op, x, y, dob = getOptPathLength(op)+1L, eol = NA_integer_, error.message = NA_character_, exec.time = NA_real_, extra = NULL, check.feasible = FALSE) { if (isTRUE(check.feasible)) { warning("check.feasible is ignored for OptPathNg") @@ -85,11 +86,12 @@ addOptPathEl.OptPathNg = function(op, x, y, dob = getOptPathLength(op)+1L, eol = } ## overwrite getters of ParamHelpers:: +#' @export getOptPathLength.OptPathNg = function(op) { nrow(op$data) } - +#' @export getOptPathExecTimes.OptPathNg = function(op, dob, eol) { if (!missing(dob) || !missing(eol)) { stop("dob and eol not supported for OptPathNg") @@ -97,7 +99,7 @@ getOptPathExecTimes.OptPathNg = function(op, dob, eol) { op$data$exec.time } - +#' @export getOptPathX.OptPathNg = function(op, dob, eol) { if (!missing(dob) || !missing(eol)) { stop("dob and eol not supported for OptPathNg") @@ -105,6 +107,7 @@ getOptPathX.OptPathNg = function(op, dob, eol) { op$data[,op$x.names, with = FALSE] } +#' @export getOptPathY.OptPathNg = function(op, names, dob, eol, drop = TRUE) { if (!missing(dob) || !missing(eol)) { stop("dob, eol and drop not supported for OptPathNg") @@ -118,12 +121,13 @@ getOptPathY.OptPathNg = function(op, names, dob, eol, drop = TRUE) { } } +#' @export getOptPathDOB.OptPathNg = function(op, dob = NULL, eol = NULL) { dobeol.sub = getOptPathDobAndEolIndex(op, dob, eol) op$data$dob[dobeol.sub] } - +#' @export getOptPathErrorMessages.OptPathNg = function(op, dob, eol) { if (!missing(dob) || !missing(eol)) { stop("dob and eol not supported for OptPathNg") @@ -131,7 +135,7 @@ getOptPathErrorMessages.OptPathNg = function(op, dob, eol) { op$data$msg } - +#' @export getOptPathEl.OptPathNg = function(op, index) { x = dfRowToList(df = getOptPathX(op), par.set = op$par.set, i = index) y = getOptPathY(op) @@ -145,19 +149,24 @@ getOptPathEl.OptPathNg = function(op, index) { #not supported warnings +#' @export getOptPathCol.OptPathNg = function(op, name, dob = op$env$dob, eol = op$env$eol) { stop("Not supported for OptPathNg!") } +#' @export getOptPathCols.OptPathNg = function(op, names, dob = op$env$dob, eol = op$env$eol, row.names = NULL) { stop("Not supported for OptPathNg!") } +#' @export getOptPathEOL.OptPathNg = function(op, dob = op$env$dob, eol = op$env$eol) { stop("Not supported for OptPathNg!") } # data.frame conversion + +#' @export as.data.frame.OptPathNg = function(x, row.names = NULL, optional, include.x = TRUE, include.y = TRUE, include.rest = TRUE, dob = NULL, eol = NULL, ...) { if (!missing(optional)) { From df4cc89bc10cd3533bca7db3e05d23582bad228e Mon Sep 17 00:00:00 2001 From: Jakob Richter Date: Tue, 19 Sep 2017 17:28:39 +0200 Subject: [PATCH 8/8] subset optPath --- R/OptPathNg.R | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/R/OptPathNg.R b/R/OptPathNg.R index 26f98be45..2a4ca7911 100644 --- a/R/OptPathNg.R +++ b/R/OptPathNg.R @@ -211,3 +211,18 @@ getOptPathDobAndEolIndex = function(op, dob = NULL, eol = NULL) { } dob.sub & eol.sub } + + + +# WARNING: Obviously subsetting an OptPath can result in objects that do not resemble what we expect from an OptPath +`[.OptPathNg` = function(x, ...) { + z = x$clone() + z$data = '['(z$data, ...) + z +} + +`[[.OptPathNg` = function(x, ...) { + z = x$clone() + z$data = '[['(z$data, ...) + z +}