Python 实现遗传算法求解函数最优值

290 阅读2分钟
"""
染色体种群

变量:
种群大小
染色体位数
种群的染色体集合
该种群当前的最优值(同时记录下该最优值对应的染色体)
交配概率
变异概率

主要方法:
初始化
选择染色体复制(轮盘赌,需要计算适应度)
交配(交配采用i与i+1进行交配的办法)
变异(随机选择一位进行反转)

辅助方法:
适应度函数,用于轮盘赌的时候生成概率
编码和解码的函数


假设计算y = 2/(x1*x1+x2*x2+100),
注意计算其他函数的时候加个偏移量保证函数值不会出现负数,目的是方便轮盘赌计算适应度不会出现负值
x1 取值范围[0,127],x2取值范围[0,16383],方便起见均为整数
编码中x1占染色体7位,x2占染色体后13位
因为范围太大结果要迭代很多次。。。。建议x1x2开小点
"""

import random

class Population:
    def __init__(self):
        self.size = 1 # 种群大小
        self.cn_length = 20 #染色体长度
        self.cns = [] # 染色体集合
        self.pc = 0.6  # 交配概率
        self.pm = 0.01  # 变异概率
        self.ans = [0,""] #目前的最优解及对应的染色体

    def coding(self,x1,x2):  #数字编码后的二进制字符串
        return format(bin(x1)[2:], '0>7')+format(bin(x2)[2:], '0>13')

    def decoding(self,s): #染色体解码后的十进制数字
        return [int(s[:7],2),int(s[7:],2)]

    def function(self,x1,x2): #适应度函数
        return 2/(x1*x1+x2*x2 + 100)

    def  initialization(self): #初始化一个种群
        for i in range(self.size):
            x1 = random.randint(0,127)
            x2  =random.randint(0,16383)
            self.cns.append(self.coding(x1,x2))

    def choose(self): # 选择复制,使用轮盘赌算法
        # 计算概率
        p = [0.0]*self.size
        for i in range(self.size):
            x = self.decoding(self.cns[i])
            p[i] = self.function(x[0],x[1])
        tmp = sum(p)
        for i in range(self.size):
            p[i] = p[i]/tmp
            p[i] = p[i]+p[i-1] if i>0 else p[i]
        # 选择复制
        new_cns = []
        for i in range(self.size):
            rand = random.random() #生成[0.1)之间的随机数
            for j in range(self.size):
                if p[j] >= rand:
                    new_cns.append(self.cns[j])
                    break
        self.cns = new_cns
        # print(f'选择复制后的种群{self.cns}')

    def crossover(self): # 交配,策略为pc概率下i与self.size-1-i交换随机一位之后全部段
        for i in range(self.size>>1):
            if random.random() < self.pc:
                continue
            j = self.size-1-i
            a,b = self.cns[i],self.cns[j]
            pos = random.randint(0,self.cn_length-1)
            self.cns[i] = a[:pos] + b[pos:]
            self.cns[j] = b[:pos] + a[pos:]
        # print(f'交换后的种群{self.cns}')

    def mutation(self): # 变异,策略为对每个染色体在self.pm概率下随机翻转一位
        for i in range(self.size):
            if random.random() < self.pm:
                continue
            pos = random.randint(0,self.cn_length-1)
            bit = "0" if self.cns[i][pos] == "1" else "0"
            self.cns[i] = self.cns[i][:pos] + bit + self.cns[i][pos+1:]
        # print(f'变异后的种群{self.cns}')

    def get_ans(self): # 计算当前种群最优解
        for cn in self.cns:
            x = self.decoding(cn)
            now = self.function(x[0],x[1])
            if now > self.ans[0]:
                self.ans = [now,cn]
        print(self.ans)

    def solving(self,size,n): # 总的计算过程
        """
        :param size: 种群大小
        :param n: 迭代次数
        :return: [最优解,x1,x2]
        """
        self.size = size
        self.initialization()

        for i in range(n):
            self.choose()
            self.crossover()
            self.mutation()
            self.get_ans()
        x = self.decoding(self.ans[1])
        return [self.ans[0],x[0],x[1]]

test = Population()
print(test.solving(10,100))