garizz's picture
Upload 31 files
8e7d8ae
raw
history blame
7.77 kB
from model.Schedule import Schedule
import numpy as np
import random
import sys
from time import time
# K.Deb, A.Pratap, S.Agrawal, T.Meyarivan, A fast and elitist multiobjective genetic algorithm:
# NSGA-II, IEEE Transactions on Evolutionary Computation 6 (2002) 182–197.
# NSGA II
class NsgaII:
def initAlgorithm(self, prototype, numberOfChromosomes=100):
# Prototype of chromosomes in population
self._prototype = prototype
# there should be at least 2 chromosomes in population
if numberOfChromosomes < 2:
numberOfChromosomes = 2
# Population of chromosomes
self._chromosomes = []
self._populationSize = numberOfChromosomes
self._repeatRatio = .0
# 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
@property
# Returns pointer to best chromosomes in population
def result(self):
return self._chromosomes[0]
# non-dominated sorting function
def nonDominatedSorting(self, totalChromosome):
doublePopulationSize = self._populationSize * 2
s = doublePopulationSize * [ set() ]
n = np.zeros(doublePopulationSize, dtype=int)
front = [ set() ]
for p in range(doublePopulationSize):
for q in range(doublePopulationSize):
if totalChromosome[p].fitness > totalChromosome[q].fitness:
s[p].add(q)
elif totalChromosome[p].fitness < totalChromosome[q].fitness:
n[p] += 1
if n[p] == 0:
front[0].add(p)
i = 0
while front[i]:
Q = set()
for p in front[i]:
for q in s[p]:
n[q] -= 1
if n[q] == 0:
Q.add(q)
i += 1
front.append(Q)
front.pop()
return front
# calculate crowding distance function
def calculateCrowdingDistance(self, front, totalChromosome):
distance, obj = {}, {}
for key in front:
distance[key] = 0
fitness = totalChromosome[key].fitness
if fitness not in obj.values():
obj[key] = fitness
sorted_keys = sorted(obj, key=obj.get)
size = len(obj)
distance[sorted_keys[0]] = distance[sorted_keys[-1]] = sys.float_info.max
if size > 1:
diff2 = totalChromosome[sorted_keys[-1]].getDifference(totalChromosome[sorted_keys[0]])
for i in range(1, size - 1):
diff = totalChromosome[sorted_keys[i + 1]].getDifference(totalChromosome[sorted_keys[i - 1]]) / diff2
distance[sorted_keys[i]] += diff
return distance
def selection(self, front, totalChromosome):
populationSize = self._populationSize
calculateCrowdingDistance = self.calculateCrowdingDistance
N = 0
newPop = []
while N < populationSize:
for row in front:
N += len(row)
if N > populationSize:
distance = calculateCrowdingDistance(row, totalChromosome)
sortedCdf = sorted(distance, key=distance.get, reverse=True)
for j in sortedCdf:
if len(newPop) >= populationSize:
break
newPop.append(j)
break
newPop.extend(row)
return [totalChromosome[n] for n in newPop]
def replacement(self, population):
populationSize = self._populationSize
numberOfCrossoverPoints = self._numberOfCrossoverPoints
crossoverProbability = self._crossoverProbability
offspring = []
# generate a random sequence to select the parent chromosome to crossover
S = np.arange(populationSize)
np.random.shuffle(S)
halfPopulationSize = populationSize // 2
for m in range(halfPopulationSize):
parent0 = population[S[2 * m]]
parent1 = population[S[2 * m + 1]]
child0 = parent0.crossover(parent1, numberOfCrossoverPoints, crossoverProbability)
child1 = parent1.crossover(parent0, numberOfCrossoverPoints, crossoverProbability)
# append child chromosome to offspring list
offspring.extend((child0, child1))
return offspring
# initialize new population with chromosomes randomly built using prototype
def initialize(self, population):
prototype = self._prototype
for i in range(len(population)):
# add new chromosome to population
population[i] = prototype.makeNewFromPrototype()
def reform(self):
random.seed(round(time() * 1000))
np.random.seed(int(time()))
if self._crossoverProbability < 95:
self._crossoverProbability += 1.0
elif self._mutationProbability < 30:
self._mutationProbability += 1.0
# Starts and executes algorithm
def run(self, maxRepeat=9999, minFitness=0.999):
mutationSize = self._mutationSize
mutationProbability = self._mutationProbability
nonDominatedSorting = self.nonDominatedSorting
selection = self.selection
populationSize = self._populationSize
population = populationSize * [None]
self.initialize(population)
random.seed(round(time() * 1000))
np.random.seed(int(time()))
# Current generation
currentGeneration = 0
repeat = 0
lastBestFit = 0.0
while 1:
if currentGeneration > 0:
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
self._repeatRatio = repeat * 100 / maxRepeat
if repeat > (maxRepeat / 100):
self.reform()
# crossover
offspring = self.replacement(population)
# mutation
for child in offspring:
child.mutation(mutationSize, mutationProbability)
totalChromosome = population + offspring
# non-dominated sorting
front = nonDominatedSorting(totalChromosome)
if len(front) == 0:
break
# selection
population = selection(front, totalChromosome)
self._populationSize = populationSize = len(population)
# comparison
if currentGeneration == 0:
self._chromosomes = population
else:
totalChromosome = population + self._chromosomes
newBestFront = nonDominatedSorting(totalChromosome)
if len(newBestFront) == 0:
break
self._chromosomes = selection(newBestFront, totalChromosome)
lastBestFit = best.fitness
currentGeneration += 1
def __str__(self):
return "NSGA II"