题目
1.tsp问题
以下是中国34个城市的坐标值,利用遗传算法求出最短路径和最短路径距离。
北京 ;116.46;39.92
天津 ;117.2;39.13
上海 ;121.48;31.22
重庆 ;106.54;29.59
拉萨 ;91.11;29.97
乌鲁木齐 ;87.68;43.77
银川 ;106.27;38.47
呼和浩特 ;111.65;40.82
南宁 ;108.33;22.84
哈尔滨 ;126.63;45.75
长春 ;125.35;43.88
沈阳 ;123.38;41.8
石家庄 ;114.48;38.03
太原 ;112.53;37.87
西宁 ;101.74;36.56
济南 ;117;36.65
郑州;113.6;34.76
南京;118.78;32.04
合肥;117.27;31.86
杭州;120.19;30.26
福州;119.3;26.08
南昌;115.89;28.68
长沙;113;28.21
武汉;114.31;30.52
广州;113.23;23.16
台北;121.5;25.05
海口;110.35;20.02
兰州;103.73;36.03
西安;108.95;34.27
成都;104.06;30.67
贵阳;106.71;26.57
昆明;102.73;25.04
香港;114.1;22.2
澳门;113.33;22.13
2.多峰函数优化问题
Michalewicz函数如下:
1.TSP问题
import random
import math
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from math import radians, cos, sin, asin, sqrt
class GA(object):
def __init__(self, num_city, num_total, iteration, data):
self.num_city = num_city
self.num_total = num_total
self.scores = []
self.iteration = iteration
self.location = data
self.ga_choose_ratio = 0.2
self.mutate_ratio = 0.05
# fruits中存每一个个体是下标的list
self.dis_mat = self.city_distance(data)
self.fruits = self.greedy_init(self.dis_mat,num_total,num_city)
# 显示初始化后的最佳路径
scores = self.compute_adp(self.fruits)
sort_index = np.argsort(-scores)
init_best = self.fruits[sort_index[0]]
init_best = self.location[init_best]
print(self.dis_mat)
# 存储每个iteration的结果,画出收敛图
self.iter_x = [0]
self.iter_y = [1. / scores[sort_index[0]]]
def random_init(self, num_total, num_city): #随机初始化路径
tmp = [x for x in range(num_city)]
result = []
for i in range(num_total):
random.shuffle(tmp)
result.append(tmp.copy())
return result
def greedy_init(self, dis_mat, num_total, num_city): #贪心初始化
start_index = 0
result = []
for i in range(num_total):
rest = [x for x in range(0, num_city)]
# 所有起始点都已经生成了
if start_index >= num_city:
start_index = np.random.randint(0, num_city)
result.append(result[start_index].copy())
continue
current = start_index
rest.remove(current)
# 找到一条最近邻路径
result_one = [current]
while len(rest) != 0:
tmp_min = math.inf
tmp_choose = -1
for x in rest:
if dis_mat[current][x] < tmp_min:
tmp_min = dis_mat[current][x]
tmp_choose = x
current = tmp_choose
result_one.append(tmp_choose)
rest.remove(tmp_choose)
result.append(result_one)
start_index += 1
return result
def earth_distance(self,lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
# 将十进制度数转化为弧度
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine公式
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
c = 2 * asin(sqrt(a))
r = 6371 # 地球平均半径,单位为公里
return c * r
def calc_path_distance(self,distance_matrix, solution):
"""
Total distance of the current solution path.
"""
N = distance_matrix.shape[0]
cur_dist = 0
for i in range(N):
cur_dist += distance_matrix[solution[i % N], solution[(i + 1) % N]]
return cur_dist
def city_distance(self,cities):
N = len(cities)
distance_matrix = np.zeros((N, N))
for i in range(N):
loni, lati = cities[i]
for j in range(i, N):
lonj, latj = cities[j]
dist = self.earth_distance(loni, lati, lonj, latj)
distance_matrix[i][j] = distance_matrix[j][i] = dist
distance_matrix = np.round(distance_matrix, 2)
print(distance_matrix)
return distance_matrix
# 计算不同城市之间的距离
def compute_dis_mat(self, num_city, location):
dis_mat = np.zeros((num_city, num_city))
for i in range(num_city):
for j in range(num_city):
if i == j:
dis_mat[i][j] = np.inf
continue
a = location[i]
b = location[j]
tmp = np.sqrt(sum([(x[0] - x[1]) ** 2 for x in zip(a, b)]))
dis_mat[i][j] = tmp
return dis_mat
# 计算路径长度
def compute_pathlen(self, path, dis_mat):
try:
a = path[0]
b = path[-1]
except:
import pdb
pdb.set_trace()
result = dis_mat[a][b]
for i in range(len(path) - 1):
a = path[i]
b = path[i + 1]
result += dis_mat[a][b]
return result
# 计算种群适应度
def compute_adp(self, fruits):
adp = []
for fruit in fruits:
if isinstance(fruit, int):
import pdb
pdb.set_trace()
length = self.compute_pathlen(fruit, self.dis_mat)
adp.append(1.0 / length) #路径越长,种群适应度越差
return np.array(adp)
def swap_part(self, list1, list2):
index = len(list1)
list = list1 + list2
list = list[::-1]
return list[:index], list[index:]
def ga_cross(self, x, y): # 交叉
len_ = len(x)
assert len(x) == len(y)
path_list = [t for t in range(len_)]
order = list(random.sample(path_list, 2)) #从里面随机选择n个数
order.sort()
start, end = order
# 找到冲突点并存下他们的下标,x中存储的是y中的下标,y中存储x与它冲突的下标,就是找不一样的点
tmp = x[start:end]
x_conflict_index = []
for sub in tmp:
index = y.index(sub)
if not (index >= start and index < end):
x_conflict_index.append(index)
y_confict_index = []
tmp = y[start:end]
for sub in tmp:
index = x.index(sub)
if not (index >= start and index < end):
y_confict_index.append(index)
assert len(x_conflict_index) == len(y_confict_index)
# 交叉
tmp = x[start:end].copy()
x[start:end] = y[start:end]
y[start:end] = tmp
# 解决冲突
for index in range(len(x_conflict_index)):
i = x_conflict_index[index]
j = y_confict_index[index]
y[i], x[j] = x[j], y[i]
assert len(set(x)) == len_ and len(set(y)) == len_
return list(x), list(y)
# 遗传父母
def ga_parent(self, scores, ga_choose_ratio):
sort_index = np.argsort(-scores).copy() # 排序然后提取他排序前的位置
sort_index = sort_index[0:int(ga_choose_ratio * len(sort_index))] # 按照ratio选择
parents = []
parents_score = []
for index in sort_index:
parents.append(self.fruits[index])
parents_score.append(scores[index])
return parents, parents_score
# 选择算子,轮盘赌
def ga_choose(self, genes_score, genes_choose):
sum_score = sum(genes_score)
score_ratio = [sub * 1.0 / sum_score for sub in genes_score]
rand1 = np.random.rand()
rand2 = np.random.rand()
for i, sub in enumerate(score_ratio):
if rand1 >= 0:
rand1 -= sub
if rand1 < 0:
index1 = i
if rand2 >= 0:
rand2 -= sub
if rand2 < 0:
index2 = i
if rand1 < 0 and rand2 < 0:
break
return list(genes_choose[index1]), list(genes_choose[index2])
#选择算子,锦标赛
def ga_choose1(self,genes_score,genes_choose):
index1=0
index2=0
index=0
now=0
for i in genes_score:
if i>now:
i=now
index1=index
index2=index1
index+=1
return list(genes_choose[index1]),list(genes_choose[index2])
# 变异
def ga_mutate(self, gene):
path_list = [t for t in range(len(gene))]
order = list(random.sample(path_list, 2))
start, end = min(order), max(order)
tmp = gene[start:end]
# np.random.shuffle(tmp)
tmp = tmp[::-1]
gene[start:end] = tmp
return list(gene)
# 遗传
def ga(self):
# 获得优质父代
scores = self.compute_adp(self.fruits) # 计算适应度
# 选择部分优秀个体作为父代候选集合
parents, parents_score = self.ga_parent(scores, self.ga_choose_ratio)
tmp_best_one = parents[0]
tmp_best_score = parents_score[0]
# 新的种群fruits
fruits = parents.copy()
# 生成新的种群
while len(fruits) < self.num_total:
# 轮盘赌方式就用ga_choose,锦标赛方式就用ga_choose1
gene_x, gene_y = self.ga_choose(parents_score, parents)
# 交叉
gene_x_new, gene_y_new = self.ga_cross(gene_x, gene_y)
# 变异
if np.random.rand() < self.mutate_ratio:
gene_x_new = self.ga_mutate(gene_x_new)
if np.random.rand() < self.mutate_ratio:
gene_y_new = self.ga_mutate(gene_y_new)
x_adp = 1. / self.compute_pathlen(gene_x_new, self.dis_mat)
y_adp = 1. / self.compute_pathlen(gene_y_new, self.dis_mat)
# 将适应度高的放入种群中
if x_adp > y_adp and (not gene_x_new in fruits):
fruits.append(gene_x_new)
elif x_adp <= y_adp and (not gene_y_new in fruits):
fruits.append(gene_y_new)
self.fruits = fruits
return tmp_best_one, tmp_best_score
#开跑
def run(self):
BEST_LIST = None
best_score = -math.inf
self.best_record = []
for i in range(1, self.iteration + 1):
tmp_best_one, tmp_best_score = self.ga()
self.iter_x.append(i)
self.iter_y.append(1. / tmp_best_score)
if tmp_best_score > best_score:
best_score = tmp_best_score
BEST_LIST = tmp_best_one
self.best_record.append(1./best_score)
print(i,1./best_score)
print(1./best_score)
return self.location[BEST_LIST], 1. / best_score
# 读取数据
def read_tsp(path):
data=pd.read_csv(path,sep=';',header=None)
print(data)
data=data.loc[:,:]
return data
data = read_tsp('data/test.csv')
data = np.array(data)
data = data[:, 1:]
print(data)
Best, Best_path = math.inf, None
model = GA(num_city=data.shape[0], num_total=25, iteration=500, data=data.copy())
path, path_len = model.run()
if path_len < Best:
Best = path_len
Best_path = path
print(Best_path)
# 加上一行因为会回到起点
fig, axs = plt.subplots(2, 1, sharex=False, sharey=False)
axs[0].scatter(Best_path[:, 0], Best_path[:,1])
Best_path = np.vstack([Best_path, Best_path[0]])
axs[0].plot(Best_path[:, 0], Best_path[:, 1])
axs[0].set_title('Planning results')
iterations = range(model.iteration)
best_record = model.best_record
axs[1].plot(iterations, best_record)
axs[1].set_title('Convergence curve')
plt.show()
多峰函数优化
import random
import math
import matplotlib.pyplot as plt
personNum=1000 #种群数量
mutationProbability=0.9 #变异概率
iteration=50 #假设迭代50次即终止
length=30
def getAbsList(theList):
for i in range(len(theList)):
if theList[i]<0:
theList[i]=theList[i]*(-1)
return theList
# 功能:生成初始化种群
# 参数:personNum为种群数量,length为种群每个个体编码的位数
def initialPopulation(personNum=50,length=30):
totalPopulation=[]
while len(totalPopulation)!=personNum:
person=[]
for i in range(length):
temp = random.uniform(-1, 1) # 生成-1<=X<=1的数字
if temp<0:
person.append(0)
else:
person.append(1)
theStr = ''
for item in person:
theStr += str(item)
#print(theStr)
if theStr not in totalPopulation:
if evaluate(theStr)>0:
totalPopulation.append(theStr)
#print(len(totalPopulation))
return totalPopulation
# 函数功能:将编码转换为x,y的十进制解
def decode(onePerson,length=30):
index=0
data=[]
while index<length:
#print(onePerson[index:index+15])
data.append(int(onePerson[index:index+15],2)*math.pi/32678)
index+=15
#print("没报错")
return data
# 功能:计算x,y对应的函数值
# 参数:一个个体的编码
def evaluate(onePerson,length=30):
data=decode(onePerson,length)
result=0
for i in range(int(length/15)):
x=data[i]
result+=math.sin(x) * math.pow(math.sin((i+1)*x * x / math.pi), 20)
#print(result)
return result
# 功能:获取一个父母进行交叉
# 输出:返回的是一个双亲在population的index
def getParents(evalList):
temp = random.uniform(0, 1)
#print(temp)
portionList=[];theSum=0
totalEval=sum(evalList)
#print(totalEval)
for eval in evalList:
theSum+=eval/totalEval
portionList.append(theSum)
location=0
while(temp>portionList[location]):
location+=1
#print('location=',location)
return location
# 输入:两个person
# 输出:生成的子代person编码
def getCross(father,mother,length=30):
theVisit=[]
crossLocation=random.randint(0,length-1)
theVisit.append(crossLocation)
#print(crossLocation)
child=''
child += father[0:crossLocation]
child += mother[crossLocation:length]
while evaluate(child)<0:
#print("重新交叉")
while crossLocation in theVisit and len(theVisit)<length:
crossLocation = random.randint(0, length-1)
#print(crossLocation)
child += father[0:crossLocation]
child += mother[crossLocation:]
theVisit.append(crossLocation)
if len(theVisit)>=length:
child=father
#print(len(child))
return child
# 功能:进行变异
def getVari(person,length=30):
#print(person)
temp = random.uniform(0, 1)
if temp<mutationProbability:
#print('变异')
location=random.randint(0,length-1)
#print(location)
tempStr=person[0:location]
tempStr+=str(1-int(person[location]))
tempStr+=person[location+1:]
if evaluate(tempStr)>evaluate(person):
return tempStr
return person
if __name__=='__main__':
theScore=[]
bestPerson=[]
theBestEval=0
print("输入d的大小:")
d=int(input())
length=d*15
population = initialPopulation(personNum,length)
flag = 0
bestRecord=[]
while flag!=iteration:
print("第",flag+1,"代")
evalList=[]
tempPopulation=[]
for person in population:
evalList.append(evaluate(person,length))
maxEval=max(evalList)
print('maxEval=',maxEval)
theIndex=evalList.index(maxEval)
tempPopulation.append(population[theIndex]) #每次迭代时先将上一代最大的个体放到下一代种群中
# print("开始交叉")
for i in range(personNum):
#获得用于交叉的父母
parentsFaIndex=getParents(evalList)
parentsFa=population[parentsFaIndex]
parentsMaIndex=getParents(evalList)
parentsMa=population[parentsMaIndex]
child=getCross(parentsFa,parentsMa,length)
child=getVari(child,length)
tempPopulation.append(child)
population=tempPopulation
flag+=1
evalList = []
for person in population:
#print(person)
evalList.append(evaluate(person,length))
maxEval=max(evalList)
if theBestEval<maxEval:
theBestEval=maxEval
theIndex = evalList.index(maxEval)
person = population[theIndex]
if person not in bestPerson:
bestPerson.append(person)
theScore.append(1)
else:
theScore[bestPerson.index(person)] += 1
bestRecord.append(-theBestEval)
# print('duration=',time.time()-timeStart)
print(theScore)
print(bestPerson)
theBestEvalList=[]
for item in bestPerson:
theBestEvalList.append(evaluate(item,length))
print(theBestEvalList)
print(theBestEval)
print(max(theScore))
print(bestRecord)
iterations=[i for i in range(iteration)]
plt.plot(iterations, bestRecord, 'bo-')
plt.title("Convergence curve")
plt.show()