遗传算法GA

遗传算法

下面是修改封装过后的正确代码

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import random as rd
import time
plt.rcParams['font.serif'] = 'Times New Roman'
plt.rcParams['font.size'] = 10.0
plt.rcParams['xaxis.labellocation'] =  'right'
plt.rcParams['yaxis.labellocation'] = 'top'
# print(plt.rcParams.keys())



def select(inti_pop,popsize,GENE_LEN,size,lb,ub,F):  # 选择
    fitness,X= Decode_fitness(inti_pop,popsize,GENE_LEN,size,lb,ub,F)
    ind = np.random.choice(a=np.arange(popsize), size=popsize, replace=True, p=fitness)
    return inti_pop[ind],X,fitness.max()

def Decode_fitness(inti_pop,popsize,GENE_LEN,size,lb,ub,F):  # 基因解码并计算适应度的值,返回适应度概率
    x = np.zeros((popsize, size))  # 记录每个基因产生的X
    for i in range(popsize):  # self.inti_pop【i】中的每一个种子基因,# 遍历每一个基因,然后计算基因对应的X值
        single = inti_pop[i].reshape(size, GENE_LEN)  # 将每一个基因拆分成指定的个数
        for j in range(size):  #
            bin_x = ''.join(single[j])  # 转换成二进制解码所需要的形式:01010100101的字符串
            x[i][j] = lb[j] + int(bin_x, 2) / (2 ** GENE_LEN - 1) * (ub[j] - lb[j])  # 解码为十进制
        values = F(x)  # 计算函数值,以便计算适应度概率值
        values[values < 0] = 1e-2
        fitness = values  # -values.min()+1e-1#防止适应度出现负值,导致无法计算适应度

    return fitness / fitness.sum(),x

def cross(inti_pop,popsize,GENE_LEN,size,cross_P):  # 交叉
    for _ in range(int(popsize)):  # 循环若干次
        ind = np.random.choice(range(popsize), 2)  # 随机选取两个父母的编号
        ind_fa, ind_mo = ind[0], ind[1]  # 挑选出父母的编号
        father = inti_pop[ind_fa]  # 父亲
        # mather = inti_pop[ind_mo]  # 母亲
        if rd.random() < cross_P:  # 按照概率执行交叉操作
            cross_point = rd.randint(0, GENE_LEN * size - 1)  # 随机选取交叉点
            inti_pop[ind_mo][:cross_point] = father[:cross_point]  # 一 fa:BA , mo:AB--->>BB
            # inti_pop[ind_fa][:cross_point] = father[:cross_point]  #    fa:ba ,mo:ab -->>aa
    return inti_pop

def mutation(inti_pop,size,GENE_LEN,mutation_P):  # 对每一个种子按照概率,执行变异操作
    NEW_INTI_POP = []
    for child in inti_pop:
        if rd.random() < mutation_P:  # 按概率执行变异操作
            ind = rd.randint(0, GENE_LEN * size - 1)  # 随机选取变异点    randint包含末位树 是个坑
            a = child[ind]  # 变异点原本数值
            child[ind] = str(int(a) ^ 1)  # 重新赋值   与或非运算
        NEW_INTI_POP.append(child)
    return np.array(NEW_INTI_POP)

def select_cross_mutation(inti_pop,popsize,GENE_LEN,size,lb,ub,cross_P,mutation_P):
    # 三个主要的函数先选择,再交叉,再变异!
    inti_pop, X,FITNESS_MAX = select(inti_pop,popsize,GENE_LEN,size,lb,ub,F)  # 选择
    inti_pop = cross(inti_pop,popsize,GENE_LEN,size,cross_P=cross_P)  # 交叉
    inti_pop = mutation(inti_pop,size,GENE_LEN,mutation_P=mutation_P)  # 变异
    return X,inti_pop,FITNESS_MAX #x,y主要用于画图,所以每循环一次就要return

def GETX(X,GENE_LEN,NV,lb,ub):#NV:Number of variables
    lb = np.array(lb);ub = np.array(ub)#convert to array
    geneX = X.reshape(NV,GENE_LEN)
    G_number = np.array(list(map(lambda x:int(''.join(x),2),geneX)))#Decoding the Numbers
    real_X = lb + G_number/np.power(2,GENE_LEN)*(ub-lb)
    return real_X

def windows(lb,ub):
    sns.set_style('darkgrid')
    plt.xlim(lb[0]-1,ub[0]+1)
    plt.ylim(lb[1]-1,ub[1]+1)
    plt.xlabel('First Dimension')
    plt.ylabel('Second Dimension')
    plt.pause(2)
    plt.show()

