主要是参考了https://blog.csdn.net/qq_14809723/article/details/79013691这篇文章,完善了一定的小功能。
本代码可以完善的功能有1、选择算子方面,轮盘赌误差比较大,可以采取最优保存和排序选择策略。2、交叉和突变算子方面可以采取其他方法 3、绘图方面 只是简单的描点连线
import random
import math
from math import radians, cos, sin, asin, sqrt
import matplotlib.pyplot as plt
# 计算两省会城市之间的距离 x经度 y维度
def Distance(x1, y1,x2,y2):
x1, y1, x2, y2 = map(radians, [x1, y1, x2, y2])
disx = x1-x2
disy = y1-y2
a = sin(disy/2)**2 + cos(y1)* cos(y2)* sin(disx/2)** 2
dis = 2* asin(sqrt(a)) * 6371
return dis
SCORE_NONE = -1
#单个城市个体信息
class Life(object):
def __init__(self,aGene = None):
self.gene = aGene
self.score = SCORE_NONE
#遗传算法
class GA(object):
def __init__(self, aCrossRate, aMutationRate, aLifeCount, aGeneLength, aMatchFun):
# 交叉概率
self.crossrate = aCrossRate
# 突变概率
self.mutationrate = aMutationRate
# 种群大小
self.lifecount = aLifeCount
# 基因长度
self.genelength = aGeneLength
# 适应度函数
self.matchfun = aMatchFun
# 种群数组
self.lives = []
# 最优个体 选择
self.best = None
# 代数
self.generation = 1
# 交叉计数
self.crosscount = 0
# 变异计数
self.mutationcount = 0
# 适应度之和 判定选择概率
self.masum = 0.0
# 适应度平均值
self.mean = 1.0
self.initPopulation()
# 初始化种群
def initPopulation(self):
self.lives = []
# 对序列随机排序
for i in range(self.lifecount):
gene = [x for x in range(self.genelength)]
random.shuffle(gene)
life = Life(gene)
self.lives.append(life)
# 适应度函数
def judge(self):
# 计算每一个个体的适应度
self.masum = 0.0
self.best = self.lives[0]
for life in self.lives:
life.score = self.matchfun(life)
self.masum += life.score
if self.best.score < life.score:
self.best = life
self.mean = self.masum / self.lifecount
# 交叉算子
def cross(self, dad, mom):
n = 0
while 1:
newGene = []
# 生成交叉范围
index1 = random.randint(0, self.genelength-1)
index2 = random.randint(index1, self.genelength -1)
tempGene = mom.gene[index1:index2]
#交叉
p1len = 0
for g in dad.gene:
if p1len == index1:
newGene.extend(tempGene)
p1len +=1
if g not in tempGene:
newGene.append(g)
p1len +=1
if(self.matchfun(Life(newGene)) > max(self.matchfun(dad), self.matchfun(mom))):
self.crosscount +=1
return newGene
if (n > 100):
self.crosscount +=1
return newGene
n += 1
# 突变算子
def mutation(self, wang):
#产生新的基因序列
index1 = random.randint(0, self.genelength - 1)
index2 = random.randint(0, self.genelength - 1)
newGene = wang.gene[:]
newGene[index1], newGene[index2] = newGene[index2], newGene[index1]
if self.matchfun(Life(newGene)) > self.matchfun(wang):
self.mutationcount += 1
return newGene
else:
rate = random.random()
if rate < math.exp(-10 / math.sqrt(self.generation)):
self.mutationcount +=1
return newGene
return wang.gene
# 选择某个体
def choose(self):
# 随机采样
r = random.uniform(0, self.masum)
# 轮盘赌方法
for life in self.lives:
r -= life.score
if r <= 0:
return life
raise Exception("选择错误", self.masum)
# 产生后代
def child(self):
dad = self.choose()
# 概率交叉
rate = random.random()
if rate < self.crossrate:
mom = self.choose()
gene = self.cross(dad, mom)
else:
gene = dad.gene
# 概率突变
rate = random.random()
if rate < self.mutationrate:
gene = self.mutation(Life(gene))
return Life(gene)
# 产生下一代
def next(self):
self.judge()
newLives = []
# 把最好的加入下一代
newLives.append(self.best)
while len(newLives) < self.lifecount:
newLives.append(self.child())
self.lives = newLives
self.generation +=1
# TSP类
class TSP(object):
def __init__(self, aLifeCount = 100):
self.initCitys()
self.lifeCount = aLifeCount
self.ga = GA(aCrossRate=CROSSRATE,
aMutationRate=MUTATIONRATE,
aLifeCount=self.lifeCount,
aGeneLength=len(self.citys),
aMatchFun=self.matchFun())
# 省会城市经纬度
def initCitys(self):
self.citys = []
self.citys.append((116.46, 39.92))
self.citys.append((117.2, 39.13))
self.citys.append((121.48, 31.22))
self.citys.append((106.54, 29.59))
self.citys.append((91.11, 29.97))
self.citys.append((87.68, 43.77))
self.citys.append((106.27, 38.47))
self.citys.append((111.65, 40.82))
self.citys.append((108.33, 22.84))
self.citys.append((126.63, 45.75))
self.citys.append((125.35, 43.88))
self.citys.append((123.38, 41.8))
self.citys.append((114.48, 38.03))
self.citys.append((112.53, 37.87))
self.citys.append((101.74, 36.56))
self.citys.append((117, 36.65))
self.citys.append((113.65, 34.76))
self.citys.append((118.78, 32.04))
self.citys.append((117.27, 31.86))
self.citys.append((120.19, 30.26))
self.citys.append((119.3, 26.08))
self.citys.append((115.89, 28.68))
self.citys.append((113, 28.21))
self.citys.append((114.31, 30.52))
self.citys.append((113.23, 23.16))
self.citys.append((121.5, 25.05))
self.citys.append((110.35, 20.02))
self.citys.append((103.73, 36.03))
self.citys.append((108.95, 34.27))
self.citys.append((104.06, 30.67))
self.citys.append((106.71, 26.57))
self.citys.append((102.73, 25.04))
self.citys.append((114.1, 22.2))
self.citys.append((113.33, 22.13))
# 计算总里程
def distance(self, order):
distance = 0.0
for i in range(-1, len(self.citys) - 1):
index1, index2 = order[i], order[i+1]
city1, city2 = self.citys[index1], self.citys[index2]
distance += Distance(city1[0], city1[1], city2[0], city2[1])
return distance
# 适应度函数 距离的倒数
def matchFun(self):
return lambda life: 1.0/self.distance(life.gene)
# 主函数
def main(self, n = 0):
while n > 0:
self.ga.next()
distance = self.distance(self.ga.best.gene)
# 输出当前代数和路径长度
print(("Generation: %4d \t\t Distance: %f") % (self.ga.generation - 1, distance))
# 输出最佳路径
self.ga.best.gene.append(self.ga.best.gene[0])
print("Path: ", self.ga.best.gene)
self.ga.best.gene.pop()
n -= 1
# 绘图
def draw(bestPath, cities):
ax = plt.subplot(111, aspect = 'equal')
x = []
y = []
for i in range(-1, len(cities) - 1):
index = bestPath[i]
city = cities[index]
x.append(city[0])
y.append(city[1])
x.append(x[0])
y.append(y[0])
ax.plot(x, y)
plt.show()
# 主函数
if __name__ == '__main__':
# 迭代次数
num = input("请输入迭代次数:")
num = int(num)
# 交叉与突变概率
global CROSSRATE
global MUTATIONRATE
CROSSRATE = input("请输入交叉概率:")
CROSSRATE = float(CROSSRATE)
MUTATIONRATE = input("请输入突变概率:")
MUTATIONRATE = float(MUTATIONRATE)
# 初始序列
bp = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
tsp=TSP()
print("初始路径长度:", tsp.distance(bp))
tsp.main(num)
draw(tsp.ga.best.gene, tsp.citys)