遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。在求解较为复杂的组合优化问题时,相对一些常规的优化算法,通常能够较快地获得较好的优化结果。遗传算法已被人们广泛地应用于组合优化、机器学习、信号处理、自适应控制和人工生命等领域。
遗传算法的基本运算过程如下:
遗传操作包括以下三个基本遗传算子(genetic operator):选择(selection);交叉(crossover);变异(mutation)。
import random
import numpy as np
def log(i, a, b):
print("epoch --> ",
str(i + 1).rjust(5, " "), " max:",
str(round(a, 4)).rjust(8, " "), "mean:",
str(round(b, 4)).rjust(8, " "), "alpha:",
str(round(a / b, 4)).rjust(8, " "))
class GeneSolve:
## 初始定义,后续引用GeneSolve类方法为(初始种群数,最大迭代数,交叉概率,变异概率,最大适应度/平均适应度(扰动率趋于平稳则越接近1越好))
def __init__(self, pop_size, epoch, cross_prob, mutate_prob, alpha, print_batch=10):
self.pop_size = pop_size
self.epoch = epoch
self.cross_prob = cross_prob
self.mutate_prob = mutate_prob
self.print_batch = print_batch
self.alpha = alpha
self.width = 11
self.best = None
# 产生初始种群
self.genes = np.array(
[''.join([random.choice(['0', '1']) for i in range(self.width)]) for j in range(self.pop_size)])
def inter_cross(self):
"""对染色体进行交叉操作"""
ready_index = list(range(self.pop_size))
while len(ready_index) >= 2:
d1 = random.choice(ready_index)
ready_index.remove(d1)
d2 = random.choice(ready_index)
ready_index.remove(d2)
if np.random.uniform(0, 1) <= self.cross_prob:
loc = random.choice(range(1, self.width - 1))
d1_a, d1_b = self.genes[d1][0:loc], self.genes[d1][loc:]
d2_a, d2_b = self.genes[d2][0:loc], self.genes[d2][loc:]
self.genes[d1] = d1_a + d2_b
self.genes[d2] = d2_a + d1_b
def mutate(self):
"""基因突变"""
ready_index = list(range(self.pop_size))
for i in ready_index:
if np.random.uniform(0, 1) <= self.mutate_prob:
loc = random.choice(range(0, self.width))
t0 = list(self.genes[i])
t0[loc] = str(1 - int(self.genes[i][loc]))
self.genes[i] = ''.join(t0)
def get_adjust(self):
"""计算适应度(只有在计算适应度的时候要反函数,其余过程全都是随机的二进制编码)"""
x = self.get_decode()
return x * np.sin(x) + 12
def get_decode(self):
"""编码,从表现型到基因型的映射"""
# 编码其中int(x,2)表示讲x换为二进制编码,12.55则为区间[0,12.55]的delta,2**11则为2^11 这里的11则是编码长度(也就是转换的精度)
# 求解精度为10^-2,即将一个单位长度(这里是12.55划分成1255份)进行划分,由于2^10 = 1024 < 2^11 = 2048,于是编码长度选取为11
return np.array([int(x,2) * 12.55 / (2 ** 12 - 1) for x in self.genes])
def cycle_select(self):
"""通过轮盘赌来进行选择"""
adjusts = self.get_adjust()
if self.best is None or np.max(adjusts) > self.best[1]:
self.best = self.genes[np.argmax(adjusts)], np.max(adjusts)
p = adjusts / np.sum(adjusts)
cu_p = []
for i in range(self.pop_size):
cu_p.append(np.sum(p[0:i]))
cu_p = np.array(cu_p)
r0 = np.random.uniform(0, 1, self.pop_size)
sel = [max(list(np.where(r > cu_p)[0]) + [0]) for r in r0]
# 保留最优的个体
if np.max(adjusts[sel]) < self.best[1]:
self.genes[sel[np.argmin(adjusts[sel])]] = self.best[0]
self.genes = self.genes[sel]
def evolve(self):
"""逐代演化"""
for i in range(self.epoch):
self.cycle_select() #种群选取
self.inter_cross() #染色体交叉
self.mutate() #计算适应度
a, b = np.max(gs.get_adjust()), np.mean(gs.get_adjust())
if i % self.print_batch == self.print_batch - 1 or i == 0:
log(i, a, b)
if a / b < self.alpha:
log(i, a, b)
print("进化终止,算法已收敛!共进化 ", i + 1, " 代!")
break
1. 函数优化
函数优化是遗传算法的经典应用领域,也是遗传算法进行性能评价的常用算例,许多人构造出了各种各样复杂形式的测试函数:连续函数和离散函数、凸函数和凹函数、低维函数和高维函数、单峰函数和多峰函数等。对于一些非线性、多模型、多目标的函数优化问题,用其它优化方法较难求解,而遗传算法可以方便的得到较好的结果。
2. 组合优化
随着问题规模的增大,组合优化问题的搜索空间也急剧增大,有时在计算上用枚举法很难求出最优解。对这类复杂的问题,人们已经意识到应把主要精力放在寻求满意解上,而遗传算法是寻求这种满意解的最佳工具之一。实践证明,遗传算法对于组合优化中的NP问题非常有效。例如遗传算法已经在求解旅行商问题、 背包问题、装箱问题、图形划分问题等方面得到成功的应用
此外,GA也在生产调度问题、自动控制、机器人学、图象处理、人工生命、遗传编码和机器学习等方面获得了广泛的运用。
3. 车间调度
车间调度问题是一个典型的NP-Hard问题,遗传算法作为一种经典的智能算法广泛用于车间调度中,很多学者都致力于用遗传算法解决车间调度问题,现今也取得了十分丰硕的成果。从最初的传统车间调度(JSP)问题到柔性作业车间调度问题(FJSP),遗传算法都有优异的表现,在很多算例中都得到了最优或近优解。