class GA():
    def __init__(self,OF,popsize,gene_length,Iteration,Length_of_X,lb,ub,timeout=10,cross_P=0.6,mutation_P=0.01,PF=0,):
        self.NAME = 'GA'
        self.PF = PF#Penalty function
        self.Func = OF #Object Function
        self.Iteration = Iteration #Iteration
        self.bestY = []#Record best valueY
        self.popsize = popsize#the size of population
        self.GENE_LEN = gene_length#length of gene
        self.Length_of_X = Length_of_X#amount of variences
        self.lb =lb ; self.ub=ub#constraints
        self.cross_P = cross_P;self.mutation_P = mutation_P
        self.timeout = timeout
    def run(self):#主程序
        Process_P = []#record the best value of every Iteration
        fig = plt.figure()
        plt.ion()  # 将画图模式改为交互模式,程序遇到plt.show不会暂停,而是继续执行
        windows(self.lb,self.ub)

        inti_pop = np.random.randint(0, 2, size=(self.popsize, self.GENE_LEN * self.Length_of_X)).astype('str') # Initialize
        best_y = -np.inf

        t1 = time.perf_counter()
        Process = 0
        # for Process in range(self.Iteration):
        while True:
            Process+=1
            X, inti_pop, FITNESS_MAX = \
                select_cross_mutation(
                inti_pop,#初始基因群
                self.popsize,
                self.GENE_LEN,#基因长度
                self.Length_of_X,#变量个数
                self.lb, self.ub,
                cross_P = self.cross_P,mutation_P = self.mutation_P
                )#return X Population and the MAX fitness  X是解码后的数据
            Z = self.Func(X)#Object value
            # Process_P.append(Z.max())
            Process_P.append(FITNESS_MAX.max())
            #dynamic widows to observe Function convergence
            x,y = X[:,0],X[:,1]
            if 'sca' in locals():
                sca.remove()
            sca = plt.scatter(x, y, marker='o',edgecolor='black',color='blue',alpha=0.3)
            plt.title(f'Cycle:{Process+1}/{self.Iteration}')
            plt.show()
            plt.pause(0.1)
            ####################################
            if Z.max() > best_y:
                best_y = Z.max()  # use for compare with Z.max
                self.bestY.append(best_y)#Record the optimal solution
                ind_best = Z.argmax()  # return index of best value
                GENE_BEST = inti_pop[ind_best]#Record best x
            bestX = GETX(GENE_BEST,self.GENE_LEN,self.Length_of_X,self.lb,self.ub)
            if np.all(FITNESS_MAX<1/self.popsize+1e-5):break#达到精度退出程序
            if time.perf_counter() - t1 > self.timeout:break#超时退出程序
        return bestX, self.bestY,Process_P

if __name__=="__main__":
    def F(X):  # 目标函数
        x = X[:,0]
        y = X[:,1]
        res = np.sin(x*y)*np.cos(x)*np.cos(y)
        return res.ravel()

    lb = [0,0]  # 约束下线
    ub = [10,10]  # 约束上限
    bestX,bestY,Process_P = GA(OF=F,popsize=500,gene_length=24,
                     Iteration=100,Length_of_X=2,lb=lb,ub=ub,
                     cross_P=0.6,mutation_P=.01).run()
    print(f'bestX:{bestX}\nbestY:{bestY[-1]}')

    plt.ioff()
    fig,ax = plt.subplots(1,2,)
    ax[1].plot(bestY,linestyle='-.')
    ax[0].plot(np.array(Process_P),linestyle='-.')
    plt.show()


正确代码

import numpy as np
import random as rd
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D



def F(x, y):  # 目标函数
    return 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)

fitF = F  # 目标函数
lb = [-3, -3]  # 约束下线
ub = [3, 3]  # 约束上限
# #算法的基本参数
size = 2  # 变量个数
GENE_LEN = 24  # 基因长度
popsize = 220  # 种群大小
mutation_P = 0.01  # 变异概率
cross_P = 0.6  # 交叉的概率

