79 lines
3.5 KiB
Python
79 lines
3.5 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):
|
||
self.config = config
|
||
self.utils = utils
|
||
|
||
def two_point_crossover(self, parent1: np.ndarray, parent2: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
|
||
"""两点交叉"""
|
||
length = self.utils.chromosome_length
|
||
if length < 2:
|
||
return parent1.copy(), parent2.copy()
|
||
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]
|
||
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:
|
||
"""均匀变异:遍历三层每个基因"""
|
||
mutated = chromosome.copy()
|
||
enterprise_layer, capacity_layer, quantity_layer = self.utils._split_chromosome(mutated)
|
||
split_points = np.cumsum(self.utils.material_enterprise_count)
|
||
# 企业层变异(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]
|
||
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]
|
||
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]
|
||
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):
|
||
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.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 |