当前位置:   article > 正文

数学建模学习(1)遗传算法

数学建模学习(1)遗传算法

一、简介

        遗传算法(Genetic Algorithm, GA)是一种用于解决优化搜索问题的进化算法。它基于自然选择和遗传学原理,通过模拟生物进化过程来寻找最优解。

        以下是遗传算法的主要步骤和概念:

  • 初始化种群(Initialization):随机生成一组可能的解(个体),形成初始种群。

  • 适应度评估(Fitness Evaluation):根据适应度函数评估每个个体的质量,即其解问题的效果。

  • 选择(Selection):根据适应度选择较优的个体进行繁殖。常见的选择方法包括轮盘赌选择锦标赛选择排序选择

  • 交叉(Crossover):将两个个体的部分基因组合生成新的个体(子代)。交叉操作模拟生物的基因重组,常见的交叉方法有单点交叉和多点交叉。

  • 变异(Mutation):随机改变个体的部分基因,以增加种群的多样性,防止算法陷入局部最优。变异操作模拟生物的基因突变。

  • 替换(Replacement):将子代个体加入种群中,通常会替换掉适应度较低的个体,以保持种群规模恒定。

  • 终止条件(Termination Condition):当达到预定的终止条件时(如运行一定代数、适应度达到某个阈值),算法停止,输出最优解。

        遗传算法通常用于解决以下类型的问题:

  • 优化问题,例如函数优化、路径优化(如旅行商问题)。
  • 搜索问题,例如求解数独、密码破解。
  • 机器学习中的参数优化,例如神经网络权重优化。

优点

  • 遗传算法具有全局搜索能力,能够在较大的搜索空间中找到全局最优解。
  • 适用于复杂的、多维的、非线性的优化问题。
  • 不依赖于问题的具体数学性质,可以处理各种类型的目标函数和约束条件。

缺点

  • 计算代价较高,尤其是适应度评估过程可能耗时。
  • 需要精心设计适应度函数、选择方法、交叉和变异操作,才能获得好的效果。
  • 对于某些问题,可能会收敛到局部最优解,而非全局最优解。

二、算法介绍 

(1)适应度函数

(2)轮盘赌选择

(3)锦标赛选择

(4)排序选择

 

(5)单点交叉 

应用场景

        单点交叉适用于问题规模较小或基因序列较短的情况。

        对于复杂问题或基因序列较长的情况,可以考虑多点交叉均匀交叉等更复杂的交叉方法,以提高解的多样性和质量。

(6) 多点交叉

(7)均匀交叉 

 

 

(8)变异 

        通常设置较低的变异率(如 0.1% 到 1%)

