添加遍历-遗传算法求解
This commit is contained in:
parent
a9ee5ceec7
commit
c9db9244b3
2
GA/ga.py
2
GA/ga.py
@ -165,7 +165,7 @@ class GA(object):
|
||||
continue
|
||||
else:
|
||||
flight_time += self.rectangles[point - 1]['flight_time'] # 注意,这里要减一!!!
|
||||
bs_time += self.rectangles[point - 1]['comp_bs_time']
|
||||
bs_time += self.rectangles[point - 1]['bs_time']
|
||||
system_time = max(flight_time + car_info['car_time'], bs_time)
|
||||
T_k_list.append(system_time)
|
||||
T_max = max(T_k_list)
|
||||
|
101
GA/main.py
Normal file
101
GA/main.py
Normal file
@ -0,0 +1,101 @@
|
||||
import random
|
||||
import math
|
||||
import yaml
|
||||
import numpy as np
|
||||
from utils import if_valid_partition, GA_solver
|
||||
from itertools import product
|
||||
import json
|
||||
from tqdm import tqdm
|
||||
|
||||
np.random.seed(42)
|
||||
random.seed(42)
|
||||
best_T = float('inf')
|
||||
best_solution = None
|
||||
best_row_boundaries = None
|
||||
best_col_boundaries = None
|
||||
|
||||
params_file = 'params2.yml'
|
||||
with open(params_file, 'r', encoding='utf-8') as file:
|
||||
params = yaml.safe_load(file)
|
||||
|
||||
H = params['H']
|
||||
W = params['W']
|
||||
k = params['num_cars']
|
||||
|
||||
flight_time_factor = params['flight_time_factor']
|
||||
comp_time_factor = params['comp_time_factor']
|
||||
trans_time_factor = params['trans_time_factor']
|
||||
car_time_factor = params['car_time_factor']
|
||||
bs_time_factor = params['bs_time_factor']
|
||||
|
||||
flight_energy_factor = params['flight_energy_factor']
|
||||
comp_energy_factor = params['comp_energy_factor']
|
||||
trans_energy_factor = params['trans_energy_factor']
|
||||
battery_energy_capacity = params['battery_energy_capacity']
|
||||
|
||||
# 定义数字列表
|
||||
numbers = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
|
||||
|
||||
# 生成所有的排列情况(取三次,每次都可以从10个数中选)
|
||||
row_product = list(product(numbers, repeat=3))
|
||||
# 对每种情况从小到大排序,并剔除重复的情况
|
||||
row_cuts_set = set(
|
||||
tuple(sorted(set(item for item in prod if item > 0))) for prod in row_product)
|
||||
row_cuts_set = sorted(row_cuts_set)
|
||||
|
||||
col_product = list(product(numbers, repeat=3))
|
||||
col_cuts_set = set(
|
||||
tuple(sorted(set(item for item in prod if item > 0))) for prod in col_product)
|
||||
col_cuts_set = sorted(col_cuts_set)
|
||||
|
||||
total_iterations = len(row_cuts_set) * len(col_cuts_set)
|
||||
with tqdm(total=total_iterations, desc="Processing") as pbar:
|
||||
for row_cuts in row_cuts_set:
|
||||
for col_cuts in col_cuts_set:
|
||||
row_boundaries = [0.0] + list(row_cuts) + [1.0]
|
||||
col_boundaries = [0.0] + list(col_cuts) + [1.0]
|
||||
|
||||
# 这里面的距离不再是比例,而是真实距离!
|
||||
rectrangles = if_valid_partition(row_boundaries, col_boundaries, params)
|
||||
if not rectrangles:
|
||||
pbar.update(1)
|
||||
continue
|
||||
else:
|
||||
# 使用遗传算法求出每一种网格划分的可行解,然后选择其中的最优解
|
||||
current_solution, current_time, to_process_idx = GA_solver(rectrangles, k)
|
||||
|
||||
if current_time < best_T:
|
||||
best_T = current_time
|
||||
best_solution = current_solution
|
||||
best_row_boundaries = row_boundaries
|
||||
best_col_boundaries = col_boundaries
|
||||
|
||||
# 将best_solution分解成每个车队的路径
|
||||
found_start_points_indices = []
|
||||
for i in range(len(best_solution)):
|
||||
if best_solution[i] in to_process_idx:
|
||||
found_start_points_indices.append(i)
|
||||
car_paths = []
|
||||
for j in range(len(found_start_points_indices) - 1):
|
||||
from_index = found_start_points_indices[j]
|
||||
end_index = found_start_points_indices[j + 1]
|
||||
car_path = []
|
||||
for k in range(from_index, end_index + 1):
|
||||
rectrangle_idx = best_solution[k]
|
||||
car_path.append(rectrangles[rectrangle_idx]['center'])
|
||||
car_paths.append(car_path)
|
||||
pbar.update(1)
|
||||
|
||||
# 输出最佳方案
|
||||
print("Best solution:", best_solution)
|
||||
print("Time:", best_T)
|
||||
print("Row boundaries:", best_row_boundaries)
|
||||
print("Col boundaries:", best_col_boundaries)
|
||||
|
||||
output_data = {
|
||||
'row_boundaries': row_boundaries,
|
||||
'col_boundaries': col_boundaries,
|
||||
'car_paths': car_paths
|
||||
}
|
||||
with open(f'./solutions/traverse_ga_{params_file}.json', 'w', encoding='utf-8') as file:
|
||||
json.dump(output_data, file, ensure_ascii=False, indent=4)
|
130
GA/main_parallel.py
Normal file
130
GA/main_parallel.py
Normal file
@ -0,0 +1,130 @@
|
||||
import random
|
||||
import math
|
||||
import yaml
|
||||
import numpy as np
|
||||
from utils import if_valid_partition, GA_solver
|
||||
from itertools import product
|
||||
import json
|
||||
from tqdm import tqdm
|
||||
from concurrent.futures import ProcessPoolExecutor, as_completed
|
||||
|
||||
np.random.seed(42)
|
||||
random.seed(42)
|
||||
|
||||
|
||||
params_file = 'params2.yml'
|
||||
with open(params_file, 'r', encoding='utf-8') as file:
|
||||
params = yaml.safe_load(file)
|
||||
|
||||
H = params['H']
|
||||
W = params['W']
|
||||
k = params['num_cars']
|
||||
|
||||
flight_time_factor = params['flight_time_factor']
|
||||
comp_time_factor = params['comp_time_factor']
|
||||
trans_time_factor = params['trans_time_factor']
|
||||
car_time_factor = params['car_time_factor']
|
||||
bs_time_factor = params['bs_time_factor']
|
||||
|
||||
flight_energy_factor = params['flight_energy_factor']
|
||||
comp_energy_factor = params['comp_energy_factor']
|
||||
trans_energy_factor = params['trans_energy_factor']
|
||||
battery_energy_capacity = params['battery_energy_capacity']
|
||||
|
||||
# 定义数字列表
|
||||
numbers = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
|
||||
|
||||
# 生成所有的排列情况(取三次,每次都可以从10个数中选)
|
||||
row_product = list(product(numbers, repeat=3))
|
||||
# 对每种情况从小到大排序,并剔除重复的情况
|
||||
row_cuts_set = set(
|
||||
tuple(sorted(set(item for item in prod if item > 0))) for prod in row_product)
|
||||
row_cuts_set = sorted(row_cuts_set)
|
||||
|
||||
col_product = list(product(numbers, repeat=3))
|
||||
col_cuts_set = set(
|
||||
tuple(sorted(set(item for item in prod if item > 0))) for prod in col_product)
|
||||
col_cuts_set = sorted(col_cuts_set)
|
||||
|
||||
|
||||
def process_partition(row_cuts, col_cuts):
|
||||
row_boundaries = [0.0] + list(row_cuts) + [1.0]
|
||||
col_boundaries = [0.0] + list(col_cuts) + [1.0]
|
||||
rectrangles = if_valid_partition(row_boundaries, col_boundaries, params)
|
||||
|
||||
if not rectrangles:
|
||||
return None # 过滤无效划分
|
||||
|
||||
current_solution, current_time, to_process_idx = GA_solver(rectrangles, k)
|
||||
|
||||
return (current_solution, current_time, row_boundaries, col_boundaries, to_process_idx, rectrangles)
|
||||
|
||||
|
||||
if __name__ == "__main__": # 重要:在 Windows 上必须加这一行
|
||||
best_T = float('inf')
|
||||
best_solution = None
|
||||
best_row_boundaries = None
|
||||
best_col_boundaries = None
|
||||
batch_size = 60 # 控制一次最多并行多少个任务
|
||||
|
||||
all_tasks = [(row_cuts, col_cuts) for row_cuts in row_cuts_set for col_cuts in col_cuts_set]
|
||||
total_iterations = len(all_tasks)
|
||||
|
||||
with ProcessPoolExecutor(max_workers=batch_size) as executor:
|
||||
futures = set()
|
||||
results = []
|
||||
|
||||
with tqdm(total=total_iterations) as pbar:
|
||||
for task in all_tasks:
|
||||
if len(futures) >= batch_size: # 如果并行任务数达到 batch_size,等待已有任务完成
|
||||
for future in as_completed(futures):
|
||||
results.append(future.result())
|
||||
pbar.update(1) # 更新进度条
|
||||
futures.clear() # 清空已完成的任务
|
||||
|
||||
futures.add(executor.submit(process_partition, *task)) # 提交新任务
|
||||
|
||||
# 处理剩余未完成的任务
|
||||
for future in as_completed(futures):
|
||||
results.append(future.result())
|
||||
pbar.update(1)
|
||||
|
||||
# 处理计算结果,找到最优解
|
||||
for result in results:
|
||||
if result:
|
||||
current_solution, current_time, row_boundaries, col_boundaries, to_process_idx, rectrangles = result
|
||||
if current_time < best_T:
|
||||
best_T = current_time
|
||||
best_solution = current_solution
|
||||
best_row_boundaries = row_boundaries
|
||||
best_col_boundaries = col_boundaries
|
||||
|
||||
# 解析最佳路径
|
||||
found_start_points_indices = []
|
||||
for i in range(len(best_solution)):
|
||||
if best_solution[i] in to_process_idx:
|
||||
found_start_points_indices.append(i)
|
||||
car_paths = []
|
||||
for j in range(len(found_start_points_indices) - 1):
|
||||
from_index = found_start_points_indices[j]
|
||||
end_index = found_start_points_indices[j + 1]
|
||||
car_path = []
|
||||
for k in range(from_index, end_index + 1):
|
||||
rectrangle_idx = best_solution[k]
|
||||
if rectrangle_idx not in to_process_idx:
|
||||
car_path.append(rectrangles[rectrangle_idx]['center'])
|
||||
car_paths.append(car_path)
|
||||
|
||||
# 输出最佳方案
|
||||
print("Best solution:", best_solution)
|
||||
print("Time:", best_T)
|
||||
print("Row boundaries:", best_row_boundaries)
|
||||
print("Col boundaries:", best_col_boundaries)
|
||||
|
||||
output_data = {
|
||||
'row_boundaries': row_boundaries,
|
||||
'col_boundaries': col_boundaries,
|
||||
'car_paths': car_paths
|
||||
}
|
||||
with open(f'./solutions/travse_ga_{params_file}.json', 'w', encoding='utf-8') as file:
|
||||
json.dump(output_data, file, ensure_ascii=False, indent=4)
|
93
GA/utils.py
Normal file
93
GA/utils.py
Normal file
@ -0,0 +1,93 @@
|
||||
import numpy as np
|
||||
from ga import GA
|
||||
|
||||
|
||||
def if_valid_partition(row_boundaries, col_boundaries, params):
|
||||
H = params['H']
|
||||
W = params['W']
|
||||
k = params['num_cars']
|
||||
|
||||
flight_time_factor = params['flight_time_factor']
|
||||
comp_time_factor = params['comp_time_factor']
|
||||
trans_time_factor = params['trans_time_factor']
|
||||
car_time_factor = params['car_time_factor']
|
||||
bs_time_factor = params['bs_time_factor']
|
||||
|
||||
flight_energy_factor = params['flight_energy_factor']
|
||||
comp_energy_factor = params['comp_energy_factor']
|
||||
trans_energy_factor = params['trans_energy_factor']
|
||||
battery_energy_capacity = params['battery_energy_capacity']
|
||||
|
||||
# 根据分割边界生成所有矩形任务
|
||||
rectangles = []
|
||||
for i in range(len(row_boundaries) - 1):
|
||||
for j in range(len(col_boundaries) - 1):
|
||||
r1 = row_boundaries[i]
|
||||
r2 = row_boundaries[i + 1]
|
||||
c1 = col_boundaries[j]
|
||||
c2 = col_boundaries[j + 1]
|
||||
d = (r2 - r1) * H * (c2 - c1) * W # 任务的照片数量(矩形面积)
|
||||
|
||||
# 求解rho
|
||||
rho_time_limit = (flight_time_factor - trans_time_factor) / \
|
||||
(comp_time_factor - trans_time_factor)
|
||||
rho_energy_limit = (battery_energy_capacity - flight_energy_factor * d - trans_energy_factor * d) / \
|
||||
(comp_energy_factor * d - trans_energy_factor * d)
|
||||
if rho_energy_limit < 0:
|
||||
return []
|
||||
|
||||
rho = min(rho_time_limit, rho_energy_limit)
|
||||
flight_time = flight_time_factor * d
|
||||
comp_time = comp_time_factor * rho * d
|
||||
trans_time = trans_time_factor * (1 - rho) * d
|
||||
bs_time = bs_time_factor * (1 - rho) * d
|
||||
|
||||
# 计算任务矩形中心,用于后续车辆移动时间计算
|
||||
center_r = (r1 + r2) / 2.0 * H
|
||||
center_c = (c1 + c2) / 2.0 * W
|
||||
|
||||
rectangles.append({
|
||||
# 'r1': r1, 'r2': r2, 'c1': c1, 'c2': c2,
|
||||
'd': d,
|
||||
'rho': rho,
|
||||
'flight_time': flight_time,
|
||||
'comp_time': comp_time,
|
||||
'trans_time': trans_time,
|
||||
'bs_time': bs_time,
|
||||
'center': (center_r, center_c)
|
||||
})
|
||||
return rectangles
|
||||
|
||||
|
||||
def GA_solver(rectangles, k):
|
||||
num_city = len(rectangles) + 1 # 划分好的区域中心点+整个区域的中心
|
||||
|
||||
# 初始化坐标 (第一个点是整个区域的中心)
|
||||
center_data = [[1 / 2.0, 1 / 2.0]]
|
||||
for rec in rectangles:
|
||||
center_data.append(rec['center'])
|
||||
center_data = np.array(center_data)
|
||||
|
||||
# 关键:有k架无人机,则再增加N-1个`点` (坐标是起始点),这些点之间的距离是inf
|
||||
for d in range(k - 1):
|
||||
center_data = np.vstack([center_data, center_data[0]])
|
||||
num_city += 1 # 增加欺骗城市
|
||||
|
||||
to_process_idx = [0]
|
||||
# print("start point:", location[0])
|
||||
for d in range(1, k): # 1, ... drone-1
|
||||
# print("added base point:", location[num_city - d])
|
||||
to_process_idx.append(num_city - d)
|
||||
|
||||
model = GA(num_drones=k, num_city=center_data.shape[0], num_total=20, data=center_data.copy(
|
||||
), to_process_idx=to_process_idx, rectangles=rectangles)
|
||||
Best_path, Best = model.run()
|
||||
|
||||
# 根据最佳路径计算各系统任务分配
|
||||
if Best_path[0] not in to_process_idx:
|
||||
Best_path.insert(0, 0)
|
||||
|
||||
if Best_path[-1] not in to_process_idx:
|
||||
Best_path.append(0)
|
||||
|
||||
return Best_path, Best, to_process_idx
|
9
env.py
9
env.py
@ -244,25 +244,25 @@ class PartitionMazeEnv(gym.Env):
|
||||
new_row = current_row - 1
|
||||
else: # 错误的移动给一些惩罚?
|
||||
new_row = current_row
|
||||
# reward -= 10
|
||||
# reward -= 1
|
||||
elif move_dir == 'down':
|
||||
if current_row < len(self.row_cuts) - 2:
|
||||
new_row = current_row + 1
|
||||
else:
|
||||
new_row = current_row
|
||||
# reward -= 10
|
||||
# reward -= 1
|
||||
elif move_dir == 'left':
|
||||
if current_col > 0:
|
||||
new_col = current_col - 1
|
||||
else:
|
||||
new_col = current_col
|
||||
# reward -= 10
|
||||
# reward -= 1
|
||||
elif move_dir == 'right':
|
||||
if current_col < len(self.col_cuts) - 2:
|
||||
new_col = current_col + 1
|
||||
else:
|
||||
new_col = current_col
|
||||
# reward -= 10
|
||||
# reward -= 1
|
||||
# 如果移动不合法,或者动作为stay,则保持原位置
|
||||
|
||||
# 检查是否移动
|
||||
@ -320,7 +320,6 @@ class PartitionMazeEnv(gym.Env):
|
||||
# # TODO 让奖励在baseline附近变化更剧烈
|
||||
# # reward = math.exp(-T / self.BASE_LINE) * 1000
|
||||
reward += self.BASE_LINE / real_T * 5
|
||||
print(real_T, "="*20)
|
||||
|
||||
# if reward > self.BASE_LINE:
|
||||
# reward -= 200
|
||||
|
@ -12,7 +12,8 @@ num_iterations = 10000
|
||||
# ---------------------------
|
||||
# 参数设置
|
||||
# ---------------------------
|
||||
with open('params.yml', 'r', encoding='utf-8') as file:
|
||||
params_file = 'params2.yml'
|
||||
with open(params_file, 'r', encoding='utf-8') as file:
|
||||
params = yaml.safe_load(file)
|
||||
|
||||
H = params['H']
|
||||
@ -38,8 +39,8 @@ best_solution = None
|
||||
|
||||
for iteration in range(num_iterations):
|
||||
# 随机生成分区的行分段数与列分段数
|
||||
R = random.randint(0, 5) # 行分段数
|
||||
C = random.randint(0, 5) # 列分段数
|
||||
R = random.randint(0, 3) # 行分段数
|
||||
C = random.randint(0, 3) # 列分段数
|
||||
|
||||
# 生成随机的行、列分割边界
|
||||
horiz = [np.clip(np.floor(random.random() * 10) /10, 0.0, 0.9) for _ in range(R)]
|
||||
@ -174,7 +175,7 @@ if best_solution is not None:
|
||||
print("行分割边界:", best_solution['row_boundaries'])
|
||||
print("列分割边界:", best_solution['col_boundaries'])
|
||||
print("每辆车的运行轨迹情况:")
|
||||
car_paths = {}
|
||||
car_paths = []
|
||||
for i in range(k):
|
||||
num_tasks = len(best_solution['system_tasks'][i])
|
||||
print(
|
||||
@ -193,7 +194,7 @@ if best_solution is not None:
|
||||
print(
|
||||
f" -> 任务{j}({current_pos[0]:.1f}, {current_pos[1]:.1f})", end="")
|
||||
print(" -> 区域中心")
|
||||
car_paths[i] = car_path
|
||||
car_paths.append(car_path)
|
||||
|
||||
# 保存分区边界和车辆轨迹到JSON文件
|
||||
output_data = {
|
||||
@ -201,7 +202,7 @@ if best_solution is not None:
|
||||
'col_boundaries': [boundary / W for boundary in best_solution['col_boundaries']],
|
||||
'car_paths': car_paths
|
||||
}
|
||||
with open('./solutions/best_solution_mtkl.json', 'w', encoding='utf-8') as f:
|
||||
with open(f'./solutions/mtkl_{params_file}.json', 'w', encoding='utf-8') as f:
|
||||
json.dump(output_data, f, ensure_ascii=False, indent=4)
|
||||
else:
|
||||
print("在给定的模拟次数内未找到满足所有约束的方案。")
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"row_boundaries": [
|
||||
0.0,
|
||||
0.2,
|
||||
0.4,
|
||||
0.7,
|
||||
0.3,
|
||||
0.6,
|
||||
0.8,
|
||||
1.0
|
||||
],
|
||||
"col_boundaries": [
|
||||
@ -11,44 +11,44 @@
|
||||
0.5,
|
||||
1.0
|
||||
],
|
||||
"car_paths": {
|
||||
"0": [
|
||||
"car_paths": [
|
||||
[
|
||||
[
|
||||
15.0,
|
||||
12.5
|
||||
22.5,
|
||||
37.5
|
||||
],
|
||||
[
|
||||
5.0,
|
||||
12.5
|
||||
]
|
||||
],
|
||||
"1": [
|
||||
[
|
||||
42.5,
|
||||
12.5
|
||||
],
|
||||
[
|
||||
42.5,
|
||||
7.5,
|
||||
37.5
|
||||
]
|
||||
],
|
||||
"2": [
|
||||
[
|
||||
[
|
||||
27.5,
|
||||
7.5,
|
||||
12.5
|
||||
],
|
||||
[
|
||||
27.5,
|
||||
45.0,
|
||||
37.5
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
22.5,
|
||||
12.5
|
||||
],
|
||||
[
|
||||
35.0,
|
||||
12.5
|
||||
],
|
||||
[
|
||||
35.0,
|
||||
37.5
|
||||
],
|
||||
[
|
||||
15.0,
|
||||
37.5
|
||||
],
|
||||
[
|
||||
5.0,
|
||||
37.5
|
||||
45.0,
|
||||
12.5
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -29,7 +29,7 @@ def visualize_solution(row_boundaries, col_boundaries, car_paths, W, H):
|
||||
ax.axvline(x=col * W, color='black', linestyle='--')
|
||||
|
||||
# 绘制每辆车的轨迹
|
||||
for system_id, path in car_paths.items():
|
||||
for system_id, path in enumerate(car_paths):
|
||||
path = [(region_center[0], region_center[1])] + path + [(region_center[0], region_center[1])]
|
||||
y, x = zip(*path)
|
||||
ax.plot(x, y, marker='o', color=colors[int(system_id) % len(colors)], label=f"系统 {system_id}")
|
||||
|
Loading…
Reference in New Issue
Block a user