import random import numpy as np class NSGA2: """NSGA-II算法类:实现多目标优化的非支配排序、选择、环境选择等核心操作""" def __init__(self, pop_size, objective_num): """ 初始化NSGA-II :param pop_size: 种群大小 :param objective_num: 目标函数数量 """ self.pop_size = pop_size # 种群大小 self.objective_num = objective_num # 目标数量 def fast_non_dominated_sort(self, objective_values): """ 快速非支配排序:将个体按支配关系分层(前沿) :param objective_values: 所有个体的目标函数值列表 :return: ranks(每个个体的层级)和 fronts(每层的个体索引列表) """ pop_size = len(objective_values) domination_count = [0] * pop_size # 每个个体被支配的次数 dominated_solutions = [[] for _ in range(pop_size)] # 每个个体支配的个体列表 ranks = [0] * pop_size # 每个个体的层级(0为最优) front = [[]] # 第0层前沿(初始为空) # 1. 计算支配关系 for p in range(pop_size): for q in range(pop_size): if p == q: continue # 个体不与自身比较 # 判断p是否支配q if self._dominates(objective_values[p], objective_values[q]): dominated_solutions[p].append(q) # p支配q,记录q # 判断q是否支配p elif self._dominates(objective_values[q], objective_values[p]): domination_count[p] += 1 # p被q支配,计数+1 # 若p未被任何个体支配,加入第0层前沿 if domination_count[p] == 0: ranks[p] = 0 front[0].append(p) # 2. 生成后续层级的前沿 i = 0 while len(front[i]) > 0: # 当前层非空时继续 next_front = [] # 下一层前沿 for p in front[i]: # 遍历当前层的每个个体 for q in dominated_solutions[p]: # p支配的个体q domination_count[q] -= 1 # q的被支配计数-1 if domination_count[q] == 0: # q不再被任何个体支配 ranks[q] = i + 1 # 层级为当前层+1 next_front.append(q) # 加入下一层 i += 1 front.append(next_front) # 追加下一层 return ranks, front[:-1] # 返回层级和非空前沿 def _dominates(self, a, b): """ 判断个体a是否支配个体b 支配条件:a的所有目标函数值≤b,且至少有一个目标函数值= distances[j]): selected.append(population[i]) else: selected.append(population[j]) return np.array(selected) def _calculate_all_crowding_distances(self, objective_values, ranks): """ 计算所有个体的拥挤度(内部方法) :param objective_values: 目标函数值 :param ranks: 每个个体的层级 :return: 所有个体的拥挤度列表 """ max_rank = max(ranks) if ranks else 0 # 最大层级 all_distances = [0.0] * len(objective_values) # 所有个体的拥挤度 # 按层级计算拥挤度 for r in range(max_rank + 1): front = [i for i in range(len(objective_values)) if ranks[i] == r] # 当前层级的个体 if len(front) <= 1: # 单个个体拥挤度为无穷大 for i in front: all_distances[i] = float('inf') continue # 计算当前层级的拥挤度 distances = self.crowding_distance(objective_values, front) # 映射到全局索引 for i, idx in enumerate(front): all_distances[idx] = distances[i] return all_distances def environmental_selection(self, population, objective_values): """ 环境选择:从合并的父代和子代中选择最优的pop_size个个体 :param population: 合并的种群(父代+子代) :param objective_values: 合并种群的目标函数值 :return: 选择后的种群和对应的目标值 """ # 非支配排序 ranks, fronts = self.fast_non_dominated_sort(objective_values) selected = [] # 选中的个体索引 # 按层级从优到劣选择,直到接近种群大小 for front in fronts: if len(selected) + len(front) <= self.pop_size: selected.extend(front) # 整层加入 else: # 当前层无法全加入时,按拥挤度选择剩余个体 distances = self.crowding_distance(objective_values, front) # 按拥挤度降序排序(优先选择分散的个体) sorted_front = [x for _, x in sorted(zip(distances, front), reverse=True)] # 选择剩余所需数量 selected.extend(sorted_front[:self.pop_size - len(selected)]) break # 返回选中的个体和对应的目标值 return population[selected], [objective_values[i] for i in selected]