Exemplo n.º 1
0
 def run(self, prophetPop = None): # prophetPop为先知种群(即包含先验知识的种群)
     #==========================初始化配置===========================
     population = self.population
     NIND = population.sizes
     self.initialization() # 初始化算法模板的一些动态参数
     #===========================准备进化============================
     population.initChrom(NIND) # 初始化种群染色体矩阵
     self.call_aimFunc(population) # 计算种群的目标函数值
     # 插入先验知识(注意:这里不会对先知种群prophetPop的合法性进行检查,故应确保prophetPop是一个种群类且拥有合法的Chrom、ObjV、Phen等属性)
     if prophetPop is not None:
         population = (prophetPop + population)[:NIND] # 插入先知种群
     population.FitnV = ea.scaling(population.ObjV, population.CV, self.problem.maxormins) # 计算适应度
     Sigma3 = 0.5 * (population.Field[1,:] - population.Field[0,:]) # 初始化高斯变异算子的Sigma3
     #===========================开始进化============================
     while self.terminated(population) == False:
         # 进行进化操作
         experimentPop = ea.Population(population.Encoding, population.Field, NIND) # 存储试验种群
         experimentPop.Chrom = ea.mutgau(population.Encoding, population.Chrom, population.Field, 1, Sigma3) # 高斯变异
         self.call_aimFunc(experimentPop) # 计算目标函数值
         tempPop = population + experimentPop # 临时合并,以调用otos进行一对一生存者选择
         tempPop.FitnV = ea.scaling(tempPop.ObjV, tempPop.CV, self.problem.maxormins) # 计算适应度
         chooseIdx = ea.selecting('otos', tempPop.FitnV, NIND) # 采用One-to-One Survivor选择
         population = tempPop[chooseIdx] # 产生新一代种群
         # 利用1/5规则调整变异压缩概率
         successfulRate = len(np.where(chooseIdx >= NIND)[0]) / (2 * NIND)
         if successfulRate < 1/5:
             Sigma3 *= 0.817
         elif successfulRate > 1/5:
             Sigma3 /= 0.817
     
     return self.finishing(population) # 调用finishing完成后续工作并返回结果
 def run(self, prophetPop=None):  # prophetPop为先知种群(即包含先验知识的种群)
     # ==========================初始化配置===========================
     population = self.population
     NIND = population.sizes
     self.initialization()  # 初始化算法类的一些动态参数
     # ===========================准备进化============================
     population.initChrom(NIND)  # 初始化种群染色体矩阵
     # 插入先验知识(注意:这里不会对先知种群prophetPop的合法性进行检查)
     if prophetPop is not None:
         population = (prophetPop + population)[:NIND]  # 插入先知种群
     self.call_aimFunc(population)  # 计算种群的目标函数值
     population.FitnV = ea.scaling(population.ObjV, population.CV, self.problem.maxormins)  # 计算适应度
     Sigma3 = np.random.rand(population.sizes, population.Lind) * (
                 population.Field[1, :] - population.Field[0, :]) * 0.5  # 初始化高斯变异算子的Sigma3
     # ===========================开始进化============================
     while not self.terminated(population):
         # 选择
         choose_index = ea.selecting(self.selFunc, population.FitnV, self.NSel)
         offspring = population[choose_index]
         offspring_Sigma3 = Sigma3[choose_index]
         # 进行进化操作
         offspring.Chrom = self.recOper.do(offspring.Chrom)  # 重组
         offspring_Sigma3 = self.recOper.do(offspring_Sigma3)  # 对offspring_Sigma3进行重组
         for i in range(len(choose_index)):
             offspring.Chrom[i, :] = ea.mutgau(offspring.Encoding, offspring.Chrom[i, :].reshape(1, -1),
                                               offspring.Field, 1, offspring_Sigma3[i]).reshape(-1)  # 高斯变异
         self.call_aimFunc(offspring)  # 计算目标函数值
         population = population + offspring  # 父子合并
         Sigma3 = np.vstack([Sigma3, offspring_Sigma3])
         population.FitnV = ea.scaling(population.ObjV, population.CV, self.problem.maxormins)  # 计算适应度
         # 得到新一代种群
         choose_index = ea.selecting('dup', population.FitnV, NIND)  # 采用基于适应度排序的直接复制选择
         population = population[choose_index]
         Sigma3 = Sigma3[choose_index]
     return self.finishing(population)  # 调用finishing完成后续工作并返回结果
Exemplo n.º 3
0
def nsga2(AIM_M, AIM_F, NIND, ranges, borders, precisions, MAXGEN, SUBPOP,
          GGAP, selectStyle, recombinStyle, recopt, pm, maxormin):
    """==========================初始化配置==========================="""
    GGAP = 0.5 * GGAP  # 为了避免父子两代合并后种群数量爆炸,要让代沟不超过0.5
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    FieldDR = ga.crtfld(ranges, borders, precisions)
    """=========================开始遗传算法进化======================="""
    Chrom = ga.crtrp(NIND, FieldDR)  # 创建简单离散种群
    ObjV = aimfuc(Chrom)  # 计算种群目标函数值
    NDSet = np.zeros((0, ObjV.shape[1]))  # 定义帕累托最优解集合(初始为空集)

    start_time = time.time()  # 开始计时

    [FitnV, levels, maxLevel] = ga.ndomindeb(maxormin * ObjV, 1)  # deb非支配分级
    frontIdx = np.where(levels == 1)[0]  # 处在第一级的个体即为种群的非支配个体
    # 更新帕累托最优集以及种群非支配个体的适应度
    [FitnV, NDSet, repnum] = ga.upNDSet(FitnV, maxormin * ObjV,
                                        maxormin * NDSet, frontIdx)

    # 开始进化!!
    for gen in range(MAXGEN):
        #        if NDSet.shape[0] > 2 * ObjV.shape[0]:
        #            break
        # 进行遗传操作!!
        SelCh = ga.recombin(recombinStyle, Chrom, recopt, SUBPOP)  #交叉
        SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
        if repnum > Chrom.shape[0] * 0.05:  # 当最优个体重复率高达5%时,进行一次高斯变异
            SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
        # 父子合并
        Chrom = np.vstack([Chrom, SelCh])
        ObjV = aimfuc(Chrom)  # 求目标函数值
        [FitnV, levels, maxLevel] = ga.ndomindeb(maxormin * ObjV,
                                                 1)  # deb非支配分级
        frontIdx = np.where(levels == 1)[0]  # 处在第一级的个体即为种群的非支配个体
        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, repnum] = ga.upNDSet(FitnV, maxormin * ObjV,
                                            maxormin * NDSet, frontIdx)
        # 计算每个目标下个体的聚集距离(不需要严格计算欧氏距离,计算绝对值即可)
        for i in range(ObjV.shape[1]):
            idx = np.argsort(ObjV[:, i], 0)
            dis = np.abs(np.diff(ObjV[idx, i].T, 1).T) / (
                np.max(ObjV[idx, i]) - np.min(ObjV[idx, i]) + 1)  # 差分计算距离
            dis = np.hstack([dis, dis[-1]])
            FitnV[idx, 0] += dis  # 根据聚集距离修改适应度,以增加种群的多样性
        Chrom = ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP)  # 选择出下一代

    end_time = time.time()  # 结束计时

    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, end_time - start_time]
Exemplo n.º 4
0
    def run(self):
        #==========================初始化配置===========================
        population = self.population
        NIND = population.sizes
        self.initialization()  # 初始化算法模板的一些动态参数
        #===========================准备进化============================
        if population.Chrom is None:
            population.initChrom(NIND)  # 初始化种群染色体矩阵(内含染色体解码,详见Population类的源码)
        else:
            population.Phen = population.decoding()  # 染色体解码
        self.problem.aimFunc(population)  # 计算种群的目标函数值
        population.FitnV = ea.scaling(self.problem.maxormins * population.ObjV,
                                      population.CV)  # 计算适应度
        self.evalsNum = population.sizes  # 记录评价次数
        Sigma = 0.5 * (population.Field[1, :] -
                       population.Field[0, :]) / 3  # 初始化高斯变异的Sigma
        #===========================开始进化============================
        while self.terminated(population) == False:
            # 进行进化操作
            experimentPop = population.copy()  # 存储试验种群
            experimentPop.Chrom = ea.mutgau(experimentPop.Encoding,
                                            experimentPop.Chrom,
                                            experimentPop.Field,
                                            experimentPop.Lind,
                                            Sigma)  # 高斯变异(这里变异概率设为染色体长度)
            # 求进化后个体的目标函数值
            experimentPop.Phen = experimentPop.decoding()  # 染色体解码
            self.problem.aimFunc(experimentPop)  # 计算目标函数值
            self.evalsNum += population.sizes  # 更新评价次数
            tempPop = population + experimentPop  # 临时合并,以调用otos进行一对一生存者选择
            tempPop.FitnV = ea.scaling(self.problem.maxormins * tempPop.ObjV,
                                       tempPop.CV)  # 计算适应度
            chooseIdx = ea.selecting('otos', tempPop.FitnV,
                                     NIND)  # 采用One-to-One Survivor选择
            population = tempPop[chooseIdx]  # 产生新一代种群
            # 利用1/5规则调整变异压缩概率(实质上是通过变异压缩概率来调整高斯变异的标准差,详见mutgau帮助文档)
            successfulRate = len(np.where(chooseIdx >= NIND)[0]) / (2 * NIND)
            if successfulRate < 1 / 5:
                Sigma *= 0.817
            elif successfulRate > 1 / 5:
                Sigma /= 0.817

        return self.finishing(population)  # 调用finishing完成后续工作并返回结果
Exemplo n.º 5
0
def i_awGA(AIM_M, AIM_F, NIND, ranges, borders, precisions, MAXGEN, SUBPOP,
           GGAP, selectStyle, recombinStyle, recopt, pm, maxormin):
    """==========================初始化配置==========================="""
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    FieldDR = ga.crtfld(ranges, borders, precisions)
    """=========================开始遗传算法进化======================="""
    Chrom = ga.crtrp(NIND, FieldDR)  # 创建简单离散种群
    ObjV = aimfuc(Chrom)  # 计算种群目标函数值
    NDSet = np.zeros((0, ObjV.shape[1]))  # 定义帕累托最优解集合(初始为空集)
    start_time = time.time()  # 开始计时
    # 开始进化!!
    for gen in range(MAXGEN):
        if NDSet.shape[0] > 2 * ObjV.shape[0]:
            break
        [CombinObjV, weight] = ga.awGA(ObjV)  # 适应性权重法求聚合目标函数值
        FitnV = ga.ranking(maxormin * CombinObjV)  # 根据加权单目标计算适应度
        [FitnV, frontIdx] = ga.ndominfast(maxormin * ObjV,
                                          FitnV)  # 求种群的非支配个体,并更新适应度

        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, repnum] = ga.upNDSet(FitnV, maxormin * ObjV,
                                            maxormin * NDSet, frontIdx)

        # 进行遗传操作!!
        SelCh = ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP)  # 选择
        SelCh = ga.recombin(recombinStyle, SelCh, recopt, SUBPOP)  #交叉
        SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
        if repnum > Chrom.shape[0] * 0.1:  # 进行一次高斯变异
            SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
        ObjVSel = aimfuc(SelCh)  # 求育种个体的目标函数值
        [CombinObjV, weight] = ga.awGA(maxormin * ObjVSel)  # 适应性权重法求聚合目标函数值
        FitnVSel = ga.ranking(maxormin * CombinObjV)  # 根据聚合目标求育种个体适应度
        [Chrom, ObjV] = ga.reins(Chrom, SelCh, SUBPOP, 1, 0.9, FitnV, FitnVSel,
                                 ObjV, ObjVSel)  #重插入

    end_time = time.time()  # 结束计时
    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, end_time - start_time]
