import numpy as np
import gurobipy as gp
from gurobipy import GRB
from scipy.spatial import distance
from scipy import io
import itertools
import random
import copy
import time
import matplotlib.pyplot as plt
from collections import deque
# ======================
# 仿真环境构建
# ======================
print("初始化仿真环境...")
J = 8 # 服务区域内站点数量
m = 3 # 车队规模
c = 6 # 车载容量
N = 16 # 每趟列车的乘客发生量强度
batch_size = 10 # 总batch数量
service_time = 1 # 停站服务时间(分钟)
headway = 10 # 车头时距间隔(分钟)
M = 100 # 未被服务时的出行时间
t = 0 # 当前仿真时间
btw = np.zeros((m, 1)) # 车辆可用的时间
btw_vehicle = []
for i in range(m):
vehicle = {
'record': [
[0, 0, 0, 0] # 初始化,第一行为时间、路径等信息
]
}
btw_vehicle.append(vehicle)
beta1, beta2, beta3 = 100, 10, 1 # 权重参数
metro_station = np.array([[0, 0]]) # 地铁站坐标
vehicle_speed = 30 # 公里/小时
servicearea_L, servicearea_W = 5, 3 # 服务区域尺寸
mat_data = io.loadmat('F:/LM程序/LM_stop8.mat')
LM_stop = mat_data['LM_stop']
all_stop = np.vstack([metro_station, LM_stop]) # 合并所有站点
dist_matrix = distance.squareform(distance.pdist(all_stop)) # 计算欧氏距离
traveltime_matrix = dist_matrix / vehicle_speed * 60
# ======================
# 辅助函数
# ======================
def candidate_route_gen(max_stop, max_traveltime, traveltime_matrix, service_time, J):
"""生成满足约束的候选路径"""
print(f"生成候选路径 (最多站点: {max_stop}, 最大行程时间: {max_traveltime}分钟)...")
all_routes = []
for i in range(1, max_stop + 1):
combinations = itertools.combinations(range(1, J + 1), i)
for combo in combinations:
permutations = itertools.permutations(combo)
for perm in permutations:
route = [0] + list(perm) + [0]
all_routes.append(route)
candidate_route = []
for route in all_routes:
travel_time = 0
for j in range(len(route) - 1):
from_node = route[j]
to_node = route[j + 1]
travel_time += traveltime_matrix[from_node][to_node]
total_time = travel_time + (len(route) - 2) * service_time
if total_time <= max_traveltime:
candidate_route.append({
'route': route,
'travel_time': total_time
})
print(f"生成 {len(candidate_route)} 条候选路径")
return candidate_route
def parameter_gen(candidate_routes, J, M, service_time, traveltime_matrix):
"""生成模型所需参数矩阵"""
print("生成模型参数...")
K = len(candidate_routes)
tk = [route['travel_time'] for route in candidate_routes]
phi_jk = []
for j in range(1, J + 1):
row = []
for route in candidate_routes:
# 检查站点j是否在当前路径中
route_nodes = route['route']
row.append(1 if j in route_nodes else 0)
phi_jk.append(row)
t_jk = [[M] * K for _ in range(J)]
for j_idx in range(J):
j = j_idx + 1
for k, route in enumerate(candidate_routes):
current_route = route['route']
if j not in current_route:
continue
idx = current_route.index(j)
arrival_time = 0.0
for seg in range(idx):
from_node = current_route[seg]
to_node = current_route[seg + 1]
arrival_time += traveltime_matrix[from_node, to_node]
arrival_time += service_time * (idx - 1)
t_jk[j_idx][k] = arrival_time
return phi_jk, tk, t_jk
def route_rank2(Wk, tk, Zjk, phi_jk, btw, t, headway):
"""对路径进行优先级排序"""
btw = np.maximum(btw, t)
valid_indices = np.where(Wk >= 1)[0]
if len(valid_indices) == 0:
return np.empty((0, 4), dtype=int)
route_numbers = (valid_indices + 1).astype(int)
S = np.zeros((len(route_numbers), 4), dtype=int)
S[:, 0] = route_numbers
S[:, 1] = Wk[valid_indices]
S[:, 2] = [tk[i] for i in valid_indices] # 使用列表推导式获取正确的行程时间
all_permutations = list(itertools.permutations(route_numbers))
min_ft = float('inf')
best_sequence = None
for seq in all_permutations:
current_btw = btw.copy()
total_wait = 0
for route in seq:
vid = np.argmin(current_btw)
start_time = current_btw[vid].item()
# 获取当前路径的行程时间
route_idx = route - 1
route_travel_time = tk[route_idx]
current_btw[vid] += route_travel_time
total_wait += np.sum(Zjk[:, route_idx]) * (start_time - t)
idle_time = np.sum(np.maximum(t + headway - current_btw, 0))
ft = total_wait + idle_time
if ft < min_ft:
min_ft = ft
best_sequence = seq
if best_sequence is not None:
priority_dict = {route: idx + 1 for idx, route in enumerate(best_sequence)}
S[:, 3] = np.vectorize(priority_dict.get)(S[:, 0])
return S[S[:, 3].argsort()]
else:
return S
# ======================
# 修正后的车辆调度函数
# ======================
def vehicle_dispatch(btw, t_jk, S, U, Zjk, t, headway,
total_trip, total_traveltime, total_waitingtime,
totoal_ridingtime, btw_vehicle, chengke):
"""执行车辆调度"""
U = U.copy()
btw = btw.copy()
for i in range(len(btw)):
if btw[i] < t:
vr = btw_vehicle[i]
if len(vr['record']) == 0:
vr['record'].append([t, t, 0, 0])
else:
last_end = vr['record'][-1][1]
vr['record'].append([last_end, t, 0, 0])
btw[i] = t
for current_time in range(t, t + headway + 1):
available = [i for i, bt in enumerate(btw) if current_time > bt]
sorted_available = sorted(available, key=lambda x: btw[x])
if sorted_available and np.sum(U) > 0:
for bus_idx in sorted_available:
if np.sum(U) <= 0:
break
if S.size == 0:
break
route_info = S[0]
total_trip[0] += 1
route_idx = route_info[0] - 1 # 路径索引
route_travel_time = route_info[2] # 路径行程时间
total_traveltime[0] += route_travel_time
served_pax = Zjk[:, route_idx]
totoal_ridingtime[0] += np.sum(served_pax * t_jk[:, route_idx])
waiting_time = btw[bus_idx] - t
total_waitingtime[0] += np.sum(served_pax) * waiting_time
# 更新乘客信息
for j in range(len(served_pax)):
if served_pax[j] > 0:
stop = j + 1 # 站点编号
pax_mask = (chengke[:, 2] == stop) & (chengke[:, 9] == 0)
pax_candidates = np.where(pax_mask)[0]
if len(pax_candidates) > 0:
num_pax = min(served_pax[j], len(pax_candidates))
selected = pax_candidates[:num_pax]
chengke[selected, 9] = 1 # 标记为已服务
chengke[selected, 4] = btw[bus_idx] # 上车时间
chengke[selected, 5] = chengke[selected, 4] - chengke[selected, 3] # 等待时间
chengke[selected, 6] = t_jk[j, route_idx] # 乘车时间
chengke[selected, 7] = route_info[0] # 路径ID
chengke[selected, 8] = bus_idx + 1 # 车辆ID
# 更新车辆记录
vr = btw_vehicle[bus_idx]
if not vr['record']:
vr['record'].append([
btw[bus_idx],
btw[bus_idx] + route_travel_time,
route_info[0],
route_travel_time
])
else:
last_end = vr['record'][-1][1]
vr['record'].append([
last_end,
last_end + route_travel_time,
route_info[0],
route_travel_time
])
# 更新车辆可用时间和需求
btw[bus_idx] += route_travel_time
U = U - Zjk[:, route_idx]
S = np.delete(S, 0, axis=0) # 移除已分配路径
if np.sum(U) <= 0:
break
# 处理未服务的乘客
if current_time == t + headway and np.sum(U) > 0:
total_waitingtime[0] += np.sum(U) * headway
return (btw, S, U, total_trip, total_traveltime,
total_waitingtime, totoal_ridingtime, btw_vehicle, chengke)
def lastmile_model(phi_jk, tk, t_jk, U, beta1, beta2, beta3, K, J, c):
"""构建并求解混合整数规划模型"""
print("构建并求解MIP模型...")
try:
model = gp.Model("LastMile")
model.Params.OutputFlag = 0
model.Params.TimeLimit = 30 # 设置30秒时间限制
wk = model.addVars(K, vtype=GRB.INTEGER, name="wk")
g = model.addVar(vtype=GRB.INTEGER, name="g")
zjk = model.addVars(J, K, vtype=GRB.INTEGER, name="zjk")
obj = beta1 * g
obj += beta2 * gp.quicksum(tk[k] * wk[k] for k in range(K))
obj += beta3 * gp.quicksum(t_jk[j][k] * zjk[j, k] for j in range(J) for k in range(K))
model.setObjective(obj, GRB.MINIMIZE)
# 约束1: 所有需求必须被满足
for j in range(J):
model.addConstr(
gp.quicksum(zjk[j, k] * phi_jk[j][k] for k in range(K)) == U[j],
name=f"constr1_j{j}"
)
# 约束2: 车辆容量约束
for k in range(K):
model.addConstr(
gp.quicksum(zjk[j, k] * phi_jk[j][k] for j in range(J)) <= c * wk[k],
name=f"constr2_k{k}"
)
# 约束3: 总行程数
model.addConstr(
gp.quicksum(wk[k] for k in range(K)) == g,
name="constr3_total_trips"
)
# 约束4: 非负约束
model.addConstr(g >= 1, name="constr4_g_min")
for k in range(K):
model.addConstr(wk[k] >= 0, name=f"constr4_wk{k}_min")
for j in range(J):
for k in range(K):
model.addConstr(zjk[j, k] >= 0, name=f"constr4_zjk{j}{k}_min")
model.optimize()
if model.status == GRB.OPTIMAL:
Zjk = np.zeros((J, K), dtype=int)
Wk = np.zeros(K, dtype=int)
for j in range(J):
for k in range(K):
Zjk[j][k] = round(zjk[j, k].X)
for k in range(K):
Wk[k] = round(wk[k].X)
G = round(g.X)
return Zjk, Wk, G
else:
# 如果未找到最优解,使用启发式方法生成可行解
print("未找到最优解,使用启发式方法生成可行解...")
return heuristic_solution(phi_jk, U, c, K, J)
except gp.GurobiError as e:
print(f"Gurobi错误: {e}")
return heuristic_solution(phi_jk, U, c, K, J)
def heuristic_solution(phi_jk, U, c, K, J):
"""启发式方法生成可行解"""
print("使用启发式方法生成可行解...")
Zjk = np.zeros((J, K), dtype=int)
Wk = np.zeros(K, dtype=int)
# 简单启发式:为每个站点分配车辆
remaining_demand = U.copy()
k = 0
while np.sum(remaining_demand) > 0 and k < K:
# 尝试覆盖尽可能多的站点
coverage = np.zeros(J, dtype=int)
for j in range(J):
if phi_jk[j][k] == 1 and remaining_demand[j] > 0:
coverage[j] = 1
if np.sum(coverage) > 0:
# 分配车辆
Wk[k] = 1
# 分配乘客
for j in range(J):
if coverage[j] == 1:
assign = min(remaining_demand[j], c)
Zjk[j][k] = assign
remaining_demand[j] -= assign
k += 1
else:
k += 1
G = np.sum(Wk)
return Zjk, Wk, G
# ======================
# 数据加载与预处理
# ======================
print("加载乘客分布数据...")
passenger_distributionUN = io.loadmat('F:/LM程序/passenger_distribution_16UN.mat')['passenger_distributionUN']
passenger_distributionSH = io.loadmat('F:/LM程序/passenger_distribution_16SH.mat')['passenger_distributionSH']
passenger_distributionEH = io.loadmat('F:/LM程序/passenger_distribution_16EH.mat')['passenger_distributionEH']
ui = passenger_distributionEH # 选择分布类型
chengke = [] # 初始化乘客列表
for i in range(1, batch_size + 1):
passenger_count_in_batch = 1
for j in range(1, J + 1):
passenger_num = ui[i - 1, j - 1].item()
if passenger_num > 0:
for _ in range(int(passenger_num)):
arrival_time = t + (i - 1) * headway
passenger_record = [
i, # 批次编号
passenger_count_in_batch, # 批次内序号
j, # 下车站点
arrival_time, # 到达时间
*[0] * 6 # 初始化后6个字段
]
chengke.append(passenger_record)
passenger_count_in_batch += 1
# ======================
# 候选路径生成
# ======================
candidate_route = candidate_route_gen(
max_stop=3,
max_traveltime=14,
traveltime_matrix=traveltime_matrix,
service_time=service_time,
J=J
)
K = len(candidate_route)
phi_jk, tk, t_jk = parameter_gen(candidate_route, J, M, service_time, traveltime_matrix)
# ======================
# 初始化记录变量
# ======================
total_trip = [0]
total_traveltime = [0]
total_waitingtime = [0]
totoal_ridingtime = [0]
chengke = np.array(chengke)
t_jk = np.array(t_jk)
btw = np.array(btw)
tk = np.array(tk)
btw_record = np.zeros((len(btw), batch_size + 1))
s = [{'route': None} for _ in range(batch_size + 100)] # 确保s是字典列表
pax_asg = [{'record': None} for _ in range(batch_size + 100)] # 确保pax_asg是字典列表
# ======================
# 主仿真循环
# ======================
print("开始主仿真循环...")
for i in range(batch_size):
print(f"\n处理批次 {i + 1}/{batch_size}...")
if i == 0:
U = ui[0, :].copy()
else:
U += ui[i, :]
print(f"当前需求: {U}")
# 求解模型
Zjk, Wk, G = lastmile_model(phi_jk, tk, t_jk, U, beta1, beta2, beta3, K, J, c)
print(f"模型求解完成: 总行程数={G}, 路径分配={Wk}")
# 路径排序
S = route_rank2(Wk, tk, Zjk, phi_jk, btw, t, headway)
print(f"路径排序完成: 分配{len(S)}条路径")
Temp_S = S.copy() if S.size > 0 else np.array([])
# 车辆调度
(btw, S, U, total_trip, total_traveltime,
total_waitingtime, totoal_ridingtime,
btw_vehicle, chengke) = vehicle_dispatch(
btw, t_jk, S, U, Zjk, t, headway,
total_trip, total_traveltime,
total_waitingtime, totoal_ridingtime,
btw_vehicle, chengke
)
# 保存结果
if Temp_S.size > 0:
s[i]["route"] = Temp_S
pax_asg[i]['record'] = Zjk
else:
s[i]["route"] = np.array([])
pax_asg[i]['record'] = np.zeros((J, K))
# 更新时间和车辆状态
t += headway
btw_record[:, i + 1] = btw.squeeze()
print(f"批次完成, 剩余需求: {np.sum(U)}")
# 处理剩余需求
print("\n处理剩余需求...")
plus_trip = batch_size
while np.sum(U) > 0 and plus_trip < batch_size + 10: # 添加安全限制
plus_trip += 1
print(f"额外批次 {plus_trip - batch_size}, 剩余需求: {np.sum(U)}")
# 求解模型
Zjk, Wk, G = lastmile_model(phi_jk, tk, t_jk, U, beta1, beta2, beta3, K, J, c)
print(f"模型求解完成: 总行程数={G}, 路径分配={Wk}")
# 路径排序
S = route_rank2(Wk, tk, Zjk, phi_jk, btw, t, headway)
print(f"路径排序完成: 分配{len(S)}条路径")
Temp_S = S.copy() if S.size > 0 else np.array([])
# 车辆调度
(btw, S, U, total_trip, total_traveltime,
total_waitingtime, totoal_ridingtime,
btw_vehicle, chengke) = vehicle_dispatch(
btw, t_jk, S, U, Zjk, t, headway,
total_trip, total_traveltime,
total_waitingtime, totoal_ridingtime,
btw_vehicle, chengke
)
# 保存结果
if Temp_S.size > 0:
s[plus_trip] = {"route": Temp_S}
pax_asg[plus_trip] = {'record': Zjk}
else:
s[plus_trip] = {"route": np.array([])}
pax_asg[plus_trip] = {'record': np.zeros((J, K))}
# 更新时间
t += headway
print(f"\n额外的运行周期:{plus_trip - batch_size}")
total_pax = np.sum(ui)
print(f'总的乘客数量为:{total_pax}')
print(f'总的行程数量为:{total_trip[0]}')
print(f'总的服务时间为:{total_traveltime[0]}')
print(f'乘客总的乘车时间为:{totoal_ridingtime[0]}')
print(f'乘客总的等待时间为:{total_waitingtime[0]}')
if total_pax > 0:
avg_riding = totoal_ridingtime[0] / total_pax
avg_waiting = total_waitingtime[0] / total_pax
print(f'乘客总的平均乘车时间为:{avg_riding:.2f}')
print(f'乘客总的平均等待时间为:{avg_waiting:.2f}')
else:
print('乘客总数为零,无法计算平均值')
# ======================
# 禁忌搜索优化器
# ======================
class TabuSearchOptimizer:
def __init__(self, initial_solution, candidate_routes, travel_time_matrix,
passenger_data, vehicle_capacity, headway, num_vehicles,
max_iter=50, max_no_improve=10, tabu_tenure=7):
"""
初始化禁忌搜索优化器
"""
self.initial_solution = initial_solution
self.candidate_routes = candidate_routes
self.travel_time_matrix = travel_time_matrix
self.passenger_data = passenger_data
self.vehicle_capacity = vehicle_capacity
self.headway = headway
self.num_vehicles = num_vehicles
self.max_iter = max_iter
self.max_no_improve = max_no_improve
self.tabu_tenure = tabu_tenure
# 初始化数据结构
self.best_solution = self.initialize_solution(initial_solution)
self.best_objective = self.evaluate_solution(self.best_solution)
self.current_solution = copy.deepcopy(self.best_solution)
self.current_objective = self.best_objective
self.tabu_list = deque(maxlen=tabu_tenure)
self.objective_history = [self.best_objective]
self.improvement_history = []
def initialize_solution(self, solution):
"""确保解决方案使用列表而不是numpy数组"""
initialized = []
for interval in solution:
# 转换route为列表
if 'route' in interval and isinstance(interval['route'], np.ndarray):
# 将numpy数组转换为列表
if interval['route'].size > 0:
interval['route'] = interval['route'].tolist()
else:
interval['route'] = []
initialized.append(interval)
return initialized
def evaluate_solution(self, solution):
"""
评估解决方案的目标函数值(总等待时间+乘车时间)
"""
total_waiting = 0
total_riding = 0
vehicle_available = np.zeros(self.num_vehicles)
unserved_passengers = []
# 预处理乘客数据为结构化数组
passenger_array = np.array(self.passenger_data, dtype=object)
# 处理每个时间间隔
for i, interval in enumerate(solution):
interval_start = i * self.headway
# 添加当前间隔到达的乘客
batch_mask = (passenger_array[:, 0] == i + 1)
if np.any(batch_mask):
batch_passengers = passenger_array[batch_mask].copy()
batch_passengers = np.column_stack((batch_passengers,
np.full(batch_passengers.shape[0], interval_start)))
unserved_passengers.extend(batch_passengers.tolist())
# 处理当前间隔的路径
if 'route' in interval and interval['route']:
routes = interval['route']
# 按优先级排序
sorted_routes = sorted(routes, key=lambda x: x[3] if len(x) > 3 else 0)
for route in sorted_routes:
route_idx = route[0] - 1
route_info = self.candidate_routes[route_idx]
# 选择最早可用的车辆
vehicle_idx = np.argmin(vehicle_available)
start_time = max(vehicle_available[vehicle_idx], interval_start)
# 服务乘客
capacity_used = 0
passengers_to_remove = []
route_stops = set(route_info['route'][1:-1])
# 筛选符合条件的乘客
eligible_passengers = []
for idx, p in enumerate(unserved_passengers):
if p[2] in route_stops:
eligible_passengers.append((idx, p))
# 按到达时间排序
eligible_passengers.sort(key=lambda x: x[1][3])
# 服务乘客直到车辆满载
for idx, p in eligible_passengers:
if capacity_used >= self.vehicle_capacity:
break
# 计算等待时间和乘车时间
waiting_time = start_time - p[3]
from_node = 0 # 起点(地铁站)
to_node = p[2] # 下车站点
riding_time = self.travel_time_matrix[from_node][to_node]
total_waiting += waiting_time
total_riding += riding_time
capacity_used += 1
passengers_to_remove.append(idx)
# 移除已服务乘客
for idx in sorted(passengers_to_remove, reverse=True):
unserved_passengers.pop(idx)
# 更新车辆可用时间
vehicle_available[vehicle_idx] = start_time + route_info['travel_time']
# 对未服务乘客的惩罚
last_time = len(solution) * self.headway
for p in unserved_passengers:
total_waiting += (last_time - p[3]) * 10 # 惩罚因子
return total_waiting + total_riding
def generate_neighbors(self, solution, num_neighbors=10):
"""
生成邻域解
"""
neighbors = []
for _ in range(num_neighbors):
neighbor = copy.deepcopy(solution)
interval_idx = random.randint(0, len(solution) - 1)
operation = random.choice(['replace', 'swap', 'add', 'remove'])
# 替换操作
if operation == 'replace' and 'route' in neighbor[interval_idx] and neighbor[interval_idx]['route']:
route_idx = random.randint(0, len(neighbor[interval_idx]['route']) - 1)
new_route_idx = random.randint(0, len(self.candidate_routes) - 1)
new_route = [
new_route_idx + 1,
1,
self.candidate_routes[new_route_idx]['travel_time'],
random.random() # 随机优先级
]
neighbor[interval_idx]['route'][route_idx] = new_route
move = ('replace', interval_idx, route_idx, new_route_idx)
neighbors.append((neighbor, move))
# 交换操作
elif operation == 'swap' and len(solution) > 1:
interval_idx1 = random.randint(0, len(solution) - 1)
interval_idx2 = random.randint(0, len(solution) - 1)
if interval_idx1 != interval_idx2:
if ('route' in neighbor[interval_idx1] and neighbor[interval_idx1]['route'] and
'route' in neighbor[interval_idx2] and neighbor[interval_idx2]['route']):
route_idx1 = random.randint(0, len(neighbor[interval_idx1]['route']) - 1)
route_idx2 = random.randint(0, len(neighbor[interval_idx2]['route']) - 1)
# 交换路径
(neighbor[interval_idx1]['route'][route_idx1],
neighbor[interval_idx2]['route'][route_idx2]) = (
neighbor[interval_idx2]['route'][route_idx2],
neighbor[interval_idx1]['route'][route_idx1]
)
move = ('swap', interval_idx1, interval_idx2, route_idx1, route_idx2)
neighbors.append((neighbor, move))
# 添加操作
elif operation == 'add':
new_route_idx = random.randint(0, len(self.candidate_routes) - 1)
new_route = [
new_route_idx + 1,
1,
self.candidate_routes[new_route_idx]['travel_time'],
random.random() # 随机优先级
]
if 'route' not in neighbor[interval_idx]:
neighbor[interval_idx]['route'] = [new_route]
elif neighbor[interval_idx]['route'] is None:
neighbor[interval_idx]['route'] = [new_route]
else:
neighbor[interval_idx]['route'].append(new_route)
move = ('add', interval_idx, new_route_idx)
neighbors.append((neighbor, move))
# 删除操作
elif operation == 'remove' and 'route' in neighbor[interval_idx] and neighbor[interval_idx]['route']:
route_idx = random.randint(0, len(neighbor[interval_idx]['route']) - 1)
removed_route = neighbor[interval_idx]['route'].pop(route_idx)
move = ('remove', interval_idx, removed_route[0])
neighbors.append((neighbor, move))
return neighbors
def is_tabu(self, move):
"""检查移动是否在禁忌表中"""
for tabu_move in self.tabu_list:
if move == tabu_move:
return True
return False
def optimize(self):
"""执行禁忌搜索优化"""
no_improve_count = 0
start_time = time.time()
print(f"开始禁忌搜索优化,初始目标值: {self.best_objective:.2f}")
print(f"{'迭代':<5} | {'当前目标值':<12} | {'历史最优':<12} | {'改进量':<10} | {'耗时(s)':<8}")
print("-" * 60)
for iteration in range(self.max_iter):
iter_start = time.time()
neighbors = self.generate_neighbors(self.current_solution, num_neighbors=20)
best_neighbor = None
best_neighbor_obj = float('inf')
best_move = None
# 评估邻域解
for neighbor, move in neighbors:
if self.is_tabu(move):
continue
neighbor_obj = self.evaluate_solution(neighbor)
if neighbor_obj < best_neighbor_obj:
best_neighbor = neighbor
best_neighbor_obj = neighbor_obj
best_move = move
# 更新当前解
if best_neighbor is not None:
self.current_solution = best_neighbor
self.current_objective = best_neighbor_obj
self.tabu_list.append(best_move)
# 更新历史最优解
if best_neighbor_obj < self.best_objective:
improvement = self.best_objective - best_neighbor_obj
self.improvement_history.append(improvement)
self.best_solution = copy.deepcopy(best_neighbor)
self.best_objective = best_neighbor_obj
no_improve_count = 0
# 打印改进信息
iter_time = time.time() - iter_start
print(f"{iteration + 1:<5} | {best_neighbor_obj:<12.2f} | {self.best_objective:<12.2f} | "
f"+{improvement:<10.2f} | {iter_time:<8.2f}")
else:
no_improve_count += 1
else:
no_improve_count += 1
self.objective_history.append(self.current_objective)
# 提前终止条件
if no_improve_count >= self.max_no_improve:
print(f"\n提前终止:连续 {no_improve_count} 次迭代无改进")
break
total_time = time.time() - start_time
print("\n优化完成!")
print(f"总迭代次数: {iteration + 1}")
print(f"总耗时: {total_time:.2f}秒")
print(f"初始目标值: {self.objective_history[0]:.2f}")
print(f"最终目标值: {self.best_objective:.2f}")
improvement_percent = ((self.objective_history[0] - self.best_objective) / self.objective_history[0]) * 100
print(f"改进幅度: {self.objective_history[0] - self.best_objective:.2f} ({improvement_percent:.2f}%)")
return self.best_solution, self.best_objective
def plot_optimization_progress(self):
"""绘制优化过程图"""
plt.figure(figsize=(12, 6))
# 目标函数值变化
plt.subplot(1, 2, 1)
plt.plot(self.objective_history, 'b-', linewidth=2)
plt.xlabel('迭代次数')
plt.ylabel('目标函数值')
plt.title('目标函数优化过程')
plt.grid(True)
# 改进历史
if self.improvement_history:
plt.subplot(1, 2, 2)
plt.plot(self.improvement_history, 'go-', linewidth=2)
plt.xlabel('改进次数')
plt.ylabel('改进量')
plt.title('每次改进的优化量')
plt.grid(True)
plt.tight_layout()
plt.savefig('optimization_progress.png', dpi=300)
plt.show()
# ======================
# 执行禁忌搜索优化
# ======================
print("\n准备禁忌搜索优化...")
# 准备初始解数据
initial_solution = []
for i in range(min(batch_size + plus_trip, len(s)): # 确保不越界
interval_data = {
'route': s[i].get('route', None),
'pax_asg': pax_asg[i].get('record', None) if i < len(pax_asg) else None
}
initial_solution.append(interval_data)
# 创建禁忌搜索优化器
ts_optimizer = TabuSearchOptimizer(
initial_solution=initial_solution,
candidate_routes=candidate_route,
travel_time_matrix=traveltime_matrix,
passenger_data=chengke.tolist(),
vehicle_capacity=c,
headway=headway,
num_vehicles=m,
max_iter=50,
max_no_improve=10,
tabu_tenure=7
)
# 执行优化
best_solution, best_objective = ts_optimizer.optimize()
ts_optimizer.plot_optimization_progress()
# 输出最优解
print("\n最优解结构:")
for i, interval in enumerate(best_solution):
print(f"间隔 {i + 1}:")
if 'route' in interval and interval['route']:
for
j, route in enumerate(interval['route']):
print(f" 路径 {j + 1}: ID={route[0]}, 服务时间={route[2]}, 优先级={route[3]}")
else:
print(" 无路径")
print("\n优化完成!") Traceback (most recent call last):
File "F:\PycharmProjects\PythonProject1\taboo3.py", line 755, in <module>
best_solution, best_objective = ts_optimizer.optimize()
^^^^^^^^^^^^^^^^^^^^^^^
File "F:\PycharmProjects\PythonProject1\taboo3.py", line 640, in optimize
neighbors = self.generate_neighbors(self.current_solution, num_neighbors=20)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\PycharmProjects\PythonProject1\taboo3.py", line 615, in generate_neighbors
removed_route = neighbor[interval_idx]['route'].pop(route_idx)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'numpy.ndarray' object has no attribute 'pop'. Did you mean: 'ptp'?
进程已结束,退出代码为 1