優化算法(三)遺傳算法

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章