Exemplo n.º 6
0
def q_sorted(AIM_M, AIM_F, NIND, ranges, borders, precisions, MAXGEN, SUBPOP,
             GGAP, selectStyle, recombinStyle, recopt, pm, maxormin):
    """==========================初始化配置==========================="""
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    FieldDR = ga.crtfld(ranges, borders, precisions)
    """=========================开始遗传算法进化======================="""
    Chrom = ga.crtrp(NIND, FieldDR)  # 创建简单离散种群
    ObjV = aimfuc(Chrom)  # 计算种群目标函数值
    NDSet = np.zeros((0, ObjV.shape[1]))  # 定义帕累托最优解集合(初始为空集)
    start_time = time.time()  # 开始计时
    ax = None
    # 开始进化!!
    for gen in range(MAXGEN):
        #        if NDSet.shape[0] > ObjV.shape[0]:
        #            break
        # 求种群的非支配个体以及基于被支配数的适应度
        [FitnV, frontIdx] = ga.ndominfast(maxormin * ObjV)

        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, repnum] = ga.upNDSet(FitnV, maxormin * ObjV,
                                            maxormin * NDSet, frontIdx)

        # 进行遗传操作!!
        SelCh = ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP)  # 选择
        SelCh = ga.recombin(recombinStyle, SelCh, recopt, SUBPOP)  #交叉
        SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
        if repnum > Chrom.shape[0] * 0.1:  # 进行一次高斯变异
            SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
        ObjVSel = aimfuc(SelCh)  # 求育种个体的目标函数值
        # 求种群的非支配个体以及基于被支配数的适应度
        [FitnVSel, frontIdx] = ga.ndominfast(maxormin * ObjVSel)
        [Chrom, ObjV] = ga.reins(Chrom, SelCh, SUBPOP, 1, 0.9, FitnV, FitnVSel,
                                 ObjV, ObjVSel)  #重插入
        ax = ga.frontplot(NDSet, False, ax, gen + 1)
    end_time = time.time()  # 结束计时

    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, end_time - start_time]
Exemplo n.º 7
0
 def run(self, prophetPop = None): # prophetPop为先知种群(即包含先验知识的种群)
     #==========================初始化配置===========================
     population = self.population
     NIND = population.sizes
     self.initialization() # 初始化算法模板的一些动态参数
     #===========================准备进化============================
     if population.Chrom is None:
         population.initChrom(NIND) # 初始化种群染色体矩阵(内含染色体解码,详见Population类的源码)
     else:
         population.Phen = population.decoding() # 染色体解码
     self.problem.aimFunc(population) # 计算种群的目标函数值
     self.evalsNum = population.sizes # 记录评价次数
     # 插入先验知识(注意:这里不会对先知种群prophetPop的合法性进行检查,故应确保prophetPop是一个种群类且拥有合法的Chrom、ObjV、Phen等属性)
     if prophetPop is not None:
         population = (prophetPop + population)[:NIND] # 插入先知种群
     population.FitnV = ea.scaling(self.problem.maxormins * population.ObjV, population.CV) # 计算适应度
     Sigma3 = 0.5 * (population.Field[1,:] - population.Field[0,:]) # 初始化高斯变异算子的Sigma3
     #===========================开始进化============================
     while self.terminated(population) == False:
         # 进行进化操作
         experimentPop = population.copy() # 存储试验种群
         experimentPop.Chrom = ea.mutgau(experimentPop.Encoding, experimentPop.Chrom, experimentPop.Field, 1, Sigma3) # 高斯变异
         # 求进化后个体的目标函数值
         experimentPop.Phen = experimentPop.decoding() # 染色体解码
         self.problem.aimFunc(experimentPop) # 计算目标函数值
         self.evalsNum += population.sizes # 更新评价次数
         tempPop = population + experimentPop # 临时合并,以调用otos进行一对一生存者选择
         tempPop.FitnV = ea.scaling(self.problem.maxormins * tempPop.ObjV, tempPop.CV) # 计算适应度
         chooseIdx = ea.selecting('otos', tempPop.FitnV, NIND) # 采用One-to-One Survivor选择
         population = tempPop[chooseIdx] # 产生新一代种群
         # 利用1/5规则调整变异压缩概率(实质上是通过变异压缩概率来调整高斯变异的标准差,详见mutgau帮助文档)
         successfulRate = len(np.where(chooseIdx >= NIND)[0]) / (2 * NIND)
         if successfulRate < 1/5:
             Sigma3 *= 0.817
         elif successfulRate > 1/5:
             Sigma3 /= 0.817
     
     return self.finishing(population) # 调用finishing完成后续工作并返回结果
