-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add convertToMaximization and convertToMinimization helpers
- Loading branch information
1 parent
09c2f81
commit 2af5216
Showing
4 changed files
with
155 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#' @title | ||
#' Conversion between minimization and maximization problems. | ||
#' | ||
#' @description | ||
#' We can minimize f by maximizing -f. The majority of predefined objective functions | ||
#' in \pkg{smoof} should be minimized by default. However, there is a handful of | ||
#' functions, e.g., Keane or Alpine02, which shall be maximized by default. | ||
#' For benchmarking studies it might be beneficial to inverse the direction. | ||
#' The functions \code{convertToMaximization} and \code{convertToMinimization} | ||
#' do exactly that keeping the attributes. | ||
#' | ||
#' @note | ||
#' Internally no wrapper is put around the original function. Instead the function | ||
#' is copied and the body of the function is manipulated via the \code{body} function. | ||
#' Both functions will quit with an error if multi-objective functions are passed. | ||
#' | ||
#' @param fn [\code{smoof_function}]\cr | ||
#' Smoof function. | ||
#' @return [\code{smoof_function}] | ||
#' @examples | ||
#' # create a function which should be minimized by default | ||
#' fn = makeSphereFunction(1L) | ||
#' print(shouldBeMinimized(fn)) | ||
#' # Now invert the objective direction ... | ||
#' fn2 = convertToMaximization(fn) | ||
#' # and invert it again | ||
#' fn3 = convertToMinimization(fn2) | ||
#' # Now to convince ourselves we render some plots | ||
#' opar = par(mfrow = c(1, 3)) | ||
#' plot(fn) | ||
#' plot(fn2) | ||
#' plot(fn3) | ||
#' par(opar) | ||
#' @name conversion | ||
#' @rdname conversion | ||
#' @export | ||
convertToMaximization = function(fn) { | ||
convertProblemDirection(fn, minimize.after = FALSE) | ||
} | ||
|
||
#' @rdname conversion | ||
#' @export | ||
convertToMinimization = function(fn) { | ||
convertProblemDirection(fn, minimize.after = TRUE) | ||
} | ||
|
||
convertProblemDirection = function(fn, minimize.after = TRUE) { | ||
if (isMultiobjective(fn)) { | ||
stopf("Conversion to maximization only supported for single-objective problems | ||
at the moment, but your function '%s' has %i", getName(fn), getNumberOfObjectives(fn)) | ||
} | ||
|
||
# If both are true, we want to convert min to min | ||
# If both are false, we want to convert max to max | ||
# Otherwise the conversion is ok | ||
if ((shouldBeMinimized(fn) && minimize.after) || (!shouldBeMinimized(fn) && !minimize.after)) { | ||
stopf("Function should already be %s.", (if (minimize.after) "minimized" else "maximized")) | ||
} | ||
|
||
# make copy of function | ||
fn2 = fn | ||
|
||
# multiply function body with -1 | ||
body(fn2) = substitute(-1 * FUN, list(FUN = body(fn))) | ||
|
||
# copy attributes (get dropped on body() call) | ||
attributes(fn2) = attributes(fn) | ||
|
||
# flip maximization stuff | ||
fn2 = setAttribute(fn2, "minimize", !shouldBeMinimized(fn)) | ||
return(fn2) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
context("conversion of minimization to maximization problem and vice versa") | ||
|
||
test_that("min<->max conversion works as expected", { | ||
# test function set | ||
funs = list( | ||
makeSphereFunction(1L), | ||
makeAckleyFunction(1L), | ||
makeRastriginFunction(1L) | ||
) | ||
|
||
checkSumOfMinMaxValuesVanishes = function(fun1, fun2, fun.name) { | ||
# generate some random parameters within the box constraints | ||
lb = getLowerBoxConstraints(fun) | ||
ub = getUpperBoxConstraints(fun) | ||
rnds = runif(50, min = lb, max = ub) | ||
|
||
# build sum (since f(x) + (-f(x)) = 0 should hold) | ||
sums = sapply(rnds, function(x) fun1(x) + fun2(x)) | ||
expect_true(all(sums < 0.0001), info = sprintf("Function value differences are not equal to 0 for function %s.", getName(fun))) | ||
expect_true(shouldBeMinimized(fun1) != shouldBeMinimized(fun2)) | ||
} | ||
|
||
for (fun in funs) { | ||
# convert to maximization problem and check if function values changed | ||
fun2 = convertToMaximization(fun) | ||
checkSumOfMinMaxValuesVanishes(fun, fun2, getName(fun)) | ||
|
||
# convert back | ||
expect_error(convertToMaximization(fun2)) | ||
fun3 = convertToMinimization(fun2) | ||
checkSumOfMinMaxValuesVanishes(fun2, fun3, getName(fun)) | ||
} | ||
}) |