parent 25d96832
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
 # -*- coding: utf-8 -*- """ Created on Thu Jul 8 15:28:46 2021 @author: cihan """ import datetime import random import genetic ''' Problem Definition: operate on numbers to reach a lucky number; say 35. allowed operations: * basics: +, -, * * others: ^ ''' # Measure of fitness: def get_fitness(genes, expectedTotal, fnEvaluate): result = fnEvaluate(genes) if result != expectedTotal: fitness = expectedTotal - abs(result - expectedTotal) else: fitness = 1000 - len(genes) return fitness ############################################################################## ############################################################################## def create(numbers, operations, minNumber, maxNumber): genes = [random.choice(numbers)] count = random.randint(minNumber, maxNumber+1) while count > 1: count -=1 genes.append(random.choice(operations)) genes.append(random.choice(numbers)) return genes ############################################################################## ############################################################################## def mutate(genes, numbers, operations, minNumbers, maxNumbers, fnGetFitness): count = random.randint(1, 10) initialFitness = fnGetFitness(genes) while count > 0: count -= 1 if fnGetFitness(genes) > initialFitness: return numberCount = (1 + len(genes)) / 2 appending = numberCount < maxNumbers and \ random.randint(0, 100) == 0 if appending: genes.append(random.choice(operations)) genes.append(random.choice(numbers)) continue removing = numberCount > minNumbers and \ random.randint(0, 20) == 0 if removing: index = random.randrange(0, len(genes) - 1) del genes[index] del genes[index] continue index = random.randrange(0, len(genes)) genes[index] = random.choice(operations) \ if (index & 1) == 1 else random.choice(numbers) ############################################################################## ############################################################################## # Evaluating the equation: def evaluate(genes, prioritizedOperations): equation = genes[:] for operationSet in prioritizedOperations: iOffset = 0 for i in range(1, len(equation), 2): i += iOffset opToken = equation[i] if opToken in operationSet: leftOperand = equation[i - 1] rightOperand = equation[i + 1] equation[i - 1] = operationSet[opToken](leftOperand, rightOperand) del equation[i + 1] del equation[i] iOffset += -2 return equation ############################################################################## ############################################################################## # Helpers: def add(a, b): return a + b def subtract(a, b): return a - b def multiply(a, b): return a * b def display(candidate, startTime): timeDiff = datetime.datetime.now() - startTime print("{0}\t{1}\t{2}".format( (' '.join(map(str, [i for i in candidate.Genes]))), candidate.Fitness, timeDiff)) ############################################################################## ############################################################################## # Equation generator class: def EquationGenerator(): operations = ['^', '+', '-', '*'] prioritizedOperations = [{'^': lambda a, b: a ** b}, {'*': multiply}, {'+': add, '-': subtract}] optimalLengthSolution = [6, '^', 2, '-', 1] solve(operations, prioritizedOperations, optimalLengthSolution) def solve(operations, prioritizedOperations, optimalLengthSolution): numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] expectedTotal = evaluate(optimalLengthSolution, prioritizedOperations) minNumbers = (1 + len(optimalLengthSolution)) / 2 maxNumbers = 6 * minNumbers startTime = datetime.datetime.now() def fnDisplay(candidate): display(candidate, startTime) def fnEvaluate(genes): return evaluate(genes, prioritizedOperations) def fnGetFitness(genes): return get_fitness(genes, expectedTotal, fnEvaluate) def fnCreate(): return create(numbers, operations, minNumbers, maxNumbers) def fnMutate(child): mutate(child, numbers, operations, minNumbers, maxNumbers, fnGetFitness) optimalFitness = fnGetFitness(optimalLengthSolution) genetic.get_best(fnGetFitness, None, optimalFitness, None, fnDisplay, fnMutate, fnCreate, maxAge=50) Case = EquationGenerator() \ No newline at end of file
 # -*- coding: utf-8 -*- """ Created on Mon Jul 5 08:37:20 2021 @author: C. Ates Exercise for genetic programing """ #Libs import datetime import random import statistics import time import sys from bisect import bisect_left from math import exp from enum import Enum def _generate_parent(length, geneSet, get_fitness): genes = [] while len(genes) < length: sampleSize = min(length - len(genes), len(geneSet)) genes.extend(random.sample(geneSet, sampleSize)) fitness = get_fitness(genes) return Chromosome(genes, fitness, Strategies.Create) def _mutate(parent, geneSet, get_fitness): childGenes = parent.Genes[:] index = random.randrange(0, len(parent.Genes)) newGene, alternate = random.sample(geneSet, 2) childGenes[index] = alternate \ if newGene == childGenes[index] \ else newGene fitness = get_fitness(childGenes) return Chromosome(childGenes, fitness, Strategies.Mutate) def _mutate_custom(parent, custom_mutate, get_fitness): childGenes = parent.Genes[:] custom_mutate(childGenes) fitness = get_fitness(childGenes) return Chromosome(childGenes, fitness, Strategies.Mutate) def _crossover(parentGenes, index, parents, get_fitness, crossover, mutate, generate_parent): donorIndex = random.randrange(0, len(parents)) if donorIndex == index: donorIndex = (donorIndex + 1) % len(parents) childGenes = crossover(parentGenes, parents[donorIndex].Genes) if childGenes is None: # parent and donor are indistinguishable parents[donorIndex] = generate_parent() return mutate(parents[index]) fitness = get_fitness(childGenes) return Chromosome(childGenes, fitness, Strategies.Crossover) def get_best(get_fitness, targetLen, optimalFitness, geneSet, display, custom_mutate=None, custom_create=None, maxAge=None, poolSize=1, crossover=None, maxSeconds=None): if custom_mutate is None: def fnMutate(parent): return _mutate(parent, geneSet, get_fitness) else: def fnMutate(parent): return _mutate_custom(parent, custom_mutate, get_fitness) if custom_create is None: def fnGenerateParent(): return _generate_parent(targetLen, geneSet, get_fitness) else: def fnGenerateParent(): genes = custom_create() return Chromosome(genes, get_fitness(genes), Strategies.Create) strategyLookup = { Strategies.Create: lambda p, i, o: fnGenerateParent(), Strategies.Mutate: lambda p, i, o: fnMutate(p), Strategies.Crossover: lambda p, i, o: _crossover(p.Genes, i, o, get_fitness, crossover, fnMutate, fnGenerateParent)} usedStrategies = [strategyLookup[Strategies.Mutate]] if crossover is not None: usedStrategies.append(strategyLookup[Strategies.Crossover]) def fnNewChild(parent, index, parents): return random.choice(usedStrategies)(parent, index, parents) else: def fnNewChild(parent, index, parents): return fnMutate(parent) for timedOut, improvement in _get_improvement(fnNewChild, fnGenerateParent, maxAge, poolSize, maxSeconds): if timedOut: return improvement display(improvement) f = strategyLookup[improvement.Strategy] usedStrategies.append(f) if not optimalFitness > improvement.Fitness: return improvement def _get_improvement(new_child, generate_parent, maxAge, poolSize, maxSeconds): startTime = time.time() bestParent = generate_parent() yield maxSeconds is not None and time.time() - startTime > maxSeconds, bestParent parents = [bestParent] historicalFitnesses = [bestParent.Fitness] for _ in range(poolSize - 1): parent = generate_parent() if maxSeconds is not None and time.time() - startTime > maxSeconds: yield True, parent if parent.Fitness > bestParent.Fitness: yield False, parent bestParent = parent historicalFitnesses.append(parent.Fitness) parents.append(parent) lastParentIndex = poolSize - 1 pindex = 1 while True: if maxSeconds is not None and time.time() - startTime > maxSeconds: yield True, bestParent pindex = pindex - 1 if pindex > 0 else lastParentIndex parent = parents[pindex] child = new_child(parent, pindex, parents) if parent.Fitness > child.Fitness: if maxAge is None: continue parent.Age += 1 if maxAge > parent.Age: continue index = bisect_left(historicalFitnesses, child.Fitness, 0, len(historicalFitnesses)) difference = len(historicalFitnesses) - index proportionSimilar = difference / len(historicalFitnesses) if random.random() < exp(-proportionSimilar): parents[pindex] = child continue parents[pindex] = bestParent parent.Age = 0 continue if not child.Fitness > parent.Fitness: # same fitness child.Age = parent.Age + 1 parents[pindex] = child continue parents[pindex] = child parent.Age = 0 if child.Fitness > bestParent.Fitness: yield False, child bestParent = child historicalFitnesses.append(child.Fitness) class Chromosome: Genes = None Fitness = None Age = 0 Strategy = None def __init__(self, genes, fitness, strategy): self.Genes = genes self.Fitness = fitness self.Strategy = strategy class Strategies(Enum): Create = 0, Mutate = 1, Crossover = 2 \ No newline at end of file
This diff is collapsed.