Exemplo n.º 8
0
def awGA_templet(AIM_M,
                 AIM_F,
                 PUN_M,
                 PUN_F,
                 ranges,
                 borders,
                 precisions,
                 maxormin,
                 MAXGEN,
                 MAXSIZE,
                 NIND,
                 SUBPOP,
                 GGAP,
                 selectStyle,
                 recombinStyle,
                 recopt,
                 pm,
                 drawing=1):
    """
awGA_templet.py - 基于awGA的多目标优化编程模板

语法:
    该函数除了参数drawing外,不设置可缺省参数。
    当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    awGA_templet(AIM_M, 'aimfuc', None, None, ..., maxormin)
    
输入参数:
    AIM_M - 目标函数的地址,传入该函数前通常由AIM_M = __import__('目标函数名')语句得到
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,传入该函数前通常由PUN_M = __import__('罚函数名')语句得到
    
    PUN_F : str - 罚函数名
    
    ranges : array  - 代表自变量的范围矩阵,要求上界必须大于下界
        例如:[[1, 2, 3],
              [3, 4, 5]]
        表示有3个控制变量,其范围分别是1-3, 2-4, 3-5
                         
    borders : list -(可选参数)代表是否包含变量范围的边界,为1代表控制变量的范围包含该边界
        当为None时,默认设置为全是1的矩阵
        例如:[[1, 0, 1],
              [0, 1, 1]]
        表示上面的三个控制变量的范围分别是:[1, 3)、(2, 4]、[3, 5]
    
    precisions : list -(可选参数)代表控制变量的精度,
        如等于4,表示对应的控制变量的编码可以精确到小数点后4位。
        当precisions为None时,默认precision为1*n的0矩阵(此时表示种群是离散编码的)
        precision的元素必须不小于0
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    MAXSIZE : int - 帕累托最优集最大规模
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,表示子代与父代染色体及性状不相同的概率
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图,2表示绘制进化过程的动画。
                    默认drawing为1
算法描述:
    本模板实现了基于适应性权重聚合法(awGA)的多目标优化搜索,
    通过维护一个全局帕累托最优集来实现帕累托前沿的搜索,故并不需要保证种群所有个体都是非支配的
    
"""

    #==========================初始化配置===========================
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    FieldDR = ga.crtfld(ranges, borders, precisions)
    #=========================开始遗传算法进化=======================
    Chrom = ga.crtrp(NIND, FieldDR)  # 创建简单离散种群
    ObjV = aimfuc(Chrom)  # 计算种群目标函数值
    # 定义帕累托最优解记录器
    NDSet = np.zeros((0, ObjV.shape[1]))
    ax = None
    start_time = time.time()  # 开始计时
    # 开始进化!!
    for gen in range(MAXGEN):
        if NDSet.shape[0] > MAXSIZE:
            break
        [CombinObjV, weight] = ga.awGA(maxormin * ObjV)  # 计算适应性权重以及多目标的加权单目标
        FitnV = ga.ranking(maxormin * CombinObjV)  # 根据加权单目标计算适应度
        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, repnum] = ga.upNDSet(FitnV, maxormin * ObjV,
                                            maxormin * NDSet)
        # 进行遗传操作!!
        SelCh = ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP)  # 选择
        SelCh = ga.recombin(recombinStyle, SelCh, recopt, SUBPOP)  #交叉
        SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
        if repnum > Chrom.shape[0] * 0.1:  # 进行一次高斯变异
            SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
        ObjVSel = aimfuc(SelCh)  # 求育种个体的目标函数值
        [CombinObjV, weight] = ga.awGA(maxormin * ObjVSel)
        FitnVSel = ga.ranking(maxormin * CombinObjV)
        [Chrom, ObjV] = ga.reins(Chrom, SelCh, SUBPOP, 1, 0.9, FitnV, FitnVSel,
                                 ObjV, ObjVSel)  #重插入
        if drawing == 2:
            ax = ga.frontplot(NDSet, False, ax, gen + 1)  # 绘制动态图
    end_time = time.time()  # 结束计时
    #=========================绘图及输出结果=========================
    if drawing != 0:
        ga.frontplot(NDSet, True)
    times = end_time - start_time
    print('用时:' + str(times) + '秒')
    print('帕累托前沿点个数:' + str(NDSet.shape[0]) + '个')
    print('单位时间找到帕累托前沿点个数:' + str(NDSet.shape[0] // times) + '个')
    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, end_time - start_time]
Exemplo n.º 9
0
def moea_q_sorted_templet(AIM_M, AIM_F, PUN_M, PUN_F, FieldDR, problem, maxormin, MAXGEN, MAXSIZE, NIND, SUBPOP, GGAP, selectStyle, recombinStyle, recopt, pm, distribute, drawing = 1):
    
    """
moea_q_sorted_templet.py - 基于快速非支配排序法求解多目标优化问题的进化算法模板

语法:
    该函数除参数drawing外,不设置可缺省参数。当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    moea_q_sorted_templet(AIM_M, 'aimfuc', None, None, ..., maxormin,...)

输入参数:
    AIM_M - 目标函数的地址,由AIM_M = __import__('目标函数所在文件名')语句得到
            目标函数规范定义:[f,LegV] = aimfuc(Phen,LegV)
            其中Phen是种群的表现型矩阵, LegV为种群的可行性列向量,f为种群的目标函数值矩阵
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,由PUN_M = __import__('罚函数所在文件名')语句得到
            罚函数规范定义: newFitnV = punishing(LegV, FitnV)
            其中LegV为种群的可行性列向量, FitnV为种群个体适应度列向量
            一般在罚函数中对LegV为0的个体进行适应度惩罚,返回修改后的适应度列向量newFitnV
    
    PUN_F : str - 罚函数名
    
    FieldDR : array - 实际值种群区域描述器
        [lb;		(float) 指明每个变量使用的下界
         ub]		(float) 指明每个变量使用的上界
         注:不需要考虑是否包含变量的边界值。在crtfld中已经将是否包含边界值进行了处理
         本函数生成的矩阵的元素值在FieldDR的[下界, 上界)之间
    
    problem : str - 表明是整数问题还是实数问题,'I'表示是整数问题,'R'表示是实数问题
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    MAXSIZE : int - 帕累托最优集最大规模,当设为np.inf(无穷)时,模板不对帕累托最优解集规模作限制
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,表示子代与父代染色体及性状不相同的概率
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    distribute : bool - 是否增强帕累托前沿的分布性(可能会造成收敛慢或帕累托前沿数目减少)
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图,2表示绘制进化过程的动画。
                    默认drawing为1
算法描述:
    本模板维护一个全局帕累托最优集来实现帕累托前沿的搜索
    利用快速非支配排序寻找每一代种群的非支配个体,并用它来不断更新全局帕累托最优集,
    故并不需要保证种群所有个体都是非支配的

模板使用注意:
    1.本模板调用的目标函数形如:[ObjV,LegV] = aimfuc(Phen,LegV), 
      其中Phen表示种群的表现型矩阵, LegV为种群的可行性列向量(详见Geatpy数据结构)
    2.本模板调用的罚函数形如: newFitnV = punishing(LegV, FitnV), 
      其中FitnV为用其他算法求得的适应度
    若不符合上述规范,则请修改算法模板或自定义新算法模板
    3.关于'maxormin': geatpy的内核函数全是遵循“最小化目标”的约定的,即目标函数值越小越好。
      当需要优化最大化的目标时,需要设置'maxormin'为-1。
      本算法模板是正确使用'maxormin'的典型范例,其具体用法如下:
      当调用的函数传入参数包含与“目标函数值矩阵”有关的参数(如ObjV,ObjVSel,NDSetObjV等)时,
      查看该函数的参考资料(可用'help'命令查看,也可到官网上查看相应的教程),
      里面若要求传入前对参数乘上'maxormin',则需要乘上。
      里面若要求对返回参数乘上'maxormin'进行还原,
      则调用函数返回得到的相应参数需要乘上'maxormin'进行还原,否则其正负号就会被改变。
    
"""
    
    #==========================初始化配置===========================
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F) # 获得目标函数
    if PUN_F is not None:
        punishing = getattr(PUN_M, PUN_F) # 获得罚函数
    #=========================开始遗传算法进化=======================
    if problem == 'R':
        Chrom = ga.crtrp(NIND, FieldDR) # 生成实数值种群
    elif problem == 'I':
        Chrom = ga.crtip(NIND, FieldDR) # 生成整数值种群
    LegV = np.ones((NIND, 1)) # 初始化种群的可行性列向量
    [ObjV, LegV] = aimfuc(Chrom, LegV) # 计算种群目标函数值
    NDSet = np.zeros((0, Chrom.shape[1])) # 定义帕累托最优解记录器
    NDSetObjV = np.zeros((0, ObjV.shape[1])) # 定义帕累托最优解的目标函数值记录器
    ax = None # 存储上一帧动画
    start_time = time.time() # 开始计时
    # 开始进化!!
    for gen in range(MAXGEN):
        # 求种群的非支配个体以及基于被支配数的适应度
        [FitnV, frontIdx] = ga.ndominfast(maxormin * ObjV, LegV)
        if PUN_F is not None:
            FitnV = punishing(LegV, FitnV) # 调用罚函数作进一步的惩罚
        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, NDSetObjV, repnum] = ga.upNDSet(Chrom, maxormin * ObjV, FitnV, NDSet, maxormin * NDSetObjV, frontIdx, LegV)
        NDSetObjV *= maxormin # 还原在传入upNDSet函数前被最小化处理过的NDSetObjV
        [NDSet, NDSetObjV] = ga.redisNDSet(NDSet, NDSetObjV, NDSetObjV.shape[1] * MAXSIZE) # 利用拥挤距离选择帕累托前沿的子集,在进化过程中最好比上限多筛选出几倍的点集
        if distribute == True: # 若要增强种群的分布性(可能会导致帕累托前沿搜索效率降低)
            # 计算每个目标下相邻个体的距离(不需要严格计算欧氏距离)
            for i in range(ObjV.shape[1]):
                idx = np.argsort(ObjV[:, i], 0)
                dis = np.diff(ObjV[idx, i]) / (np.max(ObjV[idx, i]) - np.min(ObjV[idx, i]) + 1) # 差分计算距离的偏移量占比,即偏移量除以目标函数的极差。加1是为了避免极差为0
                dis = np.hstack([dis, dis[-1]])
                FitnV[idx, 0] *= np.exp(dis) # 根据相邻距离修改适应度,突出相邻距离大的个体,以增加种群的多样性
        # 进行遗传操作!!
        SelCh=ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP) # 选择
        SelCh=ga.recombin(recombinStyle, SelCh, recopt, SUBPOP) #交叉
        if problem == 'R':
            SelCh=ga.mutbga(SelCh,FieldDR, pm) # 变异
            if repnum > Chrom.shape[0] * 0.01: # 当最优个体重复率高达1%时,进行一次高斯变异
                SelCh=ga.mutgau(SelCh, FieldDR, pm) # 高斯变异
        elif problem == 'I':
            SelCh=ga.mutint(SelCh, FieldDR, pm)
        LegVSel = np.ones((SelCh.shape[0], 1)) # 初始化育种种群的可行性列向量
        [ObjVSel, LegVSel] = aimfuc(SelCh, LegVSel) # 求育种个体的目标函数值
        # 求种群的非支配个体以及基于被支配数的适应度
        [FitnVSel, frontIdx] = ga.ndominfast(maxormin * ObjVSel, LegVSel)
        if PUN_F is not None:
            FitnVSel = punishing(LegVSel, FitnVSel) # 调用罚函数作进一步的惩罚
        [Chrom,ObjV,LegV] = ga.reins(Chrom,SelCh,SUBPOP,1,0.9,FitnV,FitnVSel,ObjV,ObjVSel,LegV,LegVSel) #重插入
        if drawing == 2:
            ax = ga.frontplot(NDSetObjV, False, ax, gen + 1) # 绘制动态图
    end_time = time.time() # 结束计时
    [NDSet, NDSetObjV] = ga.redisNDSet(NDSet, NDSetObjV, MAXSIZE) # 最后根据拥挤距离选择均匀分布的点
    #=========================绘图及输出结果=========================
    if drawing != 0:
        ga.frontplot(NDSetObjV,True)
    times = end_time - start_time
    print('用时:%s 秒'%(times))
    print('帕累托前沿点个数:%s 个'%(NDSet.shape[0]))
    print('单位时间找到帕累托前沿点个数:%s 个'%(int(NDSet.shape[0] // times)))
    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, NDSetObjV, end_time - start_time]
Exemplo n.º 10
0
def nsga2_templet(AIM_M, AIM_F, PUN_M, PUN_F, ranges, borders, precisions, maxormin, MAXGEN, MAXSIZE, NIND, SUBPOP, GGAP, selectStyle, recombinStyle, recopt, pm, drawing = 1):
    
    """
nsga2_templet.py - 基于改进NSGA-Ⅱ算法求解多目标优化问题编程模板

语法:
    该函数除参数drawing外,不设置可缺省参数。当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    nsga2_templet(AIM_M, 'aimfuc', None, None, ..., maxormin)
    
输入参数:
    AIM_M - 目标函数的地址,传入该函数前通常由AIM_M = __import__('目标函数名')语句得到
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,传入该函数前通常由PUN_M = __import__('罚函数名')语句得到
    
    PUN_F : str - 罚函数名
    
    ranges : array  - 代表自变量的范围矩阵,要求上界必须大于下界
        例如:[[1, 2, 3],
              [3, 4, 5]]
        表示有3个控制变量,其范围分别是1-3, 2-4, 3-5
                         
    borders : list -(可选参数)代表是否包含变量范围的边界,为1代表控制变量的范围包含该边界
        当为None时,默认设置为全是1的矩阵
        例如:[[1, 0, 1],
              [0, 1, 1]]
        表示上面的三个控制变量的范围分别是:[1, 3)、(2, 4]、[3, 5]
    
    precisions : list -(可选参数)代表控制变量的精度,
        如等于4,表示对应的控制变量的编码可以精确到小数点后4位。
        当precisions为None时,默认precision为1*n的0矩阵(此时表示种群是离散编码的)
        precision的元素必须不小于0
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    MAXSIZE : int - 帕累托最优集最大规模
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,本模板中该参数为无用参数,仅为了兼容同类模板而设
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图,2表示绘制进化过程的动画。
                    默认drawing为1
算法描述:
    传统NSGA-Ⅱ算法的帕累托最优解来只源于当代种群个体,这样难以高效地获取更多的帕累托最优解
    同时难以把种群大小控制在合适的范围内,
    改进的NSGA2整体上沿用传统的NSGA-Ⅱ算法,
    不同的是,该算法通过维护一个全局帕累托最优集来实现帕累托前沿的搜索,
    故并不需要保证种群所有个体都是非支配的。
    
值得注意的是:
    尽管当全局帕累托最优集大小比种群规模大时,算法的时间复杂度比原NSGA-Ⅱ算法要高,
    但算法整体的时间复杂度要低与原NSGA-Ⅱ算法,
    因此单位时间内生成的无重复帕累托最优解个数要多于原NSGA-Ⅱ算法
    
"""
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F) # 获得目标函数
    if PUN_F is not None:
        punishing = getattr(PUN_M, PUN_F) # 获得罚函数
    #==========================初始化配置===========================
    GGAP = 0.5 # 为了避免父子两代合并后种群数量爆炸,要让代沟为0.5
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F) # 获得目标函数
    FieldDR = ga.crtfld(ranges, borders, precisions)
    #=========================开始遗传算法进化=======================
    Chrom = ga.crtrp(NIND, FieldDR) # 创建简单离散种群
    ObjV = aimfuc(Chrom) # 计算种群目标函数值
    NDSet = np.zeros((0, ObjV.shape[1])) # 定义帕累托最优解集合(初始为空集)
    ax = None
    start_time = time.time() # 开始计时
    [FitnV, levels] = ga.ndomindeb(maxormin * ObjV, 1) # deb非支配分级
    if PUN_F is not None:
        FitnV = punishing(Chrom, FitnV) # 调用罚函数
    frontIdx = np.where(levels == 1)[0] # 处在第一级的个体即为种群的非支配个体
        # 更新帕累托最优集以及种群非支配个体的适应度
    [FitnV, NDSet, repnum] = ga.upNDSet(FitnV, maxormin * ObjV, maxormin * NDSet, frontIdx)
    # 开始进化!!
    for gen in range(MAXGEN):
        if NDSet.shape[0] > MAXSIZE:
            break
        # 进行遗传操作!!
        SelCh=ga.recombin(recombinStyle, Chrom, recopt, SUBPOP) #交叉
        SelCh=ga.mutbga(SelCh, FieldDR, pm) # 变异
        if repnum > Chrom.shape[0] * 0.05: # 当最优个体重复率高达5%时,进行一次高斯变异
            SelCh=ga.mutgau(SelCh, FieldDR, pm) # 高斯变异
        # 父子合并
        Chrom = np.vstack([Chrom, SelCh])
        ObjV =  aimfuc(Chrom) # 求目标函数值
        [FitnV, levels] = ga.ndomindeb(maxormin * ObjV, 1) # deb非支配分级
        if PUN_F is not None:
            FitnV = punishing(Chrom, FitnV) # 调用罚函数
        frontIdx = np.where(levels == 1)[0] # 处在第一级的个体即为种群的非支配个体
        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, repnum] = ga.upNDSet(FitnV, maxormin * ObjV, maxormin * NDSet, frontIdx)
        # 计算每个目标下个体的聚集距离(不需要严格计算欧氏距离,计算绝对值即可)
        for i in range(ObjV.shape[1]):
            idx = np.argsort(ObjV[:, i], 0)
            dis = np.abs(np.diff(ObjV[idx, i].T, 1).T) / (np.max(ObjV[idx, i]) - np.min(ObjV[idx, i]) + 1) # 差分计算距离
            dis = np.hstack([dis, dis[-1]])
            FitnV[idx, 0] += dis # 根据聚集距离修改适应度,以增加种群的多样性
        Chrom=ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP) # 选择出下一代
        if drawing == 2:
            ax = ga.frontplot(NDSet, False, ax, gen + 1) # 绘制动态图
    end_time = time.time() # 结束计时
    #=========================绘图及输出结果=========================
    if drawing != 0:
        ga.frontplot(NDSet,True)
    times = end_time - start_time
    print('用时:' + str(times) + '秒')
    print('帕累托前沿点个数:' + str(NDSet.shape[0]) + '个')
    print('单位时间找到帕累托前沿点个数:' + str(NDSet.shape[0] // times) + '个')
    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, times]
Exemplo n.º 11
0
def sga_mps_real_templet(AIM_M,
                         AIM_F,
                         PUN_M,
                         PUN_F,
                         FieldDRs,
                         problem,
                         maxormin,
                         MAXGEN,
                         NIND,
                         SUBPOP,
                         GGAP,
                         selectStyle,
                         recombinStyle,
                         recopt,
                         pm,
                         drawing=1):
    """
sga_mps_real_templet.py - 基于多种群独立进化单目标编程模板(实值编码)

基于多种群独立进化单目标编程模板(实值编码),各种群独立将父子两代合并进行选择,采取精英保留机制

语法:
    该函数除了drawing外,不设置可缺省参数。当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    sga_mps_real_templet(AIM_M, 'aimfuc', None, None, ..., maxormin)

输入参数:
    AIM_M - 目标函数的地址,由AIM_M = __import__('目标函数所在文件名')语句得到
            目标函数规范定义:f = aimfuc(Phen)
            其中Phen是种群的表现型矩阵
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,由PUN_M = __import__('罚函数所在文件名')语句得到
            罚函数规范定义: f = punishing(Phen, FitnV)
            其中Phen是种群的表现型矩阵, FitnV为种群个体适应度列向量
    
    PUN_F : str - 罚函数名
    
    FieldDR : array - 实际值种群区域描述器
        [lb;		(float) 指明每个变量使用的下界
         ub]		(float) 指明每个变量使用的上界
         注:不需要考虑是否包含变量的边界值。在crtfld中已经将是否包含边界值进行了处理
         本函数生成的矩阵的元素值在FieldDR的[下界, 上界)之间
    
    problem : str - 表明是整数问题还是实数问题,'I'表示是整数问题,'R'表示是实数问题                 
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,本模板中该参数为无用参数,仅为了兼容同类的其他模板而设
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图。默认drawing为1

输出参数:
    pop_trace : array - 种群进化记录器(进化追踪器),
                        第0列记录着各代种群最优个体的目标函数值
                        第1列记录着各代种群的适应度均值
                        第2列记录着各代种群最优个体的适应度值
    
    var_trace : array - 变量记录器,记录着各代种群最优个体的变量值,每一列对应一个控制变量
    
    times     : float - 进化所用时间

模板使用注意:
    1.本模板调用的目标函数形如:aimfuc(Phen), 其中Phen表示种群的表现型矩阵
    2.本模板调用的罚函数形如: punishing(Phen, FitnV), 其中FitnV为用其他算法求得的适应度
      在罚函数定义中,必须将不满足约束条件的个体对应的适应度设为0,否则请修改模板使用

"""

    #==========================初始化配置==========================="""
    GGAP = 0.5  # 因为父子合并后选择,因此要将代沟设为0.5以维持种群规模
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    if PUN_F is not None:
        punishing = getattr(PUN_M, PUN_F)  # 获得罚函数
    exIdx = np.array([])  # 存储非可行解的下标
    NVAR = FieldDRs[0].shape[1]  # 得到控制变量的个数
    # 定义全局进化记录器,初始值为nan
    pop_trace = (np.zeros((MAXGEN, 2)) * np.nan)
    pop_trace[:, 0] = 0
    # 定义变量记录器,记录控制变量值,初始值为nan
    var_trace = (np.zeros((MAXGEN, NVAR)) * np.nan)
    """=========================开始遗传算法进化======================="""
    start_time = time.time()  # 开始计时
    # 对于各个网格分别进行进化,采用全局进化记录器记录最优值
    for index in range(len(FieldDRs)):
        FieldDR = FieldDRs[index]
        if problem == 'R':
            Chrom = ga.crtrp(NIND, FieldDR)  # 生成初始种群
        elif problem == 'I':
            Chrom = ga.crtip(NIND, FieldDR)
        repnum = 0  # 初始化重复个体数为0
        # 开始进化!!
        for gen in range(MAXGEN):
            # 进行遗传算子,生成子代
            SelCh = ga.recombin(recombinStyle, Chrom, recopt, SUBPOP)  # 重组
            if problem == 'R':
                SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
                if repnum > Chrom.shape[0] * 0.01:  # 当最优个体重复率高达1%时,进行一次高斯变异
                    SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
            elif problem == 'I':
                SelCh = ga.mutint(SelCh, FieldDR, pm)
            Chrom = np.vstack([Chrom, SelCh])  # 父子合并
            ObjV = aimfuc(Chrom)  # 求后代的目标函数值
            FitnV = ga.ranking(maxormin * ObjV, None, SUBPOP)  # 适应度评价
            if PUN_F is not None:
                [FitnV, exIdx] = punishing(Chrom, FitnV)  # 调用罚函数
            repnum = len(
                np.where(ObjV[np.argmax(FitnV)] == ObjV)[0])  # 计算最优个体重复数
            # 记录进化过程
            bestIdx = np.argmax(FitnV)
            wrongSign = np.ones((FitnV.shape[0], 1))
            wrongSign[list(exIdx)] = 0  # 对非可行解作标记
            if FitnV[bestIdx] != 0:
                if (np.isnan(pop_trace[gen, 1])) or (
                    (maxormin == 1) &
                    (pop_trace[gen, 1] >= ObjV[bestIdx])) or (
                        (maxormin == -1) &
                        (pop_trace[gen, 1] <= ObjV[bestIdx])):
                    feasible = np.where(wrongSign != 0)[0]  # 排除非可行解
                    pop_trace[gen, 0] += np.sum(
                        ObjV[feasible]) / ObjV[feasible].shape[0] / len(
                            FieldDRs)  # 记录种群个体平均目标函数值
                    pop_trace[gen, 1] = ObjV[bestIdx]  # 记录当代目标函数的最优值
                    var_trace[gen, :] = Chrom[bestIdx, :]  # 记录当代最优的控制变量值
            Chrom = ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP)  # 选择
    end_time = time.time()  # 结束计时
    # 后处理进化记录器
    delIdx = np.where(np.isnan(pop_trace))[0]
    pop_trace = np.delete(pop_trace, delIdx, 0)
    var_trace = np.delete(var_trace, delIdx, 0)
    # 绘图
    if drawing == 1:
        ga.trcplot(pop_trace, [['种群个体平均目标函数值', '种群最优个体目标函数值']])
    # 输出结果
    if maxormin == 1:
        best_gen = np.argmin(pop_trace[:, 1])  # 记录最优种群是在哪一代
        print('最优的目标函数值为:', np.min(pop_trace[:, 1]))
    elif maxormin == -1:
        best_gen = np.argmax(pop_trace[:, 1])  # 记录最优种群是在哪一代
        print('最优的目标函数值为:', np.max(pop_trace[:, 1]))
    print('最优的控制变量值为:')
    for i in range(NVAR):
        print(var_trace[best_gen, i])
    print('最优的一代是第', best_gen + 1, '代')
    times = end_time - start_time
    print('时间已过', times, '秒')
    # 返回进化记录器、变量记录器以及执行时间
    return [pop_trace, var_trace, times]
