第二个项目是最大化问题,依旧沿用(一)的engine,这里的geneSet是0-1组合,即geneset = [0, 1]
。本章节一共涉及三个py文件
1. genetic.py
import random
import statistics
import sys
import time
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)
因为要求最大化数字,所以不再适合用string编码,所以直接用复制,即childGenes = parent.Genes[:]
,取代list constructure
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)
def get_best(get_fitness, targetLen, optimalFitness, geneSet, display):
random.seed()
bestParent = _generate_parent(targetLen, geneSet, get_fitness)
display(bestParent)
if bestParent.Fitness >= optimalFitness:
return bestParent
while True:
child = _mutate(bestParent, geneSet, get_fitness)
if bestParent.Fitness >= child.Fitness:
continue
display(child)
if child.Fitness >= optimalFitness:
return child
bestParent = child
class Chromosome:
def __init__(self, genes, fitness):
self.Genes = genes
self.Fitness = fitness
class Benchmark:
@staticmethod
def run(function):
timings = []
stdout = sys.stdout
for i in range(100):
sys.stdout = None
startTime = time.time()
function()
seconds = time.time() - startTime
sys.stdout = stdout
timings.append(seconds)
mean = statistics.mean(timings)
if i < 10 or i % 10 == 9:
print("{} {:3.2f} {:3.2f}".format(
1 + i, mean,
statistics.stdev(timings, mean) if i > 1 else 0))
2. guessPasswordTests.py
import datetime
import random
import unittest
import genetic
def get_fitness(guess, target):
return sum(1 for expected, actual in zip(target, guess)
if expected == actual)
def display(candidate, startTime):
timeDiff = datetime.datetime.now() - startTime
print("{}\t{}\t{}".format(
''.join(candidate.Genes),
candidate.Fitness,
timeDiff))
在display里面要重组基因成string
class GuessPasswordTests(unittest.TestCase):
geneset = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.,"
def test_Hello_World(self):
target = "Hello World!"
self.guess_password(target)
def test_For_I_am_fearfully_and_wonderfully_made(self):
target = "For I am fearfully and wonderfully made."
self.guess_password(target)
def guess_password(self, target):
startTime = datetime.datetime.now()
def fnGetFitness(genes):
return get_fitness(genes, target)
def fnDisplay(candidate):
display(candidate, startTime)
optimalFitness = len(target)
best = genetic.get_best(fnGetFitness, len(target), optimalFitness,
self.geneset, fnDisplay)
self.assertEqual(''.join(best.Genes), target)
def test_Random(self):
length = 150
target = ''.join(random.choice(self.geneset)
for _ in range(length))
self.guess_password(target)
def test_benchmark(self):
genetic.Benchmark.run(self.test_Random)
if __name__ == '__main__':
unittest.main()
3. oneMaxTest.py
import datetime
import unittest
import genetic
def get_fitness(genes):
return genes.count(1)
def display(candidate, startTime):
timeDiff = datetime.datetime.now() - startTime
print("{}...{}\t{:3.2f}\t{}".format(
''.join(map(str, candidate.Genes[:15])),
''.join(map(str, candidate.Genes[-15:])),
candidate.Fitness,
timeDiff))
class OneMaxTests(unittest.TestCase):
def test(self, length=100):
geneset = [0, 1]
startTime = datetime.datetime.now()
def fnDisplay(candidate):
display(candidate, startTime)
def fnGetFitness(genes):
return get_fitness(genes)
optimalFitness = length
best = genetic.get_best(fnGetFitness, length, optimalFitness,
geneset, fnDisplay)
self.assertEqual(best.Fitness, optimalFitness)
def test_benchmark(self):
genetic.Benchmark.run(lambda: self.test(4000))
if __name__ == '__main__':
unittest.main()
网友评论