def select_cross_mutation(inti_pop):
    # 三个主要的函数先选择,再交叉,再变异!
    def select(inti_pop):#选择
            fitness,x1,x2 = Decode_fitness(inti_pop)
            ind = np.random.choice(a=np.arange(popsize), size=popsize, replace=True, p=fitness)
            return inti_pop[ind],x1,x2,fitness.max()
    def Decode_fitness(inti_pop):# 基因解码并计算适应度的值,返回适应度概率
            x = np.zeros((popsize, size))  # 记录每个基因产生的X
            # 遍历每一个基因,然后计算基因对应的X值
            for i in range(popsize):  # self.inti_pop【i】中的每一个种子基因
                single = inti_pop[i].reshape(size, GENE_LEN)  # 将每一个基因拆分成指定的个数
                for j in range(size):  #
                    bin_x = ''.join(single[j])  # 转换成二进制解码所需要的形式:01010100101的字符串
                    x[i][j] = lb[j] + int(bin_x, 2) / (2 ** GENE_LEN - 1) * (ub[j] - lb[j])  # 解码为十进制
                # 下面这两部可以重新定义self.fitF函数,进而修改目标函数和简化代码
                # -------------------------------------------------------#
                x1 = x[:, 0]
                y1 = x[:, 1]  # 因为有两个参数:x1,x2
                values = fitF(x1, y1)  # 计算函数值,以便计算适应度概率值
                # -------------------------------------------------------#
                values[values < 0] = 1e-2
                fitness = values#-values.min()+1e-1#防止适应度出现负值,导致无法计算适应度
            return fitness / fitness.sum(),x1,y1
    def cross(inti_pop):  # 交叉
            for _ in range(int(popsize)):  # 循环若干次
                ind = np.random.choice(range(popsize), 2)  # 随机选取两个父母的编号
                ind_fa, ind_mo = ind[0], ind[1]  # 挑选出父母的编号
                father = inti_pop[ind_fa]  # 父亲
                # mather = inti_pop[ind_mo]  # 母亲
                if rd.random() < cross_P:  # 按照概率执行交叉操作
                    cross_point = rd.randint(0, GENE_LEN * size - 1)  # 随机选取交叉点
                    inti_pop[ind_mo][:cross_point] = father[:cross_point]  # 一 fa:BA , mo:AB--->>BB
                    # inti_pop[ind_fa][:cross_point] = father[:cross_point]  #    fa:ba ,mo:ab -->>aa
            return inti_pop
    def mutation(inti_pop):  # 对每一个种子按照概率,执行变异操作
            NEW_INTI_POP = []
            for child in inti_pop:
                if rd.random() < mutation_P:  # 按概率执行变异操作
                    ind = rd.randint(0, GENE_LEN * size - 1)  # 随机选取变异点    randint包含末位树 是个坑
                    a = child[ind]  # 变异点原本数值
                    child[ind] = str(int(a) ^ 1)  # 重新赋值   与或非运算
                NEW_INTI_POP.append(child)
            return np.array(NEW_INTI_POP)
        #主程序
    inti_pop, x, y,FITNESS_MAX = select(inti_pop)  # 选择
    inti_pop = cross(inti_pop)  # 交叉
    inti_pop = mutation(inti_pop)  # 变异
    return x,y,inti_pop,FITNESS_MAX #x,y主要用于画图,所以每循环一次就要return


def plot_3d(ax):
    X = np.linspace(-3, 3)
    Y = np.linspace(-3, 3)
    X, Y = np.meshgrid(X, Y)
    Z = fitF(X, Y)
    ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    plt.pause(2)
    plt.show()


def run(iteration):  # 循环迭代
    # fig = plt.figure()
    # ax = Axes3D(fig)
    # plt.ion()  # 将画图模式改为交互模式,程序遇到plt.show不会暂停,而是继续执行
    # plot_3d(ax)
    inti_pop = np.random.randint(0, 2, size=(popsize, GENE_LEN * size)).astype('str') # 初始化

    for _ in range(iteration):
        x,y,inti_pop,FITNESS_MAX = select_cross_mutation(inti_pop)
        # if 'sca' in locals():
        #     sca.remove()
        Z = F(x,y)
        # sca = ax.scatter(x, y, Z, c='black', marker='o')
        # plt.show()
        plt.pause(0.1)
        FIT_Y.append(Z.ravel().max())
        # FIT_Y.append(np.array(FITNESS_MAX))


    return FIT_Y


if __name__ == "__main__":
    fit = run(500)
    sns.lineplot(data=np.array(fit))
    plt.show()

  • [2 ] 第二个代码
import numpy as np
import random as rd
import matplotlib.pyplot as plt
from matplotlib import cm


def F(x, y):  # 目标函数
    return 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)
fitF = F  # 目标函数
lb = [-3,-3]  # 约束下线
ub = [ 3, 3]  # 约束上限
# #算法的基本参数
size = 2  # 变量个数
GENE_LEN = 25  # 基因长度
popsize = 220  # 种群大小
mutation_P = 0.01  # 变异概率
cross_P = 0.6  # 交叉的概率

def select(inti_pop):  # 选择
    fitness, x1, x2 = Decode_fitness(inti_pop)
    ind = np.random.choice(a=np.arange(popsize), size=popsize, replace=True, p=fitness)
    return inti_pop[ind], x1, x2, fitness.max()

