Source code for pycrypt.solvers.threadedgeneticsolver

import multiprocessing as mp
import dill
import itertools
import solver
from geneticsolver import GeneticSolver
from ..translators.substitutiontranslator import *
from ..keygenerators.substitutionkeygenerator import *
from ..scorers.czechscorer import *
from .. import utils
import pprint


[docs]def mapper(solver): solver, text, iterations, log = dill.loads(solver) random.seed() # since the environment is copied, we need to reinitialize the seed for each process res = solver.solve(text, iterations, return_all_keys=True) if log != None: return res, solver.log return res
[docs]class ThreadedGeneticSolver(solver.Solver): """Implements the island model using GeneticSolver""" def __init__(self, keyGenerator=SubstitutionKeyGenerator(), translator=SubstitutionTranslator(), scorer=CzechScorer(), num_processes=None, migration_iterations=10, migration_size=10, quiet=False, log=False, **kwargs): """ kwargs are simply passed to GeneticSolver. Special argument num_processes sets the number of islands created, None sets it to number of cores. migration_iterations sets how often migration (exchange of best individuals), migration_size sets the number of those individuals """ solver.Solver.__init__(self, keyGenerator, translator, scorer) if (quiet): self.printer = lambda *x: None self.lastPrint = lambda *x: None self.printLength = 80 self.num_processes = num_processes if num_processes else mp.cpu_count() # number of cores self.migration_iterations = migration_iterations self.migration_size = migration_size self.quiet = quiet self.log = [[] for i in range(self.num_processes)] if log else None self.kwargs = kwargs self.solvers = [GeneticSolver(self.keyGenerator, self.translator, self.scorer, quiet=i or quiet, log=log, **kwargs) for i in range(self.num_processes)] # only one solver will not be quiet self.solvers[0].lastPrint = lambda *x: None
[docs] def solve(self, text=None, iterations=0, return_all_keys=False): """Paralelized GeneticSolver's solve. Note that you can't interrupt the evolution as you could normally.""" while (iterations != 1): iterations -= 1 # we need to pickle all the needed information for the mapper function (as it is completely isolated) results = mp.Pool().map(mapper, [dill.dumps((s, text, self.migration_size, self.log)) for s in self.solvers]) if self.log != None: results, logs = zip(*results) # exchange best individuals in cyclicly (island 1 sends to island2, island 2 to 3 and so on) best = results[0][0] for i, solver in enumerate(self.solvers): pop = [result[1] for result in results[i]] pop += [result[1] for result in results[(i+1) % len(results)][:self.migration_size]] # add new individuals solver.setStartingPoint(pop) if results[i][0][0] >= best[0]: # find best individual for printing best = results[i][0] self.translator.setKey(best[1]) translated = self.translator.translate(text) self.printer(best[1], best[0], translated, iterations) if self.log != None: for i in range(len(self.solvers)): self.log[i].extend(logs[i]) results = itertools.chain(*results) results = sorted(results, key=lambda x: -x[0]) self.lastPrint(results[0][1], results[0][0], self.score(results[0][1], text)[1]) if return_all_keys: return results return results[0]
[docs] def printer(self, key, score, text=None, iterations=None): """Gets the best sample in population in every cycle""" print print "Migration! Best individual from all {} islands:".format(self.num_processes) print ("{:3}. Score: {:.5f} Text: {}").format(abs(iterations), score, text[:self.printLength]) if (type(key) == dict): print "Key:" utils.pprint_dict(key) else: print "Key:", key print "===================================" print
[docs] def setStartingPoint(self, startingPoint): for solver in self.solvers: solver.setStartingPoint(startingPoint)
[docs] def lock(self, string, key=None): for solver in self.solvers: solver.lock(string, key)
[docs] def plotLog(self): utils.plot_genetic_log_threaded(self.log)