import solver
from bruteforcesolver import *
from ..translators.substitutiontranslator import *
from ..keygenerators.substitutionkeygenerator import *
from ..scorers.czechscorer import *
[docs]class GeneticSolver(solver.Solver):
"""Uses own genetic algorithm, calls KeyGenerators mutateKey method"""
def __init__(self, keyGenerator=None, translator=SubstitutionTranslator(), scorer=CzechScorer(),
population_size=20, mutations=20, random_starting_population=1000, quiet=False, exclude_tried=False, log=False,
crossover=True, temperature=False, temperature_func=lambda score, iter: min(2, 4 / score)):
"""
To silence text output use quiet, exclude_tried is for not using same keys more times.
Other params to tune the genetic algorithm
"""
self.temperature = temperature
self.temperature_func = temperature_func
if keyGenerator == None:
if temperature:
keyGenerator = SubstitutionKeyGenerator(weighted=scorer.idealNgramFrequencies[0])
else:
keyGenerator = SubstitutionKeyGenerator()
solver.Solver.__init__(self, keyGenerator, translator, scorer)
if (quiet):
self.printer = lambda *x: None
self.lastPrint = lambda *x: None
self.exclude_tried = exclude_tried
self.population_size = population_size
self.mutations = mutations
self.random_starting_population = random_starting_population
self.printLength = 80
self.crossover = crossover
self.log = [] if log else None
self.bruteForceSolver = BruteForceSolver(translator=translator, scorer=scorer, quiet=True) # for scoring population
[docs] def solve(self, text=None, iterations=0, return_all_keys=False):
"""Set iterations to 0 for infinite loop"""
best = (0.0, None)
tried = []
if (self.startingPoint == None): # fill population from random samples
self.bruteForceSolver.setKeyGenerator((self.keyGenerator.getRandomKey() for i in range(self.random_starting_population)))
population = self.bruteForceSolver.solve(text=text, return_all_keys=True)[:self.population_size]
if self.log:
self.log.append(population)
else:
population = zip([self.score(i, text, False) for i in self.startingPoint], self.startingPoint)
if (self.exclude_tried):
tried.extend(population)
if iterations > 1:
iterations += 1
try:
while iterations != 1:
iterations -= 1
next_population = population[:10] # copy the best from current population, so that the keys can't get worse (maybe remove this?)
for sample in population:
for i in range(self.mutations):
if self.temperature:
mutant = self.keyGenerator.mutateKey(sample[1], temp=self.temperature_func(population[0][0], abs(iterations)))
else:
mutant = self.keyGenerator.mutateKey(sample[1])
if (self.exclude_tried):
while (mutant in tried):
if self.temperature:
mutant = self.keyGenerator.mutateKey(sample[1], temp=self.temperature_func(population[0][0], abs(iterations)))
else:
mutant = self.keyGenerator.mutateKey(sample[1])
tried.append(mutant)
next_population.append((self.score(mutant, text, False), mutant))
if self.crossover:
for offspring in self.keyGenerator.crossover(population):
next_population.append((self.score(offspring, text, False), offspring))
population = sorted(next_population, key=lambda x: -x[0])[:self.population_size]
if self.log != None:
self.log.append(population)
key = population[0][1] # best in current
score, ciphered_text = self.score(key, text)
self.printer(key, score, ciphered_text, iterations)
if (score > best[0]):
best = (score, key)
except (KeyboardInterrupt, SystemExit):
print "Evolution interrupted! Setting starting point to continue"
self.startingPoint = [best[1]]
self.lastPrint(best[1], best[0], self.score(best[1], text)[1])
if return_all_keys:
return population
return best
[docs] def printer(self, key, score, text=None, iterations=None):
"""Gets the best sample in population in every cycle"""
print ("{:3}. Score: {:.5f} Text: {}").format(abs(iterations), score, text[:self.printLength])
[docs] def setStartingPoint(self, startingPoint):
"""Starting population -> can be list"""
if (type(startingPoint) == list):
self.startingPoint = startingPoint
elif (startingPoint == None):
self.startingPoint = None
else:
self.startingPoint = [startingPoint]
[docs] def lock(self, string, key=None):
"""Lock character in the keyGenerator for the given key, if None, startingPoint key is used"""
if (key==None):
if (self.startingPoint):
key = self.startingPoint[0]
else:
key = self.translator.key
for char in string:
self.keyGenerator.lock(char, key=key)
[docs] def plotLog(self):
utils.plot_genetic_log(self.log)