A genetic algorithm library in Go
Go
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
main
.gitignore
LICENSE
README.md
chromosome.go
population.go

README.md

Genetic

A Golang library for running simple genetic algorithms.

Usage

Define a Type that adhears to the Chromosome interface.

type Chromosome interface {
  Fitness() int16
  Recombine(newPopulation chan<- Chromosome, chromosome Chromosome)
  Mutate() Chromosome
}

Here is an example implementation of a Chromosome. Given a goal string, a Chromosome's fitness is the 'distance' between it and the goal. A fitness of 0 is the best. Chromosomes are sorted by Fitness() ascending.

package main

import (
  "fmt"
  "math/rand"
  "time"
  "github.com/hstove/genetic"
)

const chars = "abcdefghijklmnopqrstuvwxyz"
const goal = "hankstoeverisabadgolangprogrammer"

// Chromosome Implementation
type RandomString struct {
  Member string
}

var memoizedFitness = make(map[string]int16)

func (this RandomString) String() (str string){
  return fmt.Sprintf("{Member: %s | Fitness: %d}", this.Member, this.Fitness())
}

func NewRandomString() *RandomString {
  member := ""
  for i := 0; i < len(goal); i++ {
    char := string(chars[rand.Intn(len(chars))])
    member += char
  }
  return &RandomString{Member: member}
}

func (r RandomString) Fitness() int16{
  if val, ok := memoizedFitness[r.Member]; ok {
    return val
  }
  fitness := int16(0)
  for i := 0; i < len(goal); i++ {
    difference := int16(goal[i]) - int16(r.Member[i])
    if difference < 0 {
      fitness += -1 * difference
    } else {
      fitness += difference
    }
  }
  fitness *= -1
  memoizedFitness[r.Member] = fitness
  return fitness
}

func (r RandomString) Recombine(newPopulation chan<- genetic.Chromosome, chromosome genetic.Chromosome) {
  var other *RandomString = chromosome.(*RandomString)
  length := len(goal)
  split := rand.Intn(length-1)
  newMember := string(r.Member[0:split])
  newMember += string(other.Member[split:length])
  newPopulation <- &RandomString{newMember}
}

func (r RandomString) Mutate() genetic.Chromosome {
  return NewRandomString()
}

Then, create a Population with a bunch of Chromosomes in it. Evolve() until satisfied.

func main(){
  rand.Seed(time.Now().UTC().UnixNano())
  popSize := genetic.MaxPopulation
  var population genetic.Population
  for i := 0; i < popSize; i++ {
    population = append(population, NewRandomString())
  }
  i := 0
  for {
    i++
    population = population.Evolve()
    fmt.Println(i, population.BestFit(), population[len(population) - 1], len(population))
    if population.BestFit().Fitness() == 0 {
      fmt.Println(fmt.Sprintf("Found Champion after %d Generations", i))
      break
    }
  }
}

This outputs:

1 {Member: bqlijpphlfphvaemfhheafmopgjiggmbd | Fitness: -158} {Member: ikeyyfwbbgofgxowbgkiqpndjulokndbb | Fitness: -270} 10000
2 {Member: bqlijpphlfphvaemfhheafmopglodkkfd | Fitness: -147} {Member: dtjltogkiyckpymtckirnoelxuizererw | Fitness: -249} 10000
3 {Member: iatqvxcfugtiojfaeuojflvpqvjuhoogs | Fitness: -122} {Member: wupvqtpdmbhjszsfgujlkdxlizbueqcdo | Fitness: -235} 10000
4 {Member: iatqvxcfugtiojfaeuojflvpqvjuhoogs | Fitness: -122} {Member: qlkyqwjosdpfsvjsrxdinsfoqsdglqidk | Fitness: -224} 10000
5 {Member: sfnvkslewcoizdlachmycmhxyqiocnsen | Fitness: -121} {Member: memlkzogvfhomqfesswnshfncojfhqdzn | Fitness: -213} 10000
6 {Member: iaogkslewcoizdlachmycmhxyqiocnstv | Fitness: -115} {Member: hggmrixdypzcrkmtiwudimgkmkjzksebt | Fitness: -204} 10000
7 {Member: iaogkslewcoizdlachmycmhxyqiocnstv | Fitness: -115} {Member: qgmjorcyzjvppedghqeflgitrqdmhqvvv | Fitness: -195} 10000
8 {Member: iaogkslewcoizdlachmycmhxyqiocnmiv | Fitness: -98} {Member: dtnhvjsgsavjdfxcdaeipnxqpzgobckht | Fitness: -187} 10000
9 {Member: iaogkslewcoizdlachmycmhxyqiocnmiv | Fitness: -98} {Member: tqvnsrrhshpmyohcocgkmkagomdwenuop | Fitness: -179} 10000
...
60 {Member: hamkssoewerisabadgolangqrogrammer | Fitness: -4} {Member: hamkstnevfrjrabadgolangotnhqammer | Fitness: -11} 10000
61 {Member: hankstoeverisabacgolangqrogrammdr | Fitness: -3} {Member: hamkstogvfrjtabacgolangorogrammds | Fitness: -10} 10000
62 {Member: hankstodwerisabadgolangqrogrammer | Fitness: -3} {Member: hamkstodwerjrabacgolangorogrammds | Fitness: -9} 10000
63 {Member: hankstoeterisabadgolangorogrammer | Fitness: -3} {Member: hamlruoeverjrabacgolangprogrammfr | Fitness: -8} 10000
64 {Member: hankstoeverjsabadgolangqrogrammer | Fitness: -2} {Member: hamkstoexerjrabacgolangorpgrammer | Fitness: -8} 10000
65 {Member: hankstoeverhsabadgolangprogrammer | Fitness: -1} {Member: hankstoeteriqabacgolangoroframmer | Fitness: -7} 10000
66 {Member: hankstoeverhsabadgolangprogrammer | Fitness: -1} {Member: hankstneverjrabacholangqrogrammer | Fitness: -6} 10000
67 {Member: hankstoevfrisabadgolangprogrammer | Fitness: -1} {Member: hamkssoewerisabacholangorogrammer | Fitness: -6} 10000
68 {Member: hankstneverisabadgolangprogrammer | Fitness: -1} {Member: hamkstneverjrabadgolangqrogrammer | Fitness: -5} 10000
69 {Member: hankstoeverisabadgolangprogrammer | Fitness: 0} {Member: hankstoewerjsacacgolangorogrammer | Fitness: -5} 10000
Found Champion after 69 Generations