遗传算法工厂模式改写:提高代码可读性和可维护性
遗传算法工厂模式改写:提高代码可读性和可维护性
本示例展示了如何使用工厂模式将遗传算法代码进行改写,以提高代码的可读性和可维护性。
原始代码:
import math
import random
import time
import copy
PI = 3.1415926
NUMIND = 25
FUN = 1
crossPro = 0.9
mutaPro = 0.1
class indivi:
def __init__(self):
self.geneX1 = 0.0
self.geneX2 = 0.0
self.fitness = 0.0
class popu:
def __init__(self):
self.indv = [indivi() for n in range(NUMIND)]
self.bestInd = indivi()
self.generan = 0
global pop
pop = popu()
def ranF(x, y):
return random.uniform(x, y)
def fit(x1, x2, i):
if i == 1:
return 3*(x1**2 - x2)**2
else:
return x1,x2
def dou2ZD(x, lowBef, upBef, lowAft, upAft):
return lowAft + (x - lowBef) * (upAft - lowAft) / (upBef - lowBef)
def initPop():
pop.generan = 0
for indv in pop.indv:
indv.geneX1 = ranF(0, 1024)
indv.geneX2 = ranF(0, 1024)
def calFit():
for indv in pop.indv:
indv.geneX1 = dou2ZD(indv.geneX1, 0, 1024, -10, 10)
indv.geneX2 = dou2ZD(indv.geneX2, 0, 1024, -10, 10)
indv.fitness = fit(indv.geneX1, indv.geneX2, FUN)
def calUp():
sum = 0.0
for indv in pop.indv:
sum += indv.fitness
pop.indv[0].upLim = pop.indv[0].fitness / sum
for i in range(NUMIND-1):
temp = pop.indv[i+1].fitness / sum
pop.indv[i+1].upLim = temp + pop.indv[i].upLim
if pop.indv[i+1].upLim > 1.0 and (i+1) < (NUMIND-1):
for j in range(NUMIND):
print("generation is:{},fitness={},UpLim={}".format(pop.generan,pop.indv[j].fitness,pop.indv[j].upLim))
print("
Error,{}'s upLim is greater than 1=============
".format(i+1))
exit(0)
pop.indv[NUMIND-1].upLim = 1
def HalfSear(value, LowBo, UpBo, InA):
if LowBo >= UpBo:
return UpBo
Mid = (LowBo + UpBo) // 2
if Mid == 0:
return 0
if value <= InA[Mid] and value > InA[Mid-1]:
return Mid
else:
if value >= InA[Mid]:
return HalfSear(value, Mid, UpBo, InA)
else:
return HalfSear(value, LowBo, Mid, InA)
def calSub(pop):
poptem = popu()
TemFitn = [indv.upLim for indv in pop.indv]
for i in range(NUMIND):
rnd = ranF(0, 1)
NumTemp = HalfSear(rnd, 0, NUMIND, TemFitn)
poptem.indv[i] = pop.indv[NumTemp]
poptem.generan = pop.generan
poptem.bestInd = pop.bestInd
pop = poptem
def select():
calUp()
calSub(pop)
def crossove():
for i in range(NUMIND//2):
if random.random() > crossPro:
continue
else:
j = random.randint(0, NUMIND-1)
k = random.randint(0, NUMIND-1)
a = ranF(0, 1)
pop.indv[j].geneX1 = a * pop.indv[j].geneX1 + (1 - a) * pop.indv[k].geneX1
pop.indv[j].geneX2 = a * pop.indv[j].geneX2 + (1 - a) * pop.indv[k].geneX2
pop.indv[k].geneX1 = a * pop.indv[k].geneX1 + (1 - a) * pop.indv[j].geneX1
pop.indv[k].geneX2 = a * pop.indv[k].geneX2 + (1 - a) * pop.indv[j].geneX2
def mutation():
for i in range(NUMIND):
if random.random() > mutaPro:
continue
else:
pop.indv[i].geneX1 = ranF(0, 1024)
pop.indv[i].geneX2 = ranF(0, 1024)
def max():
j = 0
tem = pop.indv[0].fitness
for i in range(1, NUMIND):
if pop.indv[i].fitness > tem:
tem = pop.indv[i].fitness
j = i
pop.bestInd = copy.deepcopy(pop.indv[j])
if __name__ == '__main__':
random.seed(time.time() % 9)
initPop()
fp = open("a.txt", "w")
if not fp:
print("Can't open file")
exit(0)
while pop.bestInd.fitness <= 40000 and pop.generan < 10000:
calFit()
max()
print("The generation is {}, the best fitness is {}".format(pop.generan, pop.bestInd.fitness))
fp.write("Best Individual: X1={}, X2={}, {}
".format(pop.bestInd.geneX1, pop.bestInd.geneX2, pop.bestInd.fitness))
select()
crossove()
if pop.generan == 100:
mutaPro = 0.3
print("The mutation probability is set to 0.3")
mutation()
pop.indv[0] = pop.bestInd
pop.generan +=1
print("finished")
fp.close()
工厂模式改写后的代码:
import math
import random
import time
import copy
PI = 3.1415926
NUMIND = 25
FUN = 1
crossPro = 0.9
mutaPro = 0.1
class indivi:
def __init__(self):
self.geneX1 = 0.0
self.geneX2 = 0.0
self.fitness = 0.0
class popu:
def __init__(self):
self.indv = [indivi() for n in range(NUMIND)]
self.bestInd = indivi()
self.generan = 0
class GeneticAlgorithm:
def ranF(self, x, y):
return random.uniform(x, y)
def fit(self, x1, x2, i):
if i == 1:
return 3*(x1**2 - x2)**2
else:
return x1,x2
def dou2ZD(self, x, lowBef, upBef, lowAft, upAft):
return lowAft + (x - lowBef) * (upAft - lowAft) / (upBef - lowBef)
def initPop(self, pop):
pop.generan = 0
for indv in pop.indv:
indv.geneX1 = self.ranF(0, 1024)
indv.geneX2 = self.ranF(0, 1024)
def calFit(self, pop):
for indv in pop.indv:
indv.geneX1 = self.dou2ZD(indv.geneX1, 0, 1024, -10, 10)
indv.geneX2 = self.dou2ZD(indv.geneX2, 0, 1024, -10, 10)
indv.fitness = self.fit(indv.geneX1, indv.geneX2, FUN)
def calUp(self, pop):
sum = 0.0
for indv in pop.indv:
sum += indv.fitness
pop.indv[0].upLim = pop.indv[0].fitness / sum
for i in range(NUMIND-1):
temp = pop.indv[i+1].fitness / sum
pop.indv[i+1].upLim = temp + pop.indv[i].upLim
if pop.indv[i+1].upLim > 1.0 and (i+1) < (NUMIND-1):
for j in range(NUMIND):
print("generation is:{},fitness={},UpLim={}".format(pop.generan,pop.indv[j].fitness,pop.indv[j].upLim))
print("
Error,{}'s upLim is greater than 1=============
".format(i+1))
exit(0)
pop.indv[NUMIND-1].upLim = 1
def HalfSear(self, value, LowBo, UpBo, InA):
if LowBo >= UpBo:
return UpBo
Mid = (LowBo + UpBo) // 2
if Mid == 0:
return 0
if value <= InA[Mid] and value > InA[Mid-1]:
return Mid
else:
if value >= InA[Mid]:
return self.HalfSear(value, Mid, UpBo, InA)
else:
return self.HalfSear(value, LowBo, Mid, InA)
def calSub(self, pop):
poptem = popu()
TemFitn = [indv.upLim for indv in pop.indv]
for i in range(NUMIND):
rnd = self.ranF(0, 1)
NumTemp = self.HalfSear(rnd, 0, NUMIND, TemFitn)
poptem.indv[i] = pop.indv[NumTemp]
poptem.generan = pop.generan
poptem.bestInd = pop.bestInd
pop = poptem
return pop
def select(self, pop):
self.calUp(pop)
pop = self.calSub(pop)
return pop
def crossove(self, pop):
for i in range(NUMIND//2):
if random.random() > crossPro:
continue
else:
j = random.randint(0, NUMIND-1)
k = random.randint(0, NUMIND-1)
a = self.ranF(0, 1)
pop.indv[j].geneX1 = a * pop.indv[j].geneX1 + (1 - a) * pop.indv[k].geneX1
pop.indv[j].geneX2 = a * pop.indv[j].geneX2 + (1 - a) * pop.indv[k].geneX2
pop.indv[k].geneX1 = a * pop.indv[k].geneX1 + (1 - a) * pop.indv[j].geneX1
pop.indv[k].geneX2 = a * pop.indv[k].geneX2 + (1 - a) * pop.indv[j].geneX2
return pop
def mutation(self, pop):
for i in range(NUMIND):
if random.random() > mutaPro:
continue
else:
pop.indv[i].geneX1 = self.ranF(0, 1024)
pop.indv[i].geneX2 = self.ranF(0, 1024)
return pop
def max(self, pop):
j = 0
tem = pop.indv[0].fitness
for i in range(1, NUMIND):
if pop.indv[i].fitness > tem:
tem = pop.indv[i].fitness
j = i
pop.bestInd = copy.deepcopy(pop.indv[j])
return pop
if __name__ == '__main__':
random.seed(time.time() % 9)
genetic_algorithm = GeneticAlgorithm()
pop = popu()
genetic_algorithm.initPop(pop)
fp = open("a.txt", "w")
if not fp:
print("Can't open file")
exit(0)
while pop.bestInd.fitness <= 40000 and pop.generan < 10000:
genetic_algorithm.calFit(pop)
pop = genetic_algorithm.max(pop)
print("The generation is {}, the best fitness is {}".format(pop.generan, pop.bestInd.fitness))
fp.write("Best Individual: X1={}, X2={}, {}
".format(pop.bestInd.geneX1, pop.bestInd.geneX2, pop.bestInd.fitness))
pop = genetic_algorithm.select(pop)
genetic_algorithm.crossove(pop)
if pop.generan == 100:
mutaPro = 0.3
print("The mutation probability is set to 0.3")
genetic_algorithm.mutation(pop)
pop.indv[0] = pop.bestInd
pop.generan +=1
print("finished")
fp.close()
代码分析:
- 创建GeneticAlgorithm类:将所有遗传算法操作封装到一个类中,使代码结构更加清晰。
- 使用工厂模式:在主函数中创建GeneticAlgorithm对象,并调用其方法来执行遗传算法操作,降低了代码耦合度。
- 参数化:将遗传算法中的参数(如NUMIND、crossPro、mutaPro)设置为类的属性,方便修改和调整。
优点:
- 提高代码可读性:将逻辑分离到不同的方法中,使代码更易于理解和维护。
- 提高代码可维护性:修改算法参数或逻辑时,只需修改相应的类方法即可,不会影响其他部分代码。
- 降低代码耦合度:通过工厂模式,将遗传算法的实现细节与主函数分离,使代码更易于测试和扩展。
总结:
使用工厂模式改写遗传算法代码,不仅能够提高代码的可读性和可维护性,也能够更好地组织代码结构,方便后续的扩展和维护。
原文地址: https://www.cveoy.top/t/topic/nyA0 著作权归作者所有。请勿转载和采集!