遗传算法工厂模式封装:二进制编码和实数编码

本文展示了如何使用工厂模式封装两种不同遗传算法:二进制基因编码和实数编码。代码示例包括工厂类、个体类、种群类以及相关函数,方便用户根据需要选择不同的编码方式进行遗传算法优化。

代码示例

# 封装工厂类
import math
import random
import time
import copy


class GAFactory:
    def __init__(self, problem_type):
        self.problem_type = problem_type
        self.pop = GAFactory.popu()

    class indivi:
        def __init__(self):
            if self.problem_type == 'binary':
                self.gene = ['0'] * (LENIND + 1)
            elif self.problem_type == 'real':
                self.geneX1 = 0.0
                self.geneX2 = 0.0
            self.fitness = 0.0

    class popu:
        def __init__(self):
            self.indv = [GAFactory.indivi() for n in range(NUMIND)]
            self.bestInd = GAFactory.indivi()
            self.generan = 0

    def fit(self, x, y, i):
        if i == 1:
            return self.problem_type == 'binary', x * math.sin(10 * PI * x) + 2.0 if self.problem_type == 'binary' else 3 * (x ** 2 - y) ** 2
        else:
            return x, y

    def dou2ZD(self, x, lowBef, upBef, lowAft, upAft):
        return lowAft + (x - lowBef) * (upAft - lowAft) / (upBef - lowBef)

    def initPop(self):
        self.pop.generan = 0
        for indv in self.pop.indv:
            if self.problem_type == 'binary':
                indv.gene = [str(random.randint(0, 1)) for _ in range(LENIND)]
                indv.gene.append('�')
            elif self.problem_type == 'real':
                indv.geneX1 = random.uniform(0, 1024)
                indv.geneX2 = random.uniform(0, 1024)

    def calFit(self):
        for indv in self.pop.indv:
            if self.problem_type == 'binary':
                indv.x = self.dou2ZD(self.bin2dou(indv.gene), 0, pow(2, LENIND), -1, 2)
                indv.fitness = self.fit(indv.x, 0, FUN)[1]
            elif self.problem_type == 'real':
                indv.geneX1 = self.dou2ZD(indv.geneX1, 0, 1024, -10, 10)
                indv.geneX2 = self.dou2ZD(indv.geneX2, 0, 1024, -10, 10)
                indv.fitness = self.fit(indv.geneX1, indv.geneX2, FUN)[1]

    def calUp(self):
        sum = 0.0
        for indv in self.pop.indv:
            sum += indv.fitness
        self.pop.indv[0].upLim = self.pop.indv[0].fitness / sum
        for i in range(NUMIND - 1):
            temp = self.pop.indv[i + 1].fitness / sum
            self.pop.indv[i + 1].upLim = temp + self.pop.indv[i].upLim
            if self.pop.indv[i + 1].upLim > 1.0 and (i + 1) < (NUMIND - 1):
                for j in range(NUMIND):
                    print('generation is:{},fitness={},UpLim={}'.format(self.pop.generan, self.pop.indv[j].fitness,
                                                                           self.pop.indv[j].upLim))
                print('
Error,{}'s upLim is greater than 1=============
'.format(i + 1))
                exit(0)
        self.pop.indv[NUMIND - 1].upLim = 1

    def HalfSear(self, value, LowBo, UpBo, InA):
        if LowBo >= UpBo:
            return UpBo
        Mid = (LowBo + UpBo) // 2
        if Mid == 0:
            return 0
        if value <= InA[Mid] and value > InA[Mid - 1]:
            return Mid
        else:
            if value >= InA[Mid]:
                return self.HalfSear(value, Mid, UpBo, InA)
            else:
                return self.HalfSear(value, LowBo, Mid, InA)

    def calSub(self):
        poptem = GAFactory.popu()
        TemFitn = [indv.upLim for indv in self.pop.indv]
        for i in range(NUMIND):
            rnd = random.uniform(0, 1)
            NumTemp = self.HalfSear(rnd, 0, NUMIND, TemFitn)
            poptem.indv[i] = self.pop.indv[NumTemp]
        poptem.generan = self.pop.generan
        poptem.bestInd = self.pop.bestInd
        self.pop = poptem

    def select(self):
        self.calUp()
        self.calSub()

    def swithstr(self, s, t):
        i = random.randint(1, LENIND - 1)
        for j in range(i, LENIND):
            temp = s[j]
            s[j] = t[j]
            t[j] = temp

    def bin2dou(self, bp):
        retuV = 0
        for i in range(LENIND):
            tem = 0 if bp[i] == '0' else 1
            retuV += tem * pow(2, LENIND - i - 1)
        return (retuV)

    def crossove(self):
        for i in range(NUMIND // 2):
            if random.random() > crossPro:
                continue
            else:
                j = random.randint(0, NUMIND - 1)
                k = random.randint(0, NUMIND - 1)
                if self.problem_type == 'binary':
                    self.swithstr(self.pop.indv[j].gene, self.pop.indv[k].gene)
                elif self.problem_type == 'real':
                    a = random.uniform(0, 1)
                    self.pop.indv[j].geneX1 = a * self.pop.indv[j].geneX1 + (1 - a) * self.pop.indv[k].geneX1
                    self.pop.indv[j].geneX2 = a * self.pop.indv[j].geneX2 + (1 - a) * self.pop.indv[k].geneX2
                    self.pop.indv[k].geneX1 = a * self.pop.indv[k].geneX1 + (1 - a) * self.pop.indv[j].geneX1
                    self.pop.indv[k].geneX2 = a * self.pop.indv[k].geneX2 + (1 - a) * self.pop.indv[j].geneX2

    def changeM(self, ind):
        r = random.randint(0, LENIND - 1)
        if ind[r] == '0':
            ind[r] = '1'
        else:
            ind[r] = '0'

    def mutation(self):
        for i in range(NUMIND):
            if random.random() > mutaPro:
                continue
            else:
                if self.problem_type == 'binary':
                    self.changeM(self.pop.indv[i].gene)
                elif self.problem_type == 'real':
                    self.pop.indv[i].geneX1 = random.uniform(0, 1024)
                    self.pop.indv[i].geneX2 = random.uniform(0, 1024)

    def max(self):
        j = 0
        tem = self.pop.indv[0].fitness
        for i in range(1, NUMIND):
            if self.pop.indv[i].fitness > tem:
                tem = self.pop.indv[i].fitness
                j = i
        self.pop.bestInd = copy.deepcopy(self.pop.indv[j])


# 全局变量
PI = 3.1415926
NUMIND = 25
LENIND = 20
FUN = 1
crossPro = 0.9
mutaPro = 0.1


if __name__ == '__main__':
    random.seed(time.time() % 9)

    # 创建二进制编码遗传算法对象
    ga_binary = GAFactory('binary')
    ga_binary.initPop()
    fp = open('a.txt', 'w')
    if not fp:
        print('Can't open file')
        exit(0)
    while ga_binary.pop.bestInd.fitness <= 3.85027 and ga_binary.pop.generan < 10000:
        ga_binary.calFit()
        ga_binary.max()
        print('The generation is {}, the best fitness is {}'.format(ga_binary.pop.generan, ga_binary.pop.bestInd.fitness))
        fp.write('Best Individual: {}, {}
'.format(ga_binary.pop.bestInd.gene, ga_binary.pop.bestInd.fitness))
        ga_binary.select()
        ga_binary.crossove()
        if ga_binary.pop.generan == 100:
            mutaPro = 0.3
            print('The mutation probability is set to 0.3')
        ga_binary.mutation()
        ga_binary.pop.indv[0] = ga_binary.pop.bestInd
        ga_binary.pop.generan += 1
    print('finished')
    fp.close()

    # 创建实数编码遗传算法对象
    ga_real = GAFactory('real')
    ga_real.initPop()
    fp = open('b.txt', 'w')
    if not fp:
        print('Can't open file')
        exit(0)
    while ga_real.pop.bestInd.fitness <= 40000 and ga_real.pop.generan < 10000:
        ga_real.calFit()
        ga_real.max()
        print('The generation is {}, the best fitness is {}'.format(ga_real.pop.generan, ga_real.pop.bestInd.fitness))
        fp.write('Best Individual: X1={}, X2={}, {}
'.format(ga_real.pop.bestInd.geneX1, ga_real.pop.bestInd.geneX2, ga_real.pop.bestInd.fitness))
        ga_real.select()
        ga_real.crossove()
        if ga_real.pop.generan == 100:
            mutaPro = 0.3
            print('The mutation probability is set to 0.3')
        ga_real.mutation()
        ga_real.pop.indv[0] = ga_real.pop.bestInd
        ga_real.pop.generan += 1
    print('finished')
    fp.close()

代码解析

  1. 工厂类 GAFactory

    • 接收 problem_type 参数,指定编码方式('binary' 或 'real')。
    • 内部定义 indivi 类和 popu 类,分别代表个体和种群,根据编码方式动态创建属性。
    • 包含所有遗传算法操作的函数,例如 fit()initPop()calFit() 等,这些函数根据编码方式进行相应的处理。
  2. 全局变量

    • 定义了遗传算法的参数,例如 PINUMINDLENIND 等。
  3. 主程序

    • 创建两个 GAFactory 对象,分别对应二进制编码和实数编码。
    • 使用两个对象分别运行遗传算法,并输出结果。

总结

通过工厂模式封装,我们可以轻松地创建不同编码方式的遗传算法对象,并进行相应的操作。这种方法简化了代码结构,提高了代码的可读性和可维护性。

遗传算法工厂模式封装:二进制编码和实数编码

原文地址: https://www.cveoy.top/t/topic/nyFf 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录