Skip to content

Instantly share code, notes, and snippets.

@ruippeixotog
Created November 10, 2012 00:32
Show Gist options
  • Save ruippeixotog/4049223 to your computer and use it in GitHub Desktop.
Save ruippeixotog/4049223 to your computer and use it in GitHub Desktop.
Genetic Algorithms in Scala
import annotation.tailrec
import util.Random
import scala.annotation.tailrec
import scala.collection.immutable.Stream.consWrapper
object Main2 extends App {
val target = "as armas e os baroes assinalados"
val genePool = Array[Char]('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' ')
def fitness(src: String, tgt: String): Double = src.zip(tgt).count { case (s, t) => s == t }
val testBench = new GeneticExploration[Char, String](0.01, 500, genePool, cs => new String(cs.toArray), fitness)
println(testBench.evolution(testBench.newPool(500, target.length), target))
}
class GeneticExploration[Gene, Specimen <% Iterable[Gene]](val mutation: Double, val population: Int, genePool: Array[Gene], specimenBuilder: Iterable[Gene] => Specimen, fitnessF: (Specimen, Specimen) => Double) {
type Pool = Seq[Specimen]
type MatePool = Seq[(Specimen, Double)]
def randomGenes: Stream[Gene] = genePool(Random.nextInt(genePool.length)) #:: randomGenes
def newSpecimen(len: Int): Specimen = specimenBuilder(randomGenes.take(len))
def newPool(size: Int, len: Int): Pool = (1 to size).map(_ => newSpecimen(len))
def matePool(pool: Pool, tgt: Specimen): MatePool = {
val fitnesses = pool.map(fitnessF(_, tgt))
pool.zip(renormalize(fitnesses))
}
def renormalize(vector: Iterable[Double]): Iterable[Double] = {
val sum = vector.sum
vector.map(_ / sum)
}
@tailrec final def monteCarloSelection(matePool: MatePool): Specimen = {
val (specimen, fitness) = matePool(Random.nextInt(matePool.length))
if (fitness > Random.nextFloat()) specimen else monteCarloSelection(matePool)
}
def popReproduction(matePool: MatePool): Pool = (1 to population).par.map(_ => crossover(monteCarloSelection(matePool), monteCarloSelection(matePool))).seq
def crossover(a: Specimen, b: Specimen): Specimen = specimenBuilder(a.zip(b).map(gene => if (Random.nextFloat > 0.5) gene._1 else gene._2))
def mutate(s: Specimen) = specimenBuilder(s.map(gene => if (mutation > Random.nextFloat) randomGenes.head else gene))
@tailrec final def evolution(pool: Pool, target: Specimen, generation: Int = 0): (Pool, Int) = {
val newGeneration = popReproduction(matePool(pool, target))
if (newGeneration.exists(_ == target)) (newGeneration, generation) else evolution(newGeneration, target, generation + 1)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment