实现需求
基于遗传算法在二维空间物体的排布,将随机的二维物体进行遗传进化最后得到想要的结果,代码程序中种群为100,迭代600次,每次迭代保留最好的50个种群,剩余50个种群进行交叉变异,下图为迭代的结果。
目标结果
根据matplotlib保存的图片可视化结果可以看出物体在向好的方向迭代
代码实现
干货!!!!!
import random
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import tqdm
random.seed(1024)
# 设置房间尺寸及设备尺寸
room_width = 12
room_height = 12
cabinet = (2, 2) # 机柜尺寸(宽, 高)
def calculate_ac_count(cabinet_count):
# 计算所需空调数量
# return (cabinet_count + 3) // 4
return 0
def generate_individual(cabinet_count, ac_count):
""" 生成个体,确保横向排列且纵向间隔至少为1 """
individual = []
# 为空调和机柜分配位置
for i in range(ac_count + cabinet_count):
rotation = random.randint(0, 1) # 0表示未旋转,1表示旋转
# if i < ac_count:
# width, height = (air_conditioner[1], air_conditioner[0]) if rotation else air_conditioner
# else:
width, height = (cabinet[1], cabinet[0]) if rotation else cabinet
x = random.randint(1, room_width - width)
y = random.randint(1, room_height - height)
individual.append([x, y, rotation])
# print(x,y)
return individual
def calculate_fitness(individual, cabinet_count, ac_count):
""" 计算适应度,考虑横向不重叠且纵向间隔为1 """
penalty = 200
objects = individual[:ac_count] + individual[ac_count:]
# 罚分规则
for i in range(len(objects)):
xi, yi, ri = objects[i]
for j in range(i + 1, len(objects)):
xj, yj, rj = objects[j]
# 横向不重叠检查
# horizontal_overlap = xi < xj + wj and xi + wi > xj
horizontal_overlap = abs(xi - xj) < 3
# 纵向间隔检查
vertical_gap = (abs(yi - yj) < 3)
if horizontal_overlap and vertical_gap:
penalty += 500 # 重叠或纵向间隔不足
if abs(xi - xj) == 3 and abs(yi - yj) == 3:
penalty -= 50 # 重叠或纵向间隔不足
# if (xi + xj + wj)<4 and yi -yj:
# penalty += 1000
# print("penalty",penalty)
return penalty
def crossover(ind1, ind2):
"""交叉函数"""
point = random.randint(1, len(ind1) - 1)
return ind1[:point] + ind2[point:], ind2[:point] + ind1[point:]
def mutate(individual, width, height):
"""变异函数"""
index = random.randint(0, len(individual) - 1)
individual[index] = [random.randint(1, width - 1), random.randint(1, height - 1), random.randint(0, 1)]
return individual
def genetic_algorithm(cabinet_count):
# ac_count = calculate_ac_count(cabinet_count)
ac_count = 5
population_size = 100
population = [generate_individual(cabinet_count, 0) for _ in range(population_size)]
# print("population",population)
number_of_generations = 600
# start_sorted_population = sorted(population)
sorted_population = []
for _ in tqdm.tqdm(range(1,number_of_generations+1)):
# print(_)
sorted_population = sorted(population, key=lambda x: calculate_fitness(x, cabinet_count, ac_count))
# print("sorted_population",sorted_population)
new_population = sorted_population[:50] # 保留最好的一半
while len(new_population) < population_size:
parent1, parent2 = random.sample(new_population, 2)
child1, child2 = crossover(parent1, parent2)
new_population.append(mutate(child1, room_width - 1, room_height - 1))
new_population.append(mutate(child2, room_width - 1, room_height - 1))
population = new_population
# print(population)
if _%50 ==0:
plot_layout(sorted_population[0], 0,epoch=_)
return sorted_population[0]
def plot_layout(layout, ac_count,epoch):
fig, ax = plt.subplots()
ax.set_xlim(0, room_width)
ax.set_ylim(0, room_height)
colors = ['blue', 'green']
for i, obj in enumerate(layout):
color = colors[0] if i < ac_count else colors[1]
width, height = cabinet
if obj[2] == 1: # 如果有旋转
width, height = height, width
rect = patches.Rectangle((obj[0], obj[1]), width, height, linewidth=1, edgecolor='black', facecolor=color,
alpha=0.5)
ax.add_patch(rect)
plt.title("epoch = {}".format(epoch))
plt.savefig('figures/{}.png'.format(epoch))
# plt.show()
import time
# 输入机柜数量
cabinet_count = int(input("请输入机柜数量: "))
start = time.time()
best_layout = genetic_algorithm(cabinet_count)
ac_count = calculate_ac_count(cabinet_count)
print(time.time()-start)