geatpy-dev / geatpy

Evolutionary algorithm toolbox and framework with high performance for Python
http://www.geatpy.com
GNU Lesser General Public License v3.0
1.96k stars 725 forks source link

“基于多种群个体选择的高级选择函数”存在bug #330

Open weiweiisok opened 1 year ago

weiweiisok commented 1 year ago

多种群的选择函数存在bug; 我在程序中设置了对每个种群个体的选择数量要大于当前种群的50%(也即MSel=0.5,NSel=300),共计3个种群; 执行mselecting函数后,得到的子代种群数量并没有达到每个种群数量的50%以上,如下图所示:第三个种群初始个体数量为16个,按照设置的MSel=0.5,选择后第三个种群数量起码要达到8个以上,但是结果只选择了1个。同理第二个种群的选择结果也是一样的情况; 5f9cdf493b1853738ea134f16a9dc49d c68f50c16f5eb3c07a6178938c104d68

weiweiisok commented 1 year ago

并且使用这个mselecting函数选择出来的所有种群个体数之和,在某些代数并不等于NUM

weiweiisok commented 1 year ago

这个案例是用的咱们demo里面soea的demo9问题测试的,我把algorithm主体提出来了,完整代码见下方,我设置的参数是:三个种群,大小各为100;ea.mselecting函数中的Msel=0.5,当运行到13代时,出现结果如下图所示,population中的第二个种群中有124个个体,按照Msel=0.5,选择出来的个体数量要么是大于等于124x0.5=62个,要么是大于100x0.5=50个(因此我暂时不知道Msel这个参数选择出的个体基数是基于初始群体数量还是基于迭代中的当前种群数量),但是结果选择出来的个体仅为29个,不满足上述任意一个假设。 image ` import numpy as np

import geatpy as ea

class MyProblem(ea.Problem): # 继承Problem父类

def __init__(self):
    name = 'MyProblem'  # 初始化name(函数名称,可以随意设置)
    M = 1  # 初始化M(目标维数)
    maxormins = [-1]  # 初始化maxormins(目标最小最大化标记列表,1:最小化该目标;-1:最大化该目标)
    Dim = 1  # 初始化Dim(决策变量维数)
    varTypes = [0] * Dim  # 初始化varTypes(决策变量的类型,元素为0表示对应的变量是连续的;1表示是离散的)
    lb = [-1]  # 决策变量下界
    ub = [2]  # 决策变量上界
    lbin = [1] * Dim  # 决策变量下边界(0表示不包含该变量的下边界,1表示包含)
    ubin = [1] * Dim  # 决策变量上边界(0表示不包含该变量的上边界,1表示包含)
    # 调用父类构造方法完成实例化
    ea.Problem.__init__(self,
                        name,
                        M,
                        maxormins,
                        Dim,
                        varTypes,
                        lb,
                        ub,
                        lbin,
                        ubin)

def evalVars(self, x):  # 目标函数
    f = x * np.sin(10 * np.pi * x) + 2.0
    return f

class soea_multi_SEGA_templet1(ea.soea_multi_SEGA_templet): def init(self, problem, population, MAXGEN=None, MAXTIME=None, MAXEVALS=None, MAXSIZE=None, logTras=None, verbose=None, outFunc=None, drawing=None, trappedValue=None, maxTrappedCount=None, dirName=None, **kwargs):

先调用父类构造方法

    super().__init__(problem, population, MAXGEN, MAXTIME, MAXEVALS, MAXSIZE, logTras, verbose, outFunc, drawing, trappedValue, maxTrappedCount, dirName)
    if type(population) != list:
        raise RuntimeError('传入的种群对象列表必须为list类型')
    self.name = 'multi-SEGA'
    self.PopNum = len(population)  # 种群数目
    self.selFunc = 'tour'  # 锦标赛选择算子
    self.migFr = 5  # 发生种群迁移的间隔代数
    self.migOpers = ea.Migrate(MIGR=0.2, Structure=2, Select=1, Replacement=2)  # 生成种群迁移算子对象
    # 为不同的种群设置不同的重组、变异算子
    self.recOpers = []
    self.mutOpers = []
    Pms = np.linspace(1 / self.problem.Dim, 1, self.PopNum)  # 生成变异概率列表,为不同的种群分配不同的变异概率
    Pcs = np.linspace(0.7, 1, self.PopNum)  # 生成重组概率列表,为不同的种群分配不同的重组概率
    for i in range(self.PopNum):  # 遍历种群列表
        pop = population[i]  # 得到当前种群对象
        if pop.Encoding == 'P':
            recOper = ea.Xovpmx(XOVR=Pcs[i])  # 生成部分匹配交叉算子对象
            mutOper = ea.Mutinv(Pm=float(Pms[i]))  # 生成逆转变异算子对象
        else:
            recOper = ea.Xovdp(XOVR=Pcs[i])  # 生成两点交叉算子对象
            if pop.Encoding == 'BG':
                mutOper = ea.Mutbin(Pm=float(Pms[i]))  # 生成二进制变异算子对象
            elif pop.Encoding == 'RI':
                mutOper = ea.Mutbga(Pm=float(Pms[i]), MutShrink=0.5, Gradient=20)  # 生成breeder GA变异算子对象
            else:
                raise RuntimeError('编码方式必须为''BG''、''RI''或''P''.')
        self.recOpers.append(recOper)
        self.mutOpers.append(mutOper)

def EnvSelection(self, population, NUM):  # 环境选择,选择个体保留到下一代
    FitnVs = list(pop.FitnV for pop in population)
    NewChrIxs = ea.mselecting('dup', FitnVs, NUM, 0.5)  # 采用基于适应度排序的直接复制选择
    for i in range(self.PopNum):
        population[i] = (population[i])[NewChrIxs[i]]
    count = 0
    for i in NewChrIxs:
        count += len(i)
    return population

if name == 'main':

实例化问题对象

problem = MyProblem()
# 种群设置
Encoding = 'RI'  # 编码方式
NINDs = [100, 100, 100]  # 种群规模
population = []  # 创建种群列表
for i in range(len(NINDs)):
    Field = ea.crtfld(Encoding,
                      problem.varTypes,
                      problem.ranges,
                      problem.borders)  # 创建区域描述器。
    population.append(ea.Population(
        Encoding, Field, NINDs[i]))  # 实例化种群对象(此时种群还没被初始化,仅仅是完成种群对象的实例化)。
# 构建算法
algorithm = soea_multi_SEGA_templet1(
    problem,
    population,
    MAXGEN=100,  # 最大进化代数。
    logTras=1,  # 表示每隔多少代记录一次日志信息,0表示不记录。
     )  # 进化停滞计数器最大上限值。
# 求解
res = ea.optimize(algorithm,
                  verbose=True,
                  drawing=1,
                  outputMsg=True,
                  drawLog=False,
                  saveFlag=False)
print(res)`
weiweiisok commented 1 year ago

此外,有时种群间的移民会导致部分子种群中数量个体极少(为1个个体),这也导致到所有子种群中个体数量加起来会大于NUM所指定的个体

geatpy-dev commented 1 year ago

非常感谢。已经标记该问题,将会尝试在后续版本中予以解决。