Spaces:
Sleeping
Sleeping
from model.Schedule import Schedule | |
import random | |
from random import randrange | |
from time import time | |
# Lakshmi, R. et al. “A New Biological Operator in Genetic Algorithm for Class Scheduling Problem.” | |
# International Journal of Computer Applications 60 (2012): 6-11. | |
# Genetic algorithm | |
class GeneticAlgorithm: | |
def initAlgorithm(self, prototype, numberOfChromosomes=100, replaceByGeneration=8, trackBest=5): | |
# Number of best chromosomes currently saved in best chromosome group | |
self._currentBestSize = 0 | |
# Prototype of chromosomes in population | |
self._prototype = prototype | |
# there should be at least 2 chromosomes in population | |
if numberOfChromosomes < 2: | |
numberOfChromosomes = 2 | |
# and algorithm should track at least on of best chromosomes | |
if trackBest < 1: | |
trackBest = 1 | |
# Population of chromosomes | |
self._chromosomes = numberOfChromosomes * [None] | |
# Inidicates whether chromosome belongs to best chromosome group | |
self._bestFlags = numberOfChromosomes * [False] | |
# Indices of best chromosomes | |
self._bestChromosomes = trackBest * [0] | |
# Number of chromosomes which are replaced in each generation by offspring | |
self.set_replace_by_generation(replaceByGeneration) | |
# Initializes genetic algorithm | |
def __init__(self, configuration, numberOfCrossoverPoints=2, mutationSize=2, crossoverProbability=80, | |
mutationProbability=3): | |
self.initAlgorithm(Schedule(configuration)) | |
self._mutationSize = mutationSize | |
self._numberOfCrossoverPoints = numberOfCrossoverPoints | |
self._crossoverProbability = crossoverProbability | |
self._mutationProbability = mutationProbability | |
# Returns pointer to best chromosomes in population | |
def result(self): | |
return self._chromosomes[self._bestChromosomes[0]] | |
def set_replace_by_generation(self, value): | |
numberOfChromosomes = len(self._chromosomes) | |
trackBest = len(self._bestChromosomes) | |
if (value > numberOfChromosomes - trackBest): | |
value = numberOfChromosomes - trackBest | |
self._replaceByGeneration = value | |
# Tries to add chromosomes in best chromosome group | |
def addToBest(self, chromosomeIndex): | |
bestChromosomes = self._bestChromosomes | |
length_best = len(bestChromosomes) | |
bestFlags = self._bestFlags | |
chromosomes = self._chromosomes | |
# don't add if new chromosome hasn't fitness big enough for best chromosome group | |
# or it is already in the group? | |
if (self._currentBestSize == length_best and chromosomes[bestChromosomes[self._currentBestSize - 1]].fitness >= | |
chromosomes[chromosomeIndex].fitness) or bestFlags[chromosomeIndex]: | |
return | |
# find place for new chromosome | |
j = self._currentBestSize | |
for i in range(j, -1, -1): | |
j = i | |
pos = bestChromosomes[i - 1] | |
# group is not full? | |
if i < length_best: | |
# position of new chromosomes is found? | |
if chromosomes[pos].fitness > chromosomes[chromosomeIndex].fitness: | |
break | |
# move chromosomes to make room for new | |
bestChromosomes[i] = pos | |
else: | |
# group is full remove worst chromosomes in the group | |
bestFlags[pos] = False | |
# store chromosome in best chromosome group | |
bestChromosomes[j] = chromosomeIndex | |
bestFlags[chromosomeIndex] = True | |
# increase current size if it has not reached the limit yet | |
if self._currentBestSize < length_best: | |
self._currentBestSize += 1 | |
# Returns TRUE if chromosome belongs to best chromosome group | |
def isInBest(self, chromosomeIndex) -> bool: | |
return self._bestFlags[chromosomeIndex] | |
# Clears best chromosome group | |
def clearBest(self): | |
self._bestFlags = len(self._bestFlags) * [False] | |
self._currentBestSize = 0 | |
# initialize new population with chromosomes randomly built using prototype | |
def initialize(self, population): | |
# addToBest = self.addToBest | |
prototype = self._prototype | |
length_chromosomes = len(population) | |
for i in range(0, length_chromosomes): | |
# add new chromosome to population | |
population[i] = prototype.makeNewFromPrototype() | |
# addToBest(i) | |
def selection(self, population): | |
length_chromosomes = len(population) | |
return (population[randrange(32768) % length_chromosomes], population[randrange(32768) % length_chromosomes]) | |
def replacement(self, population, replaceByGeneration) -> []: | |
mutationSize = self._mutationSize | |
numberOfCrossoverPoints = self._numberOfCrossoverPoints | |
crossoverProbability = self._crossoverProbability | |
mutationProbability = self._mutationProbability | |
selection = self.selection | |
isInBest = self.isInBest | |
length_chromosomes = len(population) | |
# produce offspring | |
offspring = replaceByGeneration * [None] | |
for j in range(replaceByGeneration): | |
# selects parent randomly | |
parent = selection(population) | |
offspring[j] = parent[0].crossover(parent[1], numberOfCrossoverPoints, crossoverProbability) | |
offspring[j].mutation(mutationSize, mutationProbability) | |
# replace chromosomes of current operation with offspring | |
# select chromosome for replacement randomly | |
ci = randrange(32768) % length_chromosomes | |
while isInBest(ci): | |
ci = randrange(32768) % length_chromosomes | |
# replace chromosomes | |
population[ci] = offspring[j] | |
# try to add new chromosomes in best chromosome group | |
self.addToBest(ci) | |
return offspring | |
# Starts and executes algorithm | |
def run(self, maxRepeat=9999, minFitness=0.999): | |
# clear best chromosome group from previous execution | |
self.clearBest() | |
length_chromosomes = len(self._chromosomes) | |
self.initialize(self._chromosomes) | |
random.seed(round(time() * 1000)) | |
# Current generation | |
currentGeneration = 0 | |
repeat = 0 | |
lastBestFit = 0.0 | |
while 1: | |
best = self.result | |
print("Fitness:", "{:f}\t".format(best.fitness), "Generation:", currentGeneration, end="\r") | |
# algorithm has reached criteria? | |
if best.fitness > minFitness: | |
break | |
difference = abs(best.fitness - lastBestFit) | |
if difference <= 0.0000001: | |
repeat += 1 | |
else: | |
repeat = 0 | |
if repeat > (maxRepeat / 100): | |
random.seed(round(time() * 1000)) | |
self.set_replace_by_generation(self._replaceByGeneration * 3) | |
self._crossoverProbability += 1 | |
self.replacement(self._chromosomes, self._replaceByGeneration) | |
lastBestFit = best.fitness | |
currentGeneration += 1 | |
def __str__(self): | |
return "Genetic Algorithm" | |