Compare commits
No commits in common. "41a43c6e4b3be3c73996d85509472fc21b4ac5ff" and "aba7dc18d326778b4dff8d377480a9a53fd64785" have entirely different histories.
41a43c6e4b
...
aba7dc18d3
|
|
@ -1,115 +1,77 @@
|
||||||
# 数据结构定义:存储订单、企业、供应商数据及算法配置
|
# 数据结构定义:存储订单、企业、供应商数据及算法配置
|
||||||
class OrderData:
|
class OrderData:
|
||||||
"""订单数据类:存储物料需求、交货期、成本等信息(贴合生产实际优化)"""
|
"""订单数据类:存储物料需求、交货期、成本等信息"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.I = 12 # 物料种类数(12种,分3类:核心/常规/小众)
|
self.I = 5 # 物料种类数
|
||||||
# 需求数量:核心物料(1-3)需求量大(1.5-2.5万)、常规物料(4-9)中等(0.7-1.2万)、小众物料(10-12)小(0.3-0.5万)
|
self.Q = [6000, 12000, 20000, 7500, 13500] # 各物料的需求数量(整数)
|
||||||
self.Q = [22000, 25000, 18000, 11000, 9500, 12000, 8500, 7000, 9000, 4500, 3800, 5000]
|
self.Dd = 30 # 需求交货期(单位:时间,整数)
|
||||||
self.Dd = 35 # 交货期微调为35(12种物料需更合理的生产周期)
|
self.P0 = [45, 30, 30, 50, 40] # 风险企业的单位采购价(整数)
|
||||||
# 风险企业采购价:核心物料批量效应价低(28-35)、常规中等(38-45)、小众物料价高(48-52)
|
self.T0 = [5, 8, 6, 7, 9] # 风险企业的单位运输成本(整数)
|
||||||
self.P0 = [32, 28, 30, 42, 40, 45, 38, 41, 43, 50, 48, 52]
|
self.transport_speed = 10 # 运输速度(单位:距离/时间,整数)
|
||||||
# 风险企业运输成本:距离近(20),成本整体偏低(5-8),小众物料因量小单位运输成本略高
|
|
||||||
self.T0 = [5, 6, 5, 7, 6, 7, 6, 8, 7, 8, 7, 8]
|
|
||||||
self.transport_speed = 12 # 运输速度微调为12(更贴合实际公路运输效率)
|
|
||||||
|
|
||||||
|
|
||||||
class RiskEnterpriseData:
|
class RiskEnterpriseData:
|
||||||
"""风险企业数据类:存储风险企业的产能、距离等信息(优化产能梯度)"""
|
"""风险企业数据类:存储风险企业的产能、距离等信息"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.I = 12 # 物料种类数(与订单一致)
|
self.I = 5 # 物料种类数(与订单一致)
|
||||||
# 单物料最小产能:核心物料产能高(120-150)、常规中等(80-110)、小众低(50-70)
|
self.C0_i_min = [50, 100, 150, 80, 100] # 单物料的单位时间最小产能(整数)
|
||||||
self.C0_i_min = [140, 150, 130, 100, 90, 110, 85, 80, 95, 65, 55, 70]
|
self.C0_total_max = 900 # 总产能上限(单位时间,整数)
|
||||||
self.C0_total_max = 1100 # 总产能上限(适配12种物料的综合供应,略高于原数值)
|
self.distance = 20 # 与需求点的距离(整数)
|
||||||
self.distance = 20 # 风险企业优先布局在需求点附近,距离保持低值
|
|
||||||
|
|
||||||
|
|
||||||
class SupplierData:
|
class SupplierData:
|
||||||
"""供应商数据类:7家供应商(专业化分工+数值贴合实际供需)"""
|
"""供应商数据类:存储各供应商的产能、价格、距离等信息"""
|
||||||
|
def __init__(self, I=5):
|
||||||
def __init__(self, I=12):
|
|
||||||
self.I = I # 物料种类数
|
self.I = I # 物料种类数
|
||||||
self.supplier_count = 7 # 供应商数量(7家,分综合/专业/小众类型)
|
self.supplier_count = 4 # 供应商数量
|
||||||
self.names = ["S0", "S1", "S2", "S3", "S4", "S5", "S6"] # 供应商命名
|
self.names = ["S0", "S1", "S2", "S3"] # 供应商名称
|
||||||
|
# 能否生产某物料的矩阵(supplier_count × I),1=能生产,0=不能
|
||||||
# 生产权限矩阵(7×12):体现专业化分工
|
|
||||||
# S0:全品类(头部综合供应商);S1:核心+部分常规;S2:常规物料;S3:小众+部分常规;S4-S6:专用物料(按物料组分工)
|
|
||||||
self.can_produce = [
|
self.can_produce = [
|
||||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], # S0:全品类覆盖
|
[1, 1, 1, 1, 1],
|
||||||
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], # S1:核心(1-3)+常规(4-6)
|
[1, 0, 1, 0, 1],
|
||||||
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0], # S2:常规物料(4-9)
|
[0, 1, 0, 1, 0],
|
||||||
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], # S3:常规(7-9)+小众(10-12)
|
[0, 0, 1, 1, 1]
|
||||||
[1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0], # S4:专用组1(1/4/7/10)
|
|
||||||
[0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0], # S5:专用组2(2/5/8/11)
|
|
||||||
[0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1] # S6:专用组3(3/6/9/12)
|
|
||||||
]
|
]
|
||||||
|
# 单物料单位时间最小产能(supplier_count × I),0表示不能生产该物料(整数)
|
||||||
# 单物料最小产能(7×12):0=不能生产,产能与物料类型匹配
|
|
||||||
self.Cj_i_min = [
|
self.Cj_i_min = [
|
||||||
[130, 140, 120, 95, 85, 105, 80, 75, 90, 60, 50, 65], # S0:全品类产能均衡
|
[30, 80, 100, 60, 80],
|
||||||
[145, 155, 135, 100, 90, 110, 0, 0, 0, 0, 0, 0], # S1:核心物料产能偏高
|
[60, 0, 180, 0, 120],
|
||||||
[0, 0, 0, 98, 88, 108, 82, 78, 92, 0, 0, 0], # S2:常规物料产能中等
|
[0, 150, 0, 120, 0],
|
||||||
[0, 0, 0, 0, 0, 0, 83, 79, 93, 62, 52, 67], # S3:小众物料产能偏低
|
[0, 0, 170, 105, 115]
|
||||||
[135, 0, 0, 96, 0, 0, 81, 0, 0, 61, 0, 0], # S4:专用组1产能适配
|
|
||||||
[0, 142, 0, 0, 87, 0, 0, 76, 0, 0, 51, 0], # S5:专用组2产能适配
|
|
||||||
[0, 0, 132, 0, 0, 106, 0, 0, 89, 0, 0, 66] # S6:专用组3产能适配
|
|
||||||
]
|
]
|
||||||
|
# 供应商单位时间的最大总产能(supplier_count,整数)
|
||||||
# 总产能上限:头部供应商(S0)最高,专业供应商次之,小众供应商最低(符合实际供应链层级)
|
self.Cj_total_max = [700, 800, 600, 850]
|
||||||
self.Cj_total_max = [950, 880, 820, 750, 700, 680, 650]
|
# 最小起订量(supplier_count × I,整数)
|
||||||
|
|
||||||
# 最小起订量:核心物料起订量高(2000-3500)、常规中等(800-1800)、小众低(300-600)
|
|
||||||
self.MinOrder = [
|
self.MinOrder = [
|
||||||
[3200, 3500, 2800, 1600, 1200, 1800, 1000, 800, 1400, 500, 350, 550],
|
[800, 1500, 3000, 800, 1500],
|
||||||
[3300, 3600, 2900, 1700, 1300, 1900, 0, 0, 0, 0, 0, 0],
|
[1000, 0, 3500, 0, 1800],
|
||||||
[0, 0, 0, 1650, 1250, 1850, 1050, 850, 1450, 0, 0, 0],
|
[0, 1700, 0, 1000, 0],
|
||||||
[0, 0, 0, 0, 0, 0, 1100, 900, 1500, 550, 400, 600],
|
[0, 0, 2500, 500, 1000]
|
||||||
[3250, 0, 0, 1620, 0, 0, 1020, 0, 0, 520, 0, 0],
|
|
||||||
[0, 3550, 0, 0, 1280, 0, 0, 880, 0, 0, 380, 0],
|
|
||||||
[0, 0, 2850, 0, 0, 1880, 0, 0, 1480, 0, 0, 580]
|
|
||||||
]
|
]
|
||||||
|
# 最大供应量(supplier_count × I,整数)
|
||||||
# 最大供应量:不低于订单需求(避免供应不足),核心物料供应能力强,小众物料供应有限
|
|
||||||
self.MaxOrder = [
|
self.MaxOrder = [
|
||||||
[25000, 28000, 21000, 14000, 12000, 15000, 11000, 9000, 12000, 6000, 5000, 7000],
|
[5000, 10000, 18000, 6500, 11000],
|
||||||
[26000, 29000, 22000, 15000, 13000, 16000, 0, 0, 0, 0, 0, 0],
|
[8000, 0, 25000, 0, 15000],
|
||||||
[0, 0, 0, 14500, 12500, 15500, 11500, 9500, 12500, 0, 0, 0],
|
[0, 8000, 0, 6000, 0],
|
||||||
[0, 0, 0, 0, 0, 0, 12000, 10000, 13000, 6500, 5500, 7500],
|
[0, 0, 20000, 7500, 13500]
|
||||||
[25500, 0, 0, 14200, 0, 0, 11200, 0, 0, 6200, 0, 0],
|
|
||||||
[0, 28500, 0, 0, 12800, 0, 0, 9800, 0, 0, 5200, 0],
|
|
||||||
[0, 0, 21500, 0, 0, 15800, 0, 0, 12800, 0, 0, 7200]
|
|
||||||
]
|
]
|
||||||
|
# 单位采购价格(supplier_count × I,整数)
|
||||||
# 单位采购价:核心物料因批量大价低(28-35)、常规中等(38-45)、小众高(48-55);专业供应商比综合供应商价略低(专业化优势)
|
|
||||||
self.P_ij = [
|
self.P_ij = [
|
||||||
[30, 28, 29, 40, 38, 43, 39, 41, 42, 50, 48, 51],
|
[50, 35, 28, 47, 38],
|
||||||
[29, 27, 28, 39, 37, 42, 0, 0, 0, 0, 0, 0],
|
[43, 0, 28, 0, 36],
|
||||||
[0, 0, 0, 38, 36, 41, 37, 39, 40, 0, 0, 0],
|
[0, 31, 0, 52, 0],
|
||||||
[0, 0, 0, 0, 0, 0, 38, 40, 41, 49, 47, 50],
|
[0, 0, 32, 52, 43]
|
||||||
[31, 0, 0, 40, 0, 0, 39, 0, 0, 51, 0, 0],
|
|
||||||
[0, 28, 0, 0, 37, 0, 0, 40, 0, 0, 49, 0],
|
|
||||||
[0, 0, 29, 0, 0, 42, 0, 0, 41, 0, 0, 52]
|
|
||||||
]
|
]
|
||||||
|
# 单位运输成本(supplier_count × I,整数)
|
||||||
# 单位运输成本:与距离正相关(核心优化点),小众物料因运输量小单位成本略高
|
|
||||||
self.T_ij = [
|
self.T_ij = [
|
||||||
[8, 7, 8, 10, 9, 11, 9, 10, 10, 13, 12, 14],
|
[6, 9, 8, 9, 12],
|
||||||
[7, 6, 7, 9, 8, 10, 0, 0, 0, 0, 0, 0],
|
[4, 0, 5, 0, 15],
|
||||||
[0, 0, 0, 11, 10, 12, 10, 11, 11, 0, 0, 0],
|
[0, 10, 0, 7, 0],
|
||||||
[0, 0, 0, 0, 0, 0, 12, 11, 12, 14, 13, 15],
|
[0, 0, 8, 9, 11]
|
||||||
[9, 0, 0, 10, 0, 0, 9, 0, 0, 13, 0, 0],
|
|
||||||
[0, 8, 0, 0, 9, 0, 0, 10, 0, 0, 12, 0],
|
|
||||||
[0, 0, 8, 0, 0, 11, 0, 0, 11, 0, 0, 14]
|
|
||||||
]
|
]
|
||||||
|
# 供应商与需求点的距离(supplier_count,整数)
|
||||||
# 供应商距离:梯度分布(40-80),运输成本随距离递增(贴合实际物流成本逻辑)
|
self.distance = [60, 50, 70, 40]
|
||||||
self.distance = [50, 40, 60, 70, 55, 45, 65]
|
|
||||||
class Config:
|
class Config:
|
||||||
"""算法参数配置类:存储NSGA-II的各类参数"""
|
"""算法参数配置类:存储NSGA-II的各类参数"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# 种群参数
|
# 种群参数
|
||||||
self.pop_size = 400 # 种群大小(相对越多越好)
|
self.pop_size = 100 # 种群大小
|
||||||
self.N1_ratio = 0.2 # 优先成本的种群比例
|
self.N1_ratio = 0.2 # 优先成本的种群比例
|
||||||
self.N2_ratio = 0.2 # 优先延期的种群比例
|
self.N2_ratio = 0.2 # 优先延期的种群比例
|
||||||
self.N3_ratio = 0.3 # 强制风险企业的种群比例
|
self.N3_ratio = 0.3 # 强制风险企业的种群比例
|
||||||
|
|
@ -117,37 +79,34 @@ class Config:
|
||||||
# 遗传操作参数
|
# 遗传操作参数
|
||||||
self.crossover_prob = 0.8 # 交叉概率
|
self.crossover_prob = 0.8 # 交叉概率
|
||||||
self.mutation_prob = 0.3 # 变异概率
|
self.mutation_prob = 0.3 # 变异概率
|
||||||
self.max_generations = 1000 # 最大进化代数
|
self.max_generations = 500 # 最大进化代数
|
||||||
# 惩罚系数
|
# 惩罚系数
|
||||||
self.delta = 1.3 # 变更惩罚系数
|
self.delta = 1.3 # 变更惩罚系数
|
||||||
# 早停参数
|
# 早停参数
|
||||||
self.early_stop_patience = 100 # 连续多少代无改进则早停
|
self.early_stop_patience = 20 # 连续多少代无改进则早停
|
||||||
self.early_stop_threshold = 0.15 # 目标值变化阈值(相对越高,收敛越稳定)
|
self.early_stop_threshold = 0.15 # 目标值变化阈值
|
||||||
# 目标函数数量
|
# 目标函数数量
|
||||||
self.objective_num = 2 # 双目标(成本+延期)
|
self.objective_num = 2 # 双目标(成本+延期)
|
||||||
self.duplicate_threshold = 0.02 # 和种群数量相乘,重复解保留数量比例(根据种群数量选择)
|
self.duplicate_threshold = 0.05 # 重复解保留数量
|
||||||
self.print_top_n = 10 # 打印前N个最优解
|
self.print_top_n = 10 # 打印前N个最优解
|
||||||
|
|
||||||
class DataStructures:
|
class DataStructures:
|
||||||
"""数据结构工具类:提供评价指标计算等功能"""
|
"""数据结构工具类:提供评价指标计算等功能"""
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def calculate_evaluation_index(objectives, optimal_cost, optimal_tardiness, max_cost, max_tardiness):
|
def calculate_evaluation_index(objectives, optimal_cost, optimal_tardiness):
|
||||||
"""
|
"""
|
||||||
计算评价指标
|
计算评价指标
|
||||||
: objectives: 解的目标值 (成本, 延期)
|
:param objectives: 解的目标值 (成本, 延期)
|
||||||
: optimal_cost: 最优成本值
|
:param optimal_cost: 最优成本值
|
||||||
: optimal_tardiness: 最优延期值
|
:param optimal_tardiness: 最优延期值
|
||||||
: max_cost: 最大成本值
|
|
||||||
: max_tardiness: 最大延期值
|
|
||||||
:return: 评价指标值
|
:return: 评价指标值
|
||||||
"""
|
"""
|
||||||
cost, tardiness = objectives
|
cost, tardiness = objectives
|
||||||
if max_cost - optimal_cost == 0:
|
# 避免除以零(成本最优值为0时的保护)
|
||||||
cost_ratio = 0
|
if optimal_cost == 0:
|
||||||
|
cost_ratio = cost
|
||||||
else:
|
else:
|
||||||
cost_ratio = cost/(max_cost - optimal_cost)
|
cost_ratio = 2*(cost / optimal_cost)
|
||||||
if max_tardiness - optimal_tardiness == 0:
|
# 延期处理(+1避免除以零)
|
||||||
tardiness_ratio = 0
|
tardiness_ratio = 8*((tardiness + 1) / (optimal_tardiness + 1))
|
||||||
else:
|
|
||||||
tardiness_ratio = tardiness/( max_tardiness - optimal_tardiness)
|
|
||||||
return cost_ratio + tardiness_ratio
|
return cost_ratio + tardiness_ratio
|
||||||
82
main.py
82
main.py
|
|
@ -8,8 +8,9 @@ from genetic_operators import GeneticOperator
|
||||||
from nsga2 import NSGA2
|
from nsga2 import NSGA2
|
||||||
from visualizer import ResultVisualizer
|
from visualizer import ResultVisualizer
|
||||||
from data_structures import DataStructures
|
from data_structures import DataStructures
|
||||||
|
"""主函数:执行NSGA-II算法求解多目标优化问题(整数化版本)"""
|
||||||
def main():
|
def main():
|
||||||
"""主函数:执行NSGA-II算法求解多目标优化问题"""
|
"""主函数:执行NSGA-II算法求解多目标优化问题(整数化版本)"""
|
||||||
try:
|
try:
|
||||||
# 1. 初始化随机种子(确保结果可复现)
|
# 1. 初始化随机种子(确保结果可复现)
|
||||||
random.seed(42)
|
random.seed(42)
|
||||||
|
|
@ -17,32 +18,32 @@ def main():
|
||||||
# 2. 初始化数据(订单、风险企业、供应商、算法配置)
|
# 2. 初始化数据(订单、风险企业、供应商、算法配置)
|
||||||
print("初始化数据结构...")
|
print("初始化数据结构...")
|
||||||
order_data = OrderData() # 订单数据(需求、交货期等,整数)
|
order_data = OrderData() # 订单数据(需求、交货期等,整数)
|
||||||
risk_data = RiskEnterpriseData() # 风险企业数据
|
risk_data = RiskEnterpriseData() # 风险企业数据(整数)
|
||||||
supplier_data = SupplierData() # 供应商数据
|
supplier_data = SupplierData() # 供应商数据(整数)
|
||||||
config = Config() # 算法参数配置
|
config = Config() # 算法参数配置
|
||||||
# 3. 初始化工具类和算法组件
|
# 3. 初始化工具类和算法组件
|
||||||
print("初始化算法组件...")
|
print("初始化算法组件...")
|
||||||
utils = ChromosomeUtils(order_data, risk_data, supplier_data) # 染色体工具
|
utils = ChromosomeUtils(order_data, risk_data, supplier_data) # 染色体工具(整数化)
|
||||||
calculator = ObjectiveCalculator(order_data, risk_data, supplier_data, utils, config) # 目标函数计算器
|
calculator = ObjectiveCalculator(order_data, risk_data, supplier_data, utils, config) # 目标函数计算器(整数化)
|
||||||
encoder = Encoder(config, utils) # 种群初始化编码器
|
encoder = Encoder(config, utils) # 种群初始化编码器(整数化)
|
||||||
genetic_op = GeneticOperator(config, utils) # 遗传操作器
|
genetic_op = GeneticOperator(config, utils) # 遗传操作器(整数化)
|
||||||
nsga2 = NSGA2(config.pop_size, config.objective_num) # NSGA-II算法实例
|
nsga2 = NSGA2(config.pop_size, config.objective_num) # NSGA-II算法实例
|
||||||
visualizer = ResultVisualizer(utils) # 结果可视化工具
|
visualizer = ResultVisualizer(utils) # 结果可视化工具(适配整数化)
|
||||||
# 4. 初始化种群
|
# 4. 初始化种群
|
||||||
print("初始化种群...")
|
print("初始化种群(整数化)...")
|
||||||
population = encoder.initialize_population()
|
population = encoder.initialize_population()
|
||||||
print(f"初始化种群完成,(种群大小,染色体长度): {population.shape if population.size > 0 else '空'}")
|
print(f"初始化种群完成,(种群大小,染色体长度): {population.shape if population.size > 0 else '空'}")
|
||||||
|
|
||||||
|
|
||||||
# 若种群初始化失败(为空),直接退出
|
# 若种群初始化失败(为空),直接退出
|
||||||
if population.size == 0:
|
if population.size == 0:
|
||||||
print("错误:种群初始化失败,无法继续进化")
|
print("错误:种群初始化失败,无法继续进化")
|
||||||
return
|
return
|
||||||
# 5. 记录进化过程中的历史数据
|
# 5. 记录进化过程中的历史数据(整数化)
|
||||||
all_objectives = [] # 所有代的目标函数值
|
all_objectives = [] # 所有代的目标函数值(整数)
|
||||||
convergence_history = [] # 收敛趋势(每代最优前沿的平均目标值,整数)
|
convergence_history = [] # 收敛趋势(每代最优前沿的平均目标值,整数)
|
||||||
best_front = [] # 最终帕累托前沿解
|
best_front = [] # 最终帕累托前沿解(整数)
|
||||||
best_front_objs = [] # 最终帕累托前沿的目标值
|
best_front_objs = [] # 最终帕累托前沿的目标值(整数)
|
||||||
|
no_improve_count = 0 # 无改进计数器(用于早停)
|
||||||
prev_avg_cost = None # 上一代的平均成本
|
prev_avg_cost = None # 上一代的平均成本
|
||||||
prev_avg_tardiness = None # 上一代的平均延期
|
prev_avg_tardiness = None # 上一代的平均延期
|
||||||
no_improve_count = 0 # 无改进计数器
|
no_improve_count = 0 # 无改进计数器
|
||||||
|
|
@ -50,17 +51,16 @@ def main():
|
||||||
print(f"开始进化(最大代数:{config.max_generations},早停耐心:{config.early_stop_patience})...")
|
print(f"开始进化(最大代数:{config.max_generations},早停耐心:{config.early_stop_patience})...")
|
||||||
for generation in range(config.max_generations):
|
for generation in range(config.max_generations):
|
||||||
try:
|
try:
|
||||||
# 计算当前种群的目标函数值
|
# 计算当前种群的目标函数值(整数)
|
||||||
objectives = [calculator.calculate_objectives(chrom) for chrom in population]
|
objectives = [calculator.calculate_objectives(chrom) for chrom in population]
|
||||||
all_objectives.extend(objectives) # 记录所有目标值
|
all_objectives.extend(objectives) # 记录所有目标值(整数)
|
||||||
# 非支配排序,获取当前代的帕累托前沿
|
# 非支配排序,获取当前代的帕累托前沿
|
||||||
ranks, fronts = nsga2.fast_non_dominated_sort(objectives)
|
ranks, fronts = nsga2.fast_non_dominated_sort(objectives)
|
||||||
current_front = fronts[0] if fronts else [] # 第0层为最优前沿
|
current_front = fronts[0] if fronts else [] # 第0层为最优前沿
|
||||||
|
|
||||||
current_front_objs = [objectives[i] for i in current_front] if current_front else []
|
current_front_objs = [objectives[i] for i in current_front] if current_front else []
|
||||||
|
|
||||||
best_front = population[current_front] if current_front else [] # 更新当前最优前沿解
|
best_front = population[current_front] if current_front else [] # 更新当前最优前沿解(整数)
|
||||||
best_front_objs = current_front_objs # 更新当前最优前沿目标值
|
best_front_objs = current_front_objs # 更新当前最优前沿目标值(整数)
|
||||||
# 记录收敛趋势(基于最优前沿的平均目标值,整数)
|
# 记录收敛趋势(基于最优前沿的平均目标值,整数)
|
||||||
# 记录收敛趋势并判断早停条件
|
# 记录收敛趋势并判断早停条件
|
||||||
if len(current_front_objs) > 0:
|
if len(current_front_objs) > 0:
|
||||||
|
|
@ -74,11 +74,10 @@ def main():
|
||||||
cost_change = abs(avg_cost - prev_avg_cost)
|
cost_change = abs(avg_cost - prev_avg_cost)
|
||||||
tardiness_change = abs(avg_tardiness - prev_avg_tardiness)
|
tardiness_change = abs(avg_tardiness - prev_avg_tardiness)
|
||||||
|
|
||||||
# 检查是否两个目标的变化率
|
# 检查是否两个目标的变化都小于阈值
|
||||||
if (cost_change < config.early_stop_threshold * prev_avg_cost and
|
if (cost_change < config.early_stop_threshold and
|
||||||
tardiness_change < config.early_stop_threshold * prev_avg_tardiness):
|
tardiness_change < config.early_stop_threshold):
|
||||||
no_improve_count += 1
|
no_improve_count += 1
|
||||||
|
|
||||||
else:
|
else:
|
||||||
no_improve_count = 0 # 有改进,重置计数器
|
no_improve_count = 0 # 有改进,重置计数器
|
||||||
prev_avg_cost = avg_cost
|
prev_avg_cost = avg_cost
|
||||||
|
|
@ -94,7 +93,7 @@ def main():
|
||||||
# 早停检查(连续多代无改进则停止)
|
# 早停检查(连续多代无改进则停止)
|
||||||
if no_improve_count >= config.early_stop_patience:
|
if no_improve_count >= config.early_stop_patience:
|
||||||
print(
|
print(
|
||||||
f"早停触发:连续{no_improve_count}代两个目标值变化率均小于{config.early_stop_threshold},终止于第{generation}代")
|
f"早停触发:连续{no_improve_count}代两个目标值变化均小于{config.early_stop_threshold},终止于第{generation}代")
|
||||||
break
|
break
|
||||||
# 选择操作(锦标赛选择)
|
# 选择操作(锦标赛选择)
|
||||||
selected = nsga2.selection(population, objectives)
|
selected = nsga2.selection(population, objectives)
|
||||||
|
|
@ -103,11 +102,10 @@ def main():
|
||||||
f"选择后的种群大小({len(selected)})与目标大小({config.pop_size})不符"
|
f"选择后的种群大小({len(selected)})与目标大小({config.pop_size})不符"
|
||||||
|
|
||||||
# 交叉操作(两点交叉)- 修复索引越界问题
|
# 交叉操作(两点交叉)- 修复索引越界问题
|
||||||
offspring = [] # 子代种群
|
offspring = [] # 子代种群(整数)
|
||||||
selected_len = len(selected) # selected的长度(等于pop_size)
|
selected_len = len(selected) # selected的长度(等于pop_size)
|
||||||
i = 0
|
i = 0
|
||||||
max_iter = 2 * config.pop_size # 最大迭代次数,避免无限循环
|
max_iter = 2 * config.pop_size # 最大迭代次数,避免无限循环
|
||||||
|
|
||||||
iter_count = 0
|
iter_count = 0
|
||||||
while len(offspring) < config.pop_size and iter_count < max_iter:
|
while len(offspring) < config.pop_size and iter_count < max_iter:
|
||||||
iter_count += 1
|
iter_count += 1
|
||||||
|
|
@ -133,7 +131,6 @@ def main():
|
||||||
i += 1 # 处理下一个个体(步长改为1,避免快速越界)
|
i += 1 # 处理下一个个体(步长改为1,避免快速越界)
|
||||||
# 若迭代次数用尽仍未生成足够子代,补充随机个体(健壮性处理,整数)
|
# 若迭代次数用尽仍未生成足够子代,补充随机个体(健壮性处理,整数)
|
||||||
while len(offspring) < config.pop_size:
|
while len(offspring) < config.pop_size:
|
||||||
|
|
||||||
offspring.append(encoder._generate_random_chromosome()) # 整数化随机染色体
|
offspring.append(encoder._generate_random_chromosome()) # 整数化随机染色体
|
||||||
# 变异操作(均匀变异,整数化)
|
# 变异操作(均匀变异,整数化)
|
||||||
offspring = [
|
offspring = [
|
||||||
|
|
@ -142,8 +139,8 @@ def main():
|
||||||
]
|
]
|
||||||
offspring = np.array(offspring[:config.pop_size]).astype(int) # 确保子代大小和整数类型
|
offspring = np.array(offspring[:config.pop_size]).astype(int) # 确保子代大小和整数类型
|
||||||
# 合并父代和子代,准备环境选择
|
# 合并父代和子代,准备环境选择
|
||||||
combined = np.vstack([population, offspring]).astype(int) # 合并种群
|
combined = np.vstack([population, offspring]).astype(int) # 合并种群(整数)
|
||||||
# 计算合并种群的目标函数值
|
# 计算合并种群的目标函数值(整数)
|
||||||
combined_objs = objectives + [calculator.calculate_objectives(chrom) for chrom in offspring]
|
combined_objs = objectives + [calculator.calculate_objectives(chrom) for chrom in offspring]
|
||||||
# 环境选择(保留最优的pop_size个个体)
|
# 环境选择(保留最优的pop_size个个体)
|
||||||
population, objectives = nsga2.environmental_selection(combined, combined_objs)
|
population, objectives = nsga2.environmental_selection(combined, combined_objs)
|
||||||
|
|
@ -155,7 +152,6 @@ def main():
|
||||||
# 早停检查(连续多代无改进则停止)
|
# 早停检查(连续多代无改进则停止)
|
||||||
if no_improve_count >= config.early_stop_patience:
|
if no_improve_count >= config.early_stop_patience:
|
||||||
print(f"早停触发:连续{no_improve_count}代无改进,终止于第{generation}代")
|
print(f"早停触发:连续{no_improve_count}代无改进,终止于第{generation}代")
|
||||||
|
|
||||||
break
|
break
|
||||||
# 每50代打印一次进度
|
# 每50代打印一次进度
|
||||||
if generation % 50 == 0:
|
if generation % 50 == 0:
|
||||||
|
|
@ -164,18 +160,20 @@ def main():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"第{generation}代进化出错:{str(e)},跳过当前代")
|
print(f"第{generation}代进化出错:{str(e)},跳过当前代")
|
||||||
continue
|
continue
|
||||||
# 7. 结果可视化与输出
|
# 7. 结果可视化与输出(整数化)
|
||||||
print("进化完成,处理结果...")
|
print("进化完成,处理结果(整数化)...")
|
||||||
if len(best_front_objs) > 0:
|
if len(best_front_objs) > 0:
|
||||||
# 1. 过滤重复解(关键改进:基于目标值去重,确保相同目标值只保留一个解)
|
# 1. 过滤重复解
|
||||||
unique_front = []
|
unique_front = []
|
||||||
unique_front_objs = []
|
unique_front_objs = []
|
||||||
seen_obj = set() # 仅跟踪目标值,确保相同目标值只保留一个
|
seen = set()
|
||||||
|
|
||||||
for sol, obj in zip(best_front, best_front_objs):
|
for sol, obj in zip(best_front, best_front_objs):
|
||||||
obj_tuple = tuple(obj) # 将目标值转为元组用于查重
|
# 将解和目标值组合为元组用于查重
|
||||||
if obj_tuple not in seen_obj:
|
sol_tuple = tuple(sol.tolist())
|
||||||
seen_obj.add(obj_tuple)
|
obj_tuple = tuple(obj)
|
||||||
|
if (sol_tuple, obj_tuple) not in seen:
|
||||||
|
seen.add((sol_tuple, obj_tuple))
|
||||||
unique_front.append(sol)
|
unique_front.append(sol)
|
||||||
unique_front_objs.append(obj)
|
unique_front_objs.append(obj)
|
||||||
|
|
||||||
|
|
@ -184,14 +182,12 @@ def main():
|
||||||
# 找出各目标的最优值
|
# 找出各目标的最优值
|
||||||
optimal_cost = min(obj[0] for obj in unique_front_objs)
|
optimal_cost = min(obj[0] for obj in unique_front_objs)
|
||||||
optimal_tardiness = min(obj[1] for obj in unique_front_objs)
|
optimal_tardiness = min(obj[1] for obj in unique_front_objs)
|
||||||
max_cost = max(obj[0] for obj in unique_front_objs)
|
|
||||||
max_tardiness = max(obj[1] for obj in unique_front_objs)
|
|
||||||
|
|
||||||
# 计算每个解的评价指标
|
# 计算每个解的评价指标
|
||||||
evaluated_solutions = []
|
evaluated_solutions = []
|
||||||
for sol, obj in zip(unique_front, unique_front_objs):
|
for sol, obj in zip(unique_front, unique_front_objs):
|
||||||
index = DataStructures.calculate_evaluation_index(
|
index = DataStructures.calculate_evaluation_index(
|
||||||
obj, optimal_cost, optimal_tardiness, max_cost, max_tardiness
|
obj, optimal_cost, optimal_tardiness
|
||||||
)
|
)
|
||||||
evaluated_solutions.append((sol, obj, index))
|
evaluated_solutions.append((sol, obj, index))
|
||||||
|
|
||||||
|
|
@ -215,8 +211,8 @@ def main():
|
||||||
top_objectives = []
|
top_objectives = []
|
||||||
|
|
||||||
# 保持原有图表绘制逻辑不变
|
# 保持原有图表绘制逻辑不变
|
||||||
visualizer.plot_pareto_front(all_objectives, best_front_objs) # 绘制帕累托前沿
|
visualizer.plot_pareto_front(all_objectives, best_front_objs) # 绘制帕累托前沿(整数)
|
||||||
visualizer.plot_convergence(convergence_history) # 绘制收敛趋势
|
visualizer.plot_convergence(convergence_history) # 绘制收敛趋势(整数)
|
||||||
|
|
||||||
# 打印处理后的最优解详情
|
# 打印处理后的最优解详情
|
||||||
if top_population:
|
if top_population:
|
||||||
|
|
@ -230,6 +226,6 @@ def main():
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc() # 打印详细错误栈
|
traceback.print_exc() # 打印详细错误栈
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("程序启动...")
|
print("程序启动(整数化版本)...")
|
||||||
main()
|
main()
|
||||||
print("程序结束")
|
print("程序结束")
|
||||||
|
|
@ -91,7 +91,7 @@ class ResultVisualizer:
|
||||||
q_segment = quantity_layer[start:end].astype(int) # 数量(整数)
|
q_segment = quantity_layer[start:end].astype(int) # 数量(整数)
|
||||||
demand_q = self.utils.order.Q[i] # 需求数量(整数)
|
demand_q = self.utils.order.Q[i] # 需求数量(整数)
|
||||||
allocated_q = np.sum(q_segment[e_segment == 1]) # 分配的总数量(整数)
|
allocated_q = np.sum(q_segment[e_segment == 1]) # 分配的总数量(整数)
|
||||||
print(f"物料 {i+1} - 需求数量: {demand_q}, 分配总量: {allocated_q}")
|
print(f"物料 {i} - 需求数量: {demand_q}, 分配总量: {allocated_q}")
|
||||||
total_q_check.append(allocated_q == demand_q) # 整数相等检查
|
total_q_check.append(allocated_q == demand_q) # 整数相等检查
|
||||||
print(f" 选择的企业及其分配:")
|
print(f" 选择的企业及其分配:")
|
||||||
for idx, ent in enumerate(ents):
|
for idx, ent in enumerate(ents):
|
||||||
|
|
@ -104,7 +104,7 @@ class ResultVisualizer:
|
||||||
print("-" * 80)
|
print("-" * 80)
|
||||||
# 验证数量约束是否满足
|
# 验证数量约束是否满足
|
||||||
if all(total_q_check):
|
if all(total_q_check):
|
||||||
print("✅ 所有物料数量满足需求约束")
|
print("✅ 所有物料数量满足需求约束(整数匹配)")
|
||||||
else:
|
else:
|
||||||
print("❌ 部分物料数量未满足需求约束")
|
print("❌ 部分物料数量未满足需求约束")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue