Pages

Tuesday 9 July 2013

The evolving string program


Before reading this you can have a look at my article on motivation behind writing this program (optional).
There are two words that sums up the definition of the word evolution:
  1. Descent with modicifation
  2. survival of the fittest
Therefore, our program will have 2 functions:




  1. Reproduce:
    • Takes in a string
    • Randomly mutate any one character of the string
    • Repeatedly do this a number of times
    • Return a list of mutated strings
  2. Natural selection:
    • Takes in a list of strings
    • Returns the fittest among them
Since our program is not very complicated, so I'll first write a working code and then explain.
import random
import time


def reproduce(string):
    children=[string]
    for i in range(100):
        mutant=list(string)
        mutant[int(random.uniform(0,1)*len(string))]=random.choice(all_char)
        mutant=reduce(lambda i,j : i+j,mutant)
        children+=[mutant]
    return children
    
def natural_selection(children,final):
    err_list=dict()
    final=list(final)
    for i in children:
        i=list(i)
        err=0
        for j in range(len(i)):
            err+=(ord(i[j])-ord(final[j]))**2

        err_list[reduce(lambda a,b : a+b,i)] = err
    return [k for k,v in err_list.iteritems() if v== min(err_list.values())][0]

        

main_str= 'i have just evolved from a random string'

all_char='abcdefghijklmnopqrstuvwxyz '

total_len= len(main_str)
temp=[]

for i in range(total_len):
    temp+=random.sample(all_char,1)

first_guess = reduce(lambda i,j : i+j, temp)


select=first_guess
print select

count=0
while 1:
    
    progeny=reproduce(select)
    select=natural_selection(progeny,main_str)
    count+=1
    time.sleep(.1)
    if select==main_str: break
    print select
print '-----------------------------------------'
print select
print '-----------------------------------------\n\n'

print 'initial guess : ' + first_guess
print 'evolved string: ' + main_str + '\n'
print 'number of generations = ' + str(count)
raw_input()

Reproduce takes the input "string" and splits it into a list of characters ['s','t','r','i','n','g']. Then randomly choose a character from the list and replace it by some other character (['s','t','r','i','a','g']). Then join the list back to form a mutated string: "striag" . Put this in the list of children and repeatedly do this to return a list (children) with 100 mutants and 1 progeny without mutation.

Natural selection takes the list of children and and the the final string i.e. the string that we need to evolve. It calculates the error for each child i.e. the difference between the the final string and the child string. To calculate this difference I have used the ord() function which returns the unicode of the character and squared it to get the absolute error. Eg.



>>> ord('a')
97
>>> ord('b')
98
>>> ord('c')
99
>>> ord('d')
100

Therefore, difference between 'abc' and 'acd' is:

>>> (ord('a')-ord('a'))**2+(ord('b')-ord('b'))**2+(ord('c')-ord('d'))**2
1

Natural selection then returns the child with the least error.

The programs starts with generating a random string (first_guess) and the taking its children and selecting the fittest progeny. Over the generations favourable mutations accumulate to give us the desired string ('i have just evolved from a random string').
That concludes our evolving string program in python. Feel free to ask me any doubts about the code.

No comments:

Post a Comment