Spaces:
Sleeping
Sleeping
| 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 | |
| # 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" | |