GA求解Benchmark函数


前言

本文用来记录GA求解Benchmark代码思路。


一、问题介绍

求解Benchmark用例为:
F ( x ) = ∑ 1 n x i 2   F(x)=\sum_{1}^{n}x_{i}^{2}\space F(x)=1nxi2 
x ∈ [ − 100 , 100 ] x\in[-100,100] x[100,100]
图形可视化为如下,容易看出最优点为(0,0,0,0,…),最优值为0。
为了可视化方便,仅计算二维情况。
在这里插入图片描述

二、Python实现GA求解

2.1 定义求解函数

def func1(x1,x2):
    return x1**2+x2**2

2.2 GA类初始化部分

    def __init__(self, pop_size, epoch, cross_prob, mutate_prob,func,print_batch=10):
        self.pop_size = pop_size # 种群数量
        self.epoch = epoch # 迭代次数
        self.cross_prob = cross_prob # 交叉概率
        self.mutate_prob = mutate_prob # 变异概率
        self.width = 48 # 一个基因的长度,长度越长精度越高
        self.best = None # 索存最优结果
        self.genes = np.array(
            ["".join([random.choice(['0', '1']) for _ in range(self.width)]) for _ in range(self.pop_size)]
        ) # 随机生成初始种群

2.3 交叉操作

    def inter_cross(self):
        # 交叉操作
        ready_index = list(range(self.pop_size)) # ready_index索存所有基因的索引号,挑选任意两个进行交叉操作。
        while len(ready_index) >= 2: # 必须有2个以上的基因存在才可以交叉。
            d1 = random.choice(ready_index)  # 从0-100挑一个父基因
            ready_index.remove(d1) # 挑选以后移除列表
            d2 = random.choice(ready_index)  # 从0-100挑一个父基因
            ready_index.remove(d2) # 挑选以后移除列表

            if np.random.uniform(0, 1) <= self.cross_prob: # 随机数判断是否需要交叉
                loc = random.choice(range(1, self.width - 1)) # 随机挑选交叉的位置
                d1_a, d1_b = self.genes[d1][0:loc], self.genes[d1][loc:] # 将d1基因分为2份
                d2_a, d2_b = self.genes[d2][0:loc], self.genes[d2][loc:] # 将d2基因分为2份
                self.genes[d1] = d1_a + d2_b # 进行交叉操作
                self.genes[d2] = d2_a + d1_b # 进行交叉操作

2.4 变异操作

    def mutate(self):
        # 变异操作
        ready_index = list(range(self.pop_size)) # ready_index索存所有基因的索引号,挑选任意两个进行变异操作。
        for i in ready_index:
            if np.random.uniform(0, 1) <= self.mutate_prob: # 随机数判断是否需要变异
                loc = random.choice(range(0, self.width)) # 随机挑选需要变异的位置
                t0 = list(self.genes[i]) # t0为列表,存储第i个基因的字符串
                t0[loc] = str(1 - int(self.genes[i][loc])) # 取反操作  1-0=1,1-1=0
                self.genes[i] = "".join(t0) 

2.5 适应度计算

    def get_adjust(self):
        # 计算适应度
        x1,x2 = self.get_decode()  # 首先解码,之后返回对应值。
        return func1(x1,x2)

    def get_decode(self):
    	# x1,x2分别对应列表中各24位,通过对其进行二进制转十进制操作后除以(2**24-1)*200,得到对应[0,200]的数,在加上-100后,变为[-100,100].
        x1 = (-100) + np.array([int(x[:24], 2) * 200 / (2 ** 24 - 1) for x in self.genes]) 
        x2 = (-100) + np.array([int(x[24:], 2) * 200 / (2 ** 24 - 1) for x in self.genes])
        return x1,x2

2.6 轮盘赌

由于轮盘赌的原理是概率越大越容易被选中,但是问题是求MIN问题,所以选择使用倒数的方法。

    def cycle_select(self):
        # 轮盘赌
        adjusts = 1/self.get_adjust() # 得到每个基因的适应度值.
        if self.best is None or 1/np.max(adjusts) < self.best[1]: # 筛选最优的基因并存到best中.
            self.best = self.genes[np.argmax(adjusts)], 1/np.max(adjusts)
        p = adjusts / np.sum(adjusts)  # 计算所有基因的概率
        cu_p = []  # 计算累计分布概率

        for i in range(self.pop_size):
            cu_p.append(np.sum(p[0:i]))
        cu_p = np.array(cu_p) # 变为np.array对象
        r0 = np.random.uniform(0, 1, self.pop_size) # 随机生成0-1的均匀分布与种群的累计分布概率比较
        sel = [max(list(np.where(r > cu_p)[0]) + [0]) for r in r0] 

        # 确保最优个体的存活.
        if 1/np.max(adjusts[sel]) < self.best[1]:
            self.genes[sel[np.argmax(adjusts[sel])]] = self.best[0]
        self.genes = self. Genes[sel]

2.7 主函数

    def evolve(self):
        # 主程序.
        for i in range(self.epoch):
            self.cycle_select() # 进行轮盘赌.
            self.inter_cross() # 交叉操作.
            self.mutate() # 变异操作.

