OrderReallocation-HeavyTruc.../genetic_operators.py

145 lines
7.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import random
import numpy as np
from data_structures import Config # 算法配置参数类
from chromosome_utils import ChromosomeUtils # 染色体工具类
class GeneticOperator:
"""遗传操作类:实现交叉和变异操作,用于产生新个体(整数化)"""
def __init__(self, config: Config, utils: ChromosomeUtils):
"""
初始化遗传操作器
:param config: 算法配置参数(如交叉概率、变异概率等)
:param utils: 染色体工具类实例(提供染色体修复等功能)
"""
self.config = config # 配置参数
self.utils = utils # 染色体工具
def two_point_crossover(self, parent1: np.ndarray, parent2: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
"""
两点交叉:在染色体上随机选择两个点,交换两点之间的基因片段
:param parent1: 父代染色体1整数
:param parent2: 父代染色体2整数
:return: 两个子代染色体(经过修复,整数)
"""
length = self.utils.chromosome_length # 染色体总长度
if length < 2: # 染色体长度不足2时无法交叉直接返回父代副本
return parent1.copy().astype(int), parent2.copy().astype(int)
# 随机选择两个交叉点point1 < point2
point1 = random.randint(0, length // 2)
point2 = random.randint(point1 + 1, length - 1)
# 复制父代基因并交换片段
child1 = parent1.copy()
child2 = parent2.copy()
child1[point1:point2] = parent2[point1:point2] # 交换point1到point2之间的基因
child2[point1:point2] = parent1[point1:point2]
# 修复染色体(确保满足约束条件)
child1 = self.utils.repair_chromosome(child1)
child2 = self.utils.repair_chromosome(child2)
return child1.astype(int), child2.astype(int)
def uniform_mutation(self, chromosome: np.ndarray) -> np.ndarray:
"""
均匀变异:对染色体的三层基因(企业层、能力层、数量层)进行随机变异(整数化)
:param chromosome: 待变异的染色体(整数)
:return: 变异后的染色体(经过修复,整数)
"""
mutated = chromosome.copy().astype(int) # 确保为整数
# 拆分染色体为三层
enterprise_layer, capacity_layer, quantity_layer = self.utils._split_chromosome(mutated)
split_points = np.cumsum(self.utils.material_enterprise_count)
# ========== 第一步:记录原始企业层状态 ==========
original_enterprise_layer = enterprise_layer.copy()
# ========== 第二步:企业层变异 ==========
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]
start = end
# 修复企业层
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]
qi = self.utils.order.Q[i]
# 初始化产能(整数)
if ent == 0:
min_cap = self.utils.risk.C0_i_min[i]
max_cap = self.utils.risk.C0_total_max
else:
supplier_id = ent - 1
min_cap = self.utils.supplier.Cj_i_min[supplier_id][i]
max_cap = self.utils.supplier.Cj_total_max[supplier_id]
capacity_layer[idx] = random.randint(min_cap, max_cap)
# 初始化数量(整数)
if ent == 0:
min_q = 0
max_q = qi
else:
supplier_id = ent - 1
min_q = self.utils.supplier.MinOrder[supplier_id][i]
max_q = self.utils.supplier.MaxOrder[supplier_id][i]
quantity_layer[idx] = random.randint(min_q, 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):
# 只对保持选中的企业进行变异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:
min_cap = self.utils.risk.C0_i_min[i]
max_cap = self.utils.risk.C0_total_max
else:
supplier_id = ent - 1
min_cap = self.utils.supplier.Cj_i_min[supplier_id][i]
max_cap = self.utils.supplier.Cj_total_max[supplier_id]
# 变异后产能为整数
capacity_layer[idx] = random.randint(min_cap, 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:
min_q = 0
max_q = qi
else:
supplier_id = ent - 1
min_q = self.utils.supplier.MinOrder[supplier_id][i]
max_q = self.utils.supplier.MaxOrder[supplier_id][i]
quantity_layer[idx] = random.randint(min_q, 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.astype(int)