Skip to content

Commit

Permalink
work with lists instead of matrices
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobbossek committed Apr 14, 2015
1 parent 6c49e1b commit 0c2cb46
Show file tree
Hide file tree
Showing 15 changed files with 165 additions and 72 deletions.
2 changes: 1 addition & 1 deletion R/computeFitness.R
Expand Up @@ -9,6 +9,6 @@
#' Fitness function.
#' @return [\code{matrix}].
computeFitness = function(population, fitness.fun) {
fitness = apply(population$individuals, 1, fitness.fun)
fitness = unlist(lapply(population$individuals, fitness.fun))
return(fitness)
}
12 changes: 4 additions & 8 deletions R/correctBounds.R
Expand Up @@ -11,12 +11,8 @@ correctBounds = function(individuals, par.set, n.params) {
lower = getLower(par.set, with.nr = TRUE)
upper = getUpper(par.set, with.nr = TRUE)

individuals = as.matrix(apply(individuals, 1, function(child) {
pmax(pmin(upper, child), lower)
}))

if (n.params > 1L) {
individuals = t(individuals)
}
individuals
individuals = lapply(individuals, function(child) {
pmin(pmax(lower, child), upper)
})
return(individuals)
}
53 changes: 28 additions & 25 deletions R/doTheEvolution.R
Expand Up @@ -49,39 +49,39 @@
#' @seealso \code{\link{setupECRControl}}
#' @export
doTheEvolution = function(objective.fun, control) {
assertClass(objective.fun, "smoof_function")
par.set = getParamSet(objective.fun)
assertClass(par.set, "ParamSet")
repr = control$representation
par.set = NULL
if (repr != "custom") {
assertClass(objective.fun, "smoof_function")
par.set = getParamSet(objective.fun)
#FIXME: is this a good idea to modify control object here?
control$par.set = par.set

# potentially global optimum
global.optimum = NULL
if (hasGlobalOptimum(objective.fun)) {
global.optimum = getGlobalOptimum(objective.fun)$param
}

if (repr == "float" && !hasFiniteBoxConstraints(par.set)) {
stopf("Lower and upper box constraints needed for representation type 'float'.")
}
} else {
# dummy par.set
par.set = makeParameterSet(makeNumericParam("x", lower = 0, upper = 1))
}

n.params = control$n.params
max.iter = control$max.iter
max.time = control$max.time
n.population = control$n.population
n.mating.pool = control$n.mating.pool
n.offspring = control$n.offspring
termination.eps = control$termination.eps
monitor = control$monitor

# potentially global optimum
global.optimum = NULL
if (hasGlobalOptimum(objective.fun)) {
global.optimum = getGlobalOptimum(objective.fun)$param
}

if (control$representation %in% c("float") && !hasFiniteBoxConstraints(par.set)) {
stopf("Lower and upper box constraints needed for representation type 'float'.")
}

lower = getLower(par.set)
upper = getUpper(par.set)

populationGenerator = control$generator
matingPoolGenerator = control$selector

population = populationGenerator(n.population, n.params, lower, upper, control)
population = populationGenerator(n.population, control)
population$fitness = computeFitness(population, objective.fun)
best = getBestIndividual(population)

buildExtras = function(iter, start.time, fitness, control) {
extra = list(
past.time = as.numeric(Sys.time() - start.time),
Expand Down Expand Up @@ -120,6 +120,7 @@ doTheEvolution = function(objective.fun, control) {

parents = matingPoolGenerator(population, n.mating.pool)
offspring = generateOffspring(parents, objective.fun, control, opt.path)
#print(offspring)

population = selectForSurvival(
population,
Expand All @@ -141,6 +142,7 @@ doTheEvolution = function(objective.fun, control) {
if (length(stop.object) > 0L) {
break
}
#print(as.data.frame(opt.path))

iter = iter + 1
}
Expand All @@ -151,8 +153,9 @@ doTheEvolution = function(objective.fun, control) {
structure(list(
objective.fun = objective.fun,
control = control,
best.param = setColNames(t(data.frame(best$individual)),
getParamIds(par.set, repeated = TRUE, with.nr = TRUE)),
best.param = best$individual,
# best.param = setColNames(t(data.frame(best$individual)),
# getParamIds(par.set, repeated = TRUE, with.nr = TRUE)),
best.value = best$fitness,
opt.path = opt.path,
population.storage = population.storage,
Expand Down Expand Up @@ -197,7 +200,7 @@ addBestToOptPath = function(opt.path, par.set, best, fitness, generation, exec.t
best.param.values = as.list(best$individual)
names(best.param.values) = getParamIds(par.set, repeated = TRUE, with.nr = TRUE)
}
addOptPathEl(opt.path, x = best.param.values, y = best$fitness, dob = generation,
addOptPathEl(opt.path, x = best.param.values, y = unlist(best$fitness), dob = generation,
exec.time = exec.time, extra = extra)
return(opt.path)
}
14 changes: 7 additions & 7 deletions R/generateOffspring.R
Expand Up @@ -14,24 +14,24 @@ generateOffspring = function(matingPool, objective.fun, control, opt.path) {
mutationStrategyAdaptor = control$mutationStrategyAdaptor
mutator.control = control$mutator.control
recombinator = control$recombinator
#parentSelector = control$parentSelector
#parentSelector = control$selector
parentSelector = simpleUniformSelection
n.offspring = control$n.offspring
par.set = getParamSet(objective.fun)
n.params = control$n.params

#offspring = list()
offspring = matrix(NA, ncol = n.params, nrow = n.offspring)
offspring = vector("list", n.offspring)

for (i in 1:n.offspring) {
parents = parentSelector(matingPool)
child = recombinator(parents)
mutator.control = mutationStrategyAdaptor(mutator.control, opt.path)
child = mutator(child, mutator.control)
child = child$individuals
offspring[i, ] = child
offspring[[i]] = child
}
offspring = correctBounds(offspring, par.set, n.params)
#offspring = correctBounds(offspring, par.set, n.params)
offspring.fitness = computeFitness(makePopulation(offspring), objective.fun)

return(makePopulation(offspring, offspring.fitness))
Expand All @@ -40,11 +40,11 @@ generateOffspring = function(matingPool, objective.fun, control, opt.path) {
simpleUniformSelection = function(matingPool) {
population = matingPool$individuals
fitness = matingPool$fitness
n = nrow(population)
n = length(population)
# if we have only one individual, return it twice
if (n == 1) {
return(makePopulation(population[c(1, 1), , drop = FALSE], fitness[c(1, 1)]))
return(makePopulation(population[c(1, 1)], fitness[c(1, 1)]))
}
idx = sample(n, size = 2, replace = FALSE)
makePopulation(population[idx, , drop = FALSE], fitness[idx])
makePopulation(population[idx], fitness[idx])
}
16 changes: 12 additions & 4 deletions R/generator.uniform.float.R
Expand Up @@ -19,10 +19,18 @@ makeUniformGenerator = function() {
# @param control [\code{ecr_control}]\cr
# Control object.
# @return [\code{setOfIndividuals}]
generateUniformPopulation = function(size, n.params, lower.bounds = NA, upper.bounds = NA, control) {
population = matrix(0, nrow = size, ncol = n.params)
for(i in 1:n.params) {
population[, i] = runif(size, min = lower.bounds[i], max = upper.bounds[i])
generateUniformPopulation = function(size, control) {
par.set = control$par.set
lower = getLower(par.set)
upper = getUpper(par.set)
n.params = sum(getParamLengths(par.set))
population = list()
for(i in seq(size)) {
ind = vector(mode = "numeric", length = n.params)
for (j in seq(n.params)) {
ind[j] = runif(1L, min = lower[j], max = upper[j])
}
population[[i]] = ind
}
makePopulation(population)
}
Expand Down
2 changes: 1 addition & 1 deletion R/getBestIndividual.R
Expand Up @@ -9,6 +9,6 @@ getBestIndividual = function(population) {
fitness = population$fitness
best.idx = which.min(population$fitness)
best.fitness = fitness[best.idx]
best.individual = population$individuals[best.idx, ]
best.individual = population$individuals[[best.idx]]
return(list(individual = best.individual, fitness = best.fitness))
}
2 changes: 1 addition & 1 deletion R/makeMutator.R
Expand Up @@ -25,5 +25,5 @@ makeMutator = function(mutator, name, description,

# Helper function which returns all supported parameter representations.
getAvailableRepresentations = function() {
c("permutation", "binary", "float", "integer")
c("permutation", "binary", "float", "custom")
}
14 changes: 8 additions & 6 deletions R/mergePopulations.R
Expand Up @@ -5,22 +5,24 @@
# @return [\code{setOfIndividuals}]
mergePopulations = function(...) {
populations = list(...)
#stop()

# get n.params
n.params = ncol(populations[[1]]$individuals)
n.params = length(populations[[1]]$individuals[[1]])

# summarize over all population sizes
pop.size = sum(sapply(populations, function(x) length(x$fitness)))

# allocate space
fitness = numeric(pop.size)
individuals = matrix(NA, ncol = n.params, nrow = pop.size)
fitness = numeric()
individuals = list()

# now iterate over populations and generate merged population
start = 1L
for (i in 1:length(populations)) {
j = nrow(populations[[i]]$individuals)
individuals[start:(start + j - 1), ] = populations[[i]]$individuals
fitness[start:(start + j - 1)] = populations[[i]]$fitness
j = length(populations[[i]]$individuals[[1]])
individuals = c(individuals, populations[[i]]$individuals)
fitness = c(fitness, unlist(populations[[i]]$fitness))
start = start + j
}
makePopulation(
Expand Down
17 changes: 9 additions & 8 deletions R/mutator.gauss.R
Expand Up @@ -21,15 +21,16 @@ makeGaussMutator = function(mutator.gauss.prob = 1L, mutator.gauss.sd = 0.05) {
mutatorCheck(defaults)

mutator = function(setOfIndividuals, control = defaults) {
n.params = ncol(setOfIndividuals$individuals)
n = nrow(setOfIndividuals$individuals)

mutation.bool = matrix(runif(n * n.params) < control$mutator.gauss.prob, ncol = n.params)
mutation = matrix(0, ncol = n.params, nrow = n)
idx = which(mutation.bool)
mutation[idx] = rnorm(length(idx), mean = 0, sd = control$mutator.gauss.sd)
setOfIndividuals$individuals = setOfIndividuals$individuals + mutation
inds = setOfIndividuals$individuals
n.params = length(inds[[1]])
n = length(inds)

for (i in seq(n)) {
idx = which(runif(n.params) < control$mutator.gauss.prob)
mut = rnorm(length(idx), mean = 0, sd = control$mutator.gauss.sd)
inds[[i]][idx] = inds[[i]][idx] + mut
}
setOfIndividuals$individuals = inds
return(setOfIndividuals)
}

Expand Down
8 changes: 4 additions & 4 deletions R/recombinator.crossover.R
Expand Up @@ -5,15 +5,15 @@
makeCrossoverRecombinator = function() {
recombinator = function(setOfIndividuals, control = list()) {
parents = setOfIndividuals$individuals
parent1 = parents[1, ]
parent2 = parents[2, ]
parent1 = parents[[1]]
parent2 = parents[[2]]
n = length(parent1)
# at least one allele of each parent should be contained
idx = sample(0:n, size = 1L)
child = parent1
child[idx:n] = parent2[idx:n]
child = matrix(child, nrow = 1L)
makePopulation(child)
child = child
p = makePopulation(child)
}

makeRecombinator(
Expand Down
8 changes: 7 additions & 1 deletion R/recombinator.intermediate.R
Expand Up @@ -4,7 +4,13 @@
#' @export
makeIntermediateRecombinator = function() {
recombinator = function(setOfIndividuals, control = list()) {
child = matrix(colSums(setOfIndividuals$individuals) / 2, nrow = 1L)
inds = setOfIndividuals$individuals
n = length(inds[[1]])
child = rep(0, n)
for (i in 1:length(inds)) {
child = child + inds[[i]]
}
child = child / length(inds)
makePopulation(child)
}

Expand Down
2 changes: 1 addition & 1 deletion R/selectForSurvival.R
Expand Up @@ -45,7 +45,7 @@ selectForSurvival = function(population, offspring, n.population, strategy = "pl
}

population2 = makePopulation(
individuals = source.individuals[to.survive, , drop = FALSE],
individuals = source.individuals[to.survive],
fitness = source.fitness[to.survive]
)

Expand Down
5 changes: 5 additions & 0 deletions R/selector.simple.R
Expand Up @@ -7,6 +7,11 @@
#' @export
makeSimpleSelector = function() {
selector = function(population, n.mating.pool) {
# inds = population$individuals
# fitn = population$fitness
# n = length(inds)
# idx = sample(n, size = 2, replace = FALSE)
# return(makePopulation(inds[idx], fitn[idx]))
return(population)
}
makeSelector(
Expand Down
72 changes: 72 additions & 0 deletions inst/examples/custom_example.R
@@ -0,0 +1,72 @@
library(methods)
library(testthat)
library(devtools)
library(BBmisc)
library(ggplot2)

load_all(".")

set.seed(123)

getPairwiseDistances = function(x) {
distances = c()
n = nrow(x)
for (i in 1:n) {
for (j in 1:n) {
if (i == j) {
next
}
d = sum(x[i, ] - x[j, ])^2
distances = c(distances, d)
}
}
return(distances)
}

#fitness = makeFitnessFunction(
fitness = function(x, ...) {
dists = getPairwiseDistances(x)
return(1 / sum(dists)) # since we want to maximise here
}
#

# control and operator settings are separated now
ctrl = setupECRControl(
n.population = 10L,
n.offspring = 10L,
representation = "custom", # bypass everything
survival.strategy = "plus",
monitor = makeConsoleMonitor()
)

myGenerator = makeGenerator("custom", function(N) {
matrix(runif(N * 2L), ncol = 2L)
})

myMutator = makeMutator(
mutator = function(x) {
N = nrow(x)
x + runif(N * 2L, ncol = 2L, min = 0, max = 0.01)
},
name = "Point-Shift mutation",
description = "Shift all points in a random direction",
supported = "custom"
)

myRecombinator = makeRecombinator(
recombinator = function(x, y) {
N = nrow(x)
0.5 * (x + y)
},
name = "Convex-Combination recombinator",
description = "Make a convex combination of the point coordinates",
supported = "custom"
)

evops = setUpECROperatorSet(
generator = myGenerator,
mutator = myMutator,
recombinator = myRecombinator
)

res = doTheEvolution(fitness, ctrl)

0 comments on commit 0c2cb46

Please sign in to comment.