Genetic Algorithms

Python - Standalone

GeneticAlgorithm

Python 3.5 Genetic Algorithm

As seen in action on the left, I built a simple genetic algorithm to get more familiar with what it is and how it works. I started by doing research into genetic biology to get a firm grasp about the fundamentals before moving on to building the basic steps of evolutionary computing in python.


This basic setup will function as my template for generating images from scratch based on any given source image. This might later be useful for potentially generating textures or even materials to be used in game engines such as Unreal Engine.


Features: Darwinian Natural Selection (Heredity, Variation, Selection).


# Paul Ambrosiussen - Technical Artist
# Free Code Snippet (Genetic Algorithm)

import time
from math import pow
from random import uniform, randrange

### USER TWEAKABLE PARAMETERS ###
TargetPhrase = 'Hi, my name is Paul Ambrosiussen'
PopulationCount = 600
MaxGenerations = 5000 #Possibility to lock max generation number, & 
MutationRate = 0.01
### END USER TWEAKABLE PARAMETERS ###

DNALength = len(TargetPhrase)
Population = []
PopulationFitness = []

#This function returns a random character
def GetRandomCharacter():
	return chr(int(randrange(32, 126, 1)))

#This function returns a random dataset with specified length
def GetRandomDataSet(a_DNALength):
	return ''.join([GetRandomCharacter() for x in range(a_DNALength)])

#This function returns a random population
def CreateRandomPopulation():
	global Population
	Population = [GetRandomDataSet(DNALength) for x in range(PopulationCount)]
	PopulationFitness = range(PopulationCount)

#This function calculates the fitness by comparing a DNA dataset to the target DNA
def CalculateFitnessDNA(a_DNA):
	t_Fitness = sum([1 if a_DNA[x] == TargetPhrase[x] else 0 for x in range(len(a_DNA))])
	return pow((t_Fitness / len(TargetPhrase)),2)

#This function crosses two datasets by randomly picking from both parents
def GetCrossover(a_Parent1, a_Parent2):
	return ''.join([a_Parent1[x] if uniform(0, 1) < 0.5 else a_Parent2[x] for x in range(len(a_Parent1))])

#This function performs a mutation on each genome in a specified DNA set based on a mutationchance probability
def PerformMutation(a_DNA, a_MutationChance):
	return ''.join([GetRandomCharacter() if uniform(0, 1) < a_MutationChance else a_DNA[x] for x in range(len(a_DNA))])

#This function returns a weigthed random element from the Population
def ReturnWeightedRandomParent():
	t_weightedTotal = sum(PopulationFitness)
	t_treshold = uniform(0, t_weightedTotal)

	for x, weight in enumerate(PopulationFitness):
		t_weightedTotal -= weight
		if t_weightedTotal < t_treshold:
			return Population[x]

#This function returns the most fit DNA (Closest to target DNA)
def GetMostFitDNA():
	t_Fitness = max(PopulationFitness)
	return [Population[PopulationFitness.index(t_Fitness)], str(round(t_Fitness,2)*100)[:4] +'%']

#This function sets the populationfitness for every member of the population
def SetPopulationFitness():
	global PopulationFitness
	PopulationFitness.clear()
	PopulationFitness = [CalculateFitnessDNA(x) for x in Population]

#The main function of the script
def MainFunction():
	global Population, PopulationFitness
	t_StartTime = time.time()
	t_FittestScore, t_currentGeneration = 0, 0
	
	###1. Create a random population of N elements
	CreateRandomPopulation()

	#This is where the evolution loop happens
	while (t_FittestScore < 1 and t_currentGeneration < MaxGenerations):
		###2. Calculate Fitness for every element in the population
		SetPopulationFitness()

		###3. Reproduction -> Create New population
		t_newPopulation = []
			
		for x in range(PopulationCount):
			# A. Create Probability for each element
			t_parents = [ReturnWeightedRandomParent(),ReturnWeightedRandomParent()]
			# B. Create new Dataset from 2 parents chosen through probability
			t_newChild = GetCrossover(t_parents[0],t_parents[1])
			# C. Apply Probability Mutation to each Genome in DNA && Add to new population
			t_newPopulation.append(PerformMutation(t_newChild, MutationRate))

		###4. Replace Old Population with New Population from step 3
		Population.clear()
		Population = t_newPopulation

		#Calculate fitness for new population to make sure we dont overshoot the evolution
		SetPopulationFitness()

		#Get highest fitness score, printing results to screen, and incrementing generation number
		t_FittestScore = max(PopulationFitness)
		print(GetMostFitDNA())
		t_currentGeneration+=1


	print('Execution Time: {0} seconds, with {1} Generations'.format(round((time.time()-t_StartTime),3), t_currentGeneration))
	exit(0)

MainFunction()