遗传算法(一元)
(解一元函数极值)
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from math import *
from numpy import *
#目标函数
def y(fun,x):
return eval(fun)
#生成初始种群
def init_pop(num,DNA_SIZE):
pop = np.random.randint(2,size = [num,DNA_SIZE])
return pop
#计算适应度
def get_fitness(pop,choice):
gene = np.array([2 ** i for i in range(DNA_SIZE)])
result = np.dot(pop,gene.T)
fitness = y(fun,result * (limit[1] - limit[0]) / (2 ** DNA_SIZE) + limit[0])
if choice == 'max':
return (fitness - np.min(fitness) + 1e-3)
elif choice == 'min':
return (np.max(fitness) - fitness + 1e-3)
#自然选择
def select(pop,fitness):
index = np.random.choice(len(pop),size = int(len(pop) * 0.8),replace = True,p = fitness / fitness.sum())
return pop[index]
#交叉和变异
def cross_and_mutate(pop,CROSS_RATE):
new_pop = []
for father in pop:
child = father
if np.random.rand() <= CROSS_RATE:
mother = pop[np.random.randint(len(pop))]
point = np.random.randint(DNA_SIZE)
child[point:] = mother[point:]
mutate(child,MUTATE_RATE)
new_pop.append(child)
return new_pop
#变异
def mutate(child,MUTATE_RATE):
if np.random.rand() <= MUTATE_RATE:
point = np.random.randint(DNA_SIZE)
child[point] = child[point] ^ 1
num = 100000 #初始种群数量
DNA_SIZE = 10 #DNA长度
fun = 'sin(x) + sin(2 * x) + cos(x ** 2) + x - x ** 2 - x ** 3 + exp(x)' #函数表达式
limit = [-2,5] #取值范围
choice = 'max' #最大值或最小值
CROSS_RATE = 0.8 #发生交叉的概率
MUTATE_RATE = 0.003 #发生交叉的概率
N_GENERATION = 100 #繁殖代数
# fun = input('输入关于x的表达式(如:x ** 2 + 2 * x + 3):')
# num = int(input('输入初始种群数:'))
# DNA_SIZE = int(input('输入DNA长度:'))
# low = float(input('输入下限:'))
# high = float(input('输入上限:'))
# limit = [low,high]
# choice = input('输入所求为最大值或最小值(最大值:max,最小值:min):')
# CROSS_RATE = float(input('输入交叉概率(0.6~1.0):'))
# MUTATE_RATE = float(input('输入变异概率(0~0.1):'))
# N_GENERATION = int(input('输入遗传代数:'))
pop = init_pop(num, DNA_SIZE)
for i in range(N_GENERATION):
fitness = get_fitness(pop,choice)
pop = select(pop,fitness)
pop = np.array(cross_and_mutate(pop,CROSS_RATE))
if len(pop) <= 5:
break
gene = np.array([2 ** i for i in range(DNA_SIZE)])
result = np.dot(pop,gene.T)
result_x = result * (limit[1] - limit[0]) / (2 ** DNA_SIZE) + limit[0]
result_y = y(fun,result_x)
print('最优解为:',result_x,end = '\n')
print('对应函数值为:',result_y,end = '\n')
x = np.arange(limit[0],limit[1],(limit[1] - limit[0]) / 50)
fx = y(fun,x)
plt.figure(figsize = (20,8),dpi = 80)
plt.title('Genetic Algorithm',fontsize = '20')
plt.xlabel('x',fontsize = 20)
plt.ylabel('y',rotation = 'horizontal',fontsize = 20)
plt.plot(x,fx,color = 'green',label = 'y = ' + fun)
plt.scatter(result_x,result_y,color = 'red',label = 'best_x')
plt.legend(loc = 'lower right',fontsize = 15,framealpha = 0.3)
plt.show()
遗传算法(二元)
(解二元函数极值)
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from math import *
from numpy import *
#目标函数
def f(fun,x,y):
return eval(fun)
#生成初始种群
def init_pop(num,DNA_SIZE):
pop = np.random.randint(2,size = [2,num,DNA_SIZE])
return pop
#计算适应度
def get_fitness(pop,choice):
gene = np.array([2 ** i for i in range(DNA_SIZE)])
result_x = np.dot(pop[0],gene.T)
result_y = np.dot(pop[1], gene.T)
fitness = f(fun,result_x * (limit_x[1] - limit_x[0]) / (2 ** DNA_SIZE) + limit_x[0],result_y * (limit_y[1] - limit_y[0]) / (2 ** DNA_SIZE) + limit_y[0])
if choice == 'max':
return (fitness - np.min(fitness) + 1e-3)
elif choice == 'min':
return (np.max(fitness) - fitness + 1e-3)
#自然选择
def select(pop,fitness):
index = np.random.choice(len(pop[0]),size = int(len(pop[0]) * 0.9),replace = True,p = fitness / fitness.sum())
return np.array([pop[0][index],pop[1][index]])
#交叉和变异
def cross_and_mutate(pop,CROSS_RATE):
new_pop = [[],[]]
for father1,father2 in list(zip(pop[0],pop[1])):
child1 = father1
child2 = father2
mother1, mother2 = pop[[0,1],np.random.randint(len(pop))]
if np.random.rand() <= CROSS_RATE:
point = np.random.randint(DNA_SIZE)
child1[point:] = mother1[point:]
mutate(child1,MUTATE_RATE)
if np.random.rand() <= CROSS_RATE:
point = np.random.randint(DNA_SIZE)
child2[point:] = mother2[point:]
mutate(child2, MUTATE_RATE)
new_pop[0].append(child1)
new_pop[1].append(child2)
return new_pop
#变异
def mutate(child,MUTATE_RATE):
if np.random.rand() <= MUTATE_RATE:
point = np.random.randint(DNA_SIZE)
child[point] = child[point] ^ 1
num = 100000 #初始种群数量
DNA_SIZE = 10 #DNA长度
# fun = '3 * (1 - x) ** 2 * np.exp(-(x ** 2) - (y + 1) ** 2)- 10 * (x / 5 - x ** 3 - y ** 5) * np.exp(-x ** 2 - y ** 2)- 1 / 3 ** np.exp(-(x + 1) ** 2 - y ** 2)' #函数表达式
# limit_x = [-2,3] #取值范围
# limit_y = [-3,6]
fun = '5 * sin(x * y) + x ** 2 + y ** 2'
limit_x = [-4,4] #取值范围
limit_y = [-4,4]
choice = 'max' #最大值或最小值
CROSS_RATE = 0.8 #发生交叉的概率
MUTATE_RATE = 0.05 #发生交叉的概率
N_GENERATION = 1000 #繁殖代数
iter_time = 50 #运行次数,防止陷入局部最优解
# fun = input('输入关于x,y的表达式(如:x ** 2 + 2 * x + 3 + y):')
# num = int(input('输入初始种群数:'))
# DNA_SIZE = int(input('输入DNA长度:'))
# low_x = float(input('输入x下限:'))
# high_x = float(input('输入x上限:'))
# limit_x = [low_x,high_y]
# low_y = float(input('输入y下限:'))
# high_y = float(input('输入y上限:'))
# limit_y = [low_y,high_y]
# choice = input('输入所求为最大值或最小值(最大值:max,最小值:min):')
# CROSS_RATE = float(input('输入交叉概率(0.6~1.0):'))
# MUTATE_RATE = float(input('输入变异概率(0~0.1):'))
# N_GENERATION = int(input('输入遗传代数:'))
scatter_x = limit_x[0]
scatter_y = limit_y[0]
scatter_z = f(fun,scatter_x,scatter_y)
for time in range(iter_time):
pop = init_pop(50, DNA_SIZE)
for i in range(N_GENERATION):
fitness = get_fitness(pop,choice)
pop = select(pop,fitness)
pop = np.array(cross_and_mutate(pop,CROSS_RATE))
if len(pop[0]) <= 5:
break
gene = np.array([2 ** i for i in range(DNA_SIZE)])
result_x = np.dot(pop[0], gene.T) * (limit_x[1] - limit_x[0]) / (2 ** DNA_SIZE) + limit_x[0]
result_y = np.dot(pop[1], gene.T) * (limit_y[1] - limit_y[0]) / (2 ** DNA_SIZE) + limit_y[0]
result_z = f(fun, result_x, result_y)
if choice == 'min':
min_index = np.argmin(result_z)
if result_z[min_index] <= scatter_z:
scatter_x = result_x[min_index]
scatter_y = result_y[min_index]
scatter_z = result_z[min_index]
elif choice == 'max':
max_index = np.argmax(result_z)
if result_z[max_index] >= scatter_z:
scatter_x = result_x[max_index]
scatter_y = result_y[max_index]
scatter_z = result_z[max_index]
print('最优解:','x = ',scatter_x,'y = ',scatter_y,end = '\n')
print('结果:','z = ',scatter_z)
x = np.arange(limit_x[0],limit_x[1],(limit_x[1] - limit_x[0]) / 50)
y = np.arange(limit_y[0],limit_y[1],(limit_y[1] - limit_y[0]) / 50)
x,y = np.meshgrid(x,y)
z = f(fun,x,y)
# 新建一个画布
figure = plt.figure(figsize = (10,8),dpi = 80)
# 新建一个3d绘图对象
ax = Axes3D(figure)
# 定义x,y 轴名称
plt.xlabel("x")
plt.ylabel("y")
# 设置间隔和颜色
ax.scatter(scatter_x,scatter_y,scatter_z,color = 'red')
ax.plot_surface(x,y,z, rstride=1, cstride=1, color ="green",alpha = 0.5)
# 展示
plt.show()
免疫算法
(找二元函数极值)
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from numpy import *
G = 100 #迭代次数
fun = '5 * sin(x * y) + x ** 2 + y ** 2' #目标函数
choice = 'max'
dim = 2 #维度
limit_x = [-4,4] #x取值范围
limit_y = [-4,4] #y取值范围
pop_size = 10 #种群规模
mutate_rate = 0.7 #变异概率
delta = 0.2 #相似度阈值
beta = 1 #激励度系数
colone_num = 10 #克隆份数
if choice == 'max':
alpha = 2 #激励度系数,求最大值为正,最小值为负
else:
alpha = -2
def f(fun,x,y):
return eval(fun)
#初始化种群
def init_pop(dim,pop_size,*limit):
pop = np.random.rand(dim,pop_size)
for i in range(dim):
pop[i,:] *= (limit[i][1] - limit[i][0])
pop[i,:] += limit[i][0]
return pop
#计算浓度
def calc_density(pop,delta):
density = np.zeros([pop.shape[1],])
for i in range(pop.shape[1]):
density[i] = np.sum(len(np.ones([pop.shape[1],])[np.sqrt(np.sum((pop - pop[:,i].reshape([2,1])) ** 2,axis = 0)) < delta]))
return density / pop.shape[1]
#计算激励度
def calc_simulation(simulation,density):
return (alpha * simulation - beta * density)
#变异,随着代数增加变异范围逐渐减小
def mutate(x,gen,mutata_rate,dim,*limit):
for i in range(dim):
if np.random.rand() <= mutata_rate:
x[i] += (np.random.rand() - 0.5) * (limit[i][1] - limit[i][0]) / (gen + 1) #加上随机数产生变异
if (x[i] > limit[i][1]) or (x[i] < limit[i][0]): #边界检测
x[i] = np.random.rand() * (limit[i][1] - limit[i][0]) + limit[i][0]
pop = init_pop(dim,pop_size,limit_x,limit_y)
init_simulation = f(fun,pop[0,:],pop[1,:])
density = calc_density(pop,delta)
simulation = calc_simulation(init_simulation,density)
# print(pop)
# print(init_simulation)
# print(calc_density(pop,delta))
#进行激励度排序
index = np.argsort(-simulation)
pop = pop[:,index]
new_pop = pop.copy() #浅拷贝
simulation = simulation[index]
#免疫循环
for gen in range(G):
best_a = np.zeros([dim,int(pop_size / 2)]) #用于保留每次克隆后亲和度最高的个体
best_a_simulation = np.zeros([int(pop_size / 2),]) #保存激励度
#选出激励度前50%的个体进行免疫
for i in range(int(pop_size / 2)):
a = new_pop[:,i].reshape([2,1])
b = np.tile(a,(1,colone_num)) #克隆10份
for j in range(colone_num):
mutate(a,gen,mutate_rate,dim,limit_x,limit_y)
b[:,0] = pop[:,i] #保留克隆源个体
#保留亲和度最高的个体
b_simulation = f(fun,b[0,:],b[1,:])
index = np.argsort(-b_simulation)
best_a_simulation = b_simulation[index][0] #最佳个体亲和度
best_a[:,i] = b[:,index][:,0] #最佳个体
#计算免疫种群的激励度
a_density = calc_density(best_a,delta)
best_a_simulation = calc_simulation(best_a_simulation,a_density)
#种群刷新
new_a = init_pop(2,int(pop_size / 2),limit_x,limit_y)
#新生种群激励度
new_a_simulation = f(fun,new_a[0,:],new_a[1,:])
new_a_density = calc_density(new_a,delta)
new_a_simulation = calc_simulation(new_a_simulation,new_a_density)
#免疫种群与新生种群合并
pop = np.hstack([best_a,new_a])
simulation = np.hstack([best_a_simulation,new_a_simulation])
index = np.argsort(-simulation)
pop = pop[:,index]
simulation = simulation[index]
new_pop = pop.copy()
# 新建一个画布
figure = plt.figure(figsize = (10,8),dpi = 80)
# 新建一个3d绘图对象
ax = Axes3D(figure)
# 定义x,y 轴名称
plt.xlabel("x")
plt.ylabel("y")
for i in range(int(pop_size / 2)):
ax.scatter(pop[0,i],pop[1,i],f(fun,pop[0,i],pop[1,i]),color = 'red')
print('最优解:','x = ',pop[0,i],'y = ',pop[1,i],end = '\n')
print('结果:','z = ',f(fun,pop[0,i],pop[1,i]))
x = np.arange(limit_x[0],limit_x[1],(limit_x[1] - limit_x[0]) / 50)
y = np.arange(limit_y[0],limit_y[1],(limit_y[1] - limit_y[0]) / 50)
x,y = np.meshgrid(x,y)
z = f(fun,x,y)
ax.plot_surface(x,y,z, rstride=1, cstride=1, color = 'green',alpha = 0.5)
plt.show()
蚁群算法
(解决TSP问题)
import numpy as np
from matplotlib import pyplot as plt
m = 50 #蚁群总数
alpha = 1 #信息度启发因子(重要程度)
beta = 2 #期望值启发因子(重要程度)
ratio = 0.6 #信息素挥发因子
num_epochs = 100 #迭代次数
Q = 80 #信息素总量
eps = 1e-5
city = [5.326,2.558,
4.276,3.452,
4.819,2.624,
3.165,2.457,
0.915,3.921,
4.637,6.026,
1.524,2.261,
3.447,2.111,
3.548,3.665,
2.649,2.556,
4.399,1.194,
4.660,2.949,
1.479,4.440,
5.036,0.244,
2.830,3.140,
1.072,3.454,
5.845,6.203,
0.194,1.767,
1.660,2.395,
2.682,6.072] #每个城市的x,y坐标
city = np.array(city).reshape((-1,2))
city_num = city.shape[0] #城市的个数
distance = np.zeros((city_num,city_num)) #每个城市间的距离
def get_distance(route): #传入路线,得到走过的总距离
L = 0
for i in range(len(route) - 1):
L += distance[route[i],route[i + 1]]
L += distance[route[-1],route[0]]
return L
def get_delta_Tau(Tabu,L): #传入禁忌表和每只蚂蚁的总路程,获得信息素改变量
delta_Tau = np.zeros((city_num, city_num)) # 用于存放信息素改变量
for i in range(m):
for j in range(city_num - 1):
delta_Tau[Tabu[i,j],Tabu[i,j + 1]] += Q / L[i]
delta_Tau[Tabu[i,city_num - 1],Tabu[i,0]] += Q / L[i]
return delta_Tau
for i in range(city_num):
for j in range(city_num):
if i == j:
distance[i,j] = eps
distance[i,j] = ((city[i][0] - city[j][0]) ** 2 + (city[i][1] - city[j][1]) ** 2) ** 0.5
Eta = 1. / distance #城市之间的能见度
Tau = np.ones((city_num,city_num)) #信息素浓度矩阵
Tabu = np.zeros((m,city_num)).astype(int) #禁忌表
Road = np.zeros((num_epochs,city_num)) #每次迭代的最佳路径
Road_Length = np.inf * np.ones((num_epochs,)) #每次最佳路径的长度
Road_Avg = np.zeros((num_epochs,)) #每次迭代路径的平均值
for epoch in range(num_epochs):
# 蚂蚁随机分布在20个城市中
all_pos = []
for i in range(np.ceil(m / city_num).astype(int)):
pos = [i for i in range(city_num)]
np.random.shuffle(pos) #每次将20个城市的顺序打乱
all_pos.extend(pos)
Tabu[:,0] = all_pos[:m]
# 蚂蚁转移
for i in range(1,city_num): # i从第二个城市开始计数(初始化时已在某个城市)
for j in range(m):
visited = Tabu[j,0:i] #已经去过的城市
unvisited = np.zeros((city_num - i,)).astype(int) #没有去过的城市
p = np.zeros_like(unvisited).astype(float) #存放去未去过的城市的概率
index = 0
for k in range(city_num):
if k not in visited:
unvisited[index] = k
index += 1
for k in range(len(p)): #计算当前城市到未去过城市的概率
p[k] = (Tau[visited[-1],unvisited[k]] ** alpha) * (Eta[visited[-1],unvisited[k]] ** beta)
p = p / sum(p) #概率
to_visit = unvisited[np.argmax(p)] #前往概率最大的城市
Tabu[j,i] = to_visit #禁忌表上记录
if epoch >= 1: #将上一次找出的最优路径放入第一行
Tabu[0,:] = Road[epoch - 1,:]
#记录本次最佳的迭代路线
L = np.zeros((m,1)) #记录每一只蚂蚁走过的总距离
for k in range(m):
route = Tabu[k,:] #每只蚂蚁走过的路线
L[k] = get_distance(route)
Road_Length[epoch] = np.min(L) #找出最短路程
Road[epoch,:] = Tabu[np.argmin(L),:] #找出最短路程的路径
Road_Avg[epoch] = np.mean(L) #记录平均路程
#更新信息素
delta_Tau = get_delta_Tau(Tabu,L)
Tau = (1 - ratio) * Tau + delta_Tau
#禁忌表清零
Tabu = np.zeros((m,city_num)).astype(int)
print('最短路程为:',np.min(Road_Length))
#绘制最短路径
plt.figure(figsize = (20,8),dpi = 80)
plt.scatter(city[:,0],city[:,1],color = 'green')
route = Road[np.argmin(Road_Length),:].astype(int)
for i in range(len(route) - 1):
plt.plot([city[route[i]][0],city[route[i + 1]][0]],[city[route[i]][1],city[route[i + 1]][1]],color = 'red')
plt.plot([city[route[0]][0],city[route[-1]][0]],[city[route[0]][1],city[route[-1]][1]],color = 'red')
plt.show()