Python遗传算法求解函数极值

注:由于编码选择二进制编码,所以只能在整数范围进行搜索,也就是说求解到的最优解一定是最优的整数解,如果选择一些映射方法可以将离散问题连续化,但这样就和进化算法本身无关了,所以本文只写了基本的遗传算法

超参设置

  • 染色体长度:10
  • 种群:20
  • 进化次数:50代
  • 变异靶点:3
  • 变异方式:插入,交换,局部逆序
  • 变异概率:0.1
  • 交叉方式:PMX修订两点交叉
import matplotlib.pyplot as plt
from math import *
import numpy as np
import random
import copy

# random.seed(0)

minNum = 10  # 区间最小值
maxNum = 101  # 区间最大值
long = 10  # 染色体编码长度
population = 20  # 初始种群数量
target_points = [1, 2, 3]  # 变异靶点
gens = 50  # 进化代数
genRate = 0.1  # 变异概率


# 转化为10进制
def parseInt(bit):
    if isinstance(bit, str):
        n = '0b' + bit
        return int(eval(n))
    else:
        # print(type(bit))
        return int(eval('0b' + ''.join(bit)))


# 转化为2进制
def parseBin(i, t=str):
    if t == str:
        return str(bin(i)[2:])
    else:
        return bin(i)[2:]


#  适应度
def fitness(x):
    if type(x) != int:
        x = parseInt(x)
    # return x + 10 * sin(5 * x) + 7 * cos(4 * x)
    return x ** 3


# 传递进来一个i,修订长度到10
def translong(i):
    length = len(i)
    n = long - length
    if n != 0:
        for h in range(n):
            i = '0' + i
    return i


def initPop(num):
    population = []
    xset = [random.randrange(minNum,maxNum) for i in range(num)]
    for j in xset:
        i = str(bin(j)[2:])
        length = len(i)
        n = long - length
        if n != 0:
            for h in range(n):
                i = '0' + i
        population.append(i)
    return population


# 判断是否需要修订
def overSection(bit):
    n = parseInt(bit)
    if minNum < n < maxNum:
        return False
    else:
        return True
    # if n > maxNum:
    #     return 'big'
    # if n < minNum:
    #     return 'small'
    # else:
    #     return False


#  两点交叉
def twoPontsCross(p1, p2):
    # 不改变原始数据进行操作
    p1_ = list(copy.deepcopy(p1))
    p2_ = list(copy.deepcopy(p2))
    # 交叉位置,point1<point2
    point1 = random.randint(0, len(p1_))
    point2 = random.randint(0., len(p1))
    while point1 > point2 or point1 == point2:
        point1 = random.randint(0, len(p1))
        point2 = random.randint(0., len(p1))
    p1_[point1:point2], p2_[point1:point2] = p2_[point1:point2], p1_[point1:point2]
    p1_ = ''.join(p1_)
    p2_ = ''.join(p2_)
    return str(p1_), str(p2_)


# 交换变异
def gene_exchange(n):
    n = list(n)
    point1 = random.randint(0, len(n) - 1)
    point2 = random.randint(0, len(n) - 1)
    while point1 == point2 or point1 > point2:
        point1 = random.randint(0, len(n) - 1)
        point2 = random.randint(0, len(n) - 1)
    n[point1], n[point2] = n[point2], n[point1]
    n = ''.join(n)
    return n


# 插入变异
def gene_insertion(n):
    n = list(n)
    point1 = random.randint(0, len(n) - 1)
    point2 = random.randint(0, len(n) - 1)
    while point1 == point2:
        point1 = random.randint(0, len(n) - 1)
        point2 = random.randint(0, len(n) - 1)
    x = n.pop(point1)
    n.insert(point2, x)
    n = ''.join(n)
    return n


# 局部逆序变异
def gene_reverse(n):
    n = list(n)
    point1 = random.randint(0, len(n) - 1)
    point2 = random.randint(0, len(n) - 1)
    while point1 == point2 or point1 > point2:
        point1 = random.randint(0, len(n) - 1)
        point2 = random.randint(0, len(n) - 1)
    ls_res = n[point1:point2]
    ls_res.reverse()
    l1 = n[:point1]
    l2 = n[point2:]
    n_res_end = l1 + ls_res + l2
    n = ''.join(n)
    return n_res_end


# 节点类
class node:
    def __init__(self, bit):
        self.bit = bit
        self.fitness = fitness(bit)


def main():
    best = []
    pops = initPop(population)
    popsfit = [node(i) for i in pops]
    popsfit.sort(key=lambda x: x.fitness)
    popsfit.reverse()
    print(parseInt(popsfit[0].bit))
    print('--' * 20)
    # print(f'pop:{pops}')
    for gen in range(gens):
        children = []
        pop_children1 = pops[1::2]  # 偶数解
        pop_children2 = pops[::2]  # 奇数解
        # 交叉
        for r in range(len(pop_children1)):
            child1, child2 = twoPontsCross(pop_children1[r], pop_children2[r])
            if overSection(child1):
                child1 = initPop(1)[0]
            if overSection(child2):
                child2 = initPop(1)[0]
            children.append(translong(child1))
            children.append(translong(child2))
        # print(f'children:{children}')
        #  变异
        for i in children:
            rate = random.random()
            if rate < genRate:
                target = random.choice(target_points)
                if target == 1:
                    c_exchange = gene_exchange(i)
                    if overSection(c_exchange):
                        children[children.index(i)] = initPop(1)[0]
                    else:
                        children[children.index(i)] = c_exchange
                elif target == 2:
                    c_insert = gene_insertion(i)
                    if overSection(c_insert):
                        children[children.index(i)] = initPop(1)[0]
                    else:
                        children[children.index(i)] = c_insert
                else:
                    c_reverse = gene_reverse(i)
                    if overSection(c_reverse):
                        children[children.index(i)] = initPop(1)[0]
                    else:
                        children[children.index(i)] = c_reverse
        childrenFitness = [node(i) for i in children]
        initpopulationFitness = [node(i) for i in pops]
        initpopulationFitness += childrenFitness
        initpopulationFitness.sort(key=lambda x: x.fitness)
        initpopulationFitness.reverse()
        del initpopulationFitness[10:]
        pops = [i.bit for i in initpopulationFitness]
        best.append(parseInt(pops[0]))
        if gen % 10 == 0:
            print(f'第{gen}代,当前最优解{parseInt(pops[0])}')
    print(f'全局最优为:{parseInt(pops[0])}')
    return parseInt(pops[0]), fitness(pops[0])


if __name__ == '__main__':
    a, b = main()
    x = np.linspace(10, 100, 1000)
    # y = [i + 10 * sin(5 * i) + 7 * cos(4 * i) for i in x]
    y = [i ** 3 for i in x]
    plt.plot(x, y)
    plt.plot(a, b, '.r')
    plt.show()

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值