- # matt owen
-
-
- # chromosone object constructor
- newchromosone <- function (v) {
- obj <- c()
- obj$genes <- sort(v)
- attr(obj, 'class') <- 'chromosone'
- obj
- }
-
- # sampling functions # # # # # #
- samp <- function (n, v, p) {
- lis <- c()
- v <- v/sum(v)
- vec <- cumsum(v)
- for (k in 1:n) {
- vc <- vec
- r <- runif(n=1, min=0, max=1)
- vc <- (r < vc)*1:length(v)
- vc <- vc[vc!=0]
- lis <- c(lis, p[min(vc)])
- }
- lis
- }
-
- sortselect <- function (p, f=function (x) { 1 }, n=1) {
- fitness <- c()
- for (n in 1:length(p)) {
- fitness <- c(fitness, f(p[n]))
- }
- samp(n=n, fitness, p)
- }
-
- # crossover functions # # # # # #
-
- # crossover average: average the two vectors
- # should be a good mechanism for mixing solutions close to optimal
- crossover_avg <- function (x, y) { newchromosone(sort((x$genes+y$genes)/2.)) }
-
- # crossover swap: swap two random entries
- # adds variability to solutions
- crossover_swap <- function (x, y) {
- i <- floor(runif(n=1, min=0, max=length(x$genes)+1))
- x$genes[i] <- y$genes[i]
- newchromosone(sort(x$genes))
- }
-
-
- # mutate functions # # # # # #
-
- # mutate: naive implementation
- mutate <- function (ch, mu=0.003) {
- for (k in 1:length(ch$genes))
- if (runif(n=1, min=0, max=1) < mu)
- ch$genes[k] = runif(n=1, min=-5, max=5)
- newchromosone(sort(ch$genes))
- }
-
- # compute which partition a point belongs to
- findpartition <- function (x, v) {
- v <- sort(v)
- maximum <- length(v)
- v <- (x < v)*(1:length(v))-1
- v <- v[v != -1]
- min(v, maximum)+1
- }
-
- # get a list of which segment something belongs to
- findpartitions <- function (x, v) {
- lis <- c()
- for (el in x)
- lis <- c(lis, findpartition(el, v))
- lis
- }
-
-
- # compute which partition a point belongs to
- findpartition <- function (x, v) {
- v <- sort(v)
- maximum <- length(v)
- v <- (x < v)*(1:length(v))-1
- v <- v[v != -1]
- min(v, maximum)+1
- }
-
- # get a list of which segment something belongs to
- findpartitions <- function (x, v) {
- lis <- c()
- for (el in x)
- lis <- c(lis, findpartition(el, v))
- lis
- }
-
- # constructor
- newpiecewise <- function (f, p) {
- p <- sort(p)
- obj <- c()
- obj$f <- c(f[[1]])
- obj$p <- p
- for (k in 1:length(p))
- obj$f[[k+1]] <- f[[k+1]]
- attr(obj, 'class') <- 'piecewisefunction'
- obj
- }
-
- # method to compute difference between functions
- piecewisedifference <- function (obj, f, x) {
- su <- 0
- x <- sort(x)
- y <- fapply(obj, x)
- for (k in 1:(length(x)-1)) {
- dx <- x[k+1] - x[k]
- p2 <- abs(y[k+1] - f(x[k+1]))
- p1 <- abs(y[k] - f(x[k]))
- trap <- (p2+p1)/2*dx
- su <- su+trap
- }
- su
- }
-
-
- # method to apply piecewise functions to points
- fapply <- function (obj, x) {
- partitions <- findpartitions(x, obj$p)
- results <- c()
- for (k in 1:length(x))
- results <- c(results, obj$f[[partitions[[k]]]](x[k]))
- results
- }
-
- # linearize a function
- linearize <- function (f, a, b) {
- m <- (f(b) - f(a))/(b-a)
- b <- f(a) - m * a
- function (x) { m * x + b }
- }
-
- # construct piecewise linear
- piecewiselinear <- function (f, p) {
- p <- sort(p)
- flis <- c()
- for (k in 1:(length(p)-1)) {
- flis <- c(flis, linearize(f, p[k], p[k+1]))
- }
- return(newpiecewise(flis, p[2:(length(p)-1)]))
- }
-
- # fitness
- fit <- function (ch) {
- y <- function (x) { x^3 }
- fi <- piecewiselinear(y, c(-5, ch$genes, 5))
- 1/piecewisedifference(fi, y , seq(-5, 5, .1))
- }
-
-
- # program start # #
-
- # create the inital population
- samples <- c()
- x <- seq(-5, 5, .1)
- y <- function (x) { x^3 }
-
- for (k in 1:10)
- samples <- c(samples, newchromosone(sort(runif(n=4, min=-5, max=5))))
-
- lis <- c()
-
- val <- 0
- m <- 0
- best <- c()
-
- for (k in 1:length(samples)) {
- lis <- c(lis, fit(samples[k]))
- val <- fit(samples[k])
- if (val > m) {
- m <- val
- best <- samples[k]
- }
- }
-
- pw <- piecewiselinear(function (x) { x^3 }, c(-5, best$genes, 5))
- plot(x, fapply(pw, x), main="OLD BEST", xlab="x", ylab="y")
- lines(x, y(x))
-
-
- # start the loop
- for (n in 1:20) {
- # sample population
- nextgeneration <- c()
- parents <- sortselect(p=samples, f=fit, n=10)
-
- # mutate
- #for (k in 1:length(parents))
- # parents[k] <- mutate(parents[k])
-
- # mix
- len <- length(parents)
- for (k in 2:len) {
- x <- parents[k-1]
- y <- parents[k]
- nextgeneration <- c(nextgeneration, crossover_avg(x, y))
- }
- nextgeneration <- c(nextgeneration, crossover_avg(parents[1], parents[length(parents)]))
- samples <- nextgeneration
- }
-
- for (k in 1:length(samples)) {
- lis <- c(lis, fit(samples[k]))
- val <- fit(samples[k])
- if (val > m) {
- m <- val
- best <- samples[k]
- }
- }
-
- # text output
- m <- 0
- best <- c()
- val <- 0
- for (k in 1:length(samples)) {
- lis <- c(lis, fit(samples[k]))
- val <- fit(samples[k])
- if (val > m) {
- m <- val
- best <- samples[k]
- }
- }
-
- pw <- piecewiselinear(function (x) { x^3 }, c(-5, best$genes, 5))
- x <- seq(-5, 5, .1)
- y <- function (x) { x^3 }
- plot(x, fapply(pw, x), main="NEW BEST", xlab="x", ylab="y")
- lines(x, y(x))
-
-
-
- # output image file
-
-
- #findpartitions(c(-1.5, -.5, .5, 1.5), c(-1, 0, 1))