Skip to content

Commit

Permalink
introduce setupEvolutionaryOperators (stepwise construction of contro…
Browse files Browse the repository at this point in the history
…l object)
  • Loading branch information
jakobbossek committed Apr 14, 2015
1 parent dafe87b commit bf650e2
Show file tree
Hide file tree
Showing 18 changed files with 237 additions and 147 deletions.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export(makeStoppingCondition)
export(makeSwapMutator)
export(makeUniformGenerator)
export(setupECRControl)
export(setupEvolutionaryOperators)
export(setupStoppingConditions)
import(BBmisc)
import(ParamHelpers)
Expand Down
2 changes: 2 additions & 0 deletions R/doTheEvolution.R
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
#' representation = "float",
#' stopping.conditions = setupStoppingConditions(max.iter = 100L)
#' )
#' # use the default operators for representation "float"
#' ctrl = setupEvolutionaryOperators(ctrl)
#'
#' res = doTheEvolution(obj.fn, control = ctrl)
#' print(res)
Expand Down
93 changes: 4 additions & 89 deletions R/ecrControl.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,6 @@
#' Name for the objective fun values. Default is \dQuote{y}.
#' @param save.population.at [\code{integer}]\cr
#' Which populations should be saved? Default is none.
#' @param selector [\code{function}]\cr
#' Generator operator which implements a procedure to copy individuals from a
#' given population to the mating pool, i. e., allow them to become parents.
#' @param generator [\code{ecr_generator}]\cr
#' Generator operator of type \code{ecr_generator} for the generation of the initial
#' population.
#' @param mutator [\code{ecr_mutator}]\cr
#' Mutation operator of type \code{ecr_mutator}.
#' @param mutationStrategyAdaptor [\code{function}]\cr
#' This is an experimental parameter. Hence, you should be careful when using it.
#' Serves to offer the possibility to adapt parameters of the mutation algorithm
#' (e. g. mutation stepsize \eqn{\sigma} for Gaussian mutation) in each iteration.
#' The function needs to expect the parameters \dQuote{operator.control} and
#' \dQuote{opt.path}, the last being of type \code{\link[ParamHelpers]{OptPath}} and
#' must return the modified \dQuote{operator.control} object. The default does
#' nothing.
#' @param recombinator [\code{ecr_recombinator}]\cr
#' Recombination operator of type \code{ecr_recombinator}.
#' @param mutator.control [\code{list}]\cr
#' List of evolutionary parameters for the corresponding mutation operator. See the
#' help pages for the mutation operators for the needed values.
#' @param recombinator.control [\code{list}]\cr
#' List of evolutionary parameters for the corresponding recombination operator. See the
#' help pages for the recombination operators for the needed values.
#' @param monitor [\code{function}]\cr
#' Monitoring function. Default is \code{consoleMonitor}.
#' @param stopping.conditions [\code{list}]\cr
Expand All @@ -68,15 +44,6 @@ setupECRControl = function(
n.params,
target.name = "y",
save.population.at = integer(0),
selector = simpleMatingPoolGenerator,
generator = makeUniformGenerator(),
mutator = makeGaussMutator(),
mutationStrategyAdaptor = function(operator.control, opt.path) {
return(operator.control)
},
recombinator = makeIntermediateRecombinator(),
mutator.control = list(),
recombinator.control = list(),
monitor = makeConsoleMonitor(),
stopping.conditions = list()) {
assertCount(n.population, positive = TRUE, na.ok = FALSE)
Expand All @@ -93,38 +60,6 @@ setupECRControl = function(
assertInteger(save.population.at, lower = 0L, any.missing = FALSE)
}

assertClass(mutator, "ecr_mutator")
assertList(mutator.control, any.missing = FALSE)
assertFunction(mutationStrategyAdaptor, args = c("operator.control", "opt.path"), ordered = TRUE)
assertList(recombinator.control, any.missing = FALSE)
if (!inherits(monitor, "ecr_monitor")) {
stopf("Currently only monitor of type 'ecr_monitor' supported")
}

# Check passed mutator
if (!inherits(mutator, "ecr_mutator")) {
stopf("Mutator must be of class ecr_mutator, not %s", paste(attr(mutator, "class")))
}
checkMutator(mutator)
mutator.control = prepareOperatorParameters(mutator, mutator.control)

# Check arguments of recombinator
if (!inherits(recombinator, "ecr_recombinator")) {
stopf("Recombinator must be of class ecr_recombinator, not %s", paste(attr(mutator, "class")))
}
checkRecombinator(recombinator)
recombinator.control = prepareOperatorParameters(recombinator, recombinator.control)

if (!inherits(generator, "ecr_generator")) {
stopf("Generator must be of class ecr_generator, not %s", paste(attr(generator, "class")))
}

sapply(c(generator, mutator, recombinator), function(operator) {
if (!is.supported(operator, representation)) {
stop(paste("Mutator '", getOperatorName(operator), "' is not compatible with representation '", representation, "'!", sep = ""))
}
})

# If the survival strategy is (mu + lambda), than the number of generated offspring in each iteration
# must greater or equal to the population size
if (survival.strategy == "comma" && n.offspring < n.population) {
Expand All @@ -147,6 +82,10 @@ setupECRControl = function(
}
}

if (!inherits(monitor, "ecr_monitor")) {
stopf("Currently only monitor of type 'ecr_monitor' supported")
}

structure(list(
n.population = n.population,
n.offspring = n.offspring,
Expand All @@ -156,37 +95,13 @@ setupECRControl = function(
n.elite = n.elite,
n.params = n.params,
n.targets = NULL, # we set this by hand here
selector = selector,
generator = generator,
mutator = mutator,
mutationStrategyAdaptor = mutationStrategyAdaptor,
recombinator = recombinator,
mutator.control = mutator.control,
recombinator.control = recombinator.control,
save.population.at = save.population.at,
target.name = target.name,
stopping.conditions = stopping.conditions,
monitor = monitor),
class = "ecr_control")
}

# Helper function which constructs control object for a given operator
# and checks the user parameters for validity.
#
# @param operator [\code{ecr_operator}]\cr
# Operator object.
# @param parameters [\code{list}]\cr
# List of parameters provedided by the user for the operator.
# @return [\code{list}]
# List of checked parameters.
prepareOperatorParameters = function(operator, input.params) {
defaults = getOperatorDefaultParameters(operator)
params = insert(defaults, input.params)
params[setdiff(names(params), names(defaults))] = NULL
do.call(getOperatorCheckFunction(operator), list(params))
return(params)
}

#' Print ecr control object.
#'
#' @param x [\code{ecr_control}]\cr
Expand Down
2 changes: 2 additions & 0 deletions R/makeMonitor.R
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
#' stopping.conditions = setupStoppingConditions(max.iter = 30L),
#' monitor = myFancyConsoleMonitor
#' )
#' ctrl = setupEvolutionaryOperators(ctrl)
#'
#' res = doTheEvolution(obj.fn, ctrl)
#' print(res)
#'
Expand Down
133 changes: 133 additions & 0 deletions R/setupECROperators.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#' Define the toolbix of all the evolutionary operators you wish to operate on
#' your problem.
#'
#' @note Keep in mind, that all of the provided operators need to be compatible
#' with the \dQuote{representation} stored in the \code{control} object.
#'
#' @param control [\code{ecr_control}]\cr
#' ECR control object generated via \code{\link{setupECRControl}}.
#' @param selector [\code{function}]\cr
#' Generator operator which implements a procedure to copy individuals from a
#' given population to the mating pool, i. e., allow them to become parents.
#' @param generator [\code{ecr_generator}]\cr
#' Generator operator of type \code{ecr_generator} for the generation of the initial
#' population.
#' @param mutator [\code{ecr_mutator}]\cr
#' Mutation operator of type \code{ecr_mutator}.
#' @param mutationStrategyAdaptor [\code{function}]\cr
#' This is an experimental parameter. Hence, you should be careful when using it.
#' Serves to offer the possibility to adapt parameters of the mutation algorithm
#' (e. g. mutation stepsize \eqn{\sigma} for Gaussian mutation) in each iteration.
#' The function needs to expect the parameters \dQuote{operator.control} and
#' \dQuote{opt.path}, the last being of type \code{\link[ParamHelpers]{OptPath}} and
#' must return the modified \dQuote{operator.control} object. The default does
#' nothing.
#' @param recombinator [\code{ecr_recombinator}]\cr
#' Recombination operator of type \code{ecr_recombinator}.
#' @param mutator.control [\code{list}]\cr
#' List of evolutionary parameters for the corresponding mutation operator. See the
#' help pages for the mutation operators for the needed values.
#' @param recombinator.control [\code{list}]\cr
#' List of evolutionary parameters for the corresponding recombination operator. See the
#' help pages for the recombination operators for the needed values.
#' @return [\code{ecr_control}] Modified control object.
#' @export
setupEvolutionaryOperators = function(
control,
selector = simpleMatingPoolGenerator,
generator = getDefaultEvolutionaryOperators(control$representation, "generator"),
mutator = getDefaultEvolutionaryOperators(control$representation, "mutator"),
#FIXME: this stuff is experimental.
mutationStrategyAdaptor = function(operator.control, opt.path) {
return(operator.control)
},
recombinator = getDefaultEvolutionaryOperators(control$representation, "recombinator"),
mutator.control = list(),
recombinator.control = list()) {
assertClass(control, "ecr_control")
representation = control$representation

assertClass(mutator, "ecr_mutator")
assertList(mutator.control, any.missing = FALSE)
assertFunction(mutationStrategyAdaptor, args = c("operator.control", "opt.path"), ordered = TRUE)
assertList(recombinator.control, any.missing = FALSE)

# Check passed mutator
if (!inherits(mutator, "ecr_mutator")) {
stopf("Mutator must be of class ecr_mutator, not %s", paste(attr(mutator, "class")))
}
checkMutator(mutator)
mutator.control = prepareOperatorParameters(mutator, mutator.control)

# Check arguments of recombinator
if (!inherits(recombinator, "ecr_recombinator")) {
stopf("Recombinator must be of class ecr_recombinator, not %s", paste(attr(mutator, "class")))
}
checkRecombinator(recombinator)
recombinator.control = prepareOperatorParameters(recombinator, recombinator.control)

if (!inherits(generator, "ecr_generator")) {
stopf("Generator must be of class ecr_generator, not %s", paste(attr(generator, "class")))
}

sapply(c(generator, mutator, recombinator), function(operator) {
if (!is.supported(operator, representation)) {
stop(paste("Mutator '", getOperatorName(operator), "' is not compatible with representation '", representation, "'!", sep = ""))
}
})

# store stuff in control object
control$selector = selector
control$generator = generator
control$mutator = mutator
control$mutationStrategyAdaptor = mutationStrategyAdaptor
control$recombinator = recombinator
control$mutator.control = mutator.control
control$recombinator.control = recombinator.control

return (control)
}

# Helper function which constructs control object for a given operator
# and checks the user parameters for validity.
#
# @param operator [\code{ecr_operator}]\cr
# Operator object.
# @param parameters [\code{list}]\cr
# List of parameters provedided by the user for the operator.
# @return [\code{list}]
# List of checked parameters.
prepareOperatorParameters = function(operator, input.params) {
defaults = getOperatorDefaultParameters(operator)
params = insert(defaults, input.params)
params[setdiff(names(params), names(defaults))] = NULL
do.call(getOperatorCheckFunction(operator), list(params))
return(params)
}

getDefaultEvolutionaryOperators = function(representation, type) {
defaults = list(
"float" = list(
"generator" = makeUniformGenerator(),
"mutator" = makeGaussMutator(),
"recombinator" = makeIntermediateRecombinator()
),
"binary" = list(
"generator" = makeBinaryGenerator(),
"mutator" = makeBitFlipMutator(),
"recombinator" = makeCrossoverRecombinator()
),
"permutation" = list(
"generator" = makePermutationGenerator(),
"mutator" = makeSwapMutator(),
#FIXME: later add a good
"recombinator" = makeNullRecombinator()
)
)

if (representation %in% names(defaults)) {
return(defaults[[representation]][[type]])
}
stopf("No defaults availiable for custom representation. You need to specify all
operators by hand.")
}
9 changes: 6 additions & 3 deletions inst/examples/1plus1_GA_example.R
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,15 @@ control = setupECRControl(
representation = "binary",
survival.strategy = "plus",
n.params = n.params,
stopping.conditions = list(makeMaximumIterationsStoppingCondition(max.iter = 500L))
)
control = setupEvolutionaryOperators(
control,
generator = makeBinaryGenerator(),
mutator = makeBitFlipMutator(),
recombinator = makeCrossoverRecombinator(),
# see the literature on 1+1 GA for this parameter recommendation
mutator.control = list(mutator.flip.prob = 1 / n.params),
stopping.conditions = list(makeMaximumIterationsStoppingCondition(max.iter = 500L))
mutator.control = list(mutator.flip.prob = 1 / n.params)
)
print(control)

Expand All @@ -53,4 +56,4 @@ res = doTheEvolution(obj.fun, control = control)
print(res)

# plot optimization trace
print(autoplot(res, log.fitness = FALSE))
print(autoplot(res, log.fitness = FALSE, complete.trace = TRUE))
2 changes: 1 addition & 1 deletion inst/examples/smoof_example.R
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ control = setupECRControl(
survival.strategy = "plus",
representation = "float",
n.params = 1L,
mutator.control = list(mutator.gauss.sd = 0.005),
monitor = myMonitor,
stopping.conditions = setupStoppingConditions(max.iter = 25L)
)
control = setupEvolutionaryOperators(control, mutator.control = list(mutator.gauss.sd = 0.005))

# do the evolutionary magic
set.seed(123)
Expand Down
3 changes: 2 additions & 1 deletion inst/examples/smoof_multi_objective_example.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ control = setupECRControl(
survival.strategy = "plus",
representation = "float",
n.params = 2L,
mutator.control = list(mutator.gauss.sd = 0.05),
stopping.conditions = setupStoppingConditions(max.iter = 50L)
)

control = setupEvolutionaryOperators(control, mutator.control = list(mutator.gauss.sd = 0.05))

# generate test function
obj.fun = makeZDT1Function(dimensions = 2L)

Expand Down
5 changes: 2 additions & 3 deletions inst/examples/tspmeta_example.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ control = setupECRControl(
survival.strategy = "plus",
n.elite = 1L,
n.params = tspmeta:::number_of_cities(inst),
generator = makePermutationGenerator(),
mutator = makeSwapMutator(),
recombinator = makeNullRecombinator(),
stopping.conditions = list(makeMaximumIterationsStoppingCondition(max.iter = 200L))
)
# here we stick to the defaults
control = setupEvolutionaryOperators(control)
print(control)

res = doTheEvolution(obj.fun, control = control)
Expand Down
2 changes: 2 additions & 0 deletions man/doTheEvolution.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ ctrl = setupECRControl(
representation = "float",
stopping.conditions = setupStoppingConditions(max.iter = 100L)
)
# use the default operators for representation "float"
ctrl = setupEvolutionaryOperators(ctrl)

res = doTheEvolution(obj.fn, control = ctrl)
print(res)
Expand Down
2 changes: 2 additions & 0 deletions man/makeMonitor.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ ctrl = setupECRControl(
stopping.conditions = setupStoppingConditions(max.iter = 30L),
monitor = myFancyConsoleMonitor
)
ctrl = setupEvolutionaryOperators(ctrl)

res = doTheEvolution(obj.fn, ctrl)
print(res)
}
Expand Down
Loading

0 comments on commit bf650e2

Please sign in to comment.