Last active
November 9, 2021 19:16
-
-
Save bened-h/854f7b69c63dd8f7571ed7896566d518 to your computer and use it in GitHub Desktop.
Simple "genetic" algorithm for Processing (Python mode) showing a random point polpulation evolving to become a circle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This demonstration evolves a random point | |
population (parent) to order its points into a | |
circular arrangement (target). | |
The fitness is computed by measuring each point's | |
distance to its destination. | |
Read an introduction to genetic algorithms with python here: | |
https://www.codeproject.com/articles/1104747/introduction-to-genetic-algorithms-with-python-hel | |
""" | |
from random import random, randrange | |
from math import pi | |
def generate_parent(leng): | |
genes = [] | |
while len(genes) < leng: | |
genes.append((random()*sx, random()*sy)) | |
return genes | |
def get_fitness(guess): | |
d = 0 | |
# add all the distances: | |
for i, t in enumerate(target): | |
d+= dist(t[0], t[1], guess[i][0], guess[i][1]) | |
return 1/d | |
def mutate_node(parent, fitness): | |
mutation_size = 20/fitness/sx/sy # as fintess gets larger, mut gets smaller | |
index = randrange(0, len(parent)) # get random index | |
x = (random()*2-1)* sx * mutation_size | |
y = (random()*2-1)* sx * mutation_size | |
# print("{}\t{}\t{}".format(mutation_size, x, y)) | |
child = parent[:] # make a copy of parent | |
# modify node at index: | |
child[index] = (child[index][0]+x, child[index][1]+y) | |
return child | |
def display(guess, shade = 0, radius = 4): | |
fill(shade) | |
for i, n in enumerate(guess): | |
x, y = n | |
# grey lines inbetween: very slow for large numbers (<10) | |
for x2, y2 in guess[::num_of_points/5]: | |
stroke(0, 20) | |
line(x,y,x2,y2) | |
fill(shade) | |
ellipse(x,y,radius,radius) | |
stroke(shade) | |
# line to last node -> circle outline: | |
line(x,y,guess[i-1][0], guess[i-1][1]) | |
# screen size: | |
sx, sy = 800, 800 | |
num_of_points = 10 # | |
# construct target population: | |
target = [] | |
for i in range(num_of_points): | |
angle = pi*2/num_of_points*i | |
# polar to cartesian coords: | |
x, y = 800/2 + sin(angle)*250, 800/2 + cos(angle)*250 | |
target.append((x,y)) | |
best_parent = generate_parent(len(target)) | |
def setup(): | |
size(sx,sy) | |
frameRate(50) | |
def draw(): | |
background(200) | |
global best_parent # get the global variable | |
best_fintess = get_fitness(best_parent) | |
fill(0) | |
# text("Fitness: " + str(best_fintess), 0,10) | |
# stroke(150) | |
# display(target, 200, 8) | |
# stroke(0) | |
display(best_parent) | |
# look for fitter child: | |
attempts = 0 | |
while True: | |
child = mutate_node(best_parent, best_fintess) | |
childFitness = get_fitness(child) | |
if best_fintess <= childFitness: | |
best_fintess = childFitness | |
best_parent = child | |
break | |
attempts += 1 | |
if attempts >200:break #draw even if no better child found | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment