Skip to content

Commit c638164

Browse files
committed
readme updates
1 parent b59cd5f commit c638164

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

Genetic/README.markdown

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int {
114114
}
115115
```
116116

117-
The above is a very simple fitness calculation, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival.
117+
The above will produce a fitness value to an individual. The perfect solution, "Hello, World" will have a fitness of 0. "Gello, World" will have a fitness of 1 since it is one ASCII value off from the optimal.
118+
119+
This example is very, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival.
118120

119121
The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or not be able to reproduce.
120122

@@ -146,13 +148,13 @@ The above function takes a list of individuals with their calculated fitness. Th
146148
The all powerful mutation. The great randomization that turns bacteria into humans, just add time. So powerful yet so simple:
147149

148150
```swift
149-
func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] {
151+
func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] {
150152
var outputDna = dna
151153

152154
for i in 0..<dna.count {
153155
let rand = Int(arc4random_uniform(UInt32(mutationChance)))
154156
if rand == 1 {
155-
outputDna[i] = randomChar()
157+
outputDna[i] = randomChar(from: lexicon)
156158
}
157159
}
158160

@@ -165,3 +167,25 @@ Takes a mutation chance and a individual and returns that individual with mutati
165167
This allows for a population to explore all the possibilities of it's building blocks and randomly stumble on a better solution. If there is too much mutation, the evolution process will get nowhere. If there is too little the populations will become too similar and never be able to branch out of a defect to meet their changing environment.
166168

167169
## Crossover
170+
171+
Crossover, the sexy part of a GA, is how offspring are created from 2 selected individuals in the current population. This is done by splitting the parents into 2 parts, then combining 1 part from each parent to create the offspring. To promote diversity, we randomly select a index to split the parents:
172+
173+
```swift
174+
func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) {
175+
let pos = Int(arc4random_uniform(UInt32(dnaSize-1)))
176+
177+
let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos)
178+
let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos)
179+
180+
return (
181+
[UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)),
182+
[UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1))
183+
)
184+
}
185+
```
186+
187+
The above is used to generate a completely new generation based on the current generation.
188+
189+
## Putting it all together -- Running the Genetic Algorithm
190+
191+
We now have all the methods we need to kick off the process. What is missing a `main()` function that loops though each generation of the GA.

Genetic/gen.playground/Contents.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int {
6060
return fitness
6161
}
6262

63-
calculateFitness(dna: "Hillo, World".asciiArray, optimal: "Hello, World".asciiArray)
63+
calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray)
6464

6565
func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) {
6666

@@ -77,15 +77,28 @@ func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], wei
7777
return items[1]
7878
}
7979

80-
func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] {
80+
func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] {
8181
var outputDna = dna
8282

8383
for i in 0..<dna.count {
8484
let rand = Int(arc4random_uniform(UInt32(mutationChance)))
8585
if rand == 1 {
86-
outputDna[i] = randomChar()
86+
outputDna[i] = randomChar(from: lexicon)
8787
}
8888
}
8989

9090
return outputDna
9191
}
92+
93+
94+
func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) {
95+
let pos = Int(arc4random_uniform(UInt32(dnaSize-1)))
96+
97+
let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos)
98+
let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos)
99+
100+
return (
101+
[UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)),
102+
[UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1))
103+
)
104+
}

Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)