-
Notifications
You must be signed in to change notification settings - Fork 0
/
hello.py
115 lines (87 loc) · 3.14 KB
/
hello.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
import argparse
import functools
import math
import random
import string
letters = ''.join([
string.ascii_letters,
string.digits,
string.printable,
string.punctuation
])
def random_character():
return random.choice(letters)
def fitness(child, target_string):
characters_distance = [
math.fabs(ord(c) - ord(s))
for c, s in zip(child, target_string)
]
return sum(characters_distance)
def create_child(length):
random_characters = [random_character() for _ in range(length)]
random_string = ''.join(random_characters)
return random_string
def create_population(population_length, child_length):
population = [create_child(child_length)
for _ in range(population_length)]
return population
def crossover(child1, child2, locus):
new_child1 = child1[:locus] + child2[locus:]
new_child2 = child2[:locus] + child1[locus:]
return new_child1, new_child2
def mutation(child, pos):
char = random_character()
child = child[:pos] + char + child[pos + 1:]
return child
def run(target_string, population_length):
child_length = len(target_string)
fitness_func = functools.partial(fitness, target_string=target_string)
population = create_population(population_length, child_length)
best = population[0]
current_generation = 0
print('Generation | Fitness | Phenotype')
print('-----------------------' + '-' * child_length)
while best != target_string:
#
# selection
#
population = sorted(population, key=fitness_func)
new_population_length = int(len(population) * 0.2)
population = population[:new_population_length]
#
# crossover
#
while population_length > len(population):
child1 = random.choice(population)
child2 = random.choice(population)
locus = random.randrange(0, child_length)
new_child1, new_child2 = crossover(child1, child2, locus)
population.append(new_child1)
population.append(new_child2)
#
# mutation
#
for i in range(len(population)):
if random.random() > 0.98:
random_position = random.randrange(0, child_length)
population[i] = mutation(population[i], random_position)
current_generation += 1
best = min(population, key=fitness_func, default=best)
verbose_line = '{0:>10} | {1:>7} | {2}'.format(
current_generation,
fitness(best, target_string),
best
)
print(verbose_line)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Welcome to Hello-Evolution!')
parser.add_argument('-n',
dest='population_length',
default=10000,
help='population 1lenght')
parser.add_argument('--target', '-t',
dest='target_string',
default='Hello-Evolution',
help='String, that you are looking for')
args = parser.parse_args()
run(args.target_string, int(args.population_length))