Skip to content

Commit

Permalink
add AS-EMOA to ecr core
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobbossek committed Aug 25, 2015
1 parent aacd34d commit fdf2239
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 0 deletions.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ S3method(print,ecr_optimization_task)
S3method(print,ecr_result)
export(approximateIdealPoint)
export(approximateNadirPoint)
export(asemoa)
export(computeAverageHausdorffDistance)
export(computeCrowdingDistance)
export(computeDistanceFromPointToSetOfPoints)
Expand Down
161 changes: 161 additions & 0 deletions R/emoa.as-emoa.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#' @title
#' Implementation of the NSGA-II EMOA algorithm by Deb.
#'
#' @description
#' The AS-EMOA, short for aspiration set evolutionary multi-objective algorithm,
#' aims to incorporate expert knowledge into multi-objective optimization [1].
#' The algorithm expects an aspiration set, i.e., a set of reference points. It
#' then creates an appriximation of the pareto front close to the aspiration set
#' utilizing the average Hausdorff distance.
#'
#' @note
#' This is a pure R implementation of the NSGA-II algorithm. It hides the regular
#' \pkg{ecr} interface and offers a more R like interface while still being quite
#' adaptable.
#'
#' @references Rudolph, G., Schuetze, S., Grimme, C., Trautmann, H: An Aspiration Set
#' EMOA Based on Averaged Hausdorff Distances. LION 2014: 153-156.
#'
#' @param task [\code{ecr_optimization_task} | \code{smoof_function}]\cr
#' Optimization task or objective function of type \code{smoof_function}.
#' @param n.population [\code{integer(1)}]\cr
#' Population size. Default is \code{100}.
#' @param n.offspring [\code{integer(1)}]\cr
#' Offspring size, i.e., number of individuals generated by variation operators
#' in each iteration. Default is \code{n.population}.
#' @param aspiration.set [\code{matrix}]\cr
#' The aspiration set. Each column contains one point of the set.
#' @param n.archive [\code{integer(1)}]\cr
#' Size of the pareto archive, i.e., the number of nondominated points which we
#' aim to generate. Default is \code{ncol(aspiration.set)}.
#' @template arg_parent_selector
#' @template arg_mutator
#' @template arg_recombinator
#' @param max.iter [\code{integer(1)}]\cr
#' Maximal number of iterations. Default ist \code{100L}.
#' @param max.evals [\code{integer(1)}]\cr
#' Maximal number of iterations/generations. Default is \code{Inf}.
#' @param max.time [\code{integer(1)}]\cr
#' Time budget in seconds. Default ist \code{Inf}.
#' @return [\code{ecr_ecr_multi_objective_result}]
#' @export
asemoa = function(
task,
n.population = 100L, n.offspring = n.population,
aspiration.set = NULL,
n.archive,
parent.selector = makeSimpleSelector(),
mutator = makeGaussMutator(),
recombinator = makeCrossoverRecombinator(),
max.iter = 100L,
max.evals = NULL,
max.time = NULL) {

if (isSmoofFunction(task)) {
task = makeOptimizationTask(task)
}
assertMatrix(aspiration.set, mode = "numeric", any.missing = FALSE, all.missing = FALSE, min.rows = 2L)
if (nrow(aspiration.set) != task$n.objectives) {
stopf("AS-EMAO: Dimension of the aspiration set needs to be equal to the number of objectives,
but %i <> %i.", nrow(aspiration.set), task$n.objectives)
}
if (is.null(n.archive)) {
n.archive = ncol(aspiration.set)
}
assertInt(n.archive, na.ok = FALSE, lower = 2L)

# This is the main selection mechanism of the AS-EMOA.
# Remove the point which leads to highest
deltaOneUpdate = function(set, aspiration.set) {
# here we need to apply this strange information. See the reference for details
# yeah, I could use range here but it is more readable this way
min1 = min(aspiration.set[1L, ])
min2 = min(aspiration.set[2L, ])
max1 = max(aspiration.set[1L, ])
max2 = max(aspiration.set[2L, ])

# transform
set[1L, ] = (set[1L, ] - min1) / (max2 - min2)
set[2L, ] = (set[2L, ] - min2) / (max1 - min1)

return(computeAverageHausdorffDistance(set, aspiration.set))
}

# Implementation of surival selection operator of the AS-EMOA algorithm.
asemoaSelector = makeSelector(
selector = function(population, storage, n.select, control) {
fitness = population$fitness
population = population$individuals

# filter nondominated points
nondom.idx = which.nondominated(fitness)
population = population[nondom.idx]
fitness = fitness[, nondom.idx, drop = FALSE]

n.archive = control$n.archive
# if maximal number of individuals is not exceeded yet
# simply return
if (length(population) <= n.archive) {
return(makePopulation(population, fitness))
}

# Otherwise we need to do the computationally more expensive part
hausdorffDistances = lapply(seq(length(population)), function(idx) {
deltaOneUpdate(fitness[, -idx, drop = FALSE], control$aspiration.set)
})

#FIXME: here we need to check if there are multiple elements with this distance
tmp = getMinIndex(hausdorffDistances)

return(makePopulation(population[-tmp], fitness[, -tmp, drop = FALSE]))
},
supported.objectives = "multi-objective",
name = "AS-EMOA selector",
description = "Selection takes place based on (modified) average Hausdorff metric"
)

asemoaGenerator = makeGenerator(
generator = function(size, control) {
uniformGenerator = makeUniformGenerator()
population = uniformGenerator(size, control)
#NOTE: here we use the objective function to compute the fitness values
fitness = computeFitness(population, task$fitness.fun)
# now filter out dominated solutions
nondom.idx = which.nondominated(fitness)
population$individuals = population$individuals[nondom.idx]
return(population)
},
name = "AS-EMOA generator",
description = "Generates uniformaly and reduces to non-dominated set",
supported = "float"
)

# AS-EMOA control object
ctrl = setupECRControl(
n.population = n.population,
n.offspring = n.offspring,
representation = "float",
monitor = makeConsoleMonitor(),
stopping.conditions = list(
makeMaximumEvaluationsStoppingCondition(max.evals),
makeMaximumTimeStoppingCondition(max.time),
makeMaximumIterationsStoppingCondition(max.iter)
)
)

ctrl = setupEvolutionaryOperators(
ctrl,
parent.selector = parent.selector,
recombinator = recombinator,
generator = asemoaGenerator,
mutator = mutator,
survival.selector = asemoaSelector
)

#FIXME: this is rather ugly. We simply add some more args to the control object
# without sanity checks and stuff like that.
ctrl$n.archive = n.archive
ctrl$aspiration.set = aspiration.set

return(doTheEvolution(task, ctrl))
}
68 changes: 68 additions & 0 deletions man/asemoa.Rd
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/emoa.as-emoa.R
\name{asemoa}
\alias{asemoa}
\title{Implementation of the NSGA-II EMOA algorithm by Deb.}
\usage{
asemoa(task, n.population = 100L, n.offspring = n.population,
aspiration.set = NULL, n.archive, parent.selector = makeSimpleSelector(),
mutator = makeGaussMutator(), recombinator = makeCrossoverRecombinator(),
max.iter = 100L, max.evals = NULL, max.time = NULL)
}
\arguments{
\item{task}{[\code{ecr_optimization_task} | \code{smoof_function}]\cr
Optimization task or objective function of type \code{smoof_function}.}

\item{n.population}{[\code{integer(1)}]\cr
Population size. Default is \code{100}.}

\item{n.offspring}{[\code{integer(1)}]\cr
Offspring size, i.e., number of individuals generated by variation operators
in each iteration. Default is \code{n.population}.}

\item{aspiration.set}{[\code{matrix}]\cr
The aspiration set. Each column contains one point of the set.}

\item{n.archive}{[\code{integer(1)}]\cr
Size of the pareto archive, i.e., the number of nondominated points which we
aim to generate. Default is \code{ncol(aspiration.set)}.}

\item{parent.selector}{[\code{ecr_selector}]\cr
Selection operator which implements a procedure to copy individuals from a
given population to the mating pool, i. e., allow them to become parents.}

\item{mutator}{[\code{ecr_mutator}]\cr
Mutation operator of type \code{ecr_mutator}.}

\item{recombinator}{[\code{ecr_recombinator}]\cr
Recombination operator of type \code{ecr_recombinator}.}

\item{max.iter}{[\code{integer(1)}]\cr
Maximal number of iterations. Default ist \code{100L}.}

\item{max.evals}{[\code{integer(1)}]\cr
Maximal number of iterations/generations. Default is \code{Inf}.}

\item{max.time}{[\code{integer(1)}]\cr
Time budget in seconds. Default ist \code{Inf}.}
}
\value{
[\code{ecr_ecr_multi_objective_result}]
}
\description{
The AS-EMOA, short for aspiration set evolutionary multi-objective algorithm,
aims to incorporate expert knowledge into multi-objective optimization [1].
The algorithm expects an aspiration set, i.e., a set of reference points. It
then creates an appriximation of the pareto front close to the aspiration set
utilizing the average Hausdorff distance.
}
\note{
This is a pure R implementation of the NSGA-II algorithm. It hides the regular
\pkg{ecr} interface and offers a more R like interface while still being quite
adaptable.
}
\references{
Rudolph, G., Schuetze, S., Grimme, C., Trautmann, H: An Aspiration Set
EMOA Based on Averaged Hausdorff Distances. LION 2014: 153-156.
}

0 comments on commit fdf2239

Please sign in to comment.