遗传算法实现寻找函数最值

遗传算法的原理参考维基百科:https://zh.wikipedia.org/wiki/%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95

遗传算法流程图:

遗传算法的思想和流程都是很简单的,但是运用在具体应用时却会常常无从下手。如何编码解码,如何进行交叉是两个难点。

遗传算法的最简单例子——寻找函数f(x)=x+5sin(5x)+2cos(4x)在区间[0,10]上的函数最值。

函数图像:

种群规模count=20,染色体长度length=18,进化次数itter_time=10

编码策略是:染色体长度length=18,有2^18个不同组合。那么如何将2^18个不同组合对应到区间[0,10]上呢?

此时对应的解码策略是:V=start+x*(end-start)/(2^length-1),这里start表示区间下限,在此例中即为0;end表示区间上限,在此例中即为10;x为2进制编码的数值;V为解码值,即染色体的真实值;length为染色体长度。

对应代码:

#解码
def decode(x):
    y=start+x*(end-start) / (2**length-1)
    return y

交叉策略:采用最简单的点交叉策略。

对于两个不同的染色体Xu和Xv,随机得到一个点交叉位置序号mask,mask为(0,length)上的随机整数。

两条染色体进行交叉:

Xu=Xu[0至mask]片段上的基因+Xv[mask至length]片段上的基因

Xv=Xv[0至mask]片段上的基因+Xu[mask至length]片段上的基因

对应代码:

#交叉繁殖
def crossover(parents):
    #生成子代的个数,以此保证种群稳定
    target_count=count-len(parents)
    #孩子列表
    children=[]
    while len(children)<target_count:
        male_index = random.randint(0, len(parents) - 1)
        female_index = random.randint(0, len(parents) - 1)
        if male_index!=female_index:
            male=parents[male_index]
            female=parents[female_index]
            cross_pos = random.randint(0, length)
            mask = 0
            for i in range(cross_pos):
                mask |= (1 << i)
            # 孩子将获得父亲在交叉点前的基因和母亲在交叉点后(包括交叉点)的基因
            child = ((male & mask) | (female & ~mask)) & ((1 << length) - 1)
            children.append(child)
    return children

全部代码:

import numpy as np
import matplotlib.pyplot as plt
import math
import random
# x=np.linspace(-10,10,100)
#
# y=x + 10*np.sin(5*x) + 7*np.cos(4*x)

#GA参数
#查找范围
start=0
end=10

#染色体长度
length=18

#种群数
count=20

#进化次数
itter_time=10

#设置强者的定义概率,即种群前30%为强者
retain_rate=0.3

#设置弱者的存活概率
random_select_rate=0.5

#变异率
mutation_rate=0.2


#目标函数
def aimFunction(x):
    y=x+5*math.sin(5*x)+2*math.cos(4*x)
    return y

#解码
def decode(x):
    y=start+x*(end-start) / (2**length-1)
    return y

#获取随机个体,用于生成种群
def gen_chromosome():
    """
    随机生成长度为length的染色体,每个基因的取值是0或1
    这里用一个bit表示一个基因
    """
    chromosome = 0
    for i in range(length):
        chromosome |= (1 << i) * random.randint(0, 1)
    return chromosome

#自然选择
def selection(population):
    """
    选择
    先对适应度从大到小排序,选出存活的染色体
    再进行随机选择,选出适应度虽然小,但是幸存下来的个体
    """
    # 对适应度从大到小进行排序
    graded = [(aimFunction(decode(chromosome)), chromosome) for chromosome in population]
    graded = [x[1] for x in sorted(graded, reverse=True)]
    # 选出适应性强的染色体
    retain_length = int(len(graded) * retain_rate)
    parents = graded[:retain_length]
    # 选出适应性不强,但是幸存的染色体
    for chromosome in graded[retain_length:]:
        if random.random() < random_select_rate:
            parents.append(chromosome)
    return parents

#交叉繁殖
def crossover(parents):
    #生成子代的个数,以此保证种群稳定
    target_count=count-len(parents)
    #孩子列表
    children=[]
    while len(children)<target_count:
        male_index = random.randint(0, len(parents) - 1)
        female_index = random.randint(0, len(parents) - 1)
        if male_index!=female_index:
            male=parents[male_index]
            female=parents[female_index]
            cross_pos = random.randint(0, length)
            mask = 0
            for i in range(cross_pos):
                mask |= (1 << i)
            # 孩子将获得父亲在交叉点前的基因和母亲在交叉点后(包括交叉点)的基因
            child = ((male & mask) | (female & ~mask)) & ((1 << length) - 1)
            children.append(child)
    return children

#变异
def mutation(children):
    for i in range(len(children)):
        if random.random() < mutation_rate:
            j = random.randint(0, length-1)
            population[i] ^= 1 << j

#得到最佳纯输出结果
def get_result(population):
    graded = [(aimFunction(decode(chromosome)), decode(chromosome)) for chromosome in population]
    graded = [x for x in sorted(graded, reverse=True)]
    print(graded[0][0],graded[0][1])

#开始遗传算法
#初始化种群,随机性得到种群
population=[gen_chromosome() for i in range(count)]
i=0
while i<itter_time:
    #选择繁殖个体群
    parents=selection(population)
    #交叉繁殖
    children=crossover(parents)
    #变异操作
    mutation(children)
    #更新种群
    population=parents+children
    get_result(population)
    i=i+1

猜你喜欢

转载自blog.csdn.net/springtostring/article/details/82221318
今日推荐