import numpy as np
# 二進制基因編碼轉十進制
def conv_2_10(x):
val = 0
for v in range(len(x)):
if x[-1*(v+1)] == 1:
val += 2 ** v
return val
# 十進制轉二進制基因編碼
def conv_10_2(x):
binary = bin(x)[2:]
gens = []
for v in binary:
if v == '0':
gens.append(0)
else:
gens.append(1)
return gens
# 選擇
def selection(fit, pop):
# 函數值越小則選中的概率越大
for v in range(len(fit)):
fit[v] = 1 / fit[v]
f = sum(fit)
# 計算概率
prob = []
for v in fit:
prob.append(v/f)
prob = np.abs(prob)
# 選擇優質個體
newp = []
n = len(prob)
# 這裏會重複選中優質個體
while len(newp) <= n:
for v in range(n):
if np.random.random() < prob[v]:
newp.append(pop[v])
# 選擇出的個體有 n+1 個
# 讓相鄰的個體交叉獲得新的族羣
# 新的族羣的規模爲 n
return newp[:n+1]
# 交叉
def cross(fitness, pop):
n = len(pop)
locate = int(len(pop[0])/2)
newp = []
for i in range(n-1):
newp1 = pop[i][:locate] + pop[i+1][locate:]
newp2 = pop[i+1][:locate] + pop[i][locate:]
if fitness(conv_2_10(newp1)) > fitness(conv_2_10(newp2)):
newp.append(newp2)
else:
newp.append(newp1)
return newp
# 變異
def mutate(pop, prob):
for i in range(len(pop)):
for j in range(len(pop[0])):
if np.random.random() < prob:
if pop[i][j] == 1:
pop[i][j] = 0
else:
pop[i][j] = 1
return pop
# 遺傳算法求函數極小值
def GA(fitness, n=1000, length=20, m=0.005, M=1000):
# fitness 表示帶求解函數
# n 表示族羣個體數
# length 表示基因長度
# m 表示變異概率
# M 表示遺傳迭代次數
# 初始化族羣
pop = np.random.rand(n, length)
pop = np.round(pop)
pop = np.int32(pop).tolist()
# 初始化自變量
x = []
for i in pop:
x.append(conv_2_10(i))
# 初始化適應度
y = []
for i in x:
y.append(fitness(i))
# 初始化最優解
pg = x[0]
# 主循環
for i in range(M):
# 選擇 & 交叉 & 變異
pop = selection(y, pop)
pop = cross(fitness, pop)
pop = mutate(pop, m)
# 更新自變量
x = []
for v in pop:
x.append(conv_2_10(v))
# 更新適應度
y = []
for v in x:
y.append(fitness(v))
# 更新最優解
for v in x:
if fitness(pg) > fitness(v):
pg = v
return pg, fitness(pg)
# 待求解函數
func = lambda x: x ** 2 - 4 * x + 9
# 求解結果
xm, fv = GA(func, n=20, length=5)
print(xm, fv)
# 2 5
優化算法(三)遺傳算法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.