遗传算法工厂模式改写:提高代码可读性和可维护性

本示例展示了如何使用工厂模式将遗传算法代码进行改写,以提高代码的可读性和可维护性。

原始代码:

import math
import random
import time
import copy

PI = 3.1415926
NUMIND = 25
FUN = 1
crossPro = 0.9
mutaPro = 0.1

class indivi:
    def __init__(self):
        self.geneX1 = 0.0
        self.geneX2 = 0.0
        self.fitness = 0.0

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

global pop
pop = popu()

def ranF(x, y):
    return random.uniform(x, y)

def fit(x1, x2, i):
    if i == 1:
        return 3*(x1**2 - x2)**2
    else:
        return x1,x2

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

def initPop():
    pop.generan = 0
    for indv in pop.indv:
        indv.geneX1 = ranF(0, 1024)
        indv.geneX2 = ranF(0, 1024)

def calFit():
    for indv in pop.indv:
        indv.geneX1 = dou2ZD(indv.geneX1, 0, 1024, -10, 10)
        indv.geneX2 = dou2ZD(indv.geneX2, 0, 1024, -10, 10)

        indv.fitness = fit(indv.geneX1, indv.geneX2, FUN)

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

def HalfSear(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 HalfSear(value, Mid, UpBo, InA)
        else:
            return HalfSear(value, LowBo, Mid, InA)

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

def select():
    calUp()
    calSub(pop)

def crossove():
    for i in range(NUMIND//2):
        if random.random() > crossPro:
            continue
        else:
            j = random.randint(0, NUMIND-1)
            k = random.randint(0, NUMIND-1)
            a = ranF(0, 1)
            pop.indv[j].geneX1 = a * pop.indv[j].geneX1 + (1 - a) * pop.indv[k].geneX1
            pop.indv[j].geneX2 = a * pop.indv[j].geneX2 + (1 - a) * pop.indv[k].geneX2
            pop.indv[k].geneX1 = a * pop.indv[k].geneX1 + (1 - a) * pop.indv[j].geneX1
            pop.indv[k].geneX2 = a * pop.indv[k].geneX2 + (1 - a) * pop.indv[j].geneX2

def mutation():
    for i in range(NUMIND):
        if random.random() > mutaPro:
            continue
        else:
            pop.indv[i].geneX1 = ranF(0, 1024)
            pop.indv[i].geneX2 = ranF(0, 1024)

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

if __name__ == '__main__':
    random.seed(time.time() % 9)
    initPop()
    fp = open("a.txt", "w")
    if not fp:
        print("Can't open file")
        exit(0)
    while pop.bestInd.fitness <=  40000 and pop.generan < 10000:
        calFit()
        max()
        print("The generation is {}, the best fitness is {}".format(pop.generan, pop.bestInd.fitness))
        fp.write("Best Individual: X1={}, X2={}, {}
".format(pop.bestInd.geneX1, pop.bestInd.geneX2, pop.bestInd.fitness))
        select()
        crossove()
        if pop.generan == 100:
            mutaPro = 0.3
            print("The mutation probability is set to 0.3")
        mutation()
        pop.indv[0] = pop.bestInd
        pop.generan +=1
    print("finished")
    fp.close()

工厂模式改写后的代码:

import math
import random
import time
import copy

PI = 3.1415926
NUMIND = 25
FUN = 1
crossPro = 0.9
mutaPro = 0.1

class indivi:
    def __init__(self):
        self.geneX1 = 0.0
        self.geneX2 = 0.0
        self.fitness = 0.0

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

class GeneticAlgorithm:
    def ranF(self, x, y):
        return random.uniform(x, y)

    def fit(self, x1, x2, i):
        if i == 1:
            return 3*(x1**2 - x2)**2
        else:
            return x1,x2

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

    def initPop(self, pop):
        pop.generan = 0
        for indv in pop.indv:
            indv.geneX1 = self.ranF(0, 1024)
            indv.geneX2 = self.ranF(0, 1024)

    def calFit(self, pop):
        for indv in pop.indv:
            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)

    def calUp(self, pop):
        sum = 0.0
        for indv in pop.indv:
            sum += indv.fitness
        pop.indv[0].upLim = pop.indv[0].fitness / sum
        for i in range(NUMIND-1):
            temp = pop.indv[i+1].fitness / sum
            pop.indv[i+1].upLim = temp + pop.indv[i].upLim
            if pop.indv[i+1].upLim > 1.0 and (i+1) < (NUMIND-1):
                for j in range(NUMIND):
                    print("generation is:{},fitness={},UpLim={}".format(pop.generan,pop.indv[j].fitness,pop.indv[j].upLim))
                print("
Error,{}'s upLim is greater than 1=============
".format(i+1))
                exit(0)
        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, pop):
        poptem = popu()
        TemFitn = [indv.upLim for indv in pop.indv]
        for i in range(NUMIND):
            rnd = self.ranF(0, 1)
            NumTemp = self.HalfSear(rnd, 0, NUMIND, TemFitn)
            poptem.indv[i] = pop.indv[NumTemp]
        poptem.generan = pop.generan
        poptem.bestInd = pop.bestInd
        pop = poptem
        return pop

    def select(self, pop):
        self.calUp(pop)
        pop = self.calSub(pop)
        return pop

    def crossove(self, pop):
        for i in range(NUMIND//2):
            if random.random() > crossPro:
                continue
            else:
                j = random.randint(0, NUMIND-1)
                k = random.randint(0, NUMIND-1)
                a = self.ranF(0, 1)
                pop.indv[j].geneX1 = a * pop.indv[j].geneX1 + (1 - a) * pop.indv[k].geneX1
                pop.indv[j].geneX2 = a * pop.indv[j].geneX2 + (1 - a) * pop.indv[k].geneX2
                pop.indv[k].geneX1 = a * pop.indv[k].geneX1 + (1 - a) * pop.indv[j].geneX1
                pop.indv[k].geneX2 = a * pop.indv[k].geneX2 + (1 - a) * pop.indv[j].geneX2
        return pop

    def mutation(self, pop):
        for i in range(NUMIND):
            if random.random() > mutaPro:
                continue
            else:
                pop.indv[i].geneX1 = self.ranF(0, 1024)
                pop.indv[i].geneX2 = self.ranF(0, 1024)
        return pop

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

if __name__ == '__main__':
    random.seed(time.time() % 9)
    genetic_algorithm = GeneticAlgorithm()
    pop = popu()
    genetic_algorithm.initPop(pop)
    fp = open("a.txt", "w")
    if not fp:
        print("Can't open file")
        exit(0)
    while pop.bestInd.fitness <=  40000 and pop.generan < 10000:
        genetic_algorithm.calFit(pop)
        pop = genetic_algorithm.max(pop)
        print("The generation is {}, the best fitness is {}".format(pop.generan, pop.bestInd.fitness))
        fp.write("Best Individual: X1={}, X2={}, {}
".format(pop.bestInd.geneX1, pop.bestInd.geneX2, pop.bestInd.fitness))
        pop = genetic_algorithm.select(pop)
        genetic_algorithm.crossove(pop)
        if pop.generan == 100:
            mutaPro = 0.3
            print("The mutation probability is set to 0.3")
        genetic_algorithm.mutation(pop)
        pop.indv[0] = pop.bestInd
        pop.generan +=1
    print("finished")
    fp.close()

代码分析:

  1. 创建GeneticAlgorithm类:将所有遗传算法操作封装到一个类中,使代码结构更加清晰。
  2. 使用工厂模式:在主函数中创建GeneticAlgorithm对象,并调用其方法来执行遗传算法操作,降低了代码耦合度。
  3. 参数化:将遗传算法中的参数(如NUMIND、crossPro、mutaPro)设置为类的属性,方便修改和调整。

优点:

  • 提高代码可读性:将逻辑分离到不同的方法中,使代码更易于理解和维护。
  • 提高代码可维护性:修改算法参数或逻辑时,只需修改相应的类方法即可,不会影响其他部分代码。
  • 降低代码耦合度:通过工厂模式,将遗传算法的实现细节与主函数分离,使代码更易于测试和扩展。

总结:

使用工厂模式改写遗传算法代码,不仅能够提高代码的可读性和可维护性,也能够更好地组织代码结构,方便后续的扩展和维护。

遗传算法工厂模式改写:提高代码可读性和可维护性

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

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