├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── img
├── 01_Battleship_Board_Solution.png
├── 02_Battleship_Random_Guess_51.png
├── 03_Random_Accuracy_53.png
├── 04_Generation_001.png
├── 05_Generation_002.png
├── 06_Generation_155.png
├── 07_Stats_10.png
├── 08_Stats_155.png
├── 09_Convergence.png
└── 10_Performance.png
├── requirements.txt
└── src
├── battleship.py
├── genetic_algorithm.py
└── genetic_algorithm_battleship.ipynb
/.gitattributes:
--------------------------------------------------------------------------------
1 | src/*.ipynb linguist-vendored
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
106 | # Logs and databases
107 | *.log
108 | *.sql
109 | *.sqlite
110 |
111 | # OS generated files
112 | .DS_Store
113 | .DS_Store?
114 | ._*
115 | .Spotlight-V100
116 | .Trashes
117 | ehthumbs.db
118 | Thumbs.db
119 |
120 | # config file
121 | config.py
122 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Adam C Dick
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DATA STRUCTURES AND ALGORITHMS
2 | # Understanding Genetic Algorithms
3 | SOLVING A BATTLESHIP BOARD GAME AS AN OPTIMIZATION PROBLEM
4 |
5 | A genetic algorithm is a prime example of technology imitating nature to solve complex problems, in this case, by adopting the concept of natural selection in an evolutionary algorithm. Genetic algorithms, introduced in 1960 by John Holland, extend Alan Turing’s concept of a “learning machine” and are best-suited for solving optimization problems such as the traveling salesman.
6 |
7 | To intuitively understand the practical implementation and fundamental requirements for employing genetic algorithms, we can set up a toy problem and solve the board of the classic guessing game, Battleship, first released by Milton Bradley in 1967. But rather than calling a sequence of individual shots, let’s ask our genetic algorithm to make a series of guesses of the entire board.
8 |
9 | [Continue reading the full story curated by Towards Data Science, a Medium publication...](https://towardsdatascience.com/understanding-genetic-algorithms-cd556e9089cb?source=friends_link&sk=70e5b098ef167ff2d1132396ab441030)
10 |
11 | ## Repository Contents
12 |
13 | * [Project Features](#project-features)
14 | * [Source Code](#source-code)
15 | * [Output Results](#output-results)
16 | * [Contribute](#contribute)
17 |
18 | ## Project Features
19 | ARTIFICIAL INTELLIGENCE | MACHINE LEARNING | OPTIMIZATION | EVOLUTIONARY ALGORITHMS | TOY PROBLEMS
20 |
21 |
22 |
23 |
24 |
25 | - [x] **Random Board Generator for Battleship Game**
26 | Graphical and binary representation of a Battleship board game with 5 ships occupying 17 squares
27 | - [x] **Implementation of Genetic Algorithm**
28 | Iterative solver that generates candidate solutions of an entire board of a random Battleship game, which converge to the genetic solution
29 | - [x] **Genetic Selector: Elitism**
30 | The fittest chromosomes from the former generation that are selected to be parents of all of the chromosomes in a new generation.
31 | - [x] **Genetic Operator: Crossover**
32 | Two chromosomes can be spliced at a random crossover gene and recombined to create two children, sharing gene chains from both parents.
33 | - [x] **Genetic Operator: Mutation**
34 | Random genes of one chromosome can be inverted with bit flips to create a single child that exhibits a small genetic variation from its parent.
35 |
36 | ## Source Code
37 | PYTHON | NUMPY | PANDAS
38 |
39 | **[The Random Board Generator](https://gist.github.com/acdick/11d2bc2d3c046306a143fd5a0b24b6a9)**
40 | 1. Position the head of the ship with a random two-dimensional tuple
41 | 2. Orient the heading of the ship with a random cardinal direction
42 | 3. Locate the tail of the ship based on its head position, direction and length
43 | 4. Check that the tail of the ship remains within the boundaries of the board
44 | 5. Check that the ship does not overlap with any previously positioned ships
45 | 6. Repeat the process if the ship fails either of the two assertion tests
46 |
47 | **[The Battleship Module](/src/battleship.py)**
48 |
49 | * Random board generator for a new Battleship game
50 | * Genetic representation of the board solution as binary representation
51 | * Fitness function evaluator of a candidate solution based on accuracy
52 |
53 | **[The Genetic Algorithm Module](/src/genetic_algorithm.py)**
54 | * Random solution generator for first generation
55 | * Assignment of elite chromosomes within a generation
56 | * Selection of elite parents to populate a new generation with elite rate
57 | * Creation of mutant descendents with bit flip rate
58 | * Creation of splice pair descendents with number of splice pairs
59 | * Filling of generation vacancies with random descendents
60 | * Creation of descendent generations with specified population mix and termination criterion
61 | * Solution driver to create generations until convergence to the genetic solution
62 |
63 | ## Output Results
64 | SEABORN | MATPLOTLIB
65 |
66 | **[Genetic Algorithm Demo](/src/genetic_algorithm_battleship.ipynb)**
67 | 1. Set up the board with random board generator
68 | 2. Generate candidate solution for the entire board
69 | 3. Determine fitness of candidate solution based on accuracy
70 | 4. Create descendent generations until convergence to the genetic solution
71 | 5. Describe fitness statistics of generations to inspect algorithm behavior
72 | 6. Solve 1,000 random board games to assess performance of model parameters of genetic algorithm
73 |
74 | **Random Chromosome**
75 | * 51 Occupied Squares (Solution: 1, Candidate: Red)
76 | * 49 Unoccupied Squares (Solution: 0, Candidate: Blue)
77 |
78 |
79 |
80 |
81 |
82 | **Accuracy Rate of Random Chromosome**
83 | * 52% candidate accuracy
84 | * 52 Matches (Green)
85 | * 48 Mismatches (Red)
86 |
87 |
88 |
89 |
90 |
91 | **Fitness of Generation 1**
92 | * 10 Random chromosomes
93 | * 2 top performers are 57% accurate
94 | * Median fitness of generation is 52.5%
95 |
96 |
97 |
98 |
99 |
100 | **Fitness of Generation 2**
101 | * 10 total chromosomes
102 | * 2 Elitism chromosomes (20% elite rate)
103 | * 2 Splice Pair chromosomes (20% crossover rate)
104 | * 6 Mutation chromosomes (60% mutation rate and 1% bit flip rate)
105 | * 2 top performers improve fitness to be 60% and 58% accurate
106 |
107 |
108 |
109 |
110 |
111 | **Fitness of Generation 155**
112 | * 155 generations with 10 chromosomes per generation
113 | * 1 Mutation chromosome converges to genetic solution
114 |
115 |
116 |
117 |
118 |
119 | **Fitness Distribution Statistics for Generations 1 to 10**
120 | * Natural selection gradually improves population fitness
121 | * Dispersion is highest in the first random generation
122 |
123 |
124 |
125 |
126 |
127 | **Fitness Distribution Statistics for Generations 146 to 155**
128 | * All generations are extremely fit with least fit chromosome having 95% accuracy
129 | * Improved fitness is most likely to occur through mutation of a single gene
130 | * High mutation rates and low bit flip rates give latter generations better chance to converge
131 |
132 |
133 |
134 |
135 |
136 | **Convergence of the Gene Pool Towards the Optimal Solution Over 155 Generations**
137 | * First random generation will be 50% accurate
138 | * Elitism guarantees that generational peak performance is monotonically increasing
139 | * Crossover promotes substantial improvements to fitness in initial generations
140 | * Mutation achieves convergence with genetic solution in latter generations
141 |
142 |
143 |
144 |
145 |
146 | **Performance Metric of a Genetic Algorithm with Fixed Model Parameters Over 1,000 Samples**
147 | * Genetic algoritm performance is influenced by nature of Battleship problem and the model parameters
148 | * Performance can be measured by sampling and solving 1,000 random Battleship board games
149 | * Model parameters can be tuned by using the performance distribution as an objective function
150 |
151 |
152 |
153 |
154 |
155 | ## Contribute
156 |
157 | **Contact**
158 | * [Email](mailto:adam.c.dick@gmail.com)
159 | * [LinkedIn](https://www.linkedin.com/in/adamcdick/)
160 | * [Medium](https://medium.com/@adam.c.dick)
161 | * [Scholar](https://scholar.google.com/citations?user=eMO88ogAAAAJ&hl=en)
162 |
163 | **License**
164 | * [MIT License](https://github.com/acdick/understanding_genetic_algorithms/blob/master/LICENSE)
165 |
--------------------------------------------------------------------------------
/img/01_Battleship_Board_Solution.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/01_Battleship_Board_Solution.png
--------------------------------------------------------------------------------
/img/02_Battleship_Random_Guess_51.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/02_Battleship_Random_Guess_51.png
--------------------------------------------------------------------------------
/img/03_Random_Accuracy_53.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/03_Random_Accuracy_53.png
--------------------------------------------------------------------------------
/img/04_Generation_001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/04_Generation_001.png
--------------------------------------------------------------------------------
/img/05_Generation_002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/05_Generation_002.png
--------------------------------------------------------------------------------
/img/06_Generation_155.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/06_Generation_155.png
--------------------------------------------------------------------------------
/img/07_Stats_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/07_Stats_10.png
--------------------------------------------------------------------------------
/img/08_Stats_155.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/08_Stats_155.png
--------------------------------------------------------------------------------
/img/09_Convergence.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/09_Convergence.png
--------------------------------------------------------------------------------
/img/10_Performance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acdick/understanding_genetic_algorithms/2609446dd7790287baf4e949d6c9407bca2391a3/img/10_Performance.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | matplotlib==3.0.2
2 | numpy==1.15.4
3 | pandas==0.23.4
4 | seaborn==0.9.0
--------------------------------------------------------------------------------
/src/battleship.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | # generate battleship board and solution
4 | def new_board():
5 |
6 | # create a clear board
7 | dim = 10
8 | board = np.zeros((dim, dim), dtype=int)
9 |
10 | # randomly place ships on the board
11 | ship_lengths = [5, 4, 3, 3, 2]
12 |
13 | # for each ship
14 | for ship_length in ship_lengths:
15 | is_ship_placed = False
16 |
17 | while not is_ship_placed:
18 | # seed a coordinate for the head of a ship
19 | head = tuple(np.random.randint(dim, size=2))
20 |
21 | # choose a direction for the ship to be laid out
22 | # N=0, S=1, E=2, W=3
23 | heading = np.random.randint(4)
24 |
25 | # check that the ship does not hang off the edge of the board
26 | if heading == 0:
27 | tail = (head[0] - ship_length + 1, head[1])
28 | elif heading == 1:
29 | tail = (head[0] + ship_length - 1, head[1])
30 | elif heading == 2:
31 | tail = (head[0], head[1] + ship_length - 1)
32 | elif heading == 3:
33 | tail = (head[0], head[1] - ship_length + 1)
34 |
35 | if not ((0 <= tail[0] <= dim-1) and (0 <= tail[1] <= dim-1)):
36 | continue
37 |
38 | # check that the ship does not overlap with any others
39 | NS_min = min(head[0],tail[0])
40 | NS_max = max(head[0],tail[0])
41 | EW_min = min(head[1],tail[1])
42 | EW_max = max(head[1],tail[1])
43 |
44 | if sum(sum(board[NS_min:NS_max+1,EW_min:EW_max+1])) != 0:
45 | continue
46 |
47 | # place the ship
48 | board[NS_min:NS_max+1,EW_min:EW_max+1] = 1
49 | is_ship_placed = True
50 |
51 | #check number of pieces on the board
52 | if sum(ship_lengths) == sum(sum(board)):
53 | print('Correct number of pieces on board')
54 | else:
55 | print('Incorrect number of pieces on board')
56 |
57 | # represent board solution in genetic form
58 | genetic_solution = ''.join(str(x) for x in list(board.flatten()))
59 |
60 | return board, genetic_solution
61 |
62 | # fitness function
63 | def accuracy(solution, candidate):
64 | n_gene_matches = 0
65 |
66 | for i in range(len(solution)):
67 | if solution[i] == candidate[i]:
68 | n_gene_matches += 1
69 |
70 | return n_gene_matches / len(solution)
--------------------------------------------------------------------------------
/src/genetic_algorithm.py:
--------------------------------------------------------------------------------
1 | import battleship as ship
2 | import pandas as pd
3 | import numpy as np
4 |
5 | def random_generation(generation_size, genes):
6 |
7 | # create dataframe for gene pool
8 | generation = pd.DataFrame(columns=['Sequence','Chromosome','Generation','Birth','Fitness','Parents'])
9 |
10 | # for each chromosome
11 | i = 0
12 | while i < generation_size:
13 |
14 | # create random chromosome
15 | chromosome = {}
16 | chromosome['Sequence'] = i+1
17 | chromosome['Chromosome'] = ''.join(str(x) for x in list(np.random.randint(2, size=genes)))
18 | chromosome['Generation'] = 1
19 | chromosome['Birth'] = 'Random'
20 | chromosome['Parents'] = 0
21 |
22 | # check for uniqueness and add to gene pool
23 | if chromosome['Chromosome'] not in generation['Chromosome']:
24 | generation = generation.append(chromosome, ignore_index=True)
25 | i += 1
26 |
27 | # return the generation
28 | return generation
29 |
30 | def assign_elites(generation, elite_rate):
31 |
32 | # determine number of elites
33 | generation_size = generation.shape[0]
34 | elites = elite_rate * generation_size
35 |
36 | # assign elite status to most fit chromosomes
37 | generation['Elite'] = False
38 | generation = generation.sort_values(by='Fitness', ascending=False)
39 | generation.iloc[0:int(elites),6:7] = True
40 |
41 | # return the generation
42 | return generation
43 |
44 | def select_elites(generation):
45 |
46 | # copy elites from old generation
47 | elites = generation.loc[generation['Elite'] == True].copy()
48 |
49 | # update attributes of new generation
50 | pool_size = generation['Sequence'].max()
51 | elites['Parents'] = elites['Sequence']
52 | elites['Sequence'] = range(pool_size + 1, pool_size + elites.shape[0] + 1)
53 | elites.loc[:,'Birth'] = 'Elitism'
54 | elites['Elite'] = False
55 | elites['Generation'] = generation['Generation'].max() + 1
56 |
57 | return elites
58 |
59 | def create_mutants(generation, mutants, bit_flip_rate):
60 |
61 | # get generation attributes
62 | last_generation = generation['Generation'].max()
63 | last_sequence = generation['Sequence'].max()
64 | n_elites = generation['Birth'].value_counts()['Elitism']
65 |
66 | # for each mutant
67 | i = 0
68 | while i < mutants:
69 |
70 | # create mutant chromosome
71 | chromosome = {}
72 | chromosome['Sequence'] = last_sequence + i + 1
73 | chromosome['Generation'] = last_generation
74 | chromosome['Birth'] = 'Mutation'
75 | chromosome['Elite'] = False
76 |
77 | # select random elite as new parent
78 | parent_index = np.random.choice(n_elites)
79 | chromosome['Parents'] = list(generation['Sequence'].values)[parent_index]
80 | parent = list(generation['Chromosome'].values)[parent_index]
81 |
82 | # create array of random bit flips
83 | bit_flip_array = np.random.choice(2, len(parent), p=[1 - bit_flip_rate, bit_flip_rate])
84 | bits_to_flip = ''.join(str(x) for x in list(bit_flip_array.flatten()))
85 |
86 | # create mutant child from parent and flip bits from array
87 | mutant = ''
88 | for j in range(len(bits_to_flip)):
89 | if not int(bits_to_flip[j]):
90 | mutant += parent[j]
91 | else:
92 | mutant += str(abs(int(parent[j]) - 1))
93 |
94 | # check for uniqueness and add to gene pool
95 | chromosome['Chromosome'] = mutant
96 | if chromosome['Chromosome'] not in generation['Chromosome']:
97 | generation = generation.append(chromosome, ignore_index=True)
98 | i += 1
99 |
100 | # return the generation
101 | return generation
102 |
103 | def create_splices(generation, n_splice_pairs):
104 |
105 | # get generation attributes
106 | last_generation = generation['Generation'].max()
107 | last_sequence = generation['Sequence'].max()
108 | n_elites = generation['Birth'].value_counts()['Elitism']
109 |
110 | # for each splice pair
111 | i = 0
112 | while i < n_splice_pairs:
113 |
114 | # create splice pair chromosome
115 | chromosome = {}
116 | chromosome['Generation'] = last_generation
117 | chromosome['Birth'] = 'Splice Pair'
118 | chromosome['Elite'] = False
119 |
120 | # select random elite pair as new parents
121 | parent_indices = np.random.choice(n_elites, 2, replace=False)
122 | chromosome['Parents'] = np.array(generation['Sequence'].values)[parent_indices]
123 | parents = np.array(generation['Chromosome'].values)[parent_indices]
124 |
125 | # create random splice bit
126 | splice_bit = np.random.randint(len(parents[0]))
127 |
128 | # create splice pair children from parent and cross over bits
129 | splices = []
130 | splices.append(parents[0][0:splice_bit] + parents[1][splice_bit:len(parents[1])])
131 | splices.append(parents[1][0:splice_bit] + parents[0][splice_bit:len(parents[0])])
132 |
133 | # add splices to gene pool
134 | chromosome['Chromosome'] = splices[0]
135 | chromosome['Sequence'] = last_sequence + i + 1
136 | generation = generation.append(chromosome, ignore_index=True)
137 |
138 | chromosome['Chromosome'] = splices[1]
139 | chromosome['Sequence'] = last_sequence + i + 2
140 | generation = generation.append(chromosome, ignore_index=True)
141 |
142 | i += 1
143 |
144 | # return the generation
145 | return generation
146 |
147 | def fill_random(generation, generation_size, genes):
148 |
149 | # get generation attributes
150 | last_generation = generation['Generation'].max()
151 | last_sequence = generation['Sequence'].max()
152 |
153 | # for each random chromosome
154 | i = generation.shape[0]
155 | while i < generation_size:
156 |
157 | # create random chromosome
158 | chromosome = {}
159 | chromosome['Sequence'] = last_sequence + i + 1
160 | chromosome['Chromosome'] = ''.join(str(x) for x in list(np.random.randint(2, size=genes)))
161 | chromosome['Generation'] = last_generation
162 | chromosome['Birth'] = 'Random'
163 | chromosome['Parents'] = 0
164 | chromosome['Elite'] = False
165 |
166 | # check for uniqueness and add to gene pool
167 | if chromosome['Chromosome'] not in generation['Chromosome']:
168 | generation = generation.append(chromosome, ignore_index=True)
169 | i += 1
170 |
171 | # return the generation
172 | return generation
173 |
174 | def create_descendents(gene_pool, elite_rate, solution, stop_limit):
175 |
176 | # copy initial generation
177 | next_generation = gene_pool.copy()
178 | generation_size = next_generation.shape[0]
179 |
180 | # create generations until fitness criteria is achieved
181 | while gene_pool['Fitness'].max() < stop_limit:
182 |
183 | # print current generation
184 | # print(str(gene_pool['Generation'].max()) + ': ' + str(gene_pool['Fitness'].max()))
185 |
186 | # select elites with elite rate
187 | next_generation = select_elites(next_generation)
188 |
189 | # add splice pairs to generation
190 | splice_pair_rate = elite_rate / 2
191 | n_splice_pairs = int(splice_pair_rate * generation_size)
192 | next_generation = create_splices(next_generation, n_splice_pairs)
193 |
194 | # add mutants to generation
195 | mutant_rate = 0.60
196 | bit_flip_rate = 0.01
197 | n_mutants = int(mutant_rate * generation_size)
198 | next_generation = create_mutants(next_generation, n_mutants, bit_flip_rate)
199 |
200 | # fill the rest of the generation with random chromosomes for diversity
201 | next_generation = fill_random(next_generation, generation_size, 100)
202 |
203 | # compare fitness
204 | next_generation['Fitness'] = next_generation.apply(lambda row: ship.accuracy(row.Chromosome, solution), axis=1)
205 |
206 | # assign elites with elite rate
207 | elite_rate = 0.20
208 | next_generation = assign_elites(next_generation, elite_rate)
209 | next_generation
210 |
211 | # add generation to gene pool
212 | gene_pool = gene_pool.append(next_generation)
213 |
214 | return gene_pool
215 |
216 | def solve(solution, generation_size):
217 | # initialize the first random generation
218 | gene_pool = random_generation(generation_size, 100)
219 |
220 | # compare fitness
221 | gene_pool['Fitness'] = gene_pool.apply(lambda row: ship.accuracy(row.Chromosome, solution), axis=1)
222 |
223 | # assign elites with elite rate
224 | elite_rate = 0.20
225 | gene_pool = assign_elites(gene_pool, elite_rate)
226 |
227 | # create successive generations until termination criteria is met
228 | gene_pool = create_descendents(gene_pool, elite_rate, solution, 1.0)
229 | gene_pool = gene_pool.set_index('Sequence')
230 |
231 | return gene_pool
--------------------------------------------------------------------------------