Exemplo n.º 12
0
def moea_nsga2_templet(AIM_M,
                       AIM_F,
                       PUN_M,
                       PUN_F,
                       FieldDR,
                       problem,
                       maxormin,
                       MAXGEN,
                       MAXSIZE,
                       NIND,
                       SUBPOP,
                       GGAP,
                       selectStyle,
                       recombinStyle,
                       recopt,
                       pm,
                       distribute,
                       drawing=1):
    """
moea_nsga2_templet.py - 基于改进NSGA-Ⅱ算法求解多目标优化问题的进化算法模板

语法:
    该函数除参数drawing外,不设置可缺省参数。当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    moea_nsga2_templet(AIM_M, 'aimfuc', None, None, ..., maxormin,...)
    
输入参数:
    AIM_M - 目标函数的地址,由AIM_M = __import__('目标函数所在文件名')语句得到
            目标函数规范定义:[f,LegV] = aimfuc(Phen,LegV)
            其中Phen是种群的表现型矩阵, LegV为种群的可行性列向量,f为种群的目标函数值矩阵
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,由PUN_M = __import__('罚函数所在文件名')语句得到
            罚函数规范定义: newFitnV = punishing(LegV, FitnV)
            其中LegV为种群的可行性列向量, FitnV为种群个体适应度列向量
            一般在罚函数中对LegV为0的个体进行适应度惩罚,返回修改后的适应度列向量newFitnV
    
    PUN_F : str - 罚函数名
    
    FieldDR : array - 实际值种群区域描述器
        [lb;		(float) 指明每个变量使用的下界
         ub]		(float) 指明每个变量使用的上界
         注:不需要考虑是否包含变量的边界值。在crtfld中已经将是否包含边界值进行了处理
         本函数生成的矩阵的元素值在FieldDR的[下界, 上界)之间
    
    problem : str - 表明是整数问题还是实数问题,'I'表示是整数问题,'R'表示是实数问题
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    MAXSIZE : int - 帕累托最优集最大规模,当设为np.inf(无穷)时,模板不对帕累托最优解集规模作限制
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,本模板中该参数为无用参数,仅为了兼容同类模板而设
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    distribute : bool - 是否增强帕累托前沿的分布性(可能会造成收敛慢或帕累托前沿数目减少)
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图,2表示绘制进化过程的动画。
                    默认drawing为1
算法描述:
    传统NSGA-Ⅱ算法的帕累托最优解来只源于当代种群个体,这样难以高效地获取更多的帕累托最优解
    同时难以把种群大小控制在合适的范围内,
    改进的NSGA2整体上沿用传统的NSGA-Ⅱ算法,
    不同的是,该算法通过维护一个全局帕累托最优集来实现帕累托前沿的搜索,
    故并不需要保证种群所有个体都是非支配的。
    
值得注意的是:
    尽管当全局帕累托最优集大小比种群规模大时,算法的时间复杂度比原NSGA-Ⅱ算法要高,
    但算法整体的时间复杂度要低与原NSGA-Ⅱ算法,
    因此单位时间内生成的无重复帕累托最优解个数要多于原NSGA-Ⅱ算法

模板使用注意:
    1.本模板调用的目标函数形如:[ObjV,LegV] = aimfuc(Phen,LegV), 
      其中Phen表示种群的表现型矩阵, LegV为种群的可行性列向量(详见Geatpy数据结构)
    2.本模板调用的罚函数形如: newFitnV = punishing(LegV, FitnV), 
      其中FitnV为用其他算法求得的适应度
    若不符合上述规范,则请修改算法模板或自定义新算法模板
    3.关于'maxormin': geatpy的内核函数全是遵循“最小化目标”的约定的,即目标函数值越小越好。
      当需要优化最大化的目标时,需要设置'maxormin'为-1。
      本算法模板是正确使用'maxormin'的典型范例,其具体用法如下:
      当调用的函数传入参数包含与“目标函数值矩阵”有关的参数(如ObjV,ObjVSel,NDSetObjV等)时,
      查看该函数的参考资料(可用'help'命令查看,也可到官网上查看相应的教程),
      里面若要求传入前对参数乘上'maxormin',则需要乘上。
      里面若要求对返回参数乘上'maxormin'进行还原,
      则调用函数返回得到的相应参数需要乘上'maxormin'进行还原,否则其正负号就会被改变。
    
"""
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    if PUN_F is not None:
        punishing = getattr(PUN_M, PUN_F)  # 获得罚函数
    #==========================初始化配置===========================
    GGAP = 0.5  # 为了避免父子两代合并后种群数量爆炸,要让代沟为0.5
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    #=========================开始遗传算法进化=======================
    if problem == 'R':
        Chrom = ga.crtrp(NIND, FieldDR)  # 生成实数值种群
    elif problem == 'I':
        Chrom = ga.crtip(NIND, FieldDR)  # 生成整数值种群
    LegV = np.ones((NIND, 1))  # 初始化可行性列向量
    [ObjV, LegV] = aimfuc(Chrom, LegV)  # 计算种群目标函数值
    NDSet = np.zeros((0, Chrom.shape[1]))  # 定义帕累托最优解集合(初始为空集)
    NDSetObjV = np.zeros((0, ObjV.shape[1]))  # 定义帕累托最优解对应的目标函数集合(初始为空集)
    ax = None  # 存储上一桢动画
    start_time = time.time()  # 开始计时
    # 计算初代
    [FitnV, levels] = ga.ndomindeb(maxormin * ObjV, 1, LegV)  # deb非支配分级
    frontIdx = np.where(levels == 1)[0]  # 处在第一级的个体即为种群的非支配个体
    if PUN_F is not None:
        FitnV = punishing(LegV, FitnV)  # 调用罚函数
    # 更新帕累托最优集以及种群非支配个体的适应度
    [FitnV, NDSet, NDSetObjV,
     repnum] = ga.upNDSet(Chrom, maxormin * ObjV, FitnV, NDSet,
                          maxormin * NDSetObjV, frontIdx, LegV)
    NDSetObjV *= maxormin  # 还原在传入upNDSet函数前被最小化处理过的NDSetObjV
    [NDSet, NDSetObjV] = ga.redisNDSet(
        NDSet, NDSetObjV,
        NDSetObjV.shape[1] * MAXSIZE)  # 利用拥挤距离选择帕累托前沿的子集,在进化过程中最好比上限多筛选出几倍的点集
    # 开始进化!!
    for gen in range(MAXGEN):
        # 进行遗传操作!!
        SelCh = ga.recombin(recombinStyle, Chrom, recopt, SUBPOP)  #交叉
        if problem == 'R':
            SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
            if repnum >= Chrom.shape[0] * 0.01:  # 当最优个体重复率高达1%时,进行一次高斯变异
                SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
        elif problem == 'I':
            SelCh = ga.mutint(SelCh, FieldDR, pm)
        [ObjVSel, LegVSel] = aimfuc(SelCh, LegV)  # 求育种个体的目标函数值
        # 父子合并
        Chrom = np.vstack([Chrom, SelCh])
        ObjV = np.vstack([ObjV, ObjVSel])
        LegV = np.vstack([LegV, LegVSel])
        [FitnV, levels] = ga.ndomindeb(maxormin * ObjV, 1, LegV)  # deb非支配分级
        frontIdx = np.where(levels == 1)[0]  # 处在第一级的个体即为种群的非支配个体
        if PUN_F is not None:
            FitnV = punishing(LegV, FitnV)  # 调用罚函数
        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, NDSetObjV,
         repnum] = ga.upNDSet(Chrom, maxormin * ObjV, FitnV, NDSet,
                              maxormin * NDSetObjV, frontIdx, LegV)
        NDSetObjV *= maxormin  # 还原在传入upNDSet函数前被最小化处理过的NDSetObjV
        [NDSet, NDSetObjV
         ] = ga.redisNDSet(NDSet, NDSetObjV, NDSetObjV.shape[1] *
                           MAXSIZE)  # 利用拥挤距离选择帕累托前沿的子集,在进化过程中最好比上限多筛选出几倍的点集
        if distribute == True:  # 若要增强种群的分布性(可能会导致帕累托前沿搜索效率降低)
            # 计算每个目标下相邻个体的距离(不需要严格计算欧氏距离)
            for i in range(ObjV.shape[1]):
                idx = np.argsort(ObjV[:, i], 0)
                dis = np.diff(ObjV[idx, i]) / (
                    np.max(ObjV[idx, i]) - np.min(ObjV[idx, i]) + 1
                )  # 差分计算距离的偏移量占比,即偏移量除以目标函数的极差。加1是为了避免极差为0
                dis = np.hstack([dis, dis[-1]])
                FitnV[idx,
                      0] *= np.exp(dis)  # 根据相邻距离修改适应度,突出相邻距离大的个体,以增加种群的多样性
        [Chrom, ObjV, LegV] = ga.selecting(selectStyle, Chrom, FitnV, GGAP,
                                           SUBPOP, ObjV, LegV)  # 选择出下一代
        if drawing == 2:
            ax = ga.frontplot(NDSetObjV, False, ax, gen + 1)  # 绘制动态图
    end_time = time.time()  # 结束计时
    [NDSet, NDSetObjV] = ga.redisNDSet(NDSet, NDSetObjV,
                                       MAXSIZE)  # 最后根据拥挤距离选择均匀分布的点
    #=========================绘图及输出结果=========================
    if drawing != 0:
        ga.frontplot(NDSetObjV, True)
    times = end_time - start_time
    print('用时:', times, '秒')
    print('帕累托前沿点个数:', NDSet.shape[0], '个')
    print('单位时间找到帕累托前沿点个数:', int(NDSet.shape[0] // times), '个')
    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, NDSetObjV, times]
Exemplo n.º 13
0
def q_sorted_new_templet(AIM_M,
                         AIM_F,
                         PUN_M,
                         PUN_F,
                         FieldDR,
                         problem,
                         maxormin,
                         MAXGEN,
                         MAXSIZE,
                         NIND,
                         SUBPOP,
                         GGAP,
                         selectStyle,
                         recombinStyle,
                         recopt,
                         pm,
                         distribute,
                         drawing=1):
    """
q_sorted_new_templet.py - 基于改进的快速非支配排序法求解多目标优化问题的进化算法模板

语法:
    该函数除参数drawing外,不设置可缺省参数。当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    q_sorted_new_templet(AIM_M, 'aimfuc', None, None, ..., maxormin,...)
      
输入参数:
    AIM_M - 目标函数的地址,由AIM_M = __import__('目标函数所在文件名')语句得到
            目标函数规范定义:f = aimfuc(Phen)
            其中Phen是种群的表现型矩阵
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,由PUN_M = __import__('罚函数所在文件名')语句得到
            罚函数规范定义: f = punishing(Phen, FitnV)
            其中Phen是种群的表现型矩阵, FitnV为种群个体适应度列向量
    
    PUN_F : str - 罚函数名
    
    FieldDR : array - 实际值种群区域描述器
        [lb;		(float) 指明每个变量使用的下界
         ub]		(float) 指明每个变量使用的上界
         注:不需要考虑是否包含变量的边界值。在crtfld中已经将是否包含边界值进行了处理
         本函数生成的矩阵的元素值在FieldDR的[下界, 上界)之间
    
    problem : str - 表明是整数问题还是实数问题,'I'表示是整数问题,'R'表示是实数问题
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    MAXSIZE : int - 帕累托最优集最大规模
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,本模板中该参数为无用参数,仅为了兼容同类模板而设
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    distribute : bool - 是否增强帕累托前沿的分布性(可能会造成收敛慢或帕累托前沿数目减少)
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图,2表示绘制进化过程的动画。
                    默认drawing为1
算法描述:
    本模板维护一个全局帕累托最优集来实现帕累托前沿的搜索
    利用改进快速非支配排序寻找每一代种群的非支配个体,并用它来不断更新全局帕累托最优集,
    改进之处是在进化过程中将父代和子代合并再进行选择,从而实现了经营保留策略
    故并不需要保证种群所有个体都是非支配的

模板使用注意:
    1.本模板调用的目标函数形如:ObjV = aimfuc(Phen), 
      其中Phen表示种群的表现型矩阵
    2.本模板调用的罚函数形如: [newFitnV, exIdx] = punishing(Phen, FitnV), 
      其中FitnV为用其他算法求得的适应度, exIdx为罚函数所找到的不符合约束条件的个体下标行向量
    若不符合上述规范,则请修改模板或自定义新模板
    
"""

    #==========================初始化配置===========================
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    if PUN_F is not None:
        punishing = getattr(PUN_M, PUN_F)  # 获得罚函数
    GGAP = 0.5  # 为了避免父子两代合并后种群数量爆炸,要让代沟为0.5
    ax = None  # 用于存储图形
    exIdx = np.array([])  # 非可行解的下标
    #=========================开始遗传算法进化=======================
    if problem == 'R':
        Chrom = ga.crtrp(NIND, FieldDR)  # 生成实数值种群
    elif problem == 'I':
        Chrom = ga.crtip(NIND, FieldDR)  # 生成整数值种群
    ObjV = aimfuc(Chrom)  # 计算种群目标函数值
    FitnV = np.ones((ObjV.shape[0], 1))  # 初始化适应度(仅是为了使调用罚函数时符合罚函数定义的参数列表)
    if PUN_F is not None:
        [FitnV, exIdx] = punishing(Chrom, FitnV)  # 调用罚函数,不满足约束条件的个体适应度被设为0
    NDSet = np.zeros((0, Chrom.shape[1]))  # 定义帕累托最优解集合(初始为空集)
    NDSetObjV = np.zeros((0, ObjV.shape[1]))  # 定义帕累托最优解对应的目标函数集合(初始为空集)
    start_time = time.time()  # 开始计时
    [FitnV,
     frontIdx] = ga.ndominfast(maxormin * ObjV,
                               exIdx)  # 快速非支配排序,一定要传入FitnV从而对排除考虑不满足约束条件的解
    # 更新帕累托最优集以及种群非支配个体的适应度
    [FitnV, NDSet, NDSetObjV,
     repnum] = ga.upNDSet(Chrom, maxormin * ObjV, FitnV, NDSet,
                          maxormin * NDSetObjV, frontIdx, exIdx)
    # 开始进化!!
    for gen in range(MAXGEN):
        if NDSet.shape[0] > MAXSIZE:
            NDSet = NDSet[0:MAXSIZE, :]
            NDSetObjV = NDSetObjV[0:MAXSIZE, :]
            break
        # 进行遗传操作!!
        SelCh = ga.recombin(recombinStyle, Chrom, recopt, SUBPOP)  #交叉
        if problem == 'R':
            SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
            if repnum >= Chrom.shape[0] * 0.01:  # 当最优个体重复率高达1%时,进行一次高斯变异
                SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
        elif problem == 'I':
            SelCh = ga.mutint(SelCh, FieldDR, pm)
        # 父子合并
        Chrom = np.vstack([Chrom, SelCh])
        ObjV = aimfuc(Chrom)  # 求目标函数值
        FitnV = np.ones(
            (ObjV.shape[0], 1))  # 初始化FitnV(仅是为了使调用罚函数时符合罚函数定义的参数列表)
        if PUN_F is not None:
            [FitnV, exIdx] = punishing(Chrom, FitnV)  # 调用罚函数
        ga.ndomin(maxormin * ObjV, exIdx)
        [FitnV, frontIdx] = ga.ndominfast(maxormin * ObjV, exIdx)  # 快速非支配排序
        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, NDSetObjV,
         repnum] = ga.upNDSet(Chrom, maxormin * ObjV, FitnV, NDSet,
                              maxormin * NDSetObjV, frontIdx, exIdx)
        if distribute == True:  # 若要增强帕累托解集的分布性
            # 计算每个目标下个体的聚集距离(不需要严格计算欧氏距离,计算绝对值即可)
            for i in range(ObjV.shape[1]):
                idx = np.argsort(ObjV[:, i], 0)
                dis = np.abs(np.diff(ObjV[idx, i].T, 1).T) / (
                    np.max(ObjV[idx, i]) - np.min(ObjV[idx, i]) + 1)  # 差分计算距离
                dis = np.hstack([dis, dis[-1]])
                dis = dis + np.min(dis)
                FitnV[idx, 0] *= np.exp(dis)  # 根据聚集距离修改适应度,以增加种群的多样性
        Chrom = ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP)  # 选择出下一代
        if drawing == 2:
            ax = ga.frontplot(NDSetObjV, False, ax, gen + 1)  # 绘制动态图
    end_time = time.time()  # 结束计时
    #=========================绘图及输出结果=========================
    if drawing != 0:
        ga.frontplot(NDSetObjV, True)
    times = end_time - start_time
    print('用时:', times, '秒')
    print('帕累托前沿点个数:', NDSet.shape[0], '个')
    print('单位时间找到帕累托前沿点个数:', int(NDSet.shape[0] // times), '个')
    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, NDSetObjV, times]
Exemplo n.º 14
0
def q_sorted_templet(AIM_M,
                     AIM_F,
                     PUN_M,
                     PUN_F,
                     FieldDR,
                     problem,
                     maxormin,
                     MAXGEN,
                     MAXSIZE,
                     NIND,
                     SUBPOP,
                     GGAP,
                     selectStyle,
                     recombinStyle,
                     recopt,
                     pm,
                     distribute,
                     drawing=1):
    """
q_sorted_templet.py - 基于快速非支配排序法求解多目标优化问题的进化算法模板

语法:
    该函数除参数drawing外,不设置可缺省参数。当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    q_sorted_templet(AIM_M, 'aimfuc', None, None, ..., maxormin,...)

输入参数:
    AIM_M - 目标函数的地址,由AIM_M = __import__('目标函数所在文件名')语句得到
            目标函数规范定义:f = aimfuc(Phen)
            其中Phen是种群的表现型矩阵
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,由PUN_M = __import__('罚函数所在文件名')语句得到
            罚函数规范定义: f = punishing(Phen, FitnV)
            其中Phen是种群的表现型矩阵, FitnV为种群个体适应度列向量
    
    PUN_F : str - 罚函数名
    
    FieldDR : array - 实际值种群区域描述器
        [lb;		(float) 指明每个变量使用的下界
         ub]		(float) 指明每个变量使用的上界
         注:不需要考虑是否包含变量的边界值。在crtfld中已经将是否包含边界值进行了处理
         本函数生成的矩阵的元素值在FieldDR的[下界, 上界)之间
    
    problem : str - 表明是整数问题还是实数问题,'I'表示是整数问题,'R'表示是实数问题
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    MAXSIZE : int - 帕累托最优集最大规模
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,表示子代与父代染色体及性状不相同的概率
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    distribute : bool - 是否增强帕累托前沿的分布性(可能会造成收敛慢或帕累托前沿数目减少)
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图,2表示绘制进化过程的动画。
                    默认drawing为1
算法描述:
    本模板维护一个全局帕累托最优集来实现帕累托前沿的搜索
    利用快速非支配排序寻找每一代种群的非支配个体,并用它来不断更新全局帕累托最优集,
    故并不需要保证种群所有个体都是非支配的
    
"""

    #==========================初始化配置===========================
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    if PUN_F is not None:
        punishing = getattr(PUN_M, PUN_F)  # 获得罚函数
    #=========================开始遗传算法进化=======================
    if problem == 'R':
        Chrom = ga.crtrp(NIND, FieldDR)  # 生成实数值种群
    elif problem == 'I':
        Chrom = ga.crtip(NIND, FieldDR)  # 生成整数值种群
    ObjV = aimfuc(Chrom)  # 计算种群目标函数值
    NDSet = np.zeros((0, Chrom.shape[1]))  # 定义帕累托最优解记录器
    NDSetObjV = np.zeros((0, ObjV.shape[1]))  # 定义帕累托最优解的目标函数值记录器
    ax = None
    start_time = time.time()  # 开始计时
    # 开始进化!!
    for gen in range(MAXGEN):
        if NDSet.shape[0] > MAXSIZE:
            break
        # 求种群的非支配个体以及基于被支配数的适应度
        [FitnV, frontIdx] = ga.ndominfast(maxormin * ObjV)
        if PUN_F is not None:
            FitnV = punishing(Chrom, FitnV)  # 调用罚函数
        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, NDSetObjV,
         repnum] = ga.upNDSet(Chrom, maxormin * ObjV, FitnV, NDSet,
                              maxormin * NDSetObjV, frontIdx)
        if distribute == True:  # 若要增强帕累托解集的分布性
            # 计算每个目标下个体的聚集距离(不需要严格计算欧氏距离,计算绝对值即可)
            for i in range(ObjV.shape[1]):
                idx = np.argsort(ObjV[:, i], 0)
                dis = np.abs(np.diff(ObjV[idx, i].T, 1).T) / (
                    np.max(ObjV[idx, i]) - np.min(ObjV[idx, i]) + 1)  # 差分计算距离
                dis = np.hstack([dis, dis[-1]])
                dis = dis + np.min(dis)
                FitnV[idx, 0] *= np.exp(dis)  # 根据聚集距离修改适应度,以增加种群的多样性
        # 进行遗传操作!!
        SelCh = ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP)  # 选择
        SelCh = ga.recombin(recombinStyle, SelCh, recopt, SUBPOP)  #交叉
        if problem == 'R':
            SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
            if repnum > Chrom.shape[0] * 0.01:  # 当最优个体重复率高达1%时,进行一次高斯变异
                SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
        elif problem == 'I':
            SelCh = ga.mutint(SelCh, FieldDR, pm)
        ObjVSel = aimfuc(SelCh)  # 求育种个体的目标函数值
        # 求种群的非支配个体以及基于被支配数的适应度
        [FitnVSel, frontIdx] = ga.ndominfast(maxormin * ObjVSel)
        [Chrom, ObjV] = ga.reins(Chrom, SelCh, SUBPOP, 1, 0.9, FitnV, FitnVSel,
                                 ObjV, ObjVSel)  #重插入
        if drawing == 2:
            ax = ga.frontplot(NDSetObjV, False, ax, gen + 1)  # 绘制动态图
    end_time = time.time()  # 结束计时
    #=========================绘图及输出结果=========================
    if drawing != 0:
        ga.frontplot(NDSetObjV, True)
    times = end_time - start_time
    print('用时:', times, '秒')
    print('帕累托前沿点个数:', NDSet.shape[0], '个')
    print('单位时间找到帕累托前沿点个数:', int(NDSet.shape[0] // times), '个')
    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, NDSetObjV, end_time - start_time]
Exemplo n.º 15
0
def sga_real_templet(AIM_M,
                     AIM_F,
                     PUN_M,
                     PUN_F,
                     FieldDR,
                     problem,
                     maxormin,
                     MAXGEN,
                     NIND,
                     SUBPOP,
                     GGAP,
                     selectStyle,
                     recombinStyle,
                     recopt,
                     pm,
                     distribute,
                     drawing=1):
    """
sga_real_templet.py - 单目标编程模板(实值编码)

语法:
    该函数除了参数drawing外,不设置可缺省参数。当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    sga_real_templet(AIM_M, 'aimfuc', None, None, ..., maxormin)

输入参数:
    AIM_M - 目标函数的地址,由AIM_M = __import__('目标函数所在文件名')语句得到
            目标函数规范定义:[f,LegV] = aimfuc(Phen,LegV)
            其中Phen是种群的表现型矩阵, LegV为种群的可行性列向量,f为种群的目标函数值矩阵
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,由PUN_M = __import__('罚函数所在文件名')语句得到
            罚函数规范定义: newFitnV = punishing(LegV, FitnV)
            其中LegV为种群的可行性列向量, FitnV为种群个体适应度列向量
            一般在罚函数中对LegV为0的个体进行适应度惩罚,返回修改后的适应度列向量newFitnV
    
    PUN_F : str - 罚函数名
    
    FieldDR : array - 实际值种群区域描述器
        [lb;		(float) 指明每个变量使用的下界
         ub]		(float) 指明每个变量使用的上界
         注:不需要考虑是否包含变量的边界值。在crtfld中已经将是否包含边界值进行了处理
         本函数生成的矩阵的元素值在FieldDR的[下界, 上界)之间
    
    problem : str - 表明是整数问题还是实数问题,'I'表示是整数问题,'R'表示是实数问题                 
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,表示子代与父代染色体及性状不相同的概率
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    distribute : bool - 是否增强种群的分布性(可能会造成收敛慢)
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图。默认drawing为1

输出参数:
    pop_trace : array - 种群进化记录器(进化追踪器),
                        第0列记录着各代种群最优个体的目标函数值
                        第1列记录着各代种群的适应度均值
                        第2列记录着各代种群最优个体的适应度值
    
    var_trace : array - 变量记录器,记录着各代种群最优个体的变量值,每一列对应一个控制变量
    
    times     : float - 进化所用时间

模板使用注意:
    1.本模板调用的目标函数形如:[ObjV,LegV] = aimfuc(Phen,LegV), 
      其中Phen表示种群的表现型矩阵, LegV为种群的可行性列向量(详见Geatpy数据结构)
    2.本模板调用的罚函数形如: newFitnV = punishing(LegV, FitnV), 
      其中FitnV为用其他算法求得的适应度
    若不符合上述规范,则请修改算法模板或自定义新算法模板
    3.关于'maxormin': geatpy的内核函数全是遵循“最小化目标”的约定的,即目标函数值越小越好。
      当需要优化最大化的目标时,需要设置'maxormin'为-1。
      本算法模板是正确使用'maxormin'的典型范例,其具体用法如下:
      当调用的函数传入参数包含与“目标函数值矩阵”有关的参数(如ObjV,ObjVSel,NDSetObjV等)时,
      查看该函数的参考资料(可用'help'命令查看,也可到官网上查看相应的教程),
      里面若要求传入前对参数乘上'maxormin',则需要乘上。
      里面若要求对返回参数乘上'maxormin'进行还原,
      则调用函数返回得到的相应参数需要乘上'maxormin'进行还原,否则其正负号就会被改变。

"""
    """==========================初始化配置==========================="""
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    if PUN_F is not None:
        punishing = getattr(PUN_M, PUN_F)  # 获得罚函数
    NVAR = FieldDR.shape[1]  # 得到控制变量的个数
    # 定义进化记录器,初始值为nan
    pop_trace = (np.zeros((MAXGEN, 2)) * np.nan)
    # 定义变量记录器,记录控制变量值,初始值为nan
    var_trace = (np.zeros((MAXGEN, NVAR)) * np.nan)
    ax = None  # 存储上一帧图形
    repnum = 0  # 初始化重复个体数为0
    """=========================开始遗传算法进化======================="""
    if problem == 'R':
        Chrom = ga.crtrp(NIND, FieldDR)  # 生成初始种群
    elif problem == 'I':
        Chrom = ga.crtip(NIND, FieldDR)
    LegV = np.ones((NIND, 1))  # 初始化种群的可行性列向量
    [ObjV, LegV] = aimfuc(Chrom, LegV)  # 求种群的目标函数值
    gen = 0
    badCounter = 0  # 用于记录在“遗忘策略下”被忽略的代数
    # 开始进化!!
    start_time = time.time()  # 开始计时
    while gen < MAXGEN:
        if badCounter >= 10 * MAXGEN:  # 若多花了10倍的迭代次数仍没有可行解出现,则跳出
            break
        FitnV = ga.ranking(maxormin * ObjV, LegV, None, SUBPOP)
        if PUN_F is not None:
            FitnV = punishing(LegV, FitnV)  # 调用罚函数
        # 记录进化过程
        bestIdx = np.argmax(FitnV)  # 获取最优个体的下标
        if LegV[bestIdx] != 0:
            feasible = np.where(LegV != 0)[0]  # 排除非可行解
            pop_trace[gen, 0] = np.sum(
                ObjV[feasible]) / ObjV[feasible].shape[0]  # 记录种群个体平均目标函数值
            pop_trace[gen, 1] = ObjV[bestIdx]  # 记录当代目标函数的最优值
            var_trace[gen, :] = Chrom[bestIdx, :]  # 记录当代最优的控制变量值
            repnum = len(
                np.where(ObjV[np.argmax(FitnV)] == ObjV)[0])  # 计算最优个体重复数
            # 绘制动态图
            if drawing == 2:
                ax = ga.sgaplot(pop_trace[:, [1]], '种群最优个体目标函数值', False, ax,
                                gen)
            badCounter = 0  # badCounter计数器清零
        else:
            gen -= 1  # 忽略这一代(遗忘策略)
            badCounter += 1
        if distribute == True:  # 若要增强种群的分布性(可能会造成收敛慢)
            idx = np.argsort(ObjV[:, 0], 0)
            dis = np.diff(ObjV[idx, 0]) / (np.max(ObjV[idx, 0]) - np.min(
                ObjV[idx, 0]) + 1)  # 差分计算距离的修正偏移量
            dis = np.hstack([dis, dis[-1]])
            dis = dis + np.min(dis)  # 修正偏移量+最小量=修正绝对量
            FitnV[idx, 0] *= np.exp(dis)  # 根据相邻距离修改适应度,突出相邻距离大的个体,以增加种群的多样性
        # 进行遗传算子
        SelCh = ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP)  # 选择
        SelCh = ga.recombin(recombinStyle, SelCh, recopt, SUBPOP)  # 对所选个体进行重组
        if problem == 'R':
            SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
            if repnum > Chrom.shape[0] * 0.01:  # 当最优个体重复率高达1%时,进行一次高斯变异
                SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
        elif problem == 'I':
            SelCh = ga.mutint(SelCh, FieldDR, pm)
        LegVSel = np.ones((SelCh.shape[0], 1))  # 初始化育种种群的可行性列向量
        [ObjVSel, LegVSel] = aimfuc(SelCh, LegVSel)  # 求育种种群的目标函数值
        FitnVSel = ga.ranking(maxormin * ObjVSel, LegVSel, None,
                              SUBPOP)  # 计算育种种群的适应度
        if PUN_F is not None:
            FitnVSel = punishing(LegVSel, FitnVSel)  # 调用罚函数
        # 重插入
        [Chrom, ObjV, LegV] = ga.reins(Chrom, SelCh, SUBPOP, 1, 1, FitnV,
                                       FitnVSel, ObjV, ObjVSel, LegV, LegVSel)
        gen += 1
    end_time = time.time()  # 结束计时
    times = end_time - start_time
    # 后处理进化记录器
    delIdx = np.where(np.isnan(pop_trace))[0]
    pop_trace = np.delete(pop_trace, delIdx, 0)
    var_trace = np.delete(var_trace, delIdx, 0)
    if pop_trace.shape[0] == 0:
        raise RuntimeError('error: no feasible solution. (有效进化代数为0,没找到可行解。)')
    # 绘图
    if drawing != 0:
        ga.trcplot(pop_trace, [['种群个体平均目标函数值', '种群最优个体目标函数值']])
    # 输出结果
    if maxormin == 1:
        best_gen = np.argmin(pop_trace[:, 1])  # 记录最优种群是在哪一代
        best_ObjV = np.min(pop_trace[:, 1])
    elif maxormin == -1:
        best_gen = np.argmax(pop_trace[:, 1])  # 记录最优种群是在哪一代
        best_ObjV = np.max(pop_trace[:, 1])
    print('最优的目标函数值为:%s' % (best_ObjV))
    print('最优的控制变量值为:')
    for i in range(NVAR):
        print(var_trace[best_gen, i])
    print('有效进化代数:%s' % (pop_trace.shape[0]))
    print('最优的一代是第 %s 代' % (best_gen + 1))
    print('时间已过 %s 秒' % (times))
    # 返回进化记录器、变量记录器以及执行时间
    return [pop_trace, var_trace, times]
