Skip to content

Commit 6c6b46b

Browse files
committed
typos
1 parent ca6f0f0 commit 6c6b46b

File tree

3 files changed

+53
-72
lines changed

3 files changed

+53
-72
lines changed

Genetic/README.markdown

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ The randomization that allows for organisms to change over time. In GAs we build
2929
### Problem
3030
For this quick and dirty example, we are going to produce an optimized string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing.
3131

32-
We will be creating a bio-inspired world where the absolute existence is the string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible to ensure survival.
32+
We will be creating a bio-inspired world where the absolute existence is the string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible to ensure survival.
3333

3434
### Define the Universe
3535

@@ -73,8 +73,8 @@ let MUTATION_CHANCE = 100
7373
return lexicon[rand]
7474
}
7575
```
76-
77-
**Note**: `arc4random_uniform` is strickly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html)
76+
77+
**Note**: `arc4random_uniform` is strictly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html)
7878

7979
### Population Zero
8080

@@ -83,8 +83,6 @@ Before selecting, crossover and mutation, we need a population to start with. No
8383
```swift
8484
func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] {
8585

86-
let len = UInt32(lexicon.count)
87-
8886
var pop = [[UInt8]]()
8987

9088
(0..<populationSize).forEach { _ in
@@ -96,7 +94,7 @@ Before selecting, crossover and mutation, we need a population to start with. No
9694
pop.append(dna)
9795
}
9896
return pop
99-
}
97+
}
10098
```
10199

102100
### Selection
@@ -124,17 +122,17 @@ Let's take a second and ask why on this one. Why would you not always want to se
124122
With all that, here is our weight choice function:
125123

126124
```swift
127-
func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) {
125+
func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) {
128126

129127
let total = items.reduce(0.0) { return $0 + $1.weight}
130128

131129
var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0
132130

133-
for itemTuple in items {
134-
if n < itemTuple.weight {
135-
return itemTuple
131+
for item in items {
132+
if n < item.weight {
133+
return item
136134
}
137-
n = n - itemTuple.weight
135+
n = n - item.weight
138136
}
139137
return items[1]
140138
}
@@ -144,7 +142,7 @@ The above function takes a list of individuals with their calculated fitness. Th
144142

145143
## Mutation
146144

147-
The all powerful mutation, the thing that introduces otherwise non exisitant fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achive the optimal solution.
145+
The all powerful mutation, the thing that introduces otherwise non existent fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achieve the optimal solution.
148146

149147
```swift
150148
func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] {
@@ -184,7 +182,7 @@ The above is used to generate a completely new generation based on the current g
184182

185183
## Putting it all together -- Running the Genetic Algorithm
186184

187-
We now have all the functions we need to kick off the algorthim. Let's start from the beginning, first we need a random population to serve as a starting point. We will also initialize a fittest variable to hold the fittest individual, we will initialize it with the first individual of our random population.
185+
We now have all the functions we need to kick off the algorithm. Let's start from the beginning, first we need a random population to serve as a starting point. We will also initialize a fittest variable to hold the fittest individual, we will initialize it with the first individual of our random population.
188186

189187
```swift
190188
var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE)
@@ -202,7 +200,7 @@ for generation in 0...GENERATIONS {
202200
Now, for each individual in the population, we need to calculate its fitness and weighted value. Since 0 is the best value we will use `1/fitness` to represent the weight. Note this is not a percent, but just how much more likely the value is to be selected over others. If the highest number was the most fit, the weight calculation would be `fitness/totalFitness`, which would be a percent.
203201

204202
```swift
205-
var weightedPopulation = [(item:[UInt8], weight:Double)]()
203+
var weightedPopulation = [(dna:[UInt8], weight:Double)]()
206204

207205
for individual in population {
208206
let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL)
@@ -224,7 +222,7 @@ The below loop is where we pull everything together. We loop for `POP_SIZE`, sel
224222
let ind1 = weightedChoice(items: weightedPopulation)
225223
let ind2 = weightedChoice(items: weightedPopulation)
226224

227-
let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE)
225+
let offspring = crossover(dna1: ind1.dna, dna2: ind2.dna, dnaSize: DNA_SIZE)
228226

229227
// append to the population and mutate
230228
nextGeneration.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE))
@@ -237,7 +235,7 @@ The final piece to the main loop is to select the fittest individual of a popula
237235
fittest = population[0]
238236
var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL)
239237

240-
for indv in population {lex
238+
population.forEach { indv in
241239
let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL)
242240
if indvFitness < minFitness {
243241
fittest = indv

Genetic/gen.playground/Contents.swift

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
import Foundation
44

55
extension String {
6-
var asciiArray: [UInt8] {
6+
var unicodeArray: [UInt8] {
77
return [UInt8](self.utf8)
88
}
99
}
1010

1111

12-
let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray
12+
let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray
1313

1414
// This is the end goal and what we will be using to rate fitness. In the real world this will not exist
15-
let OPTIMAL:[UInt8] = "Hello, World".asciiArray
15+
let OPTIMAL:[UInt8] = "Hello, World".unicodeArray
1616

1717
// The length of the string in our population. Organisms need to be similar
1818
let DNA_SIZE = OPTIMAL.count
@@ -34,13 +34,11 @@ func randomChar(from lexicon: [UInt8]) -> UInt8 {
3434

3535
func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] {
3636

37-
let len = UInt32(lexicon.count)
38-
3937
var pop = [[UInt8]]()
4038

41-
for _ in 0..<populationSize {
39+
(0..<populationSize).forEach { _ in
4240
var dna = [UInt8]()
43-
for _ in 0..<dnaSize {
41+
(0..<dnaSize).forEach { _ in
4442
let char = randomChar(from: lexicon)
4543
dna.append(char)
4644
}
@@ -49,38 +47,33 @@ func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int)
4947
return pop
5048
}
5149

52-
randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE)
53-
5450
func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int {
55-
5651
var fitness = 0
57-
for c in 0...dna.count-1 {
52+
(0...dna.count-1).forEach { c in
5853
fitness += abs(Int(dna[c]) - Int(optimal[c]))
5954
}
6055
return fitness
6156
}
6257

63-
calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray)
64-
65-
func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) {
58+
func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) {
6659

6760
let total = items.reduce(0.0) { return $0 + $1.weight}
6861

6962
var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0
7063

71-
for itemTuple in items {
72-
if n < itemTuple.weight {
73-
return itemTuple
64+
for item in items {
65+
if n < item.weight {
66+
return item
7467
}
75-
n = n - itemTuple.weight
68+
n = n - item.weight
7669
}
7770
return items[1]
7871
}
7972

8073
func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] {
8174
var outputDna = dna
8275

83-
for i in 0..<dna.count {
76+
(0..<dna.count).forEach { i in
8477
let rand = Int(arc4random_uniform(UInt32(mutationChance)))
8578
if rand == 1 {
8679
outputDna[i] = randomChar(from: lexicon)
@@ -108,9 +101,8 @@ func main() {
108101
var fittest = [UInt8]()
109102

110103
for generation in 0...GENERATIONS {
111-
// print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)")
112104

113-
var weightedPopulation = [(item:[UInt8], weight:Double)]()
105+
var weightedPopulation = [(dna:[UInt8], weight:Double)]()
114106

115107
// calulcated the fitness of each individual in the population
116108
// and add it to the weight population (weighted = 1.0/fitness)
@@ -129,7 +121,7 @@ func main() {
129121
let ind1 = weightedChoice(items: weightedPopulation)
130122
let ind2 = weightedChoice(items: weightedPopulation)
131123

132-
let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE)
124+
let offspring = crossover(dna1: ind1.dna, dna2: ind2.dna, dnaSize: DNA_SIZE)
133125

134126
// append to the population and mutate
135127
population.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE))
@@ -139,7 +131,7 @@ func main() {
139131
var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL)
140132

141133
// parse the population for the fittest string
142-
for indv in population {lex
134+
population.forEach { indv in
143135
let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL)
144136
if indvFitness < minFitness {
145137
fittest = indv
@@ -154,4 +146,3 @@ func main() {
154146
}
155147

156148
main()
157-

Genetic/gen.swift

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
import Foundation
44

55
extension String {
6-
var asciiArray: [UInt8] {
6+
var unicodeArray: [UInt8] {
77
return [UInt8](self.utf8)
88
}
99
}
1010

1111

12-
let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray
12+
let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray
1313

1414
// This is the end goal and what we will be using to rate fitness. In the real world this will not exist
15-
let OPTIMAL:[UInt8] = "Hello, World".asciiArray
15+
let OPTIMAL:[UInt8] = "Hello, World".unicodeArray
1616

1717
// The length of the string in our population. Organisms need to be similar
1818
let DNA_SIZE = OPTIMAL.count
@@ -34,53 +34,46 @@ func randomChar(from lexicon: [UInt8]) -> UInt8 {
3434

3535
func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] {
3636

37-
let len = UInt32(lexicon.count)
38-
39-
var pop = [[UInt8]]()
40-
41-
for _ in 0..<populationSize {
42-
var dna = [UInt8]()
43-
for _ in 0..<dnaSize {
44-
let char = randomChar(from: lexicon)
45-
dna.append(char)
46-
}
47-
pop.append(dna)
48-
}
49-
return pop
37+
var pop = [[UInt8]]()
38+
39+
(0..<populationSize).forEach { _ in
40+
var dna = [UInt8]()
41+
(0..<dnaSize).forEach { _ in
42+
let char = randomChar(from: lexicon)
43+
dna.append(char)
44+
}
45+
pop.append(dna)
46+
}
47+
return pop
5048
}
5149

52-
randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE)
53-
5450
func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int {
55-
5651
var fitness = 0
57-
for c in 0...dna.count-1 {
52+
(0...dna.count-1).forEach { c in
5853
fitness += abs(Int(dna[c]) - Int(optimal[c]))
5954
}
6055
return fitness
6156
}
6257

63-
calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray)
64-
65-
func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) {
58+
func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) {
6659

6760
let total = items.reduce(0.0) { return $0 + $1.weight}
6861

6962
var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0
7063

71-
for itemTuple in items {
72-
if n < itemTuple.weight {
73-
return itemTuple
64+
for item in items {
65+
if n < item.weight {
66+
return item
7467
}
75-
n = n - itemTuple.weight
68+
n = n - item.weight
7669
}
7770
return items[1]
7871
}
7972

8073
func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] {
8174
var outputDna = dna
8275

83-
for i in 0..<dna.count {
76+
(0..<dna.count).forEach { i in
8477
let rand = Int(arc4random_uniform(UInt32(mutationChance)))
8578
if rand == 1 {
8679
outputDna[i] = randomChar(from: lexicon)
@@ -108,9 +101,8 @@ func main() {
108101
var fittest = [UInt8]()
109102

110103
for generation in 0...GENERATIONS {
111-
// print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)")
112104

113-
var weightedPopulation = [(item:[UInt8], weight:Double)]()
105+
var weightedPopulation = [(dna:[UInt8], weight:Double)]()
114106

115107
// calulcated the fitness of each individual in the population
116108
// and add it to the weight population (weighted = 1.0/fitness)
@@ -129,7 +121,7 @@ func main() {
129121
let ind1 = weightedChoice(items: weightedPopulation)
130122
let ind2 = weightedChoice(items: weightedPopulation)
131123

132-
let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE)
124+
let offspring = crossover(dna1: ind1.dna, dna2: ind2.dna, dnaSize: DNA_SIZE)
133125

134126
// append to the population and mutate
135127
population.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE))
@@ -139,7 +131,7 @@ func main() {
139131
var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL)
140132

141133
// parse the population for the fittest string
142-
for indv in population {lex
134+
population.forEach { indv in
143135
let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL)
144136
if indvFitness < minFitness {
145137
fittest = indv

0 commit comments

Comments
 (0)