From 5d5aaae2fcfb12f1e9a18f37376732c17c44a042 Mon Sep 17 00:00:00 2001 From: Hgq <2757430053@qq.com> Date: Sat, 6 Dec 2025 11:45:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B3=A8=E9=87=8A=EF=BC=8C?= =?UTF-8?q?=E5=8F=98=E5=BC=82=E5=AE=9E=E7=8E=B0=E9=80=BB=E8=BE=91=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=8C=E5=A2=9E=E5=8A=A0=E4=BA=86=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=B1=82=E5=8F=98=E5=BC=82=E5=90=8E=E7=9A=84=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chromosome_utils.py | 9 +-- data_structures.py | 8 +-- encoder.py | 12 ++-- genetic_operators.py | 134 +++++++++++++++++++++++++++++-------------- 4 files changed, 105 insertions(+), 58 deletions(-) diff --git a/chromosome_utils.py b/chromosome_utils.py index eee419a..109d624 100644 --- a/chromosome_utils.py +++ b/chromosome_utils.py @@ -140,8 +140,9 @@ class ChromosomeUtils: max_total_cap = self.supplier.Cj_total_max[supplier_id] # 供应商总产能上限 if total_cap > max_total_cap: # 超出上限时缩放 - scale = max_total_cap / total_cap # 缩放比例 + scale = max_total_cap / total_cap # 缩放比例(会出现浮点) start = 0 + # 重新遍历,按比例缩小该企业所有物料的产能 for i in range(self.I): end = split_points[i] ents = self.material_optional_enterprises[i] @@ -160,8 +161,8 @@ class ChromosomeUtils: repaired = quantity_layer.copy() split_points = np.cumsum(self.material_enterprise_count) start = 0 - for i in range(self.I): - qi = self.order.Q[i] + for i in range(self.I): # 遍历每种物料 + qi = self.order.Q[i] # 物料i的需求量 end = split_points[i] ents = self.material_optional_enterprises[i] segment = repaired[start:end] @@ -184,7 +185,7 @@ class ChromosomeUtils: segment[idx] = min_q elif segment[idx] > max_q: segment[idx] = max_q - # 步骤2:强制总量等于需求数量(核心修复) + # 步骤2:强制总量等于需求数量 current_total = np.sum(segment[selected_indices]) if current_total <= 0: weights = np.random.rand(len(selected_indices)) diff --git a/data_structures.py b/data_structures.py index 0bdc4a7..aa6fa18 100644 --- a/data_structures.py +++ b/data_structures.py @@ -91,7 +91,7 @@ class Config: def __init__(self): # 种群参数 - self.pop_size = 50 # 种群大小 + self.pop_size = 300 # 种群大小 self.N1_ratio = 0.2 # 优先成本的种群比例 self.N2_ratio = 0.2 # 优先延期的种群比例 self.N3_ratio = 0.3 # 强制风险企业的种群比例 @@ -99,12 +99,12 @@ class Config: # 遗传操作参数 self.crossover_prob = 0.8 # 交叉概率 - self.mutation_prob = 0.3 # 变异概率 - self.max_generations = 100 # 最大进化代数 + self.mutation_prob = 0.2 # 变异概率 + self.max_generations = 800 # 最大进化代数 # 惩罚系数 self.delta = 1.3 # 变更惩罚系数 - self.gamma = 0.8 # 提前交付惩罚系数 + self.gamma = 500 # 提前交付惩罚系数 # 早停参数 self.early_stop_patience = 50 # 连续多少代无改进则早停 diff --git a/encoder.py b/encoder.py index d5cfe08..f998355 100644 --- a/encoder.py +++ b/encoder.py @@ -1,9 +1,9 @@ import random import numpy as np -from data_structures import Config # 配置参数类 -from chromosome_utils import ChromosomeUtils # 染色体工具类 -from objective_calculator import ObjectiveCalculator # 目标函数计算器 -from nsga2 import NSGA2 # NSGA-II算法类 +from data_structures import Config +from chromosome_utils import ChromosomeUtils +from objective_calculator import ObjectiveCalculator +from nsga2 import NSGA2 class Encoder: @@ -109,8 +109,8 @@ class Encoder: if count <= 0: # 数量为0时返回空数组 return np.array([]) - # 生成候选解(数量为count的2倍或至少20个,确保有足够选择空间) - candidate_count = max(2 * count, 20) + # 生成候选解(数量为count的3倍或至少20个,确保有足够选择空间) + candidate_count = max(3 * count, 20) candidates = [self._generate_random_chromosome() for _ in range(candidate_count)] # 计算候选解的目标函数值 diff --git a/genetic_operators.py b/genetic_operators.py index dc3ebe3..0fce959 100644 --- a/genetic_operators.py +++ b/genetic_operators.py @@ -52,67 +52,113 @@ class GeneticOperator: # 拆分染色体为三层 enterprise_layer, capacity_layer, quantity_layer = self.utils._split_chromosome(mutated) - # 计算各物料的企业编码在染色体中的分割点(用于分层处理) split_points = np.cumsum(self.utils.material_enterprise_count) - # 1. 企业层变异(0/1翻转,即是否选择该企业) - start = 0 # 起始索引 - for i in range(self.utils.I): # 遍历每种物料 - end = split_points[i] # 当前物料的企业编码结束索引 - # 遍历该物料的所有可选企业 - for idx in range(start, end): - # 以设定的变异概率进行翻转 - if random.random() < self.config.mutation_prob: - enterprise_layer[idx] = 1 - enterprise_layer[idx] # 0→1或1→0 - start = end # 更新起始索引为下一个物料 - # 修复企业层(确保每种物料至少选择一个企业) - enterprise_layer = self.utils.repair_enterprise_layer(enterprise_layer) + # ========== 第一步:记录原始企业层状态 ========== + original_enterprise_layer = enterprise_layer.copy() - # 2. 能力层变异(调整选中企业的产能) + # ========== 第二步:企业层变异 ========== start = 0 for i in range(self.utils.I): end = split_points[i] - ents = self.utils.material_optional_enterprises[i] # 当前物料的可选企业列表 - e_segment = enterprise_layer[start:end] # 当前物料的企业选择状态 for idx in range(start, end): - # 仅对被选中的企业(e_segment[idx-start]==1)进行变异 - if random.random() < self.config.mutation_prob and e_segment[idx - start] == 1: - ent = ents[idx - start] # 企业ID(0为风险企业,1+为供应商) - # 确定该企业的最大产能 - if ent == 0: - max_cap = self.utils.risk.C0_i_std[i] # 风险企业的单物料产能 - else: - supplier_id = ent - 1 # 供应商索引(转换为0基) - max_cap = self.utils.supplier.Cj_i_std[supplier_id][i] # 供应商的单物料产能 - # 随机生成1到max_cap之间的新产能 - capacity_layer[idx] = random.uniform(1, max_cap) + if random.random() < self.config.mutation_prob: + enterprise_layer[idx] = 1 - enterprise_layer[idx] start = end - # 修复能力层(确保不超过企业总产能约束) - capacity_layer = self.utils.repair_capacity_layer(enterprise_layer, capacity_layer) - # 3. 数量层变异(调整选中企业的生产数量) + # 修复企业层 + enterprise_layer = self.utils.repair_enterprise_layer(enterprise_layer) + + # ========== 第三步:同步更新能力和数量层 ========== + start = 0 + for i in range(self.utils.I): + end = split_points[i] + ents = self.utils.material_optional_enterprises[i] + + for idx in range(start, end): + current_ent_selected = enterprise_layer[idx] # 变异后的选择状态 + original_ent_selected = original_enterprise_layer[idx] # 变异前的选择状态 + + # 情况1:企业从选中变为未选中(1→0) + if original_ent_selected == 1 and current_ent_selected == 0: + capacity_layer[idx] = 0 # 产能设为0 + quantity_layer[idx] = 0 # 数量设为0 + + # 情况2:企业从未选中变为选中(0→1) + elif original_ent_selected == 0 and current_ent_selected == 1: + ent = ents[idx - start] + + # 初始化产能 + if ent == 0: + max_cap = self.utils.risk.C0_i_std[i] + else: + supplier_id = ent - 1 + max_cap = self.utils.supplier.Cj_i_std[supplier_id][i] + capacity_layer[idx] = random.uniform(1, max_cap) + + # 初始化数量 + qi = self.utils.order.Q[i] + if ent == 0: + max_q = qi + else: + supplier_id = ent - 1 + max_q = self.utils.supplier.MaxOrder[supplier_id][i] + quantity_layer[idx] = random.uniform(1, max_q) + + # 情况3:企业保持选中(1→1)或保持未选中(0→0) + # 保持不变,后续的变异步骤会处理 + + start = end + + # ========== 第四步:能力层变异(仅对保持选中的企业) ========== start = 0 for i in range(self.utils.I): end = split_points[i] ents = self.utils.material_optional_enterprises[i] e_segment = enterprise_layer[start:end] + for idx in range(start, end): - # 仅对被选中的企业进行变异 - if random.random() < self.config.mutation_prob and e_segment[idx - start] == 1: - ent = ents[idx - start] - qi = self.utils.order.Q[i] # 当前物料的总需求 - # 确定该企业的最大可分配数量 - if ent == 0: - max_q = qi # 风险企业最多分配全部需求 - else: - supplier_id = ent - 1 - max_q = self.utils.supplier.MaxOrder[supplier_id][i] # 供应商的最大供应量 - # 随机生成1到max_q之间的新数量 - quantity_layer[idx] = random.uniform(1, max_q) + # 只对保持选中的企业进行变异(1→1的情况) + if e_segment[idx - start] == 1 and original_enterprise_layer[idx] == 1: + if random.random() < self.config.mutation_prob: + ent = ents[idx - start] + if ent == 0: + max_cap = self.utils.risk.C0_i_std[i] + else: + supplier_id = ent - 1 + max_cap = self.utils.supplier.Cj_i_std[supplier_id][i] + capacity_layer[idx] = random.uniform(1, max_cap) + start = end - # 修复数量层(确保总数量满足需求,且不超过企业最大供应) + + # 修复能力层(考虑所有选中企业的产能) + capacity_layer = self.utils.repair_capacity_layer(enterprise_layer, capacity_layer) + + # ========== 第五步:数量层变异(仅对保持选中的企业) ========== + start = 0 + for i in range(self.utils.I): + end = split_points[i] + ents = self.utils.material_optional_enterprises[i] + e_segment = enterprise_layer[start:end] + + for idx in range(start, end): + # 只对保持选中的企业进行变异(1→1的情况) + if e_segment[idx - start] == 1 and original_enterprise_layer[idx] == 1: + if random.random() < self.config.mutation_prob: + ent = ents[idx - start] + qi = self.utils.order.Q[i] + if ent == 0: + max_q = qi + else: + supplier_id = ent - 1 + max_q = self.utils.supplier.MaxOrder[supplier_id][i] + quantity_layer[idx] = random.uniform(1, max_q) + + start = end + + # 修复数量层(考虑所有选中企业的分配) quantity_layer = self.utils.repair_quantity_layer(enterprise_layer, quantity_layer) - # 合并三层并返回 + # 合并三层 mutated = self.utils._merge_chromosome(enterprise_layer, capacity_layer, quantity_layer) return mutated \ No newline at end of file