Exemplo n.º 16
0
def nsga2_templet(AIM_M,
                  AIM_F,
                  PUN_M,
                  PUN_F,
                  FieldDR,
                  problem,
                  maxormin,
                  MAXGEN,
                  MAXSIZE,
                  NIND,
                  SUBPOP,
                  GGAP,
                  selectStyle,
                  recombinStyle,
                  recopt,
                  pm,
                  distribute,
                  drawing=1):
    """
nsga2_templet.py - 基于改进NSGA-Ⅱ算法求解多目标优化问题的进化算法模板

语法:
    该函数除参数drawing外,不设置可缺省参数。当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    nsga2_templet(AIM_M, 'aimfuc', None, None, ..., maxormin,...)
    
输入参数:
    AIM_M - 目标函数的地址,由AIM_M = __import__('目标函数所在文件名')语句得到
            目标函数规范定义:f = aimfuc(Phen)
            其中Phen是种群的表现型矩阵
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,由PUN_M = __import__('罚函数所在文件名')语句得到
            罚函数规范定义: f = punishing(Phen, FitnV)
            其中Phen是种群的表现型矩阵, FitnV为种群个体适应度列向量
    
    PUN_F : str - 罚函数名
    
    FieldDR : array - 实际值种群区域描述器
        [lb;		(float) 指明每个变量使用的下界
         ub]		(float) 指明每个变量使用的上界
         注:不需要考虑是否包含变量的边界值。在crtfld中已经将是否包含边界值进行了处理
         本函数生成的矩阵的元素值在FieldDR的[下界, 上界)之间
    
    problem : str - 表明是整数问题还是实数问题,'I'表示是整数问题,'R'表示是实数问题
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    MAXSIZE : int - 帕累托最优集最大规模
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,本模板中该参数为无用参数,仅为了兼容同类模板而设
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    distribute : bool - 是否增强帕累托前沿的分布性(可能会造成收敛慢或帕累托前沿数目减少)
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图,2表示绘制进化过程的动画。
                    默认drawing为1
算法描述:
    传统NSGA-Ⅱ算法的帕累托最优解来只源于当代种群个体,这样难以高效地获取更多的帕累托最优解
    同时难以把种群大小控制在合适的范围内,
    改进的NSGA2整体上沿用传统的NSGA-Ⅱ算法,
    不同的是,该算法通过维护一个全局帕累托最优集来实现帕累托前沿的搜索,
    故并不需要保证种群所有个体都是非支配的。
    
值得注意的是:
    尽管当全局帕累托最优集大小比种群规模大时,算法的时间复杂度比原NSGA-Ⅱ算法要高,
    但算法整体的时间复杂度要低与原NSGA-Ⅱ算法,
    因此单位时间内生成的无重复帕累托最优解个数要多于原NSGA-Ⅱ算法
    
"""
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    if PUN_F is not None:
        punishing = getattr(PUN_M, PUN_F)  # 获得罚函数
    #==========================初始化配置===========================
    GGAP = 0.5  # 为了避免父子两代合并后种群数量爆炸,要让代沟为0.5
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    #=========================开始遗传算法进化=======================
    if problem == 'R':
        Chrom = ga.crtrp(NIND, FieldDR)  # 生成实数值种群
    elif problem == 'I':
        Chrom = ga.crtip(NIND, FieldDR)  # 生成整数值种群
    ObjV = aimfuc(Chrom)  # 计算种群目标函数值
    NDSet = np.zeros((0, Chrom.shape[1]))  # 定义帕累托最优解集合(初始为空集)
    NDSetObjV = np.zeros((0, ObjV.shape[1]))  # 定义帕累托最优解对应的目标函数集合(初始为空集)
    ax = None
    start_time = time.time()  # 开始计时
    [FitnV, levels] = ga.ndomindeb(maxormin * ObjV, 1)  # deb非支配分级
    if PUN_F is not None:
        FitnV = punishing(Chrom, FitnV)  # 调用罚函数
    frontIdx = np.where(levels == 1)[0]  # 处在第一级的个体即为种群的非支配个体
    # 更新帕累托最优集以及种群非支配个体的适应度
    [FitnV, NDSet, NDSetObjV,
     repnum] = ga.upNDSet(Chrom, maxormin * ObjV, FitnV, NDSet,
                          maxormin * NDSetObjV, frontIdx)
    # 开始进化!!
    for gen in range(MAXGEN):
        if NDSet.shape[0] > MAXSIZE:
            break
        # 进行遗传操作!!
        SelCh = ga.recombin(recombinStyle, Chrom, recopt, SUBPOP)  #交叉
        if problem == 'R':
            SelCh = ga.mutbga(SelCh, FieldDR, pm)  # 变异
            if repnum >= Chrom.shape[0] * 0.01:  # 当最优个体重复率高达1%时,进行一次高斯变异
                SelCh = ga.mutgau(SelCh, FieldDR, pm)  # 高斯变异
        elif problem == 'I':
            SelCh = ga.mutint(SelCh, FieldDR, pm)
        # 父子合并
        Chrom = np.vstack([Chrom, SelCh])
        ObjV = aimfuc(Chrom)  # 求目标函数值
        [FitnV, levels] = ga.ndomindeb(maxormin * ObjV, 1)  # deb非支配分级
        if PUN_F is not None:
            FitnV = punishing(Chrom, FitnV)  # 调用罚函数
        frontIdx = np.where(levels == 1)[0]  # 处在第一级的个体即为种群的非支配个体
        # 更新帕累托最优集以及种群非支配个体的适应度
        [FitnV, NDSet, NDSetObjV,
         repnum] = ga.upNDSet(Chrom, maxormin * ObjV, FitnV, NDSet,
                              maxormin * NDSetObjV, frontIdx)
        if distribute == True:  # 若要增强帕累托解集的分布性
            # 计算每个目标下个体的聚集距离(不需要严格计算欧氏距离,计算绝对值即可)
            for i in range(ObjV.shape[1]):
                idx = np.argsort(ObjV[:, i], 0)
                dis = np.abs(np.diff(ObjV[idx, i].T, 1).T) / (
                    np.max(ObjV[idx, i]) - np.min(ObjV[idx, i]) + 1)  # 差分计算距离
                dis = np.hstack([dis, dis[-1]])
                dis = dis + np.min(dis)
                FitnV[idx, 0] *= np.exp(dis)  # 根据聚集距离修改适应度,以增加种群的多样性
        Chrom = ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP)  # 选择出下一代
        if drawing == 2:
            ax = ga.frontplot(NDSetObjV, False, ax, gen + 1)  # 绘制动态图
    end_time = time.time()  # 结束计时
    #=========================绘图及输出结果=========================
    if drawing != 0:
        ga.frontplot(NDSetObjV, True)
    times = end_time - start_time
    print('用时:', times, '秒')
    print('帕累托前沿点个数:', NDSet.shape[0], '个')
    print('单位时间找到帕累托前沿点个数:', int(NDSet.shape[0] // times), '个')
    # 返回帕累托最优集以及执行时间
    return [ObjV, NDSet, NDSetObjV, times]
Exemplo n.º 17
0
def sga_mpc_real_templet(AIM_M,
                         AIM_F,
                         PUN_M,
                         PUN_F,
                         FieldDRs,
                         problem,
                         maxormin,
                         MAXGEN,
                         NIND,
                         SUBPOP,
                         GGAP,
                         selectStyle,
                         recombinStyle,
                         recopt,
                         pm,
                         distribute,
                         drawing=1):
    """
sga_mpc_real_templet.py - 基于多种群竞争进化单目标编程模板(实值编码)

基于多种群竞争进化单目标编程模板(实值编码),多种群之间加入竞争,同时各种群独立进化

语法:
    该函数除了drawing外,不设置可缺省参数。当某个参数需要缺省时,在调用函数时传入None即可。
    比如当没有罚函数时,则在调用编程模板时将第3、4个参数设置为None即可,如:
    sga_mpc_real_templet(AIM_M, 'aimfuc', None, None, ..., maxormin)

输入参数:
    AIM_M - 目标函数的地址,由AIM_M = __import__('目标函数所在文件名')语句得到
            目标函数规范定义:[f,LegV] = aimfuc(Phen,LegV)
            其中Phen是种群的表现型矩阵, LegV为种群的可行性列向量,f为种群的目标函数值矩阵
    
    AIM_F : str - 目标函数名
    
    PUN_M - 罚函数的地址,由PUN_M = __import__('罚函数所在文件名')语句得到
            罚函数规范定义: newFitnV = punishing(LegV, FitnV)
            其中LegV为种群的可行性列向量, FitnV为种群个体适应度列向量
            一般在罚函数中对LegV为0的个体进行适应度惩罚,返回修改后的适应度列向量newFitnV
    
    PUN_F : str - 罚函数名
    
    FieldDR : array - 实际值种群区域描述器
        [lb;		(float) 指明每个变量使用的下界
         ub]		(float) 指明每个变量使用的上界
         注:不需要考虑是否包含变量的边界值。在crtfld中已经将是否包含边界值进行了处理
         本函数生成的矩阵的元素值在FieldDR的[下界, 上界)之间
    
    problem : str - 表明是整数问题还是实数问题,'I'表示是整数问题,'R'表示是实数问题                 
    
    maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化
    
    MAXGEN : int - 最大遗传代数
    
    NIND : int - 种群规模,即种群中包含多少个个体
    
    SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群
    
    GGAP : float - 代沟,本模板中该参数为无用参数,仅为了兼容同类的其他模板而设
    
    selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)
    
    recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)
    
    recopt : float - 交叉概率
    
    pm : float - 重组概率
    
    distribute : bool - 是否增强种群的分布性(可能会造成收敛慢)
    
    drawing : int - (可选参数),0表示不绘图,1表示绘制最终结果图。默认drawing为1

输出参数:
    pop_trace : array - 种群进化记录器(进化追踪器),
                        第0列记录着各代种群最优个体的目标函数值
                        第1列记录着各代种群的适应度均值
                        第2列记录着各代种群最优个体的适应度值
    
    var_trace : array - 变量记录器,记录着各代种群最优个体的变量值,每一列对应一个控制变量
    
    times     : float - 进化所用时间

模板使用注意:
    1.本模板调用的目标函数形如:[ObjV,LegV] = aimfuc(Phen,LegV), 
      其中Phen表示种群的表现型矩阵, LegV为种群的可行性列向量(详见Geatpy数据结构)
    2.本模板调用的罚函数形如: newFitnV = punishing(LegV, FitnV), 
      其中FitnV为用其他算法求得的适应度
    若不符合上述规范,则请修改算法模板或自定义新算法模板
    3.关于'maxormin': geatpy的内核函数全是遵循“最小化目标”的约定的,即目标函数值越小越好。
      当需要优化最大化的目标时,需要设置'maxormin'为-1。
      本算法模板是正确使用'maxormin'的典型范例,其具体用法如下:
      当调用的函数传入参数包含与“目标函数值矩阵”有关的参数(如ObjV,ObjVSel,NDSetObjV等)时,
      查看该函数的参考资料(可用'help'命令查看,也可到官网上查看相应的教程),
      里面若要求传入前对参数乘上'maxormin',则需要乘上。
      里面若要求对返回参数乘上'maxormin'进行还原,
      则调用函数返回得到的相应参数需要乘上'maxormin'进行还原,否则其正负号就会被改变。
      
"""
    """==========================初始化配置==========================="""
    GGAP = 0.5  # 因为父子合并后选择,因此要将代沟设为0.5以维持种群规模
    # 获取目标函数和罚函数
    aimfuc = getattr(AIM_M, AIM_F)  # 获得目标函数
    if PUN_F is not None:
        punishing = getattr(PUN_M, PUN_F)  # 获得罚函数
    NVAR = FieldDRs[0].shape[1]  # 得到控制变量的个数
    # 定义全局进化记录器,初始值为nan
    pop_trace = (np.zeros((MAXGEN, 2)) * np.nan)
    pop_trace[:, 0] = 0
    # 定义变量记录器,记录控制变量值,初始值为nan
    var_trace = (np.zeros((MAXGEN, NVAR)) * np.nan)
    ax = None  # 存储上一帧图形
    """=========================开始遗传算法进化======================="""
    Chroms = []  # 存储所有子种群的染色体
    LegVs = []  # 存储所有子种群的可行性列向量
    ObjVs = []  # 存储所有子种群的目标函数值
    repnums = [0] * len(FieldDRs)  # 初始化重复个体数为0
    for index in range(len(FieldDRs)):
        if problem == 'R':
            Chrom = ga.crtrp(NIND, FieldDRs[index])  # 生成初始种群
        elif problem == 'I':
            Chrom = ga.crtip(NIND, FieldDRs[index])
        # 初始化相关变量
        Chroms.append(Chrom)
        LegV = np.ones((NIND, 1))  # 初始化初代种群的可行性列向量
        [ObjV, LegV] = aimfuc(Chrom, LegV)  # 求初始种群的目标函数值
        ObjVs.append(ObjV)
        LegVs.append(LegV)
    gen = 0
    badCounter = 0  # 用于记录在“遗忘策略下”被忽略的代数
    # 开始进化!!
    start_time = time.time()  # 开始计时
    while gen < MAXGEN:
        if badCounter >= 10 * MAXGEN:  # 若多花了10倍的迭代次数仍没有可行解出现,则跳出
            break
        allChroms = np.zeros((NVAR, 0)).T  # 存储所有子种群父子合并的染色体
        allObjVs = np.zeros((1, 0)).T  # 存储所有子种群父子合并的目标函数值
        allLegVs = np.zeros((1, 0)).T  # 存储所有子种群父子合并的可行性列向量
        if problem == 'R':
            for index in range(len(FieldDRs)):  # 遍历各个子种群
                Chrom = Chroms[index]  # 取某个子种群的Chrom
                ObjV = ObjVs[index]  # 取某个子种群的ObjV
                LegV = LegVs[index]  # 取某个子种群的LegV
                # 进行遗传算子,生成子代
                SelCh = ga.recombin(recombinStyle, Chrom, recopt, SUBPOP)  # 重组
                SelCh = ga.mutbga(SelCh, FieldDRs[index], pm)  # 变异
                if repnums[index] > Chrom.shape[
                        0] * 0.01:  # 当最优个体重复率高达1%时,进行一次高斯变异
                    SelCh = ga.mutgau(SelCh, FieldDRs[index], pm)  # 高斯变异
                LegVSel = np.ones((SelCh.shape[0], 1))  # 初始化育种种群的可行性列向量
                [ObjVSel, LegVSel] = aimfuc(SelCh, LegVSel)
                # 父子合并
                Chrom = np.vstack([Chrom, SelCh])
                ObjV = np.vstack([ObjV, ObjVSel])
                LegV = np.vstack([LegV, LegVSel])
                allChroms = np.vstack([allChroms, Chrom])
                allObjVs = np.vstack([allObjVs, ObjV])
                allLegVs = np.vstack([allLegVs, LegV])
        elif problem == 'I':
            for index in range(len(FieldDRs)):
                Chrom = Chroms[index]
                # 进行遗传算子,生成子代
                SelCh = ga.recombin(recombinStyle, Chrom, recopt, SUBPOP)  # 重组
                SelCh = ga.mutint(SelCh, FieldDRs[index], pm)  # 变异
                LegVSel = np.ones((SelCh.shape[0], 1))  # 初始化育种种群的可行性列向量
                [ObjVSel, LegVSel] = aimfuc(SelCh, LegVSel)  # 计算育种种群的目标函数值
                # 父子合并
                Chrom = np.vstack([Chrom, SelCh])
                ObjV = np.vstack([ObjV, ObjVSel])
                LegV = np.vstack([LegV, LegVSel])
                allChroms = np.vstack([allChroms, Chrom])
                allObjVs = np.vstack([allObjVs, ObjV])
                allLegVs = np.vstack([allLegVs, LegV])
        allFitnVs = ga.ranking(maxormin * allObjVs, allLegVs, None,
                               SUBPOP)  # 计算所有子种群的适应度
        if PUN_F is not None:
            allFitnVs = punishing(allLegVs, allFitnVs)  # 调用罚函数
        # 记录进化过程
        bestIdx = np.argmax(allFitnVs)
        if allLegVs[bestIdx] != 0:
            feasible = np.where(allLegVs != 0)[0]  # 排除非可行解
            pop_trace[gen, 0] = np.sum(
                allObjVs[feasible]) / allObjVs[feasible].shape[0]
            pop_trace[gen, 1] = allObjVs[bestIdx]
            var_trace[gen, :] = allChroms[bestIdx]
            # 绘制动态图
            if drawing == 2:
                ax = ga.sgaplot(pop_trace[:, [1]], '种群最优个体目标函数值', False, ax,
                                gen)
            badCounter = 0  # badCounter计数器清零
        else:
            gen -= 1  # 忽略这一代(遗忘策略)
            badCounter += 1
        # 最后对合并的种群进行适应度评价并选出一半个体留到下一代(加入竞争的适应度评价)
        for index in range(len(FieldDRs)):
            Chrom = allChroms[index * NIND:(index + 2) * NIND]
            FitnV = allFitnVs[index * NIND:(index + 2) * NIND]
            ObjV = allObjVs[index * NIND:(index + 2) * NIND]
            LegV = allLegVs[index * NIND:(index + 2) * NIND]
            repnums[index] = len(
                np.where(FitnV[np.argmax(FitnV)] == FitnV)[0])  # 计算最优个体重复数
            if distribute == True:  # 若要增强种群的分布性(可能会造成收敛慢)
                idx = np.argsort(ObjV[:, 0], 0)
                dis = np.diff(ObjV[idx, 0]) / (np.max(ObjV[idx, 0]) - np.min(
                    ObjV[idx, 0]) + 1)  # 差分计算距离的修正偏移量
                dis = np.hstack([dis, dis[-1]])
                dis = dis + np.min(dis)  # 修正偏移量+最小量=修正绝对量
                FitnV[idx,
                      0] *= np.exp(dis)  # 根据相邻距离修改适应度,突出相邻距离大的个体,以增加种群的多样性
            [Chroms[index], ObjVs[index],
             LegVs[index]] = ga.selecting(selectStyle, Chrom, FitnV, GGAP,
                                          SUBPOP, ObjV, LegV)  # 选择
        gen += 1
    end_time = time.time()  # 结束计时
    times = end_time - start_time
    # 后处理进化记录器
    delIdx = np.where(np.isnan(pop_trace))[0]
    pop_trace = np.delete(pop_trace, delIdx, 0)
    var_trace = np.delete(var_trace, delIdx, 0)
    if pop_trace.shape[0] == 0:
        raise RuntimeError('error: no feasible solution. (有效进化代数为0,没找到可行解。)')
    # 绘图
    if drawing != 0:
        ga.trcplot(pop_trace, [['种群个体平均目标函数值', '种群最优个体目标函数值']])
    # 输出结果
    if maxormin == 1:
        best_gen = np.argmin(pop_trace[:, 1])  # 记录最优种群是在哪一代
        best_ObjV = np.min(pop_trace[:, 1])
    elif maxormin == -1:
        best_gen = np.argmax(pop_trace[:, 1])  # 记录最优种群是在哪一代
        best_ObjV = np.max(pop_trace[:, 1])
    print('最优的目标函数值为:%f' % (best_ObjV))
    print('最优的控制变量值为:')
    for i in range(NVAR):
        print(var_trace[best_gen, i])
    print('有效进化代数:%d' % (pop_trace.shape[0]))
    print('最优的一代是第 %d 代' % (best_gen + 1))
    print('时间已过 %f 秒' % (times))
    # 返回进化记录器、变量记录器以及执行时间
    return [pop_trace, var_trace, times]