-
-
Notifications
You must be signed in to change notification settings - Fork 46.6k
/
Copy pathgeneric mutation.py
146 lines (116 loc) · 4.21 KB
/
generic mutation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# Python3 program to create target string, starting from
# random string using Genetic Algorithm
import random
# Number of individuals in each generation
POPULATION_SIZE = 10
# Valid genes
GENES = '''abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP
QRSTUVWXYZ 1234567890, .-;:_!"#%&/()=?@${[]}'''
# Target string to be generated
TARGET = "I love GeeksforGeeks"
class Individual(object):
'''
Class representing individual in population
'''
def __init__(self, chromosome):
self.chromosome = chromosome
self.fitness = self.cal_fitness()
@classmethod
def mutated_genes(self):
'''
Create random genes for mutation
'''
global GENES
gene = random.choice(GENES)
return gene
@classmethod
def create_gnome(self):
'''
Create chromosome or string of genes
'''
global TARGET
gnome_len = len(TARGET)
return [self.mutated_genes() for _ in range(gnome_len)]
def mate(self, par2):
'''
Perform mating and produce new offspring
'''
# Chromosome for offspring
child_chromosome = []
for gp1, gp2 in zip(self.chromosome, par2.chromosome):
# Random probability
prob = random.random()
# If prob is less than 0.45, insert gene
# from parent 1
if prob < 0.45:
child_chromosome.append(gp1)
# If prob is between 0.45 and 0.90, insert
# gene from parent 2
elif prob < 0.90:
child_chromosome.append(gp2)
# Otherwise insert random gene (mutate),
# for maintaining diversity
else:
child_chromosome.append(self.mutated_genes())
# Create new Individual (offspring) using
# generated chromosome for offspring
return Individual(child_chromosome)
def cal_fitness(self):
'''
Calculate fitness score, it is the number of
characters in string which differ from target
string.
'''
global TARGET
fitness = 0
for gs, gt in zip(self.chromosome, TARGET):
if gs != gt:
fitness += 1
return fitness
# Driver code
def main():
global POPULATION_SIZE
# Current generation
generation = 1
found = False
population = []
# Create initial population
for _ in range(POPULATION_SIZE):
gnome = Individual.create_gnome() # Fixed this
population.append(Individual(gnome))
while not found:
# Sort the population in increasing order of fitness score
population = sorted(population, key = lambda x:x.fitness)
# If the individual having the lowest fitness score is 0,
# we have reached the target
if population[0].fitness <= 0:
found = True
break
# Otherwise, generate new offsprings for new generation
new_generation = []
# Perform Elitism, that means 10% of fittest population
# goes to the next generation
s = int((10 * POPULATION_SIZE) / 100)
new_generation.extend(population[:s])
# From 50% of the fittest population, individuals
# will mate to produce offspring
s = int((90 * POPULATION_SIZE) / 100)
for _ in range(s):
parent1 = random.choice(population[:50])
parent2 = random.choice(population[:50])
child = parent1.mate(parent2)
new_generation.append(child)
population = new_generation
# Print current generation details
print("Generation: {}\tString: {}\tFitness: {}".format(
generation,
"".join(population[0].chromosome),
population[0].fitness))
generation += 1
# Print final result
print("Generation: {}\tString: {}\tFitness: {}".format(
generation,
"".join(population[0].chromosome),
population[0].fitness))
if __name__ == '__main__':
main()