Skip to content

Commit bba6aba

Browse files
committed
Add basic string genetic algorithm
1 parent 4b93143 commit bba6aba

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

genetic-algorithm/genetic_algo.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"math/rand"
7+
"os"
8+
"sort"
9+
"strconv"
10+
"time"
11+
"unicode/utf8"
12+
)
13+
14+
type populationItem struct {
15+
Key string
16+
Value float64
17+
}
18+
19+
func main() {
20+
// Define a random seed
21+
rand.Seed(time.Now().UnixNano())
22+
23+
// Define parameters
24+
sentence := string("This is a genetic algorithm to evaluate, combine, evolve mutate a string!")
25+
charmap := []rune(" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,;!?+-*#@^'èéòà€ù=)(&%$£/\\")
26+
populationNum := 200
27+
selectionNum := 50
28+
mutationProb := .1
29+
30+
// Verify the presence of all char in sentence
31+
for position, r := range []rune(sentence) {
32+
find := func() bool {
33+
for _, n := range charmap {
34+
if n == r {
35+
return true
36+
}
37+
}
38+
return false
39+
}
40+
if !find() {
41+
fmt.Println(errors.New("Character not aviable in charmap"), position, "\"", string(r), "\"")
42+
os.Exit(1)
43+
}
44+
}
45+
46+
// Generate random population
47+
pop := make([]populationItem, populationNum, populationNum)
48+
for i := 0; i < populationNum; i++ {
49+
key := ""
50+
for x := 0; x < utf8.RuneCountInString(sentence); x++ {
51+
choice := rand.Intn(len(charmap))
52+
key += string(charmap[choice])
53+
}
54+
pop[i] = populationItem{key, 0}
55+
}
56+
57+
for gen, generatedPop := 1, 0; ; gen++ {
58+
generatedPop += len(pop)
59+
60+
// Random population created now it's time to evaluate
61+
for i, item := range pop {
62+
itemKey, sentenceRune := []rune(item.Key), []rune(sentence)
63+
for x := 0; x < len(sentence); x++ {
64+
if itemKey[x] == sentenceRune[x] {
65+
pop[i].Value++
66+
}
67+
}
68+
pop[i].Value = pop[i].Value / float64(len(sentenceRune))
69+
}
70+
// Check if there is a right evolution
71+
sort.SliceStable(pop, func(i, j int) bool { return pop[i].Value > pop[j].Value })
72+
if pop[0].Key == sentence {
73+
fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", pop[0])
74+
break
75+
}
76+
// Print the best result
77+
if gen%1000 == 0 {
78+
fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", pop[0])
79+
}
80+
// Combine, Evolve and Mutate
81+
var popChildren []populationItem
82+
for i := 0; i < int(selectionNum); i++ {
83+
parent1 := pop[i]
84+
parent2 := pop[i+1]
85+
split := rand.Intn(utf8.RuneCountInString(sentence))
86+
87+
// Save Children 1
88+
child := append([]rune(parent1.Key)[:split], []rune(parent2.Key)[split:]...)
89+
if rand.Float64() > mutationProb {
90+
child[rand.Intn(len(child))] = charmap[rand.Intn(len(charmap))]
91+
}
92+
popChildren = append(popChildren, populationItem{string(child), 0})
93+
94+
// Save Children 2
95+
child = append([]rune(parent2.Key)[:split], []rune(parent1.Key)[split:]...)
96+
if rand.Float64() > mutationProb {
97+
child[rand.Intn(len(child))] = charmap[rand.Intn(len(charmap))]
98+
}
99+
popChildren = append(popChildren, populationItem{string(child), 0})
100+
}
101+
pop = popChildren
102+
}
103+
}

0 commit comments

Comments
 (0)