def run(self, prophetPop = None): # prophetPop为先知种群(即包含先验知识的种群) #==========================初始化配置=========================== population = self.population self.initialization() # 初始化算法模板的一些动态参数 #===========================准备进化============================ uniformPoint, NIND = ea.crtup(self.problem.M, population.sizes) # 生成在单位目标维度上均匀分布的参考点集 population.initChrom(NIND) # 初始化种群染色体矩阵,此时种群规模将调整为uniformPoint点集的大小,initChrom函数会把种群规模给重置 self.call_aimFunc(population) # 计算种群的目标函数值 # 插入先验知识(注意:这里不会对先知种群prophetPop的合法性进行检查,故应确保prophetPop是一个种群类且拥有合法的Chrom、ObjV、Phen等属性) if prophetPop is not None: population = (prophetPop + population)[:NIND] # 插入先知种群 # 确定邻域大小 if self.neighborSize is None: self.neighborSize = population.sizes self.neighborSize = max(self.neighborSize, 2) # 确保不小于2 # 生成由所有邻居索引组成的矩阵 neighborIdx = np.argsort(cdist(uniformPoint, uniformPoint), axis=1, kind='mergesort')[:, :self.neighborSize] # 计算理想点 idealPoint = ea.crtidp(population.ObjV, population.CV, self.problem.maxormins) # 创建全局存档 if self.MAXSIZE is None: self.MAXSIZE = 10 * population.sizes # 默认为10倍的种群个体数 [levels, criLevel] = ea.ndsortDED(population.ObjV, NIND, None, population.CV, self.problem.maxormins) # 对NIND个个体进行非支配分层 globalNDSet = population[np.where(levels == 1)[0]] # 创建全局存档,该全局存档贯穿进化始终,随着进化不断更新 if globalNDSet.CV is not None: # CV不为None说明有设置约束条件 globalNDSet = globalNDSet[np.where(np.all(globalNDSet.CV <= 0, 1))[0]] # 排除非可行解 #===========================开始进化============================ while self.terminated(population) == False: select_rands = np.random.rand(population.sizes) # 生成一组随机数 for i in range(population.sizes): indices = neighborIdx[i, :] # 得到邻居索引 if select_rands[i] < self.Ps: chooseIdx = indices[ea.rps(self.neighborSize, 2)] # 只从邻域中选择 else: chooseIdx = ea.rps(population.sizes, 2) matting_Chrom = population.Chrom[chooseIdx, :] # 选出2条来自被选个体的染色体 offspring = ea.Population(population.Encoding, population.Field, 1) # 实例化一个种群对象用于存储进化的后代(这里只进化生成一个后代) # 对选出的个体进行进化操作 offspring.Chrom = self.recOper.do(matting_Chrom) # 重组 offspring.Chrom = self.mutOper.do(offspring.Encoding, offspring.Chrom, offspring.Field) # 变异 self.call_aimFunc(offspring) # 求进化后个体的目标函数值 # 更新理想点 idealPoint = ea.crtidp(offspring.ObjV, offspring.CV, self.problem.maxormins, idealPoint) # 重插入更新种群个体 self.reinsertion(indices, population, offspring, idealPoint, uniformPoint) # 完成当代的进化后,更新全局存档 globalNDSet = population + globalNDSet # 将population与全局归档集合并 [levels, criLevel] = ea.ndsortDED(globalNDSet.ObjV, None, None, globalNDSet.CV, self.problem.maxormins) # 非支配排序 globalNDSet = globalNDSet[np.where(levels == 1)[0]] if globalNDSet.CV is not None: # CV不为None说明有设置约束条件 globalNDSet = globalNDSet[np.where(np.all(globalNDSet.CV <= 0, 1))[0]] # 排除非可行解 if globalNDSet.sizes > self.MAXSIZE: globalNDSet = globalNDSet[ea.rps(globalNDSet.sizes, self.MAXSIZE)] # 采用rps随机排列选择,控制全局存档的大小 self.passTime += time.time() - self.timeSlot # 更新用时记录 #=========================绘图及输出结果========================= if self.drawing != 0: ea.moeaplot(globalNDSet.ObjV, 'Pareto Front', saveFlag = True, gridFlag = True) # 返回帕累托最优集 return globalNDSet
def finishing(self, population): """ 进化完成后调用的函数 """ # 得到非支配种群 [levels, criLevel] = ea.ndsortDED(self.problem.maxormins * population.ObjV, None, 1, population.CV) # 非支配分层 NDSet = population[np.where(levels == 1)[0]] # 只保留种群中的非支配个体,形成一个非支配种群 if NDSet.CV is not None: # CV不为None说明有设置约束条件 NDSet = NDSet[np.where(np.all(NDSet.CV <= 0, 1))[0]] # 最后要彻底排除非可行解 self.passTime += time.time() - self.timeSlot # 更新用时记录 # 绘图 if self.drawing != 0: if NDSet.ObjV.shape[1] == 2 or NDSet.ObjV.shape[1] == 3: ea.moeaplot(NDSet.ObjV, 'Pareto Front', saveFlag=True, gridFlag=True) else: ea.moeaplot(NDSet.ObjV, 'Value Path', saveFlag=True, gridFlag=False) # 返回帕累托最优集 return NDSet
def updateNDSet(population, maxormins, MAXSIZE, NDSet=None): """ 描述: 用于计算种群个体的适应度及更新全局非支配种群。 输入参数: population : Population - 种群对象。 maxormins : list - 优化目标的最大最小化标记列表。 MAXSIZE : int - 示全局非支配个体的最大数目。 NDSet : Population - (可选参数)全局非支配个体, 若缺省或为None时,NDSet为所传入种群的非支配个体组成的种群。 输出参数: NDSet : Population - (可选参数)全局非支配种群。 种群适应度FitnV已经在函数中进行更新,因此这该参数不用返回。 """ ObjV = maxormins * population.ObjV # 对目标进行统一最小化 [levels, criLevel] = ea.ndsortDED(ObjV, None, 1, population.CV) # 只对个体划分出第一层 [CombinObjV, weight] = ea.awGA(ObjV, population.CV) # 计算适应性权重以及多目标的加权单目标 population.FitnV = (np.max(CombinObjV) - CombinObjV + 0.5) / ( np.max(CombinObjV) - np.min(CombinObjV) + 0.5) # 计算种群适应度 # 更新NDSet if NDSet is None: return population[np.where(levels == 1)[0]] else: tempPop = population[np.where( levels == 1)[0]] + NDSet # 将种群可行个体与NDSet合并 [levels, criLevel] = ea.ndsortDED(maxormins * tempPop.ObjV, None, 1, tempPop.CV) # 只对个体划分出第一层 liveIdx = np.where(levels == 1)[0] # 选择非支配个体 NDSet = tempPop[liveIdx] # 对种群中被NDSet支配的个体进行惩罚 punishFlag = np.zeros(population.sizes) punishFlag[np.where(liveIdx < population.sizes)[0]] == 1 population.FitnV[np.where(punishFlag == 0)[0]] *= 0.5 if len(liveIdx) > MAXSIZE: # 若要保留下来的NDSet个体数大于MAXSIZE,则根据拥挤距离进行筛选 dis = ea.crowdis(NDSet.ObjV, levels[liveIdx]) # 计算拥挤距离 NDSet = NDSet[ea.selecting('dup', np.array([dis]).T, MAXSIZE)] # 进行筛选 return NDSet
def calReferObjV(self): # 设定目标数参考值(本问题目标函数参考值设定为理论最优值,即“真实帕累托前沿点”) Num = 10000 # 生成10000个参考点 temp = np.linspace(0, 1, Num) ObjV1 = 1 + np.cos(temp * np.pi * 10) / 5 - temp ObjV2 = temp referenceObjV = np.array([ObjV1, ObjV2]).T [levels, criLevel] = ea.ndsortDED(referenceObjV, None, 1) referenceObjV = referenceObjV[np.where(levels == 1)[0], :] return referenceObjV
def updateNDSet(self, population, globalNDSet=None): """ 描述: 更新globalNDSet。 """ if globalNDSet is None: globalNDSet = population else: globalNDSet = population + globalNDSet # 将population与全局归档集合并 if globalNDSet.CV is not None: # CV不为None说明有设置约束条件 globalNDSet = globalNDSet[np.where(np.all(globalNDSet.CV <= 0, 1))[0]] # 排除非可行解 if globalNDSet.sizes != 0: [levels, criLevel] = ea.ndsortDED(globalNDSet.ObjV, None, None, globalNDSet.CV, self.problem.maxormins) # 非支配排序 globalNDSet = globalNDSet[np.where(levels == 1)[0]] if globalNDSet.sizes > self.MAXSIZE: globalNDSet = globalNDSet[ea.rps(globalNDSet.sizes, self.MAXSIZE)] # 采用rps随机排列选择,控制全局存档的大小 return globalNDSet
def logging(self, pop): """ 描述: 用于在进化过程中记录日志。该函数在stat()函数里面被调用。 如果需要在日志中记录其他数据,需要在自定义算法模板类中重写该函数。 输入参数: pop : class <Population> - 种群对象。 输出参数: 无输出参数。 """ self.passTime += time.time() - self.timeSlot # 更新用时记录,不计算logging的耗时 if len(self.log['gen']) == 0: # 初始化log的各个键值 if self.problem.ReferObjV is not None: self.log['gd'] = [] self.log['igd'] = [] self.log['hv'] = [] self.log['spacing'] = [] self.log['gen'].append(self.currentGen) self.log['eval'].append(self.evalsNum) # 记录评价次数 [levels, _] = ea.ndsortDED(pop.ObjV, needLevel=1, CV=pop.CV, maxormins=self.problem.maxormins) # 非支配分层 NDSet = pop[np.where(levels == 1)[0]] # 只保留种群中的非支配个体,形成一个非支配种群 if self.problem.ReferObjV is not None: self.log['gd'].append( ea.indicator.GD(NDSet.ObjV, self.problem.ReferObjV)) # 计算GD指标 self.log['igd'].append( ea.indicator.IGD(NDSet.ObjV, self.problem.ReferObjV)) # 计算IGD指标 self.log['hv'].append( ea.indicator.HV(NDSet.ObjV, self.problem.ReferObjV)) # 计算HV指标 else: self.log['hv'].append(ea.indicator.HV(NDSet.ObjV)) # 计算HV指标 self.log['spacing'].append(ea.indicator.Spacing( NDSet.ObjV)) # 计算Spacing指标 self.timeSlot = time.time() # 更新时间戳
def finishing(self, pop, globalNDSet=None): """ 描述: 进化完成后调用的函数。 输入参数: pop : class <Population> - 种群对象。 globalNDSet : class <Population> - (可选参数)全局存档。 输出参数: [NDSet, pop],其中pop为种群类型;NDSet的类型与pop的一致。 """ if globalNDSet is None: # 得到非支配种群 [levels, _] = ea.ndsortDED(pop.ObjV, needLevel=1, CV=pop.CV, maxormins=self.problem.maxormins) # 非支配分层 NDSet = pop[np.where(levels == 1)[0]] # 只保留种群中的非支配个体,形成一个非支配种群 if NDSet.CV is not None: # CV不为None说明有设置约束条件 NDSet = NDSet[np.where(np.all(NDSet.CV <= 0, 1))[0]] # 最后要彻底排除非可行解 else: NDSet = globalNDSet if self.logTras != 0 and NDSet.sizes != 0 and ( len(self.log['gen']) == 0 or self.log['gen'][-1] != self.currentGen): # 补充记录日志和输出 self.logging(NDSet) if self.verbose: self.display() self.passTime += time.time( ) - self.timeSlot # 更新用时记录,因为已经要结束,因此不用再更新时间戳 self.draw(NDSet, EndFlag=True) # 显示最终结果图 if self.plotter is not None: self.plotter.show() # 返回帕累托最优个体以及最后一代种群 return [NDSet, pop]
def updateNDSet(self, population, globalNDSet=None): """ 描述: 更新globalNDSet。 """ if globalNDSet is None: globalNDSet = population else: globalNDSet = population + globalNDSet # 将population与全局归档集合并 if globalNDSet.CV is not None: # CV不为None说明有设置约束条件 globalNDSet = globalNDSet[np.where(np.all(globalNDSet.CV <= 0, 1))[0]] # 排除非可行解 if globalNDSet.sizes != 0: [levels, criLevel] = ea.ndsortDED(globalNDSet.ObjV, None, None, globalNDSet.CV, self.problem.maxormins) # 非支配排序 globalNDSet = globalNDSet[np.where(levels == 1)[0]] if globalNDSet.sizes > self.MAXSIZE: dis = ea.crowdis(globalNDSet.ObjV, np.ones(globalNDSet.sizes)) # 计算拥挤距离 globalNDSet = globalNDSet[np.argsort(-dis)[:self.MAXSIZE]] # 根据拥挤距离选择符合个数限制的解保留在存档中 return globalNDSet