diff --git a/data_structures.py b/data_structures.py index a8dd21e..d7e8bac 100644 --- a/data_structures.py +++ b/data_structures.py @@ -71,7 +71,7 @@ class Config: """算法参数配置类:存储NSGA-II的各类参数""" def __init__(self): # 种群参数 - self.pop_size = 300 # 种群大小 + self.pop_size = 100 # 种群大小 self.N1_ratio = 0.2 # 优先成本的种群比例 self.N2_ratio = 0.2 # 优先延期的种群比例 self.N3_ratio = 0.3 # 强制风险企业的种群比例 @@ -83,11 +83,12 @@ class Config: # 惩罚系数 self.delta = 1.3 # 变更惩罚系数 # 早停参数 - self.early_stop_patience = 50 # 连续多少代无改进则早停 + self.early_stop_patience = 20 # 连续多少代无改进则早停 + self.early_stop_threshold = 0.15 # 目标值变化阈值 # 目标函数数量 self.objective_num = 2 # 双目标(成本+延期) - self.duplicate_threshold = 0.1 # 重复解保留数量 - self.print_top_n = 5 # 打印前N个最优解 + self.duplicate_threshold = 0.05 # 重复解保留数量 + self.print_top_n = 10 # 打印前N个最优解 class DataStructures: """数据结构工具类:提供评价指标计算等功能""" @@ -103,9 +104,9 @@ class DataStructures: cost, tardiness = objectives # 避免除以零(成本最优值为0时的保护) if optimal_cost == 0: - cost_ratio = 0 if cost == 0 else float('inf') + cost_ratio = cost else: - cost_ratio = cost / optimal_cost + cost_ratio = 2*(cost / optimal_cost) # 延期处理(+1避免除以零) - tardiness_ratio = (tardiness + 1) / (optimal_tardiness + 1) + tardiness_ratio = 8*((tardiness + 1) / (optimal_tardiness + 1)) return cost_ratio + tardiness_ratio \ No newline at end of file diff --git a/main.py b/main.py index 4266a39..768d871 100644 --- a/main.py +++ b/main.py @@ -44,7 +44,9 @@ def main(): best_front = [] # 最终帕累托前沿解(整数) best_front_objs = [] # 最终帕累托前沿的目标值(整数) no_improve_count = 0 # 无改进计数器(用于早停) - prev_best_avg = float('inf') # 上一代的最优平均目标值(整数求和) + prev_avg_cost = None # 上一代的平均成本 + prev_avg_tardiness = None # 上一代的平均延期 + no_improve_count = 0 # 无改进计数器 # 6. 进化主循环 print(f"开始进化(最大代数:{config.max_generations},早停耐心:{config.early_stop_patience})...") for generation in range(config.max_generations): @@ -60,20 +62,39 @@ def main(): best_front = population[current_front] if current_front else [] # 更新当前最优前沿解(整数) best_front_objs = current_front_objs # 更新当前最优前沿目标值(整数) # 记录收敛趋势(基于最优前沿的平均目标值,整数) + # 记录收敛趋势并判断早停条件 if len(current_front_objs) > 0: - avg_cost = sum(obj[0] for obj in current_front_objs) // len(current_front_objs) # 整数平均 - avg_tardiness = sum(obj[1] for obj in current_front_objs) // len(current_front_objs) # 整数平均 + avg_cost = sum(obj[0] for obj in current_front_objs) // len(current_front_objs) + avg_tardiness = sum(obj[1] for obj in current_front_objs) // len(current_front_objs) convergence_history.append((avg_cost, avg_tardiness)) - # 判断是否改进(用于早停) - current_avg = avg_cost + avg_tardiness # 合并两个目标的平均值(整数) - if abs(current_avg - prev_best_avg) < 1e-4: # 变化小于阈值,视为无改进 - no_improve_count += 1 + # 早停判断逻辑 + if prev_avg_cost is not None and prev_avg_tardiness is not None: + # 计算两个目标的变化量 + cost_change = abs(avg_cost - prev_avg_cost) + tardiness_change = abs(avg_tardiness - prev_avg_tardiness) + + # 检查是否两个目标的变化都小于阈值 + if (cost_change < config.early_stop_threshold and + tardiness_change < config.early_stop_threshold): + no_improve_count += 1 + else: + no_improve_count = 0 # 有改进,重置计数器 + prev_avg_cost = avg_cost + prev_avg_tardiness = avg_tardiness else: - no_improve_count = 0 # 有改进,重置计数器 - prev_best_avg = current_avg + # 初始化历史值(第一代) + prev_avg_cost = avg_cost + prev_avg_tardiness = avg_tardiness + no_improve_count = 0 else: no_improve_count += 1 # 无前沿解,视为无改进 + + # 早停检查(连续多代无改进则停止) + if no_improve_count >= config.early_stop_patience: + print( + f"早停触发:连续{no_improve_count}代两个目标值变化均小于{config.early_stop_threshold},终止于第{generation}代") + break # 选择操作(锦标赛选择) selected = nsga2.selection(population, objectives) # 校验选择后的种群大小