diff --git a/evolve_text.py b/evolve_text.py index e0202d2..f042efa 100644 --- a/evolve_text.py +++ b/evolve_text.py @@ -92,8 +92,23 @@ def get_text(self): # Genetic operators #----------------------------------------------------------------------------- -# TODO: Implement levenshtein_distance function (see Day 9 in-class exercises) -# HINT: Now would be a great time to implement memoization if you haven't +def levenshtein_distance(s1, s2, memo=None): + if memo is None: + memo = {} + if len(s1) == 0: + return len(s2) + if len(s2) == 0: + return len(s1) + if (len(s1), len(s2)) in memo: + return memo[(len(s1), len(s2))] + delta = 1 if s1[-1] != s2[-1] else 0 + diag = levenshtein_distance(s1[:-1], s2[:-1], memo) + delta + vert = levenshtein_distance(s1[:-1], s2, memo) + 1 + horz = levenshtein_distance(s1, s2[:-1], memo) + 1 + ans = min(diag, vert, horz) + memo[(len(s1), len(s2))] = ans + return ans + def evaluate_text(message, goal_text, verbose=VERBOSE): """ @@ -121,13 +136,12 @@ def mutate_text(message, prob_ins=0.05, prob_del=0.05, prob_sub=0.05): """ if random.random() < prob_ins: - # TODO: Implement insertion-type mutation - pass - - # TODO: Also implement deletion and substitution mutations - # HINT: Message objects inherit from list, so they also inherit - # useful list methods - # HINT: You probably want to use the VALID_CHARS global variable + message.insert(random.randrange(len(message)), random.choice(VALID_CHARS)) + elif random.random() < prob_del: + message.pop(random.randrange(len(message))) + elif random.random() < prob_sub: + index = random.randrange(len(message)) + message[index] = random.choice(VALID_CHARS) return (message, ) # Length 1 tuple, required by DEAP @@ -181,8 +195,10 @@ def evolve_string(text): # Run simple EA # (See: http://deap.gel.ulaval.ca/doc/dev/api/algo.html for details) - pop, log = algorithms.eaSimple(pop, + pop, log = algorithms.eaMuPlusLambda(pop, toolbox, + mu=300, + lambda_=300, cxpb=0.5, # Prob. of crossover (mating) mutpb=0.2, # Probability of mutation ngen=500, # Num. of generations to run diff --git a/results.txt b/results.txt new file mode 100644 index 0000000..1d51eef --- /dev/null +++ b/results.txt @@ -0,0 +1,5 @@ +Modification 1: + DEAP's eaMuPlusLambda algorithm, with a value of 300 for both mu and lambda, seemed to marginally improve the number of generations taken to converge on the target string. Increasing these values had the same type of effect. + +Modification 2: + Increasing the probabilities of mutation dramatically increased the speed of convergence, as one might expect. With probabilities of 50% for each of the three types of mutations, it took just over 100 generations. \ No newline at end of file