156 lines
6.7 KiB
Python
156 lines
6.7 KiB
Python
import random
|
||
import matplotlib.pyplot as plt
|
||
import numpy as np
|
||
from Decode import Decode
|
||
from Encode import Encode
|
||
from GA import GA
|
||
from Instance import *
|
||
from NSGA2 import NSGA2
|
||
|
||
# 绘制甘特图
|
||
def Gantt(Machines):
|
||
M = ['red', 'blue', 'yellow', 'orange', 'green', 'palegoldenrod', 'purple', 'pink', 'Thistle', 'Magenta',
|
||
'SlateBlue', 'RoyalBlue', 'Cyan', 'Aqua', 'floralwhite', 'ghostwhite', 'goldenrod', 'mediumslateblue',
|
||
'navajowhite', 'nawy', 'sandybrown', 'moccasin']
|
||
for i in range(len(Machines)):
|
||
Machine = Machines[i]
|
||
Start_time = Machine.O_start
|
||
End_time = Machine.O_end
|
||
for i_1 in range(len(End_time)):
|
||
plt.barh(i, width=End_time[i_1] - Start_time[i_1], height=0.8, left=Start_time[i_1],
|
||
color=M[Machine.assigned_task[i_1][0] - 1], edgecolor='black')
|
||
plt.text(x=Start_time[i_1] + (End_time[i_1] - Start_time[i_1]) / 2 - 0.5, y=i,
|
||
s=Machine.assigned_task[i_1][0])
|
||
plt.yticks(np.arange(len(Machines) + 1), np.arange(1, len(Machines) + 2))
|
||
plt.title('Scheduling Gantt chart')
|
||
plt.ylabel('Machines')
|
||
plt.xlabel('Time(min)')
|
||
plt.savefig('优化后排程方案的甘特图.png')
|
||
plt.show()
|
||
|
||
if __name__ == '__main__':
|
||
# 初始化参数
|
||
g = GA()
|
||
e = Encode(Processing_time, g.Pop_size, J, J_num, M_num)
|
||
CHS1 = e.Global_initial()
|
||
CHS2 = e.Random_initial()
|
||
CHS3 = e.Local_initial()
|
||
C = np.vstack((CHS1, CHS2, CHS3))
|
||
|
||
# 双目标优化相关
|
||
nsga2 = NSGA2(g.Pop_size, 2) # 2个优化目标
|
||
Optimal_solutions = [] # 存储非支配解
|
||
Optimal_fit_values = [] # 存储非支配解的目标值
|
||
|
||
# 新增:用于存储所有代的所有解
|
||
all_solutions = [] # 存储所有个体(染色体)
|
||
all_fitnesses = [] # 存储所有个体的目标值
|
||
|
||
for i in range(g.Max_Itertions):
|
||
print(f"iter_{i} start!")
|
||
Fit = g.fitness(C, J, Processing_time, M_num, O_num)
|
||
|
||
# 记录当前代的所有解
|
||
all_solutions.extend(C)
|
||
all_fitnesses.extend(Fit)
|
||
|
||
# 非支配排序
|
||
rank = nsga2.fast_non_dominated_sort(Fit)
|
||
current_non_dominated = [C[j] for j in range(len(C)) if rank[j] == 0]
|
||
current_non_dominated_fit = [Fit[j] for j in range(len(C)) if rank[j] == 0]
|
||
|
||
# 更新全局非支配解
|
||
Optimal_solutions.extend(current_non_dominated)
|
||
Optimal_fit_values.extend(current_non_dominated_fit)
|
||
|
||
# 对全局解重新筛选非支配解
|
||
if Optimal_solutions:
|
||
rank_all = nsga2.fast_non_dominated_sort(Optimal_fit_values)
|
||
# 保留等级为0的解
|
||
Optimal_solutions = [Optimal_solutions[j] for j in range(len(Optimal_solutions)) if rank_all[j] == 0]
|
||
Optimal_fit_values = [Optimal_fit_values[j] for j in range(len(Optimal_fit_values)) if rank_all[j] == 0]
|
||
# 控制解的数量,过多时保留拥挤度高的解
|
||
if len(Optimal_solutions) > g.Pop_size:
|
||
distance = nsga2.crowding_distance(Optimal_fit_values, rank_all)
|
||
# 按拥挤度排序并保留前Pop_size个解
|
||
sorted_indices = sorted(range(len(distance)), key=lambda k: distance[k], reverse=True)
|
||
Optimal_solutions = [Optimal_solutions[j] for j in sorted_indices[:g.Pop_size]]
|
||
Optimal_fit_values = [Optimal_fit_values[j] for j in sorted_indices[:g.Pop_size]]
|
||
|
||
# 选择操作(基于NSGA-II)
|
||
selected = nsga2.selection(C, Fit)
|
||
|
||
# 交叉变异操作
|
||
new_pop = []
|
||
for j in range(len(selected)):
|
||
if random.random() < g.Pc:
|
||
# 选择另一个个体进行交叉
|
||
mate_idx = random.randint(0, len(selected) - 1)
|
||
if random.random() < g.Pv:
|
||
offspring1, offspring2 = g.machine_cross(selected[j], selected[mate_idx], O_num)
|
||
else:
|
||
offspring1, offspring2 = g.operation_cross(selected[j], selected[mate_idx], O_num, J_num)
|
||
new_pop.append(offspring1)
|
||
new_pop.append(offspring2)
|
||
else:
|
||
new_pop.append(selected[j])
|
||
|
||
# 变异操作
|
||
if random.random() < g.Pm:
|
||
if random.random() < g.Pw:
|
||
mutated = g.machine_variation(selected[j], Processing_time, O_num, J)
|
||
else:
|
||
mutated = g.operation_variation(selected[j], O_num, J_num, J, Processing_time, M_num)
|
||
new_pop.append(mutated)
|
||
|
||
# 保持种群规模
|
||
if len(new_pop) > g.Pop_size:
|
||
# 对新种群进行筛选
|
||
new_fit = g.fitness(new_pop, J, Processing_time, M_num, O_num)
|
||
new_rank = nsga2.fast_non_dominated_sort(new_fit)
|
||
new_distance = nsga2.crowding_distance(new_fit, new_rank)
|
||
# 按等级和拥挤度排序
|
||
sorted_indices = sorted(range(len(new_pop)), key=lambda k: (new_rank[k], -new_distance[k]))
|
||
C = [new_pop[j] for j in sorted_indices[:g.Pop_size]]
|
||
else:
|
||
C = new_pop
|
||
|
||
# 输出结果
|
||
print("\n=== 优化结果 ===")
|
||
print(f"非支配解数量: {len(Optimal_solutions)}")
|
||
print("非支配解目标值 (最大完工时间, 负载标准差):")
|
||
for fit in Optimal_fit_values:
|
||
print(f"({fit[0]}, {fit[1]:.2f})")
|
||
|
||
# 选择一个折中解绘制甘特图(例如Cmax最小的解)
|
||
if Optimal_solutions:
|
||
# 找到Cmax最小的解
|
||
cmax_values = [fit[0] for fit in Optimal_fit_values]
|
||
best_idx = cmax_values.index(min(cmax_values))
|
||
Optimal_CHS = Optimal_solutions[best_idx]
|
||
# 解码并绘图
|
||
d = Decode(J, Processing_time, M_num)
|
||
final_fitness = d.decode(Optimal_CHS, O_num)
|
||
print(f"\n选中解的目标值: (最大完工时间: {final_fitness[0]}, 负载标准差: {final_fitness[1]:.2f})")
|
||
Gantt(d.Machines)
|
||
|
||
# 绘制帕累托前沿(非支配解)
|
||
if Optimal_fit_values:
|
||
plt.figure(figsize=(10, 6))
|
||
cmax_nd = [fit[0] for fit in Optimal_fit_values]
|
||
load_std_nd = [fit[1] for fit in Optimal_fit_values]
|
||
plt.scatter(cmax_nd, load_std_nd, color='red', label='Non-dominated solutions', zorder=5)
|
||
|
||
# 绘制所有解的点图(所有代的所有个体)
|
||
if all_fitnesses:
|
||
cmax_all = [fit[0] for fit in all_fitnesses]
|
||
load_std_all = [fit[1] for fit in all_fitnesses]
|
||
plt.scatter(cmax_all, load_std_all, color='blue', alpha=0.5, label='All solutions', zorder=1)
|
||
|
||
plt.title('All Solutions and Pareto Front')
|
||
plt.xlabel('Max Completion Time (Cmax)')
|
||
plt.ylabel('Load Standard Deviation')
|
||
plt.legend()
|
||
plt.grid(True)
|
||
plt.savefig('all_solutions_pareto.png')
|
||
plt.show() |