import numpy as np class FinessEvaluator(object): def __init__(self): self.x = np.linspace(-10,10,21) pass def process(self, c): mse = 0 for x in self.x: y = c.process(x) mse += (y - self.fx(x))**2 mse *= 1/len(self.x) fit = 1/(1 + mse) return fit def fx(self, x): y = 5 + 3 * x + 7 * x**2 return y class Cromosome(object): def __init__(self, id, param=None): self.id = id self.fit = 0 self.fitAccum = 0 self.param = param def process(self, x): result = self.param[0] + self.param[1]*x + self.param[2]*x**2 return result[0] def cross(self, p2): a = 0.5 param1 = (1-a)*self.param + a*p2.param param2 = (1-a)*p2.param + a*self.param ca = Cromosome(self.id, param1) cb = Cromosome(p2.id, param2) return ca, cb def mutate(self): gene = int(np.random.rand() * 3) allele = int(5*(0.5 - np.random.rand())) self.param[gene] += allele def __str__(self): return "Id: {}, f={:0.6f}, fitAccum={:0.6f}, param=\n{}".format(self.id, self.fitness, self.fitAccum, str(self.param)) class Population(object): def __init__(self, numCromosomes): self.bestFit = 0 self.sumFit = 0 self.cromosomes = [] for i in range(0, numCromosomes): self.cromosomes.append(Cromosome(str(i), np.random.rand(3,1))) def print(self): print ("Population fitness = {:0.6f}".format(self.sumFit)) print ("Best indiv. fitness = {:0.6f}".format(self.bestFit)) def process(self): for c in self.cromosomes: y = c.process(1) return def fitness(self, fitnessEval): self.sumFit = 0 self.bestFit = 0 for c in self.cromosomes: f = fitnessEval.process(c) c.fitness = f self.sumFit += f if f > self.bestFit: self.bestFit = f # 1.) Sort by fitness sorted = self.sort(self.cromosomes) # 2.) Assign accumulated fitness sum = 0 for c in sorted: sum += c.fitness c.fitAccum = sum self.cromosomes = sorted return self.sumFit def mate(self, chanceOfReproduction=0.3): newPop = self.cromosomes count = 0 for i in range(0, int(len(self.cromosomes)/2)): p = np.random.rand() if p < chanceOfReproduction: # 3.) Select parents p1 = self.select(self.cromosomes) p2 = p1 while(p2 == p1): p2 = self.select(self.cromosomes) ca, cb = p1.cross(p2) newPop[count+0] = ca newPop[count+1] = cb count += 2 self.cromosomes = newPop return newPop def select(self, sorted): p = self.sumFit * np.random.rand() for c in sorted: if c.fitAccum > p: break return c def mutate(self, chanceOfMutation=0.06): for c in self.cromosomes: p = np.random.rand() if p < chanceOfMutation: c.mutate() pass def best(self): return self.cromosomes[len(self.cromosomes)-1] def starve(self): pass def sort(self, array): less = [] equal = [] greater = [] if len(array) > 1: pivot = array[0].fitness for x in array: if x.fitness < pivot: less.append(x) elif x.fitness == pivot: equal.append(x) elif x.fitness > pivot: greater.append(x) # Don't forget to return something! return self.sort(less)+equal+self.sort(greater) # Just use the + operator to join lists # Note that you want equal ^^^^^ not pivot else: # You need to hande the part at the end of the recursion - when you only have one element in your array, just return the array. return array if __name__ == '__main__': f = FinessEvaluator() p = Population(50) for i in range(0, 500): p.mutate(0.1) p.fitness(f) p.mate() p.print() p.fitness(f) p.print() print(p.best()) print ("End of Program")