Skip to content

Instantly share code, notes, and snippets.

@VizGhar
Last active March 8, 2022 07:18
Show Gist options
  • Save VizGhar/8736733abc91d7131afbe89ae7b774b6 to your computer and use it in GitHub Desktop.
Save VizGhar/8736733abc91d7131afbe89ae7b774b6 to your computer and use it in GitHub Desktop.
"Hello World!" Simplistic Genetic Algorithm with tournament selectionThis sample is meant to be readable and is not efficient at all, so!!! Do not use in production !!!
import kotlin.math.abs
import kotlin.random.Random
const val target = "Hello World!"
const val possibilities = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789 .,!?"
const val mutationProbability = 0.05 // each block of chromosome mutates with this probability
const val populationSize = 1000 // this many individuals will be in each generation
const val keepNBest = 200 // this many best individuals will be taken without change to next gen
const val tournamentSize = 3 // this many individuals will fight in tournament
val random = Random(System.currentTimeMillis())
fun randomIndividual() = (target.indices).map { possibilities.random(random) }.joinToString("")
var population = (0 until populationSize).map { randomIndividual() }.sortedBy { it.fitness }
val String.fitness: Int get() = // lower fitness better (for this case) fitness of 0 = solution
indices.sumOf { index ->
val indexFirst = possibilities.indexOf(target[index])
val indexSecond = possibilities.indexOf(this[index])
val high = maxOf(indexFirst, indexSecond)
val low = minOf(indexFirst, indexSecond)
if ((high - low) > possibilities.length / 2) {
abs(high - possibilities.length - low)
} else {
high - low
}
}
fun mutation(individual: String) =
individual.map { if (Math.random() <= mutationProbability) possibilities.random(random) else it }.joinToString("")
fun crossover(individual1: String, individual2: String) =
random.nextInt(target.length).let { individual1.substring(0, it) + individual2.substring(it) }
fun tournament() =
(1..tournamentSize).map { population.random(random) }.minByOrNull { it.fitness }!!
fun nextPopulation() {
val best = (0 until keepNBest).map { population[it] }
val kids = (keepNBest until populationSize).map {
val individual1 = tournament()
val individual2 = tournament()
val child = crossover(individual1, individual2)
mutation(child)
}
population = (best + kids).sortedBy { it.fitness }
}
fun main() {
var generation = 0
while (population[0].fitness != 0) {
println("Generation $generation : fitness = ${population[0].fitness} : best = ${population[0]}")
nextPopulation()
generation++
}
println("Generation $generation : result : ${population[0]}")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment