Dieguito
Dieguito

Reputation: 18

Creating a genetic algorithm

Im trying to recreate this code: https://github.com/Code-Bullet/Smart-Dots-Genetic-Algorithm-Tutorial/tree/master/BestTutorialEver , but in python, and it doesn't work, it keeps mutating the best dot and every generation starts with less dots. Here is the code (i use pygame for graphics):

Brain class:

class Brain(object):

    def __init__(self, size):
        self.size = size
        self.step = 0
        self.directions = [[0.0, 0.0] for j in range(size)]
        for i in range(len(self.directions)):
            randomAngle = random.uniform(0, 2 * math.pi)
            self.directions[i][0] = math.sin(randomAngle)
            self.directions[i][1] = math.cos(randomAngle)

    def mutate(self):
        mutationRate = 1
        for i in range(self.size):
            rand = random.random()
            if rand < mutationRate:
                dirAngle = math.acos(self.directions[i][1]) * (1.0 + random.random())
                self.directions[i][0] = math.sin(dirAngle)
                self.directions[i][1] = math.cos(dirAngle)

Population Class:

class Population(object):

    def __init__(self, size, win):
        self.bestDot = 0
        self.fitnessSum = 0.0
        self.win = win
        self.size = size
        self.dots = [Dot(win) for i in range(size)]

    def show(self):
        for i in range(self.size-1):
            self.dots[i+1].show()
        self.dots[0].show()

    def updt(self):
        for i in range(self.size):
            self.dots[i].updt()

    def calculateFitness(self):
        for i in range(self.size):
            self.dots[i].calculateFitness()


    def allDotsDead(self):
        for i in range(self.size):
            if not self.dots[i].dead and not self.dots[i].reachGoal:
                return False
        return True

    def naturalSelection(self):
        newDots = [Dot(self.win) for i in range(self.size)]
        self.setBestDot()
        self.calculateFitnessSum()
        newDots[0] = self.dots[self.bestDot].baby()
        newDots[0].isBest = True
        for i in range(self.size-1):
            parent = self.selectParent()
            newDots[i+1] = parent.baby()

        print(newDots[1])
        self.dots = newDots

    def calculateFitnessSum(self):
        self.fitnessSum = 0.0
        for i in range(self.size):
            self.fitnessSum += self.dots[i].fitness
        print(self.fitnessSum)

    def selectParent(self):
        rand = random.uniform(0, self.fitnessSum)
        runningSum = 0.0
        for i in range(self.size):
            runningSum += self.dots[i].fitness
            if runningSum >= rand:
                return self.dots[i]
        return None

    def mutate(self):
        for i in range(self.size):
            if not self.dots[i].isBest:
                self.dots[i].brain.mutate()

    def setBestDot(self):
        max = 0.0
        maxIndex = 0
        for i in range(len(self.dots)):
            if self.dots[i].fitness > max:
                max = self.dots[i].fitness
                maxIndex = i
        self.bestDot = maxIndex

Dot Class:

WIDTH, HEIGHT = 720, 640
GOAL = (WIDTH / 2, 50)


class Dot(object):
    def __init__(self, win):
        self.win = win
        self.fitness = 0
        self.reachGoal = False
        self.dead = False
        self.brain = Brain(200)
        self.pos = [WIDTH / 2, HEIGHT - 50]
        self.vel = [0, 0]
        self.acc = [0, 0]
        self.isBest = False

    def move(self):
        if len(self.brain.directions) > self.brain.step:
            self.acc = self.brain.directions[self.brain.step]
            self.brain.step += 1
        else:
            self.dead = True

        for i in range(len(self.vel)): self.vel[i] += self.acc[i]
        if self.vel[0] >= 5: self.vel[0] = 5
        if self.vel[1] >= 5: self.vel[1] = 5
        for i in range(len(self.pos)): self.pos[i] += self.vel[i]

    def show(self):
        if self.isBest:
            pygame.draw.circle(self.win, (0, 255, 0), self.pos, 4)
        else:
            pygame.draw.circle(self.win, (200, 100, 0), self.pos, 2)

    def updt(self):
        if not self.dead and not self.reachGoal:
            self.move()
            if self.pos[0] < 4 or self.pos[1] < 4 or self.pos[0] > WIDTH - 4 or self.pos[1] > HEIGHT - 4:
                self.dead = True
            elif math.hypot(self.pos[0] - GOAL[0], self.pos[1] - GOAL[1]) < 5:
                self.reachGoal = True

    def calculateFitness(self):
        distToGoal = math.hypot(self.pos[0] - GOAL[0], self.pos[1] - GOAL[1])
        self.fitness = 1.0 / 16.0 + 10000.0 / (distToGoal * distToGoal)

    def baby(self):
        baby = Dot(self.win)
        baby.brain.directions = self.brain.directions
        return baby

The problem is that i especify that the best dot dont mutate, but its mutate or change to a worst dot, also, i dont know why but in every generetion less dots spawn(or dots has exactly the same brain a dont mutate not even a litle), the mutation rate is in 100% but in every run there are less and less dots. Here screenshots of the first and 5th generation: https://i.sstatic.net/cGUJG.jpg

Also, if someone has some genetic algorithm in python to take as a model it would help.

Upvotes: 0

Views: 735

Answers (1)

Ahmed Gad
Ahmed Gad

Reputation: 866

I did not try the project you mentioned. You may try PyGAD, a Python 3 library for building the genetic algorithm and training machine learning algorithms. It is open-source where you can find the code at GitHub.

It is simple to use which allows you to control the crossover, mutation, and parent selection operators in an easy way. You can also control many parameters of the genetic algorithm using PyGAD.

PyGAD also works with a user-defined fitness function so you can adapt it to a wide-range of problems.

After installing PyGAD (pip install pygad), here is a simple example to get started that tries to find the best values for W1, W2, and W3 that satisfies the following equation:

44 = 4xW_1 - 2xW_2 + 1.2xW_3

import pygad
import numpy

function_inputs = [4,-2, 1.2]
desired_output = 44

def fitness_func(solution, solution_idx):
    output = numpy.sum(solution*function_inputs)
    fitness = 1.0 / (numpy.abs(output - desired_output) + 0.000001)

    return fitness

def on_generation(ga_instance):
    print(ga_instance.population)

ga_instance = pygad.GA(num_generations=50,
                       num_parents_mating=2,
                       fitness_func=fitness_func,
                       num_genes=3,
                       sol_per_pop=5)

ga_instance.run()
ga_instance.plot_result()

solution, solution_fitness, _ = ga_instance.best_solution()
print("Parameters of the best solution : {solution}".format(solution=solution))
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))

Upvotes: 2

Related Questions