forked from blaa/PyGene
-
Notifications
You must be signed in to change notification settings - Fork 0
/
demo_case.py
executable file
·165 lines (125 loc) · 4.28 KB
/
demo_case.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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#! /usr/bin/env python
"""
demo that tries to show one reason why genetic algorithms are successful.
It tries to crack open a suitcase with a few locks, each with 1-5
digits. Fitness function can only determine that the lock is open, not
the progress of opening the lock (how much the lock is opened)
Genetic algorithm can keep partial results (e.g. 1 lock open) while
trying other locks.
In general each lock represents a partial solution to the problem
described by organism.
"""
import random
from time import time
import sys
from pygene.gene import IntGene, IntGeneRandom, IntGeneExchange
from pygene.organism import Organism, GenomeSplitOrganism
from pygene.population import Population
# Parameters
locks = 8
digits_in_lock = 3
# Generate codes
codes = []
for lock in range(locks):
code = [random.randint(0, 9) for i in range(digits_in_lock)]
codes.append(code)
class DigitCodeGene(IntGeneRandom):
"""
a gene which holds a single digit, and can mutate into another digit.
Mutation randomizes gene for IntGeneRandom class.
"""
mutProb = 0.3
# mutAmt = 2
randMin = 0
randMax = 9
def __repr__(self):
return str(self.value)
# generate a genome, one gene for each digit in suitcase
genome = {}
for l in range(locks):
for d in range(digits_in_lock):
key = '%d_%d' % (l, d)
genome[key] = DigitCodeGene
# an organism that evolves towards the required string
class CodeHacker(GenomeSplitOrganism):
chromosome_intersections = 2
genome = genome
def get_code(self, lock):
"Decode the chromosome (genome) into code for specific lock"
code = []
for d in range(digits_in_lock):
key = '%d_%d' % (lock, d)
code.append(self[key])
return code
def fitness(self):
"calculate fitness - number of locks opened by genome."
opened_locks = 0
for l in range(locks):
code = self.get_code(l)
if code == codes[l]:
opened_locks += 1
# The lower the better
# add 0 - 0.5 to force randomization of organisms selection
fitness = float(locks - opened_locks) #+ random.uniform(0, 0.5)
return fitness
def __repr__(self):
"Display result nicely"
s='<CodeHacker '
for l in range(locks):
code = self.get_code(l)
code_str = "".join(str(i) for i in code)
if code == codes[l]:
s += " %s " % code_str # space - opened lock
else:
s += "(%s)" % code_str # () - closed lock
s = s.strip() + ">"
return s
class CodeHackerPopulation(Population):
"Configuration of population"
species = CodeHacker
initPopulation = 500
# Tips: Leave a space for mutants to live.
# cull to this many children after each generation
childCull = 600
# number of children to create after each generation
childCount = 500
# Add this many mutated organisms.
mutants = 1.0
# Mutate organisms after mating (better results with False)
mutateAfterMating = False
numNewOrganisms = 0
# Add X best parents into new population
# Good configuration should in general work without an incest.
# Incest can cover up too much mutation
incest = 2
def main():
# Display codes
print("CODES TO BREAK:", end=' ')
for code in codes:
print("".join(str(digit) for digit in code), end=' ')
print()
# Display some statistics
combinations = 10**(locks * digits_in_lock)
operations = 10000 * 10**6
print("Theoretical number of combinations", combinations)
print("Optimistic operations per second:", operations)
print("Direct bruteforce time:", 1.0* combinations / operations / 60.0/60/24, "days")
# Hack the case.
started = time()
# Create population
ph = CodeHackerPopulation()
i = 0
while True:
b = ph.best()
print("generation %02d: %s best=%s average=%s)" % (
i, repr(b), b.get_fitness(), ph.fitness()))
if b.get_fitness() < 1:
#for org in ph:
# print " ", org
print("cracked in ", i, "generations and ", time() - started, "seconds")
break
sys.stdout.flush()
i += 1
ph.gen()
if __name__ == '__main__':
main()