三、遗传算法解TSP 

  1. import copy
  2. import random
  3. import math
  4. import numpy as np
  5. import matplotlib.pyplot as plt
  6. N = 20000 # 最大迭代次数
  7. city_num = 31
  8. pop_size = 100 # 种群数量
  9. pc = 0.8 # 交叉概率
  10. pm = 0.05 # 变异概率
  11. # 城市坐标
  12. city_position = [(1304, 2312), (3639, 1315), (4177, 2244), (3712, 1399), (3488, 1535),
  13. (3326, 1556), (3238, 1229), (4196, 1004), (4312, 790), (4380, 570),
  14. (3007, 1970), (2562, 1756), (2788, 1491), (2381, 1676), (1332, 695),
  15. (3715, 1678), (3918, 2179), (4061, 2370), (3780, 2212), (3676, 2578),
  16. (4029, 2838), (4263, 2931), (3429, 1908), (3507, 2367), (3394, 2643),
  17. (3439, 3201), (2935, 3240), (3140, 3550), (2545, 2357), (2778, 2826), (2370, 2975)]
  18. # 距离矩阵,城市之间的距离
  19. dis = np.zeros((31, 31))
  20. for i in range(31):
  21. for j in range(31):
  22. if i != j:
  23. dis[i][j] = ((city_position[i][0] - city_position[j][0]) ** 2 + (city_position[i][1] - city_position[j][1]) ** 2) ** 0.5
  24. # 初始化种群并去重
  25. def init(pop_size, city_num):
  26. population = []
  27. while len(population) < pop_size:
  28. temp = random.sample(range(city_num), city_num)
  29. if temp not in population:
  30. population.append((temp))
  31. return population
  32. # 适应度函数
  33. def fitness(population, dis):
  34. fitness = []
  35. for i in range(len(population)):
  36. distance = 0
  37. for j in range(city_num - 1):
  38. distance += dis[population[i][j]][population[i][j + 1]]
  39. distance += dis[population[i][-1]][population[i][0]]
  40. if distance == 0:
  41. f = float('inf')
  42. else:
  43. f = 1 / (distance ** 2)
  44. fitness.append(f)
  45. return fitness
  46. # 选择函数:轮盘赌选择
  47. def select(population, fitness):
  48. index = random.randint(0, pop_size - 1)
  49. num = 0
  50. r = random.uniform(0, sum(fitness))
  51. for i in range(len(population)):
  52. num += fitness[i]
  53. if num >= r:
  54. index = i
  55. break
  56. return population[index]
  57. # 交叉函数
  58. def cross(fa1, fa2):
  59. if random.random() < pc:
  60. chrom1 = fa1[:]
  61. chrom2 = fa2[:]
  62. cpoint1 = random.randint(0, city_num - 1)
  63. cpoint2 = random.randint(0, city_num - 1)
  64. if cpoint1 > cpoint2:
  65. temp = cpoint1
  66. cpoint1 = cpoint2
  67. cpoint2 = temp
  68. temp1 = []
  69. temp2 = []
  70. for i in range(cpoint1, len(chrom1)):
  71. temp1.append(chrom1[i])
  72. temp2.append(chrom2[i])
  73. for i in range(cpoint1, cpoint2 + 1):
  74. chrom1[i] = fa2[i]
  75. chrom2[i] = fa1[i]
  76. new_chrom1 = []
  77. new_chrom2 = []
  78. for i in range(cpoint2 + 1):
  79. new_chrom1.append(chrom1[i])
  80. new_chrom2.append(chrom2[i])
  81. new_chrom1.extend(temp1)
  82. new_chrom2.extend(temp2)
  83. ans1 = []
  84. ans2 = []
  85. for i in range(len(new_chrom1)):
  86. if new_chrom1[i] not in ans1:
  87. ans1.append(new_chrom1[i])
  88. for i in range(len(new_chrom2)):
  89. if new_chrom2[i] not in ans2:
  90. ans2.append(new_chrom2[i])
  91. return ans1, ans2
  92. else:
  93. return fa1[:], fa2[:]
  94. # 变异函数
  95. def mutate(chrom):
  96. if random.random() < pm:
  97. mpoint1 = random.randint(0, city_num - 1)
  98. mpoint2 = random.randint(0, city_num - 1)
  99. temp = chrom[mpoint1]
  100. chrom[mpoint1] = chrom[mpoint2]
  101. chrom[mpoint2] = temp
  102. return chrom
  103. def show(lx, ly, fit_history):
  104. # 画出每代最好适应值的图像
  105. plt.plot(range(len(fit_history)), fit_history)
  106. plt.xlabel("Generation")
  107. plt.ylabel("Fitness")
  108. plt.show()
  109. # 画出最短路径大小的变化图
  110. a = []
  111. for i in range(len(fit_history)):
  112. a.append(math.sqrt(1 / fit_history[i]))
  113. plt.plot(range(len(a)), a)
  114. plt.xlabel("Generation")
  115. plt.ylabel("Best_path_size")
  116. plt.show()
  117. def best_show(x, y, Best_Fitness):
  118. # 定义两个子图
  119. fig, ax = plt.subplots(1, 2, figsize=(12, 5), facecolor='#ccddef')
  120. # 定义子图1标题
  121. ax[0].set_title("Best route")
  122. # 定义子图2标题
  123. ax[1].set_title("Best_Fitness Change Procession")
  124. # 画线
  125. ax[0].plot(x, y)
  126. # 画点(第一个子图)
  127. ax[0].scatter(x, y, color='r')
  128. # 画线(第二个子图)
  129. ax[1].plot(range(len(Best_Fitness)), [Best_Fitness[i] for i in range(len(Best_Fitness))])
  130. plt.show()
  131. # 主程序
  132. if __name__ == '__main__':
  133. best_fit = 0.0
  134. ans = []
  135. best_path = []
  136. population = init(pop_size, city_num) # 初始化种群,pop_size:种群个数
  137. for i in range(N):
  138. fit = fitness(population, dis) # 计算适应度列表
  139. max_fit = max(fit) # 因为适应度是采用距离和的平方的倒数,故最大的适应度代表距离最小
  140. max_index = fit.index(max_fit) # 最大适应度的方案索引
  141. lx = []
  142. ly = []
  143. for j in population[max_index][:]:
  144. j = int(j) # 保证整数
  145. lx.append(city_position[j][0])
  146. ly.append(city_position[j][1])
  147. if max_fit > best_fit: # 假如路径更短
  148. best_fit = max_fit # 修正了这里的错别字
  149. ans = population[max_index][:]
  150. x = copy.copy(lx)
  151. y = copy.copy(ly)
  152. best_path.append(best_fit) # 记录适应度变化,为画图准备
  153. # 变异、交叉
  154. new_population = []
  155. n = 0
  156. while n < pop_size:
  157. p1 = select(population, fit)
  158. p2 = select(population, fit)
  159. while p2 == p1:
  160. p2 = select(population, fit)
  161. # 交叉
  162. chrom1, chrom2 = cross(p1, p2)
  163. # 变异
  164. chrom1 = mutate(chrom1)
  165. chrom2 = mutate(chrom2)
  166. new_population.append(chrom1)
  167. new_population.append(chrom2)
  168. n += 2
  169. population = new_population
  170. print("######################################################")
  171. print(f"第{i + 1}代的最优路径为:", ans)
  172. print("最短路径为:", (1 / best_fit) ** 0.5)
  173. show(lx,ly,best_path)
  174. x.append(x[0])
  175. y.append(y[0])
  176. best_show(x,y,best_path)

结果:

 

 

对比模拟退火算法的结果:

(以下是模拟退火算法的结果) 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/876269
推荐阅读
相关标签
  

闽ICP备14008679号