OrderReallocation-HeavyTruc.../visualizer.py

93 lines
4.2 KiB
Python

import matplotlib.pyplot as plt
import numpy as np
from chromosome_utils import ChromosomeUtils
class ResultVisualizer:
"""结果可视化工具"""
def __init__(self, utils: ChromosomeUtils):
self.utils = utils
self.figsize = (12, 8)
self.supplier_names = ["RiskEnterprise"] + self.utils.supplier.names
def plot_pareto_front(self, all_objectives: list[tuple[float, float]],
non_dominated_objectives: list[tuple[float, float]]):
"""绘制帕累托前沿"""
plt.figure(figsize=self.figsize)
if all_objectives:
c_all = [obj[0] for obj in all_objectives]
t_all = [obj[1] for obj in all_objectives]
plt.scatter(c_all, t_all, color='blue', alpha=0.3, label='All Solutions', zorder=1)
if non_dominated_objectives:
c_nd = [obj[0] for obj in non_dominated_objectives]
t_nd = [obj[1] for obj in non_dominated_objectives]
plt.scatter(c_nd, t_nd, color='red', s=50, label='Pareto Front', zorder=5)
plt.title('Pareto Front: Change Cost vs Tardiness')
plt.xlabel('Change Cost')
plt.ylabel('Tardiness')
plt.legend()
plt.grid(True, alpha=0.5)
plt.savefig('pareto_front.png', dpi=300, bbox_inches='tight')
plt.show()
def plot_convergence(self, convergence_history: list[tuple[float, float]]):
"""绘制收敛趋势图"""
if len(convergence_history) == 0:
return
plt.figure(figsize=self.figsize)
generations = list(range(len(convergence_history)))
costs = [h[0] for h in convergence_history]
tardiness = [h[1] for h in convergence_history]
plt.subplot(2, 1, 1)
plt.plot(generations, costs, 'b-')
plt.title('Convergence History')
plt.ylabel('Average Change Cost')
plt.grid(True, alpha=0.5)
plt.subplot(2, 1, 2)
plt.plot(generations, tardiness, 'r-')
plt.xlabel('Generation')
plt.ylabel('Average Tardiness')
plt.grid(True, alpha=0.5)
plt.tight_layout()
plt.savefig('convergence_history.png', dpi=300, bbox_inches='tight')
plt.show()
def print_solution_details(self, solution: np.ndarray, objectives: tuple[float, float]):
"""打印单个解的详细信息(含数量校验)"""
enterprise_layer, capacity_layer, quantity_layer = self.utils._split_chromosome(solution)
split_points = np.cumsum(self.utils.material_enterprise_count)
print(f"\n变更成本: {objectives[0]:.2f}, 交付延期: {objectives[1]:.2f}")
print("=" * 80)
total_q_check = []
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]
c_segment = capacity_layer[start:end]
q_segment = quantity_layer[start:end]
demand_q = self.utils.order.Q[i]
print(f"物料 {i} - 需求数量: {demand_q}, 分配总量: {np.sum(q_segment[e_segment==1]):.2f}")
total_q_check.append(abs(np.sum(q_segment[e_segment==1]) - demand_q) < 1e-2)
print(f" 选择的企业及其分配:")
for idx, ent in enumerate(ents):
if e_segment[idx] == 1:
ent_name = self.supplier_names[ent]
cap = c_segment[idx]
qty = q_segment[idx]
print(f" 企业: {ent_name}, 产能: {cap:.2f}, 分配数量: {qty:.2f}")
start = end
print("-" * 80)
if all(total_q_check):
print("✅ 所有物料数量满足需求约束")
else:
print("❌ 部分物料数量未满足需求约束")
def print_pareto_solutions(self, population: np.ndarray, objectives: list[tuple[float, float]]):
"""打印帕累托前沿解的详细信息"""
print("\n" + "=" * 100)
print("帕累托前沿解详细方案")
print("=" * 100)
for i in range(min(5, len(population))):
print(f"\n===== 最优解 {i+1} =====")
self.print_solution_details(population[i], objectives[i])