import itertools import random import numpy as np from Decode import Decode from Instance import * class GA(): def __init__(self): self.Pop_size = 500 # 种群数量 self.Pc = 0.8 # 交叉概率 self.Pm = 0.15 # 降低变异概率到0.15 self.Pv = 0.5 # 选择何种方式进行交叉的概率阈值 self.Pw = 0.95 # 选择何种方式进行变异的概率阈值 self.Max_Itertions = 100 # 适应度 def fitness(self, CHS, J, Processing_time, M_num, Len): Fit = [] for i in range(len(CHS)): d = Decode(J, Processing_time, M_num) # 实例化一个解码器,传入问题参数 Fit.append(d.decode(CHS[i], Len)) return Fit def pmx_crossover(self, parent1, parent2, length): if length <= 1: return parent1.copy(), parent2.copy() # 确保交叉区间[a, b]有效(a < b) a = random.randint(0, length - 2) b = random.randint(a + 1, length - 1) child1 = parent1.copy() child2 = parent2.copy() # 建立映射表(parent1[a:b+1]与parent2[a:b+1]的对应关系) map1 = {parent1[i]: parent2[i] for i in range(a, b + 1)} # p1→p2的映射 map2 = {parent2[i]: parent1[i] for i in range(a, b + 1)} # p2→p1的映射 # 处理child1:交叉区间外的元素替换 for i in range(length): if i < a or i > b: val = child1[i] # 限制循环次数,避免无限循环(最多循环len(map1)次) loop_count = 0 max_loop = len(map1) while val in map1 and map1[val] in parent1[a:b + 1] and loop_count < max_loop: val = map1[val] loop_count += 1 child1[i] = map1.get(val, val) # 若超出循环次数,直接使用当前val # 处理child2:交叉区间外的元素替换 for i in range(length): if i < a or i > b: val = child2[i] loop_count = 0 max_loop = len(map2) while val in map2 and map2[val] in parent2[a:b + 1] and loop_count < max_loop: val = map2[val] loop_count += 1 child2[i] = map2.get(val, val) return child1, child2 # 机器部分交叉 def machine_cross(self, CHS1, CHS2, T0): """ :param CHS1: 基因1 :param CHS2: 基因2 :param T0: 工序总数 :return: 交叉后的基因 """ OS1, MS1 = CHS1[:T0], CHS1[T0:] OS2, MS2 = CHS2[:T0], CHS2[T0:] # 随机选择交叉位置 T_r = list(range(T0)) random.shuffle(T_r) r = random.randint(1, T0 // 2) # 交叉部分长度 R = T_r[:r] # 交换机器选择部分 for i in R: MS1[i], MS2[i] = MS2[i], MS1[i] return np.hstack((OS1, MS1)), np.hstack((OS2, MS2)) # 工序部分交叉(使用PMX交叉) def operation_cross(self, CHS1, CHS2, T0, J_num): OS1 = list(CHS1[T0:2 * T0]) # 确保转换为列表 OS2 = list(CHS2[T0:2 * T0]) MS1 = CHS1[0:T0].copy() MS2 = CHS2[0:T0].copy() # 调用修复后的PMX交叉 new_os1, new_os2 = self.pmx_crossover(OS1, OS2, T0) CHS1 = np.hstack((MS1, new_os1)) CHS2 = np.hstack((MS2, new_os2)) return CHS1, CHS2 # 机器部分变异(仅在可用机器集中选择) def machine_variation(self, CHS, O, T0, J): """ :param CHS: 基因 :param O: 加工时间矩阵 :param T0: 工序总数 :param J: 各工件加工信息 :return: 变异后的基因 """ OS = CHS[:T0] MS = CHS[T0:] # 确定变异位置数量 r = random.randint(1, max(1, T0 // 10)) # 最多变异10%的位置 positions = random.sample(range(T0), r) for pos in positions: # 找到该位置对应的工件和工序 site = 0 job = -1 op = -1 for k, v in J.items(): if site + v > pos: job = k - 1 # 转换为0索引 op = pos - site break site += v # 获取该工序的可用机器 D = O[job][op] available_machines = [k for k, val in enumerate(D) if val != 9999] if len(available_machines) <= 1: continue # 只有一个可用机器时不变异 # 随机选择一个不同的可用机器 current_idx = MS[pos] current_machine = available_machines[current_idx] new_machine = random.choice([m for m in available_machines if m != current_machine]) MS[pos] = available_machines.index(new_machine) return np.hstack((OS, MS)) # 工序部分变异 def operation_variation(self, CHS, T0, J_num, J, O, M_num): """ :param CHS: 基因 :param T0: 工序总数 :param J_num: 工件总数 :param J: 各工件加工信息 :param O: 加工时间矩阵 :param M_num: 机器总数 :return: 变异后的基因 """ OS = list(CHS[:T0]) MS = CHS[T0:] # 随机选择两个位置交换 i, j = random.sample(range(T0), 2) OS[i], OS[j] = OS[j], OS[i] return np.hstack((OS, MS))