118 lines
5.9 KiB
Python
118 lines
5.9 KiB
Python
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(), parent2.copy()
|
||
|
||
# 随机选择两个交叉点(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, child2
|
||
|
||
def uniform_mutation(self, chromosome: np.ndarray) -> np.ndarray:
|
||
"""
|
||
均匀变异:对染色体的三层基因(企业层、能力层、数量层)进行随机变异
|
||
:param chromosome: 待变异的染色体
|
||
:return: 变异后的染色体(经过修复)
|
||
"""
|
||
mutated = chromosome.copy() # 复制原始染色体,避免直接修改
|
||
|
||
# 拆分染色体为三层
|
||
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)
|
||
|
||
# 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)
|
||
start = end
|
||
# 修复能力层(确保不超过企业总产能约束)
|
||
capacity_layer = self.utils.repair_capacity_layer(enterprise_layer, capacity_layer)
|
||
|
||
# 3. 数量层变异(调整选中企业的生产数量)
|
||
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)
|
||
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 |