三、代码整体

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :最优化方法 
@File    :GA-1.py
@IDE     :PyCharm 
@Author  :Pan  YX
@Date    :2023/4/29 15:24 
@Descib  :
'''
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import re
import math
import random

def func1(x1,x2):
    return x1**2+x2**2

def show(x_s,x_e,func,end1=None,end2=None):
    fig = plt.figure(figsize=(10, 7))
    ax = Axes3D(fig, auto_add_to_figure=False)
    fig.add_axes(ax)
    ax.set_xlabel('$x1$', fontsize=16)
    ax.set_ylabel('$x2$', fontsize=16)
    ax.set_zlabel('$f(x)$', fontsize=16)
    x1 = np.linspace(x_s, x_e, 100)
    x2 = np.linspace(x_s, x_e, 100)
    # x-y 平面的网格
    x1, x2 = np.meshgrid(x1, x2)
    z = func(x1,x2)
    ax.plot_surface(x1, x2, z, rstride=1, cstride=1, cmap=plt.get_cmap('cool'))
    if end1 != None and end2 != None:
        ax.scatter(end1,end2,func(end1,end2),s=500,c='r',marker='.')
    plt.show()

class GeneSolve:
    def __init__(self, pop_size, epoch, cross_prob, mutate_prob,func,print_batch=10):
        self.pop_size = pop_size # 种群数量
        self.epoch = epoch # 迭代次数
        self.cross_prob = cross_prob # 交叉概率
        self.mutate_prob = mutate_prob # 变异概率
        self.width = 48 # 一个基因的长度,长度越长精度越高
        self.best = None # 索存最优结果
        self.genes = np.array(
            ["".join([random.choice(['0', '1']) for _ in range(self.width)]) for _ in range(self.pop_size)]
        ) # 随机生成初始种群

    def inter_cross(self):
        # 交叉操作
        ready_index = list(range(self.pop_size)) # ready_index索存所有基因的索引号,挑选任意两个进行交叉操作。
        while len(ready_index) >= 2: # 必须有2个以上的基因存在才可以交叉。
            d1 = random.choice(ready_index)  # 从0-100挑一个父基因
            ready_index.remove(d1) # 挑选以后移除列表
            d2 = random.choice(ready_index)  # 从0-100挑一个父基因
            ready_index.remove(d2) # 挑选以后移除列表

            if np.random.uniform(0, 1) <= self.cross_prob: # 随机数判断是否需要交叉
                loc = random.choice(range(1, self.width - 1)) # 随机挑选交叉的位置
                d1_a, d1_b = self.genes[d1][0:loc], self.genes[d1][loc:] # 将d1基因分为2份
                d2_a, d2_b = self.genes[d2][0:loc], self.genes[d2][loc:] # 将d2基因分为2份
                self.genes[d1] = d1_a + d2_b # 进行交叉操作
                self.genes[d2] = d2_a + d1_b # 进行交叉操作

    def mutate(self):
        # 变异操作
        ready_index = list(range(self.pop_size))
        for i in ready_index:
            if np.random.uniform(0, 1) <= self.mutate_prob:
                loc = random.choice(range(0, self.width))
                t0 = list(self.genes[i])
                t0[loc] = str(1 - int(self.genes[i][loc]))
                self.genes[i] = "".join(t0)

    def get_adjust(self):
        # 计算适应度
        x1,x2 = self.get_decode()  # 首先解码,之后返回对应值。
        return func1(x1,x2)

    def get_decode(self):
    	# x1,x2分别对应列表中各24位,通过对其进行二进制转十进制操作后除以(2**24-1)*200,得到对应[0,200]的数,在加上-100后,变为[-100,100].
        x1 = (-100) + np.array([int(x[:24], 2) * 200 / (2 ** 24 - 1) for x in self.genes])
        x2 = (-100) + np.array([int(x[24:], 2) * 200 / (2 ** 24 - 1) for x in self.genes])
        return x1,x2

    def cycle_select(self):
        # 轮盘赌
        adjusts = 1/self.get_adjust() # 得到每个基因的适应度值.
        if self.best is None or 1/np.max(adjusts) < self.best[1]: # 筛选最优的基因并存到best中.
            self.best = self.genes[np.argmax(adjusts)], 1/np.max(adjusts)
        p = adjusts / np.sum(adjusts)  # 计算所有基因的概率
        cu_p = []  # 计算累计分布概率

        for i in range(self.pop_size):
            cu_p.append(np.sum(p[0:i]))
        cu_p = np.array(cu_p) # 变为np.array对象
        r0 = np.random.uniform(0, 1, self.pop_size) # 随机生成0-1的均匀分布与种群的累计分布概率比较
        sel = [max(list(np.where(r > cu_p)[0]) + [0]) for r in r0]

        # 确保最优个体的存活.
        if 1/np.max(adjusts[sel]) < self.best[1]:
            self.genes[sel[np.argmax(adjusts[sel])]] = self.best[0]
        self.genes = self.genes[sel]

    def evolve(self):
        # 主程序.
        for i in range(self.epoch):
            self.cycle_select() # 进行轮盘赌.
            self.inter_cross() # 交叉操作.
            self.mutate() # 变异操作.
# 求解Benchmark1 -GA
show(-100,100,func=func1)

gs = GeneSolve(100,500,0.85,0.1,func=func1)
gs.evolve()

x1 = -100+ int(gs.best[0][:24], 2) * 200 / (2 ** 24 - 1)
x2 = -100+ int(gs.best[0][24:], 2) * 200 / (2 ** 24 - 1)
print(gs.best[0])
print('x1={},x2={},最优值为{}.'.format(x1,x2,gs.best[1]))
# show(-100,100,func=func1,end1=x1,end2=x2)
# 输出结果:
#011111111111111111111111100000000000000000000000
#x1=-5.96046483281043e-06,x2=5.96046483281043e-06,最优值为7.105428204633975e-11.


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值