tmsquill / simple-ga

Sample code for an incredibly simple genetic algorithm.
MIT License
25 stars 25 forks source link

Python3 compatibility: string.letters, range() and dividing by 2 #1

Open benjordanstanford opened 5 years ago

benjordanstanford commented 5 years ago

Hello Troy, thanks for this code.

I added Python 3 funcitonality by

  1. changing xrange() to range()
  2. dividing by 2 not like " / 2" but like " // 2" to only get integers as a result
  3. changing string.letters to string.ascii_letters

My kind regards, Ben

This is your code example compatible with Python3:

from fuzzywuzzy import fuzz
import random, string

population = 20
generations = 10000
in_str = None
in_str_len = None

class Agent:
    def __init__(self, length):
        self.string = ''.join(random.choice(string.ascii_letters) for _ in range(length))
        self.fitness = -1

    def __str__(self):
        return f'{self.string}\t| {self.fitness}'

def genetic_algorithm():
    agents = init_agents(population, in_str_len)

    for generation in range(generations):
        print(f'Generation {generation}')

        agents = fitness(agents)
        agents = selection(agents)
        agents = crossover(agents)
        agents = mutation(agents)

        if any(agent.fitness >= 90 for agent in agents):
            print('Threshold met.')
            exit(0)

def init_agents(population, length):
    return [Agent(length) for _ in range(population)]

def fitness(agents):
    for agent in agents:
        agent.fitness = fuzz.ratio(agent.string, in_str)
    return agents

def selection(agents):
    agents = sorted(agents, key=lambda agent: agent.fitness, reverse=True)

    print('\n'.join(map(str, agents)))

    agents = agents[:int(0.2 * len(agents))]
    return agents

def crossover(agents):
    offspring = []

    for _ in range((population - len(agents)) // 2):
        parent1 = random.choice(agents)
        parent2 = random.choice(agents)
        child1 = Agent(in_str_len)
        child2 = Agent(in_str_len)
        split = random.randint(0, in_str_len)
        child1.string = parent1.string[0:split] + parent2.string[split:in_str_len]
        child2.string = parent2.string[0:split] + parent1.string[split:in_str_len]

        offspring.append(child1)
        offspring.append(child2)

    agents.extend(offspring)

    return agents

def mutation(agents):
    for agent in agents:
        for idx, param in enumerate(agent.string):
            if random.uniform(0.0, 1.0) <= 0.1:
                agent.string = agent.string[0:idx] + random.choice(string.ascii_letters) + agent.string[idx+1:in_str_len]

    return agents

if __name__ == '__main__':
    in_str = 'TroySquillaci'
    in_str_len = len(in_str)
    genetic_algorithm()
karippery commented 4 years ago

I got this error when I run your code. I already install fuzzywuzzy package Python 3.8.2 pip 20.0.2 fuzzywuzzy 0.18.0

Traceback (most recent call last):
  File "D:/python/firstml/geneicAlgo.py", line 3, in <module>
    from fuzzywuzzy import fuzz
ModuleNotFoundError: No module named 'fuzzywuzzy'
Asrua commented 2 years ago

@benjordanstanford Thanks for your update. It's a great help to me.