def Decode_fitness(inti_pop):  # 基因解码并计算适应度的值,返回适应度概率
    x = np.zeros((popsize, size))  # 记录每个基因产生的X
    # 遍历每一个基因,然后计算基因对应的X值
    for i in range(popsize):  # self.inti_pop【i】中的每一个种子基因
        single = inti_pop[i].reshape(size, GENE_LEN)  # 将每一个基因拆分成指定的个数
        for j in range(size):  #
            bin_x = ''.join(single[j])  # 转换成二进制解码所需要的形式:01010100101的字符串
            x[i][j] = lb[j] + int(bin_x, 2) / (2 ** GENE_LEN - 1) * (ub[j] - lb[j])  # 解码为十进制
        # 下面这两部可以重新定义self.fitF函数,进而修改目标函数和简化代码
        # -------------------------------------------------------#
        x1 = x[:, 0]
        y1 = x[:, 1]  # 因为有两个参数:x1,x2
        values = fitF(x1, y1)  # 计算函数值,以便计算适应度概率值
        # -------------------------------------------------------#
        values[values < 0] = 1e-2
        fitness = values  # -values.min()+1e-1#防止适应度出现负值,导致无法计算适应度
    return fitness / fitness.sum(), x1, y1

def cross(inti_pop):  # 交叉
    for _ in range(int(popsize)):  # 循环若干次
        ind = np.random.choice(range(popsize), 2)  # 随机选取两个父母的编号
        ind_fa, ind_mo = ind[0], ind[1]  # 挑选出父母的编号
        father = inti_pop[ind_fa]  # 父亲
        # mather = inti_pop[ind_mo]  # 母亲
        if rd.random() < cross_P:  # 按照概率执行交叉操作
            cross_point = rd.randint(0, GENE_LEN * size - 1)  # 随机选取交叉点
            inti_pop[ind_mo][:cross_point] = father[:cross_point]  # 一 fa:BA , mo:AB--->>BB
            # inti_pop[ind_fa][:cross_point] = father[:cross_point]  #    fa:ba ,mo:ab -->>aa
    return inti_pop

def mutation(inti_pop):  # 对每一个种子按照概率,执行变异操作
    NEW_INTI_POP = []
    for child in inti_pop:
        if rd.random() < mutation_P:  # 按概率执行变异操作
            ind = rd.randint(0, GENE_LEN * size - 1)  # 随机选取变异点    randint包含末位树 是个坑
            a = child[ind]  # 变异点原本数值
            child[ind] = str(int(a) ^ 1)  # 重新赋值   与或非运算
        NEW_INTI_POP.append(child)
    return np.array(NEW_INTI_POP)

def select_cross_mutation(inti_pop):
    # 三个主要的函数先选择,再交叉,再变异!
    #主程序
    inti_pop, x, y,FITNESS_MAX = select(inti_pop)  # 选择
    inti_pop = cross(inti_pop)  # 交叉
    inti_pop = mutation(inti_pop)  # 变异
    return x,y,inti_pop,FITNESS_MAX #x,y主要用于画图,所以每循环一次就要return

def plot_3d(ax):
    X = np.linspace(-3, 3)
    Y = np.linspace(-3, 3)
    X, Y = np.meshgrid(X, Y)
    Z = fitF(X, Y)
    ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    plt.pause(2)
    plt.show()

def run(iteration):  # 循环迭代
    inti_pop = np.random.randint(0, 2, size=(popsize, GENE_LEN * size)).astype('str') # 初始化
    best_y=-np.inf
    for _ in range(iteration):
        x,y,inti_pop,FITNESS_MAX = select_cross_mutation(inti_pop)
        Z = F(x,y)
        #保存最优值和最优解
        if Z.max()>best_y:
            ind_best = Z.argmax()
            best_y = Z[ind_best] #
            GENE_BEST = inti_pop[ind_best]
    return best_y,GENE_BEST

def answer(best_y,GENE_BEST):
    def GENE_DECODE(GENE_BEST):
        values = []
        genes = GENE_BEST.reshape(size, GENE_LEN)
        erjinzhishu = np.array(list(map(lambda gene_ :int(''.join(gene_),2),genes)))
        for j in range(size):
            values.append(lb[j] + erjinzhishu[j]/ (2 ** GENE_LEN - 1) * (ub[j] - lb[j]) ) # 解码为十进制
        return values
    print(f'BEST_Y:{best_y}')
    print(f'BEST_X:{GENE_DECODE(GENE_BEST)}')

if __name__ == "__main__":
    best_y,best_x = run(500)
    answer(best_y, best_x)





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值